1
0
Fork 0

Migrate configuration paths to /etc/easyhaproxy and improve health check support in E2E tests

- Refactored HAProxy configuration files, templates, and paths to use `/etc/easyhaproxy` instead of `/etc/haproxy`.
- Updated Dockerfile to generate DH params and placeholder certificates in the new configuration directory.
- Added health check support with timeout to `DockerComposeFixture` in E2E test utilities.
- Adjusted tests, templates, and plugins to use the new `Consts`-based configuration paths.
- Introduced pytest fixtures for environment isolation and temporary directory management.
This commit is contained in:
Joao Gilberto Magalhaes 2026-02-15 14:32:16 -05:00
parent 3e963228f3
commit 045dd3817e
73 changed files with 600 additions and 287 deletions

View file

@ -6,7 +6,7 @@ from dataclasses import dataclass, field
from enum import Enum
from typing import Any
from functions import logger_easyhaproxy
from functions import logger_easyhaproxy, Consts
class PluginType(Enum):
@ -108,12 +108,12 @@ class PluginManager:
Initialize the plugin manager
Args:
plugins_dir: Directory containing plugin files (defaults to EASYHAPROXY_PLUGINS_DIR env var or /etc/haproxy/plugins)
plugins_dir: Directory containing plugin files (defaults to EASYHAPROXY_PLUGINS_DIR env var or /etc/easyhaproxy/plugins)
abort_on_error: If True, abort on plugin errors; if False, log and continue
"""
self.plugins_dir = plugins_dir or os.getenv(
"EASYHAPROXY_PLUGINS_DIR",
"/etc/haproxy/plugins"
Consts.base_path + "/plugins"
)
self.abort_on_error = abort_on_error
self.plugins: dict[str, PluginInterface] = {}

View file

@ -8,7 +8,7 @@ The plugin includes built-in Cloudflare IP ranges that are automatically
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_path: Path to file containing Cloudflare IP ranges (default: /etc/easyhaproxy/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)
@ -17,7 +17,7 @@ Example YAML config:
plugins:
cloudflare:
enabled: true
ip_list_path: /etc/haproxy/cloudflare_ips.lst
ip_list_path: /etc/easyhaproxy/cloudflare_ips.lst
use_builtin_ips: true
update_log_format: true
@ -32,7 +32,7 @@ Example Container Label:
HAProxy Config Generated:
# Cloudflare - Restore original visitor IP
acl from_cloudflare src -f /etc/haproxy/cloudflare_ips.lst
acl from_cloudflare src -f /etc/easyhaproxy/cloudflare_ips.lst
http-request set-var(txn.real_ip) req.hdr(CF-Connecting-IP) if from_cloudflare
http-request set-header X-Forwarded-For %[var(txn.real_ip)] if from_cloudflare
@ -48,7 +48,7 @@ import sys
# Add parent directory to path for imports
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from functions import logger_easyhaproxy
from functions import logger_easyhaproxy, Consts
from plugins import InitializationResult, PluginContext, PluginInterface, PluginResult, PluginType, ResourceRequest
@ -85,7 +85,7 @@ class CloudflarePlugin(PluginInterface):
]
def __init__(self):
self.ip_list_path = "/etc/haproxy/cloudflare_ips.lst"
self.ip_list_path = Consts.base_path + "/cloudflare_ips.lst"
self.enabled = True
self.use_builtin_ips = True
self.update_log_format = True

View file

@ -10,7 +10,7 @@ The plugin creates:
Configuration:
- enabled: Enable/disable the plugin (default: true)
- document_root: Document root path (default: /var/www/html)
- document_root: Document root path (default: /etc/easyhaproxy/www)
- script_filename: Pattern for SCRIPT_FILENAME (default: %[path])
- index_file: Default index file (default: index.php)
- path_info: Enable PATH_INFO support (default: true)
@ -39,6 +39,8 @@ Example Kubernetes Annotation:
import os
import sys
from functions import Consts
# Add parent directory to path for imports
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
@ -50,7 +52,7 @@ class FastcgiPlugin(PluginInterface):
def __init__(self):
self.enabled = True
self.document_root = "/var/www/html"
self.document_root = Consts.base_path + "/www"
self.script_filename = "%[path]"
self.index_file = "index.php"
self.path_info = True

View file

@ -47,7 +47,7 @@ Example YAML config:
algorithm: RS256
issuer: https://myaccount.auth0.com/
audience: https://api.mywebsite.com
pubkey_path: /etc/haproxy/jwt_keys/pubkey.pem
pubkey_path: /etc/easyhaproxy/jwt_keys/pubkey.pem
paths:
- /api/admin
- /api/sensitive
@ -58,7 +58,7 @@ Example Container Label:
easyhaproxy.http.plugin.jwt_validator.algorithm: RS256
easyhaproxy.http.plugin.jwt_validator.issuer: https://auth.example.com/
easyhaproxy.http.plugin.jwt_validator.audience: https://api.example.com
easyhaproxy.http.plugin.jwt_validator.pubkey_path: /etc/haproxy/jwt_keys/api_pubkey.pem
easyhaproxy.http.plugin.jwt_validator.pubkey_path: /etc/easyhaproxy/jwt_keys/api_pubkey.pem
easyhaproxy.http.plugin.jwt_validator.paths: /api/admin,/api/sensitive
easyhaproxy.http.plugin.jwt_validator.only_paths: true
@ -86,7 +86,7 @@ HAProxy Config Generated:
http-request deny content-type 'text/html' string 'Unsupported JWT signing algorithm' unless { var(txn.alg) -m str RS256 }
http-request deny content-type 'text/html' string 'Invalid JWT issuer' unless { var(txn.iss) -m str https://auth.example.com/ }
http-request deny content-type 'text/html' string 'Invalid JWT audience' unless { var(txn.aud) -m str https://api.example.com }
http-request deny content-type 'text/html' string 'Invalid JWT signature' unless { http_auth_bearer,jwt_verify(txn.alg,"/etc/haproxy/jwt_keys/api_pubkey.pem") -m int 1 }
http-request deny content-type 'text/html' string 'Invalid JWT signature' unless { http_auth_bearer,jwt_verify(txn.alg,"/etc/easyhaproxy/jwt_keys/api_pubkey.pem") -m int 1 }
# Validate expiration
http-request set-var(txn.now) date()
@ -100,7 +100,7 @@ import sys
# Add parent directory to path for imports
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from functions import Functions, logger_easyhaproxy
from functions import Functions, logger_easyhaproxy, Consts
from plugins import InitializationResult, PluginContext, PluginInterface, PluginResult, PluginType, ResourceRequest
@ -118,7 +118,7 @@ class JwtValidatorPlugin(PluginInterface):
self.only_paths = False # If true, only specified paths are accessible
self.allow_anonymous = False # If true, allow requests without Authorization header
# Make JWT_KEYS_DIR configurable via environment variable (for testing)
self.jwt_keys_dir = os.getenv("EASYHAPROXY_JWT_KEYS_DIR", "/etc/haproxy/jwt_keys")
self.jwt_keys_dir = os.getenv("EASYHAPROXY_JWT_KEYS_DIR", Consts.base_path + "/jwt_keys")
@property
def name(self) -> str: