Enhance plugin documentation and add Kubernetes plugin annotation support
- Updated `plugins.md` and `kubernetes.md` with detailed plugin configuration examples for Kubernetes annotations.
- Introduced support for `easyhaproxy.plugins` and `easyhaproxy.plugin.{name}.{key}` annotations in Kubernetes.
- Added comprehensive examples for JWT validation, IP whitelisting, and deny pages
This commit is contained in:
parent
ebc4b2bf7a
commit
75d6833769
3 changed files with 206 additions and 6 deletions
|
|
@ -98,9 +98,144 @@ You don't need to expose any port in your container.
|
||||||
| easyhaproxy.redirect | (optional) JSON. Key pair with a domain and its destination. | *empty* | \{"domain":"redirect_url"} |
|
| easyhaproxy.redirect | (optional) JSON. Key pair with a domain and its destination. | *empty* | \{"domain":"redirect_url"} |
|
||||||
| easyhaproxy.mode | (optional) Set the HTTP mode for that connection. | http | http or tcp |
|
| easyhaproxy.mode | (optional) Set the HTTP mode for that connection. | http | http or tcp |
|
||||||
| easyhaproxy.listen_port | (optional) Override the HTTP listen port created for that ingress | 80 | 8081 |
|
| easyhaproxy.listen_port | (optional) Override the HTTP listen port created for that ingress | 80 | 8081 |
|
||||||
|
| easyhaproxy.plugins | (optional) Comma-separated list of plugins to enable for this ingress | *empty* | cloudflare,deny_pages |
|
||||||
|
| easyhaproxy.plugin.{name}.{key} | (optional) Plugin-specific configuration (see [Using Plugins](plugins.md)) | *varies* | See examples below |
|
||||||
|
|
||||||
**Important**: The annotations are per ingress and applied to all hosts in that ingress configuration.
|
**Important**: The annotations are per ingress and applied to all hosts in that ingress configuration.
|
||||||
|
|
||||||
|
## Using Plugins with Kubernetes
|
||||||
|
|
||||||
|
Plugins extend HAProxy configuration with additional functionality like JWT validation, IP whitelisting, or Cloudflare IP restoration. For a complete list of available plugins, see the [Using Plugins](plugins.md) guide.
|
||||||
|
|
||||||
|
### Enabling Plugins for an Ingress
|
||||||
|
|
||||||
|
Add the `easyhaproxy.plugins` annotation with a comma-separated list of plugin names:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
kubernetes.io/ingress.class: easyhaproxy-ingress
|
||||||
|
easyhaproxy.plugins: "cloudflare,deny_pages"
|
||||||
|
name: example-ingress
|
||||||
|
namespace: example
|
||||||
|
spec:
|
||||||
|
rules:
|
||||||
|
- host: example.org
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- backend:
|
||||||
|
service:
|
||||||
|
name: example-service
|
||||||
|
port:
|
||||||
|
number: 8080
|
||||||
|
pathType: ImplementationSpecific
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuring Plugin Options
|
||||||
|
|
||||||
|
Use `easyhaproxy.plugin.{plugin_name}.{option}` annotations to configure individual plugins:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
kubernetes.io/ingress.class: easyhaproxy-ingress
|
||||||
|
easyhaproxy.plugins: "deny_pages"
|
||||||
|
easyhaproxy.plugin.deny_pages.paths: "/admin,/private,/config"
|
||||||
|
easyhaproxy.plugin.deny_pages.status_code: "403"
|
||||||
|
name: secure-app-ingress
|
||||||
|
namespace: production
|
||||||
|
spec:
|
||||||
|
rules:
|
||||||
|
- host: myapp.example.com
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- backend:
|
||||||
|
service:
|
||||||
|
name: myapp-service
|
||||||
|
port:
|
||||||
|
number: 8080
|
||||||
|
pathType: ImplementationSpecific
|
||||||
|
```
|
||||||
|
|
||||||
|
### Common Plugin Examples
|
||||||
|
|
||||||
|
**Protect API with JWT validation:**
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
kubernetes.io/ingress.class: easyhaproxy-ingress
|
||||||
|
easyhaproxy.plugins: "jwt_validator"
|
||||||
|
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"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note:** For JWT validation, you'll need to mount the public key file into the EasyHAProxy pod. See [Using Plugins](plugins.md#jwt-validator-plugin-domain) for details.
|
||||||
|
|
||||||
|
**Restrict access to specific IPs:**
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
kubernetes.io/ingress.class: easyhaproxy-ingress
|
||||||
|
easyhaproxy.plugins: "ip_whitelist"
|
||||||
|
easyhaproxy.plugin.ip_whitelist.allowed_ips: "192.168.1.0/24,10.0.0.5"
|
||||||
|
easyhaproxy.plugin.ip_whitelist.status_code: "403"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Restore Cloudflare visitor IPs:**
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
kubernetes.io/ingress.class: easyhaproxy-ingress
|
||||||
|
easyhaproxy.plugins: "cloudflare"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Multiple plugins together:**
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
kubernetes.io/ingress.class: easyhaproxy-ingress
|
||||||
|
easyhaproxy.plugins: "cloudflare,deny_pages"
|
||||||
|
easyhaproxy.plugin.deny_pages.paths: "/wp-admin,/wp-login.php"
|
||||||
|
easyhaproxy.plugin.deny_pages.status_code: "404"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Global Plugin Configuration
|
||||||
|
|
||||||
|
Some plugins (like `cleanup`) are global and execute once per discovery cycle. Configure these via environment variables or YAML configuration:
|
||||||
|
|
||||||
|
**Using Helm values.yaml:**
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
easyhaproxy:
|
||||||
|
plugins:
|
||||||
|
enabled: cleanup
|
||||||
|
config:
|
||||||
|
cleanup:
|
||||||
|
max_idle_time: 600
|
||||||
|
```
|
||||||
|
|
||||||
|
**Using environment variables:**
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
env:
|
||||||
|
- name: EASYHAPROXY_PLUGINS_ENABLED
|
||||||
|
value: "cleanup"
|
||||||
|
- name: EASYHAPROXY_PLUGIN_CLEANUP_MAX_IDLE_TIME
|
||||||
|
value: "600"
|
||||||
|
```
|
||||||
|
|
||||||
|
For more information on plugin types and available plugins, see the [Using Plugins](plugins.md) guide.
|
||||||
|
|
||||||
## Certbot / ACME / Letsencrypt
|
## Certbot / ACME / Letsencrypt
|
||||||
|
|
||||||
It is necessary add the annotation `easyhaproxy.certbot` to the ingress configuration:
|
It is necessary add the annotation `easyhaproxy.certbot` to the ingress configuration:
|
||||||
|
|
|
||||||
|
|
@ -236,11 +236,52 @@ http-request deny content-type 'text/html' string 'JWT has expired' if { var(txn
|
||||||
|
|
||||||
## Configuration Methods
|
## Configuration Methods
|
||||||
|
|
||||||
Plugins can be configured using three methods, listed in order of precedence (highest to lowest):
|
Plugins can be configured using different methods depending on your deployment environment:
|
||||||
|
|
||||||
### 1. Container Labels (Domain Plugins Only)
|
### 1. Kubernetes Annotations (Ingress Resources)
|
||||||
|
|
||||||
Enable and configure domain plugins for specific containers:
|
Enable and configure domain plugins for specific Kubernetes ingresses:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
kubernetes.io/ingress.class: easyhaproxy-ingress
|
||||||
|
# Enable plugins
|
||||||
|
easyhaproxy.plugins: "jwt_validator,deny_pages"
|
||||||
|
# Configure jwt_validator plugin
|
||||||
|
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"
|
||||||
|
# Configure deny_pages plugin
|
||||||
|
easyhaproxy.plugin.deny_pages.paths: "/admin,/private"
|
||||||
|
easyhaproxy.plugin.deny_pages.status_code: "403"
|
||||||
|
name: api-ingress
|
||||||
|
namespace: production
|
||||||
|
spec:
|
||||||
|
rules:
|
||||||
|
- host: api.example.com
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- backend:
|
||||||
|
service:
|
||||||
|
name: api-service
|
||||||
|
port:
|
||||||
|
number: 8080
|
||||||
|
pathType: ImplementationSpecific
|
||||||
|
```
|
||||||
|
|
||||||
|
**Annotation format:**
|
||||||
|
- Enable plugins: `easyhaproxy.plugins: plugin1,plugin2`
|
||||||
|
- Configure plugin: `easyhaproxy.plugin.<plugin_name>.<config_key>: value`
|
||||||
|
|
||||||
|
See the [Kubernetes guide](kubernetes.md#using-plugins-with-kubernetes) for more examples.
|
||||||
|
|
||||||
|
### 2. Container Labels (Docker/Docker Compose)
|
||||||
|
|
||||||
|
Enable and configure domain plugins for specific Docker containers:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
services:
|
services:
|
||||||
|
|
@ -262,7 +303,7 @@ services:
|
||||||
|
|
||||||
**Where `<definition>` is:** `http`, `https`, `tcp`, etc.
|
**Where `<definition>` is:** `http`, `https`, `tcp`, etc.
|
||||||
|
|
||||||
### 2. Static YAML Configuration
|
### 3. Static YAML Configuration
|
||||||
|
|
||||||
Configure plugins globally in `/etc/haproxy/static/config.yaml`:
|
Configure plugins globally in `/etc/haproxy/static/config.yaml`:
|
||||||
|
|
||||||
|
|
@ -288,7 +329,7 @@ plugins:
|
||||||
enabled: false # Disable globally, enable per-container via labels
|
enabled: false # Disable globally, enable per-container via labels
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. Environment Variables
|
### 4. Environment Variables
|
||||||
|
|
||||||
Configure plugins via environment variables:
|
Configure plugins via environment variables:
|
||||||
|
|
||||||
|
|
@ -461,11 +502,18 @@ DEBUG: Plugin cloudflare metadata: {'domain': 'example.com', 'ip_list_path': '/e
|
||||||
### Configuration Not Applied
|
### Configuration Not Applied
|
||||||
|
|
||||||
**Check precedence order:**
|
**Check precedence order:**
|
||||||
|
|
||||||
|
For Kubernetes deployments:
|
||||||
|
1. Ingress annotations (highest)
|
||||||
|
2. YAML configuration
|
||||||
|
3. Environment variables (lowest)
|
||||||
|
|
||||||
|
For Docker deployments:
|
||||||
1. Container labels (highest)
|
1. Container labels (highest)
|
||||||
2. YAML configuration
|
2. YAML configuration
|
||||||
3. Environment variables (lowest)
|
3. Environment variables (lowest)
|
||||||
|
|
||||||
Container labels override YAML and env vars.
|
Per-ingress/per-container settings override global configuration.
|
||||||
|
|
||||||
### Plugin Output Missing
|
### Plugin Output Missing
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -251,6 +251,13 @@ class Kubernetes(ProcessorInterface):
|
||||||
redirect = self._check_annotation(ingress.metadata.annotations, "easyhaproxy.redirect")
|
redirect = self._check_annotation(ingress.metadata.annotations, "easyhaproxy.redirect")
|
||||||
mode = self._check_annotation(ingress.metadata.annotations, "easyhaproxy.mode")
|
mode = self._check_annotation(ingress.metadata.annotations, "easyhaproxy.mode")
|
||||||
listen_port = self._check_annotation(ingress.metadata.annotations, "easyhaproxy.listen_port", 80)
|
listen_port = self._check_annotation(ingress.metadata.annotations, "easyhaproxy.listen_port", 80)
|
||||||
|
plugins = self._check_annotation(ingress.metadata.annotations, "easyhaproxy.plugins")
|
||||||
|
|
||||||
|
# Extract plugin-specific configurations
|
||||||
|
plugin_annotations = {}
|
||||||
|
for annotation_key, annotation_value in ingress.metadata.annotations.items():
|
||||||
|
if annotation_key.startswith("easyhaproxy.plugin."):
|
||||||
|
plugin_annotations[annotation_key] = annotation_value
|
||||||
|
|
||||||
data = {"creation_timestamp": ingress.metadata.creation_timestamp.strftime("%x %X"),
|
data = {"creation_timestamp": ingress.metadata.creation_timestamp.strftime("%x %X"),
|
||||||
"resource_version": ingress.metadata.resource_version, "namespace": ingress.metadata.namespace}
|
"resource_version": ingress.metadata.resource_version, "namespace": ingress.metadata.namespace}
|
||||||
|
|
@ -297,6 +304,16 @@ class Kubernetes(ProcessorInterface):
|
||||||
rule_data["%s.mode" % definition] = mode
|
rule_data["%s.mode" % definition] = mode
|
||||||
rule_data["%s.balance" % definition] = self._check_annotation(ingress.metadata.annotations, "easyhaproxy.balance", "roundrobin")
|
rule_data["%s.balance" % definition] = self._check_annotation(ingress.metadata.annotations, "easyhaproxy.balance", "roundrobin")
|
||||||
|
|
||||||
|
# Add plugin configuration
|
||||||
|
if plugins is not None:
|
||||||
|
rule_data["%s.plugins" % definition] = plugins
|
||||||
|
|
||||||
|
# Add plugin-specific configurations
|
||||||
|
for plugin_key, plugin_value in plugin_annotations.items():
|
||||||
|
# Convert easyhaproxy.plugin.X.Y to easyhaproxy.{definition}.plugin.X.Y
|
||||||
|
plugin_config_key = plugin_key.replace("easyhaproxy.plugin.", "%s.plugin." % definition)
|
||||||
|
rule_data[plugin_config_key] = plugin_value
|
||||||
|
|
||||||
service_name = rule.http.paths[0].backend.service.name
|
service_name = rule.http.paths[0].backend.service.name
|
||||||
try:
|
try:
|
||||||
api_response = self.api_instance.read_namespaced_service(service_name, ingress.metadata.namespace)
|
api_response = self.api_instance.read_namespaced_service(service_name, ingress.metadata.namespace)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue