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

@ -28,7 +28,7 @@ Prevents disk space issues by automatically cleaning up temporary files created
### Static YAML Configuration
```yaml
# /etc/haproxy/static/config.yaml
# /etc/easyhaproxy/static/config.yaml
plugins:
enabled: [cleanup]
config:
@ -53,7 +53,7 @@ Configure the Cleanup plugin globally:
### Custom Idle Time (1 hour)
```yaml
# /etc/haproxy/static/config.yaml
# /etc/easyhaproxy/static/config.yaml
plugins:
enabled: [cleanup]
config:

View file

@ -17,11 +17,11 @@ Cloudflare replaces the visitor's IP with its own. This plugin restores the orig
## Configuration Options
| Option | Description | Default |
|-------------------|------------------------------------------|-----------------------------------|
| `enabled` | Enable/disable plugin | `true` |
| `use_builtin_ips` | Use built-in Cloudflare IP ranges | `true` |
| `ip_list_path` | Path to Cloudflare IP list | `/etc/haproxy/cloudflare_ips.lst` |
| Option | Description | Default |
|-------------------|------------------------------------------|---------------------------------------|
| `enabled` | Enable/disable plugin | `true` |
| `use_builtin_ips` | Use built-in Cloudflare IP ranges | `true` |
| `ip_list_path` | Path to Cloudflare IP list | `/etc/easyhaproxy/cloudflare_ips.lst` |
## Configuration Examples
@ -55,7 +55,7 @@ kind: Ingress
metadata:
annotations:
easyhaproxy.plugins: "cloudflare"
easyhaproxy.plugin.cloudflare.ip_list_path: "/etc/haproxy/cloudflare_ips.lst"
easyhaproxy.plugin.cloudflare.ip_list_path: "/etc/easyhaproxy/cloudflare_ips.lst"
spec:
rules:
- host: example.com
@ -72,7 +72,7 @@ spec:
### Static YAML Configuration
```yaml
# /etc/haproxy/static/config.yaml
# /etc/easyhaproxy/static/config.yaml
plugins:
config:
cloudflare:
@ -84,11 +84,11 @@ plugins:
Configure Cloudflare plugin defaults for all domains:
| Environment Variable | Config Key | Type | Default | Description |
|-------------------------------------------------|-------------------|----------|-----------------------------------|---------------------------------------|
| `EASYHAPROXY_PLUGIN_CLOUDFLARE_ENABLED` | `enabled` | boolean | `true` | Enable/disable plugin for all domains |
| `EASYHAPROXY_PLUGIN_CLOUDFLARE_USE_BUILTIN_IPS` | `use_builtin_ips` | boolean | `true` | Use built-in Cloudflare IP ranges |
| `EASYHAPROXY_PLUGIN_CLOUDFLARE_IP_LIST_PATH` | `ip_list_path` | string | `/etc/haproxy/cloudflare_ips.lst` | Path to Cloudflare IP list file |
| Environment Variable | Config Key | Type | Default | Description |
|-------------------------------------------------|-------------------|----------|---------------------------------------|---------------------------------------|
| `EASYHAPROXY_PLUGIN_CLOUDFLARE_ENABLED` | `enabled` | boolean | `true` | Enable/disable plugin for all domains |
| `EASYHAPROXY_PLUGIN_CLOUDFLARE_USE_BUILTIN_IPS` | `use_builtin_ips` | boolean | `true` | Use built-in Cloudflare IP ranges |
| `EASYHAPROXY_PLUGIN_CLOUDFLARE_IP_LIST_PATH` | `ip_list_path` | string | `/etc/easyhaproxy/cloudflare_ips.lst` | Path to Cloudflare IP list file |
**Note:** Environment variables set defaults for ALL domains. To enable/disable per-domain, use container labels or Kubernetes annotations.
@ -96,7 +96,7 @@ Configure Cloudflare plugin defaults for all domains:
```haproxy
# 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-header X-Forwarded-For %[req.hdr(CF-Connecting-IP)] if from_cloudflare
```
@ -114,7 +114,7 @@ The plugin includes the current Cloudflare IP ranges (22 ranges total):
- 2400:cb00::/32, 2606:4700::/32, 2803:f800::/32, 2405:b500::/32
- 2405:8100::/32, 2a06:98c0::/29, 2c0f:f248::/32
These ranges are automatically written to `/etc/haproxy/cloudflare_ips.lst` during each discovery cycle.
These ranges are automatically written to `/etc/easyhaproxy/cloudflare_ips.lst` during each discovery cycle.
## Important Notes

View file

@ -73,7 +73,7 @@ spec:
### Static YAML Configuration
```yaml
# /etc/haproxy/static/config.yaml
# /etc/easyhaproxy/static/config.yaml
containers:
"example.com:80":
ip: ["webapp:80"]

