1
0
Fork 0

Add Cloudflare plugin tests with base64-encoded IP list support

- Enhanced the Cloudflare plugin by adding support for base64-encoded IP lists, prioritizing them over built-in lists.
- Introduced Kubernetes integration tests for the Cloudflare IP restoration feature.
- Validated plugin behavior for resource creation, pod readiness, ingress access, and HAProxy configurations.
- Improved annotations in `cloudflare.yml` for Kubernetes-native compatibility.
- Updated unit tests to cover IP list precedence, invalid base64 handling, and metadata verification.
This commit is contained in:
Joao Gilberto Magalhaes 2026-02-12 16:03:50 -05:00
parent 90b01b1f13
commit 1fd5873dc9
4 changed files with 439 additions and 10 deletions

View file

@ -9,6 +9,7 @@ updated and written to the IP list file.
Configuration:
- ip_list_path: Path to file containing Cloudflare IP ranges (default: /etc/haproxy/cloudflare_ips.lst)
- ip_list: Base64-encoded list of IP ranges (one per line), takes precedence over ip_list_path
- use_builtin_ips: Use built-in Cloudflare IP ranges (default: true)
- update_log_format: Update HAProxy log format to show real visitor IP (default: true)
@ -20,6 +21,11 @@ Example YAML config:
use_builtin_ips: true
update_log_format: true
Example Kubernetes Ingress Annotation:
easyhaproxy.plugins: "cloudflare"
easyhaproxy.plugin.cloudflare.ip_list: "MTAuMC4wLjAvOAoxNzIuMTYuMC4wLzEyCjE5Mi4xNjguMC4wLzE2Cg=="
easyhaproxy.plugin.cloudflare.update_log_format: "true"
Example Container Label:
easyhaproxy.http.plugins: "cloudflare"
easyhaproxy.http.plugin.cloudflare.update_log_format: "true"
@ -35,6 +41,7 @@ Log Format (when update_log_format=true):
Format: real_ip/connection_ip [timestamp] request status bytes ...
"""
import base64
import os
import sys
@ -82,6 +89,7 @@ class CloudflarePlugin(PluginInterface):
self.enabled = True
self.use_builtin_ips = True
self.update_log_format = True
self.ip_list = None
@property
def name(self) -> str:
@ -98,6 +106,7 @@ class CloudflarePlugin(PluginInterface):
Args:
config: Dictionary with configuration options
- ip_list_path: Path to Cloudflare IP list file
- ip_list: Base64-encoded list of IP ranges (one per line)
- enabled: Whether plugin is enabled
- use_builtin_ips: Use built-in Cloudflare IP ranges (default: true)
- update_log_format: Update HAProxy log format to show real IP (default: true)
@ -105,6 +114,14 @@ class CloudflarePlugin(PluginInterface):
if "ip_list_path" in config:
self.ip_list_path = config["ip_list_path"]
if "ip_list" in config:
# Decode from base64 (consistent with JWT validator pubkey parameter)
try:
self.ip_list = base64.b64decode(config["ip_list"]).decode('utf-8')
except Exception as e:
logger_easyhaproxy.warning(f"Cloudflare plugin: Failed to decode ip_list: {e}")
self.ip_list = None
if "enabled" in config:
self.enabled = str(config["enabled"]).lower() in ["true", "1", "yes"]
@ -127,22 +144,41 @@ class CloudflarePlugin(PluginInterface):
if not self.enabled:
return PluginResult()
# Write built-in Cloudflare IPs to file if using built-in IPs
if self.use_builtin_ips:
# Determine which IPs to write to file
ips_to_write = None
ip_source = None
if self.ip_list:
# Priority 1: Base64-encoded ip_list from annotation
ip_lines = [line.strip() for line in self.ip_list.split('\n') if line.strip()]
ips_to_write = ip_lines
ip_source = "base64 ip_list"
elif self.use_builtin_ips:
# Priority 2: Built-in Cloudflare IPs
ips_to_write = self.CLOUDFLARE_IPS
ip_source = "built-in IPs"
# Write IPs to file if we have any
if ips_to_write:
try:
# Create directory if it doesn't exist
# Create directory if needed
ip_list_dir = os.path.dirname(self.ip_list_path)
if ip_list_dir and not os.path.exists(ip_list_dir):
os.makedirs(ip_list_dir, exist_ok=True)
# Write Cloudflare IPs to file
# Write IPs to file
with open(self.ip_list_path, 'w') as f:
for ip_range in self.CLOUDFLARE_IPS:
for ip_range in ips_to_write:
f.write(f"{ip_range}\n")
logger_easyhaproxy.info(f"Cloudflare plugin: Written {len(self.CLOUDFLARE_IPS)} IP ranges to {self.ip_list_path}")
logger_easyhaproxy.info(
f"Cloudflare plugin: Written {len(ips_to_write)} IP ranges "
f"from {ip_source} to {self.ip_list_path}"
)
except Exception as e:
logger_easyhaproxy.warning(f"Cloudflare plugin: Failed to write IP list to {self.ip_list_path}: {e}")
logger_easyhaproxy.warning(
f"Cloudflare plugin: Failed to write IP list to {self.ip_list_path}: {e}"
)
# Generate HAProxy config snippet for backend
haproxy_config = f"""# Cloudflare - Restore original visitor IP
@ -164,9 +200,11 @@ log-format "%{+Q}[var(txn.real_ip)]:-/%ci:%cp [%tr] %ft %b/%s %TR/%Tw/%Tc/%Tr/%T
metadata={
"domain": context.domain,
"ip_list_path": self.ip_list_path,
"ip_list_provided": self.ip_list is not None,
"use_builtin_ips": self.use_builtin_ips,
"update_log_format": self.update_log_format,
"defaults_config": log_format_config,
"ip_count": len(self.CLOUDFLARE_IPS) if self.use_builtin_ips else None
"ip_count": len(ips_to_write) if ips_to_write else None,
"ip_source": ip_source if ips_to_write else "existing file"
}
)