1
0
Fork 0

Add Kubernetes integration tests for EasyHAProxy examples

- Introduced a suite of pytest-based integration tests for Kubernetes using `kind`.
- Automated local installation of dependencies (`kind`, `kubectl`, and `helm`) when missing.
- Implemented fixtures for Kubernetes resource management and TLS secrets.
- Added end-to-end tests for HTTP and HTTPS ingress functionality.
This commit is contained in:
Joao Gilberto Magalhaes 2026-02-11 23:32:44 -05:00
parent 5767e55dea
commit 90b01b1f13
18 changed files with 2978 additions and 24 deletions

View file

@ -9,12 +9,28 @@ Configuration:
- algorithm: JWT signing algorithm (default: RS256)
- issuer: Expected JWT issuer (optional, set to "none"/"null" to skip validation)
- audience: Expected JWT audience (optional, set to "none"/"null" to skip validation)
- pubkey_path: Path to public key file (required if pubkey not provided)
- pubkey: Public key content as base64-encoded string (required if pubkey_path not provided)
- pubkey_path: Path to public key file in container (priority: 1)
- pubkey: Public key content as base64-encoded string (priority: 2)
- k8s_secret.pubkey: Kubernetes secret containing public key (priority: 3, Kubernetes only)
- paths: List of paths that require JWT validation (optional, if not set ALL domain is protected)
- only_paths: If true, only specified paths are accessible; if false (default), only specified paths require JWT validation
- allow_anonymous: If true, allows requests without Authorization header (validates JWT if present); if false (default), requires Authorization header
Priority Order (first configured option wins):
1. pubkey_path - Direct file path (explicit configuration)
2. pubkey - Base64-encoded key content (inline configuration)
3. k8s_secret.pubkey - Kubernetes secret name (processed by K8s processor into pubkey)
Kubernetes Secret Pattern (Kubernetes only):
For Kubernetes deployments, you can load the public key from a Kubernetes Secret:
- Auto-detect key: easyhaproxy.plugin.jwt_validator.k8s_secret.pubkey: "secret_name"
- Explicit key: easyhaproxy.plugin.jwt_validator.k8s_secret.pubkey: "secret_name/key_name"
See documentation for details:
- General k8s_secret pattern: docs/kubernetes.md#loading-plugin-configuration-from-kubernetes-secrets
- JWT Validator with Secrets: docs/Plugins/jwt-validator.md#kubernetes-with-secrets-recommended
Path Validation Logic:
- No paths configured: ALL requests to the domain require JWT validation (default behavior)
- Paths configured + only_paths=false: Only specified paths require JWT validation, others pass through
@ -46,6 +62,16 @@ Example Container Label:
easyhaproxy.http.plugin.jwt_validator.paths: /api/admin,/api/sensitive
easyhaproxy.http.plugin.jwt_validator.only_paths: true
Example Kubernetes Annotations:
# Using k8s_secret pattern (recommended for Kubernetes):
easyhaproxy.plugin.jwt_validator.k8s_secret.pubkey: "my-jwt-secret"
easyhaproxy.plugin.jwt_validator.algorithm: "RS256"
easyhaproxy.plugin.jwt_validator.issuer: "https://auth.example.com/"
easyhaproxy.plugin.jwt_validator.audience: "https://api.example.com"
# Using inline pubkey (for testing):
easyhaproxy.plugin.jwt_validator.pubkey: "LS0tLS1CRUdJTi..."
HAProxy Config Generated:
# JWT Validator - Validate JWT tokens
http-request deny content-type 'text/html' string 'Missing Authorization HTTP header' unless { req.hdr(authorization) -m found }
@ -74,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 logger_easyhaproxy
from functions import Consts, logger_easyhaproxy
from plugins import PluginContext, PluginInterface, PluginResult, PluginType
@ -178,7 +204,7 @@ class JwtValidatorPlugin(PluginInterface):
elif self.pubkey:
# Generate path for pubkey based on domain
domain_safe = context.domain.replace(".", "_").replace(":", "_")
pubkey_file = f"/etc/haproxy/jwt_keys/{domain_safe}_pubkey.pem"
pubkey_file = f"{Consts.jwt_keys}/{domain_safe}_pubkey.pem"
else:
logger_easyhaproxy.warning(f"JWT validator plugin for {context.domain}: No pubkey or pubkey_path configured")
return PluginResult()