View file

@ -20,7 +20,7 @@ Automatically generates HAProxy `fcgi-app` configuration that defines required C
| Option | Description | Default |
|-------------------|-----------------------------------------|------------------------------------|
| `enabled` | Enable/disable plugin | `true` |
| `document_root` | Document root path | `/var/www/html` |
| `document_root` | Document root path | `/etc/easyhaproxy/www` |
| `script_filename` | Custom pattern for SCRIPT_FILENAME | `%[path]` (uses HAProxy's default) |
| `index_file` | Default index file | `index.php` |
| `path_info` | Enable PATH_INFO support | `true` |
@ -40,10 +40,10 @@ services:
easyhaproxy.http.localport: 9000
easyhaproxy.http.proto: fcgi
easyhaproxy.http.plugins: fastcgi
easyhaproxy.http.plugin.fastcgi.document_root: /var/www/html
easyhaproxy.http.plugin.fastcgi.document_root: /etc/easyhaproxy/www
easyhaproxy.http.plugin.fastcgi.index_file: index.php
volumes:
- ./app:/var/www/html
- ./app:/etc/easyhaproxy/www
```
### Docker/Docker Compose (Unix socket)
@ -57,10 +57,10 @@ services:
easyhaproxy.http.socket: /run/php/php-fpm.sock
easyhaproxy.http.proto: fcgi
easyhaproxy.http.plugins: fastcgi
easyhaproxy.http.plugin.fastcgi.document_root: /var/www/html
easyhaproxy.http.plugin.fastcgi.document_root: /etc/easyhaproxy/www
easyhaproxy.http.plugin.fastcgi.index_file: index.php
volumes:
- ./app:/var/www/html
- ./app:/etc/easyhaproxy/www
- /run/php:/run/php
```
@ -82,7 +82,7 @@ kind: Ingress
metadata:
annotations:
easyhaproxy.plugins: "fastcgi"
easyhaproxy.plugin.fastcgi.document_root: "/var/www/html"
easyhaproxy.plugin.fastcgi.document_root: "/etc/easyhaproxy/www"
easyhaproxy.plugin.fastcgi.index_file: "index.php"
spec:
rules:
@ -100,7 +100,7 @@ spec:
### Static YAML Configuration
```yaml
# /etc/haproxy/static/config.yaml
# /etc/easyhaproxy/static/config.yaml
easymapping:
- host: phpapp.local
port: 80
@ -110,7 +110,7 @@ easymapping:
- fastcgi
plugin_config:
fastcgi:
document_root: /var/www/html
document_root: /etc/easyhaproxy/www
index_file: index.php
path_info: true
```
@ -122,7 +122,7 @@ Configure FastCGI plugin defaults for all domains:
| Environment Variable | Config Key | Type | Default | Description |
|----------------------------------------------|-------------------|----------|-----------------|---------------------------------------|
| `EASYHAPROXY_PLUGIN_FASTCGI_ENABLED` | `enabled` | boolean | `true` | Enable/disable plugin for all domains |
| `EASYHAPROXY_PLUGIN_FASTCGI_DOCUMENT_ROOT` | `document_root` | string | `/var/www/html` | Document root path |
| `EASYHAPROXY_PLUGIN_FASTCGI_DOCUMENT_ROOT` | `document_root` | string | `/etc/easyhaproxy/www` | Document root path |
| `EASYHAPROXY_PLUGIN_FASTCGI_SCRIPT_FILENAME` | `script_filename` | string | `%[path]` | Custom pattern for SCRIPT_FILENAME |
| `EASYHAPROXY_PLUGIN_FASTCGI_INDEX_FILE` | `index_file` | string | `index.php` | Default index file |
| `EASYHAPROXY_PLUGIN_FASTCGI_PATH_INFO` | `path_info` | boolean | `true` | Enable PATH_INFO support |
@ -136,7 +136,7 @@ The plugin generates a top-level `fcgi-app` section and a `use-fcgi-app` directi
```haproxy
# Top-level fcgi-app definition (added after defaults, before frontends/backends)
fcgi-app fcgi_phpapp_local
docroot /var/www/html
docroot /etc/easyhaproxy/www
index index.php
path-info ^(/.+\.php)(/.*)?$

View file

@ -72,7 +72,7 @@ spec:
### Static YAML Configuration
```yaml
# /etc/haproxy/static/config.yaml
# /etc/easyhaproxy/static/config.yaml
easymapping:
- host: admin.example.com
port: 443

View file

@ -77,9 +77,9 @@ services:
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
volumes:
- ./pubkey.pem:/etc/haproxy/jwt_keys/api_pubkey.pem:ro
- ./pubkey.pem:/etc/easyhaproxy/jwt_keys/api_pubkey.pem:ro
```
### Protect Specific Paths Only
@ -87,7 +87,7 @@ services:
```yaml
labels:
easyhaproxy.http.plugins: jwt_validator
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: false
# /api/health, /api/docs, etc. remain publicly accessible
@ -98,7 +98,7 @@ labels:
```yaml
labels:
easyhaproxy.http.plugins: jwt_validator
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/public,/api/v1
easyhaproxy.http.plugin.jwt_validator.only_paths: true
# All paths except /api/public and /api/v1 are denied
@ -110,7 +110,7 @@ labels:
labels:
easyhaproxy.http.plugin.jwt_validator.issuer: none
easyhaproxy.http.plugin.jwt_validator.audience: none
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
```
### Allow Anonymous Access (Optional JWT)
@ -121,10 +121,10 @@ services:
labels:
easyhaproxy.http.host: api.example.com
easyhaproxy.http.plugins: jwt_validator
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.allow_anonymous: true
volumes:
- ./pubkey.pem:/etc/haproxy/jwt_keys/api_pubkey.pem:ro
- ./pubkey.pem:/etc/easyhaproxy/jwt_keys/api_pubkey.pem:ro
# Requests without Authorization header are allowed
# Requests with Authorization header are validated
# Invalid JWTs are rejected
@ -204,7 +204,7 @@ metadata:
easyhaproxy.plugin.jwt_validator.algorithm: "RS256"
easyhaproxy.plugin.jwt_validator.issuer: "https://auth.example.com/"
easyhaproxy.plugin.jwt_validator.audience: "https://api.example.com"
easyhaproxy.plugin.jwt_validator.pubkey_path: "/etc/haproxy/jwt_keys/api_pubkey.pem"
easyhaproxy.plugin.jwt_validator.pubkey_path: "/etc/easyhaproxy/jwt_keys/api_pubkey.pem"
easyhaproxy.plugin.jwt_validator.paths: "/api/admin,/api/users"
easyhaproxy.plugin.jwt_validator.only_paths: "false"
spec:
@ -227,7 +227,7 @@ spec:
### Static YAML Configuration
```yaml
# /etc/haproxy/static/config.yaml
# /etc/easyhaproxy/static/config.yaml
containers:
"api.example.com:443":
ip: ["api-service:8080"]
@ -238,7 +238,7 @@ containers:
algorithm: RS256
issuer: https://auth.example.com/
audience: https://api.example.com
pubkey_path: /etc/haproxy/jwt_keys/api_pubkey.pem
pubkey_path: /etc/easyhaproxy/jwt_keys/api_pubkey.pem
```
### Environment Variables
@ -277,7 +277,7 @@ http-request set-var(txn.exp) http_auth_bearer,jwt_payload_query('$.exp','int')
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()
@ -303,7 +303,7 @@ http-request set-var(txn.exp) http_auth_bearer,jwt_payload_query('$.exp','int')
# Validate JWT (only on protected paths)
http-request deny content-type 'text/html' string 'Unsupported JWT signing algorithm' unless { var(txn.alg) -m str RS256 } if jwt_protected_path
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 } if jwt_protected_path
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 } if jwt_protected_path
# Validate expiration
http-request set-var(txn.now) date() if jwt_protected_path
@ -332,7 +332,7 @@ http-request set-var(txn.exp) http_auth_bearer,jwt_payload_query('$.exp','int')
# Validate JWT (all requests at this point are on allowed paths)
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 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()
@ -356,7 +356,7 @@ http-request set-var(txn.exp) http_auth_bearer,jwt_payload_query('$.exp','int')
http-request deny content-type 'text/html' string 'Unsupported JWT signing algorithm' unless { var(txn.alg) -m str RS256 } if { req.hdr(authorization) -m found }
http-request deny content-type 'text/html' string 'Invalid JWT issuer' unless { var(txn.iss) -m str https://auth.example.com/ } if { req.hdr(authorization) -m found }
http-request deny content-type 'text/html' string 'Invalid JWT audience' unless { var(txn.aud) -m str https://api.example.com } if { req.hdr(authorization) -m found }
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 } if { req.hdr(authorization) -m found }
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 } if { req.hdr(authorization) -m found }
# Validate expiration (only if Authorization header is present)
http-request set-var(txn.now) date() if { req.hdr(authorization) -m found }