diff --git a/deploy/kubernetes/README.md b/deploy/kubernetes/README.md new file mode 100644 index 0000000..5030bba --- /dev/null +++ b/deploy/kubernetes/README.md @@ -0,0 +1,91 @@ +# Kubernetes Static Manifests + +⚠️ **IMPORTANT**: These files are **auto-generated** from Helm templates. Do not edit them directly! + +## About These Files + +This directory contains pre-rendered Kubernetes manifests for deploying EasyHAProxy without Helm. These are generated from the Helm chart at `../../helm/easyhaproxy/` and provide three deployment options: + +| File | Type | Use Case | +|-----------------------------|------------------------|--------------------------------------------------------------| +| `easyhaproxy-daemonset.yml` | DaemonSet + hostPort | Direct host networking, best for bare-metal or simple setups | +| `easyhaproxy-nodeport.yml` | Deployment + NodePort | Exposes via NodePort (31080/31443/31936) | +| `easyhaproxy-clusterip.yml` | Deployment + ClusterIP | Internal cluster access only, use with external LoadBalancer | + +## How to Use + +Choose the manifest that fits your deployment scenario: + +```bash +# Option 1: DaemonSet mode (hostPort) +kubectl apply -f easyhaproxy-daemonset.yml + +# Option 2: NodePort mode +kubectl apply -f easyhaproxy-nodeport.yml + +# Option 3: ClusterIP mode +kubectl apply -f easyhaproxy-clusterip.yml +``` + +For more details, see the [Kubernetes documentation](../../docs/kubernetes.md). + +## Regenerating These Files + +**When to regenerate:** +- After modifying Helm chart templates (`helm/easyhaproxy/templates/`) +- After updating default values (`helm/easyhaproxy/values.yaml`) +- After a new release to sync with latest Helm chart + +**How to regenerate:** + +```bash +# Navigate to helm directory +cd helm + +# Generate DaemonSet manifest (hostPort mode) +helm template ingress ./easyhaproxy --namespace easyhaproxy \ + --set service.create=false \ + > ../deploy/kubernetes/easyhaproxy-daemonset.yml + +# Generate NodePort manifest +helm template ingress ./easyhaproxy --namespace easyhaproxy \ + --set service.create=true \ + --set service.type=NodePort \ + > ../deploy/kubernetes/easyhaproxy-nodeport.yml + +# Generate ClusterIP manifest +helm template ingress ./easyhaproxy --namespace easyhaproxy \ + --set service.create=true \ + --set service.type=ClusterIP \ + > ../deploy/kubernetes/easyhaproxy-clusterip.yml +``` + +**Verify regeneration:** + +```bash +# Check IngressClass is present +grep "kind: IngressClass" ../deploy/kubernetes/easyhaproxy-*.yml + +# Validate manifest syntax +kubectl apply --dry-run=client -f ../deploy/kubernetes/easyhaproxy-daemonset.yml +``` + +## What's Included + +Each manifest contains: +- **ServiceAccount**: RBAC identity for EasyHAProxy +- **ClusterRole**: Permissions to read Ingress resources and Secrets +- **ClusterRoleBinding**: Binds the role to the service account +- **IngressClass**: Defines `easyhaproxy` as the ingress class +- **DaemonSet/Deployment**: The EasyHAProxy workload +- **Service** (NodePort/ClusterIP only): Network exposure + +## Source of Truth + +The Helm chart at `../../helm/easyhaproxy/` is the **source of truth**. All changes should be made there, then these static manifests regenerated. + +**To modify these deployments:** +1. Edit Helm templates in `helm/easyhaproxy/templates/` +2. Update default values in `helm/easyhaproxy/values.yaml` +3. Regenerate static manifests using commands above +4. Commit both Helm changes and regenerated manifests \ No newline at end of file diff --git a/deploy/kubernetes/easyhaproxy-clusterip.yml b/deploy/kubernetes/easyhaproxy-clusterip.yml index 18bafaf..bf1da88 100644 --- a/deploy/kubernetes/easyhaproxy-clusterip.yml +++ b/deploy/kubernetes/easyhaproxy-clusterip.yml @@ -6,7 +6,7 @@ metadata: name: ingress-easyhaproxy namespace: easyhaproxy labels: - helm.sh/chart: easyhaproxy-1.0.1 + helm.sh/chart: easyhaproxy-1.0.0 app.kubernetes.io/name: easyhaproxy app.kubernetes.io/instance: ingress app.kubernetes.io/version: "5.0.0" @@ -19,7 +19,7 @@ metadata: name: ingress-easyhaproxy namespace: easyhaproxy labels: - helm.sh/chart: easyhaproxy-1.0.1 + helm.sh/chart: easyhaproxy-1.0.0 app.kubernetes.io/name: easyhaproxy app.kubernetes.io/instance: ingress app.kubernetes.io/version: "5.0.0" @@ -41,12 +41,11 @@ rules: - list - watch - apiGroups: - - "extensions" - "networking.k8s.io" resources: - ingresses # - ingresses/status - # - ingressclasses + - ingressclasses verbs: - get - list @@ -85,7 +84,7 @@ metadata: name: ingress-easyhaproxy namespace: easyhaproxy labels: - helm.sh/chart: easyhaproxy-1.0.1 + helm.sh/chart: easyhaproxy-1.0.0 app.kubernetes.io/name: easyhaproxy app.kubernetes.io/instance: ingress app.kubernetes.io/version: "5.0.0" @@ -107,7 +106,7 @@ metadata: name: ingress-easyhaproxy namespace: easyhaproxy labels: - helm.sh/chart: easyhaproxy-1.0.1 + helm.sh/chart: easyhaproxy-1.0.0 app.kubernetes.io/name: easyhaproxy app.kubernetes.io/instance: ingress app.kubernetes.io/version: "5.0.0" @@ -139,12 +138,13 @@ metadata: name: ingress-easyhaproxy namespace: easyhaproxy labels: - helm.sh/chart: easyhaproxy-1.0.1 + helm.sh/chart: easyhaproxy-1.0.0 app.kubernetes.io/name: easyhaproxy app.kubernetes.io/instance: ingress app.kubernetes.io/version: "5.0.0" app.kubernetes.io/managed-by: Helm spec: + replicas: 1 selector: matchLabels: app.kubernetes.io/name: easyhaproxy @@ -155,15 +155,6 @@ spec: app.kubernetes.io/name: easyhaproxy app.kubernetes.io/instance: ingress spec: - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: easyhaproxy/node - operator: In - values: - - master serviceAccountName: ingress-easyhaproxy securityContext: {} @@ -184,9 +175,7 @@ spec: containerPort: 1936 resources: - requests: - cpu: 100m - memory: 128Mi + {} env: - name: EASYHAPROXY_DISCOVER value: kubernetes @@ -206,3 +195,17 @@ spec: value: DEBUG - name: CERTBOT_LOG_LEVEL value: DEBUG +--- +# Source: easyhaproxy/templates/ingressclass.yaml +apiVersion: networking.k8s.io/v1 +kind: IngressClass +metadata: + name: easyhaproxy + labels: + helm.sh/chart: easyhaproxy-1.0.0 + app.kubernetes.io/name: easyhaproxy + app.kubernetes.io/instance: ingress + app.kubernetes.io/version: "5.0.0" + app.kubernetes.io/managed-by: Helm +spec: + controller: byjg.com/easyhaproxy diff --git a/deploy/kubernetes/easyhaproxy-daemonset.yml b/deploy/kubernetes/easyhaproxy-daemonset.yml index 441aaac..190f865 100644 --- a/deploy/kubernetes/easyhaproxy-daemonset.yml +++ b/deploy/kubernetes/easyhaproxy-daemonset.yml @@ -6,7 +6,7 @@ metadata: name: ingress-easyhaproxy namespace: easyhaproxy labels: - helm.sh/chart: easyhaproxy-1.0.1 + helm.sh/chart: easyhaproxy-1.0.0 app.kubernetes.io/name: easyhaproxy app.kubernetes.io/instance: ingress app.kubernetes.io/version: "5.0.0" @@ -19,7 +19,7 @@ metadata: name: ingress-easyhaproxy namespace: easyhaproxy labels: - helm.sh/chart: easyhaproxy-1.0.1 + helm.sh/chart: easyhaproxy-1.0.0 app.kubernetes.io/name: easyhaproxy app.kubernetes.io/instance: ingress app.kubernetes.io/version: "5.0.0" @@ -41,12 +41,11 @@ rules: - list - watch - apiGroups: - - "extensions" - "networking.k8s.io" resources: - ingresses # - ingresses/status - # - ingressclasses + - ingressclasses verbs: - get - list @@ -85,7 +84,7 @@ metadata: name: ingress-easyhaproxy namespace: easyhaproxy labels: - helm.sh/chart: easyhaproxy-1.0.1 + helm.sh/chart: easyhaproxy-1.0.0 app.kubernetes.io/name: easyhaproxy app.kubernetes.io/instance: ingress app.kubernetes.io/version: "5.0.0" @@ -106,7 +105,7 @@ metadata: name: ingress-easyhaproxy namespace: easyhaproxy labels: - helm.sh/chart: easyhaproxy-1.0.1 + helm.sh/chart: easyhaproxy-1.0.0 app.kubernetes.io/name: easyhaproxy app.kubernetes.io/instance: ingress app.kubernetes.io/version: "5.0.0" @@ -151,9 +150,7 @@ spec: containerPort: 1936 hostPort: 1936 resources: - requests: - cpu: 100m - memory: 128Mi + {} env: - name: EASYHAPROXY_DISCOVER value: kubernetes @@ -173,3 +170,17 @@ spec: value: DEBUG - name: CERTBOT_LOG_LEVEL value: DEBUG +--- +# Source: easyhaproxy/templates/ingressclass.yaml +apiVersion: networking.k8s.io/v1 +kind: IngressClass +metadata: + name: easyhaproxy + labels: + helm.sh/chart: easyhaproxy-1.0.0 + app.kubernetes.io/name: easyhaproxy + app.kubernetes.io/instance: ingress + app.kubernetes.io/version: "5.0.0" + app.kubernetes.io/managed-by: Helm +spec: + controller: byjg.com/easyhaproxy diff --git a/deploy/kubernetes/easyhaproxy-nodeport.yml b/deploy/kubernetes/easyhaproxy-nodeport.yml index 50fc4c3..8cb1fb6 100644 --- a/deploy/kubernetes/easyhaproxy-nodeport.yml +++ b/deploy/kubernetes/easyhaproxy-nodeport.yml @@ -6,7 +6,7 @@ metadata: name: ingress-easyhaproxy namespace: easyhaproxy labels: - helm.sh/chart: easyhaproxy-1.0.1 + helm.sh/chart: easyhaproxy-1.0.0 app.kubernetes.io/name: easyhaproxy app.kubernetes.io/instance: ingress app.kubernetes.io/version: "5.0.0" @@ -19,7 +19,7 @@ metadata: name: ingress-easyhaproxy namespace: easyhaproxy labels: - helm.sh/chart: easyhaproxy-1.0.1 + helm.sh/chart: easyhaproxy-1.0.0 app.kubernetes.io/name: easyhaproxy app.kubernetes.io/instance: ingress app.kubernetes.io/version: "5.0.0" @@ -41,12 +41,11 @@ rules: - list - watch - apiGroups: - - "extensions" - "networking.k8s.io" resources: - ingresses # - ingresses/status - # - ingressclasses + - ingressclasses verbs: - get - list @@ -85,7 +84,7 @@ metadata: name: ingress-easyhaproxy namespace: easyhaproxy labels: - helm.sh/chart: easyhaproxy-1.0.1 + helm.sh/chart: easyhaproxy-1.0.0 app.kubernetes.io/name: easyhaproxy app.kubernetes.io/instance: ingress app.kubernetes.io/version: "5.0.0" @@ -107,7 +106,7 @@ metadata: name: ingress-easyhaproxy namespace: easyhaproxy labels: - helm.sh/chart: easyhaproxy-1.0.1 + helm.sh/chart: easyhaproxy-1.0.0 app.kubernetes.io/name: easyhaproxy app.kubernetes.io/instance: ingress app.kubernetes.io/version: "5.0.0" @@ -119,13 +118,13 @@ spec: ports: - name: http port: 80 - nodePort: 31080 + nodePort: 80 - name: https port: 443 - nodePort: 31443 + nodePort: 443 - name: stats port: 1936 - nodePort: 31936 + nodePort: 1936 selector: @@ -139,12 +138,13 @@ metadata: name: ingress-easyhaproxy namespace: easyhaproxy labels: - helm.sh/chart: easyhaproxy-1.0.1 + helm.sh/chart: easyhaproxy-1.0.0 app.kubernetes.io/name: easyhaproxy app.kubernetes.io/instance: ingress app.kubernetes.io/version: "5.0.0" app.kubernetes.io/managed-by: Helm spec: + replicas: 1 selector: matchLabels: app.kubernetes.io/name: easyhaproxy @@ -155,15 +155,6 @@ spec: app.kubernetes.io/name: easyhaproxy app.kubernetes.io/instance: ingress spec: - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: easyhaproxy/node - operator: In - values: - - master serviceAccountName: ingress-easyhaproxy securityContext: {} @@ -184,9 +175,7 @@ spec: containerPort: 1936 resources: - requests: - cpu: 100m - memory: 128Mi + {} env: - name: EASYHAPROXY_DISCOVER value: kubernetes @@ -206,3 +195,17 @@ spec: value: DEBUG - name: CERTBOT_LOG_LEVEL value: DEBUG +--- +# Source: easyhaproxy/templates/ingressclass.yaml +apiVersion: networking.k8s.io/v1 +kind: IngressClass +metadata: + name: easyhaproxy + labels: + helm.sh/chart: easyhaproxy-1.0.0 + app.kubernetes.io/name: easyhaproxy + app.kubernetes.io/instance: ingress + app.kubernetes.io/version: "5.0.0" + app.kubernetes.io/managed-by: Helm +spec: + controller: byjg.com/easyhaproxy diff --git a/docs/kubernetes.md b/docs/kubernetes.md index 3194e29..fe8afc1 100644 --- a/docs/kubernetes.md +++ b/docs/kubernetes.md @@ -8,7 +8,7 @@ sidebar_position: 1 :::info How it works EasyHAProxy for Kubernetes operates by querying all ingress definitions with either the -`spec.ingressClassName: easyhaproxy-ingress` field (recommended) or the deprecated annotation +`spec.ingressClassName: easyhaproxy` field (recommended) or the deprecated annotation `kubernetes.io/ingress.class: easyhaproxy-ingress` (for backward compatibility). Upon finding a matching ingress class, EasyHAProxy immediately sets up HAProxy and begins serving traffic. ::: @@ -55,7 +55,7 @@ If necessary, you can configure environment variables. To get a list of the vari ## Running containers -Your container only requires creating an ingress with the `spec.ingressClassName: easyhaproxy-ingress` field pointing to your service. +Your container only requires creating an ingress with the `spec.ingressClassName: easyhaproxy` field pointing to your service. e.g. @@ -66,7 +66,7 @@ metadata: namespace: example spec: # Use ingressClassName (recommended) - ingressClassName: easyhaproxy-ingress + ingressClassName: easyhaproxy rules: - host: example.org http: @@ -125,7 +125,7 @@ metadata: name: example-ingress namespace: example spec: - ingressClassName: easyhaproxy-ingress + ingressClassName: easyhaproxy rules: - host: example.org http: @@ -153,7 +153,7 @@ metadata: name: secure-app-ingress namespace: production spec: - ingressClassName: easyhaproxy-ingress + ingressClassName: easyhaproxy rules: - host: myapp.example.com http: @@ -179,7 +179,7 @@ metadata: easyhaproxy.plugin.jwt_validator.audience: "https://api.example.com" easyhaproxy.plugin.jwt_validator.pubkey_path: "/etc/haproxy/jwt_keys/api_pubkey.pem" spec: - ingressClassName: easyhaproxy-ingress + ingressClassName: easyhaproxy ``` **Note:** For JWT validation, you'll need to mount the public key file into the EasyHAProxy pod. See [Using Plugins](plugins.md#protect-api-with-jwt-authentication) for details. @@ -193,7 +193,7 @@ metadata: easyhaproxy.plugin.ip_whitelist.allowed_ips: "192.168.1.0/24,10.0.0.5" easyhaproxy.plugin.ip_whitelist.status_code: "403" spec: - ingressClassName: easyhaproxy-ingress + ingressClassName: easyhaproxy ``` **Restore Cloudflare visitor IPs:** @@ -203,7 +203,7 @@ metadata: annotations: easyhaproxy.plugins: "cloudflare" spec: - ingressClassName: easyhaproxy-ingress + ingressClassName: easyhaproxy ``` **Multiple plugins together:** @@ -215,7 +215,7 @@ metadata: easyhaproxy.plugin.deny_pages.paths: "/wp-admin,/wp-login.php" easyhaproxy.plugin.deny_pages.status_code: "404" spec: - ingressClassName: easyhaproxy-ingress + ingressClassName: easyhaproxy ``` ### Global Plugin Configuration @@ -257,7 +257,7 @@ metadata: name: example-ingress namespace: example spec: - ingressClassName: easyhaproxy-ingress + ingressClassName: easyhaproxy .... ``` @@ -288,7 +288,7 @@ metadata: name: tls-example namespace: default spec: - ingressClassName: easyhaproxy-ingress + ingressClassName: easyhaproxy tls: - hosts: - host2.local diff --git a/examples/kubernetes/cloudflare.yml b/examples/kubernetes/cloudflare.yml index 8ca4353..106a8ad 100644 --- a/examples/kubernetes/cloudflare.yml +++ b/examples/kubernetes/cloudflare.yml @@ -122,7 +122,7 @@ metadata: spec: # Use ingressClassName instead of the deprecated annotation # For backward compatibility, annotation kubernetes.io/ingress.class is still supported - ingressClassName: easyhaproxy-ingress + ingressClassName: easyhaproxy rules: - host: myapp.example.local http: diff --git a/examples/kubernetes/ip-whitelist.yml b/examples/kubernetes/ip-whitelist.yml index 4020859..a92334b 100644 --- a/examples/kubernetes/ip-whitelist.yml +++ b/examples/kubernetes/ip-whitelist.yml @@ -109,7 +109,7 @@ metadata: spec: # Use ingressClassName instead of the deprecated annotation # For backward compatibility, annotation kubernetes.io/ingress.class is still supported - ingressClassName: easyhaproxy-ingress + ingressClassName: easyhaproxy rules: - host: admin.example.local http: diff --git a/examples/kubernetes/jwt-validator.yml b/examples/kubernetes/jwt-validator.yml index eee68d5..f49f0a7 100644 --- a/examples/kubernetes/jwt-validator.yml +++ b/examples/kubernetes/jwt-validator.yml @@ -129,7 +129,7 @@ metadata: spec: # Use ingressClassName instead of the deprecated annotation # For backward compatibility, annotation kubernetes.io/ingress.class is still supported - ingressClassName: easyhaproxy-ingress + ingressClassName: easyhaproxy rules: - host: api.example.local http: diff --git a/examples/kubernetes/plugins-combined.yml b/examples/kubernetes/plugins-combined.yml index 36f0631..fc9ea74 100644 --- a/examples/kubernetes/plugins-combined.yml +++ b/examples/kubernetes/plugins-combined.yml @@ -122,7 +122,7 @@ metadata: spec: # Use ingressClassName instead of the deprecated annotation # For backward compatibility, annotation kubernetes.io/ingress.class is still supported - ingressClassName: easyhaproxy-ingress + ingressClassName: easyhaproxy rules: - host: website.example.local http: @@ -196,7 +196,7 @@ metadata: spec: # Use ingressClassName instead of the deprecated annotation # For backward compatibility, annotation kubernetes.io/ingress.class is still supported - ingressClassName: easyhaproxy-ingress + ingressClassName: easyhaproxy rules: - host: api.example.local http: @@ -265,7 +265,7 @@ metadata: spec: # Use ingressClassName instead of the deprecated annotation # For backward compatibility, annotation kubernetes.io/ingress.class is still supported - ingressClassName: easyhaproxy-ingress + ingressClassName: easyhaproxy rules: - host: admin.example.local http: diff --git a/examples/kubernetes/service.yml b/examples/kubernetes/service.yml index 71ae9ed..9770541 100644 --- a/examples/kubernetes/service.yml +++ b/examples/kubernetes/service.yml @@ -61,7 +61,7 @@ metadata: spec: # Use ingressClassName instead of the deprecated annotation # For backward compatibility, annotation kubernetes.io/ingress.class is still supported - ingressClassName: easyhaproxy-ingress + ingressClassName: easyhaproxy rules: - host: example.org http: diff --git a/examples/kubernetes/service_tls.yml b/examples/kubernetes/service_tls.yml index fd08594..11398cd 100644 --- a/examples/kubernetes/service_tls.yml +++ b/examples/kubernetes/service_tls.yml @@ -62,7 +62,7 @@ metadata: spec: # Use ingressClassName instead of the deprecated annotation # For backward compatibility, annotation kubernetes.io/ingress.class is still supported - ingressClassName: easyhaproxy-ingress + ingressClassName: easyhaproxy tls: - hosts: - host2.local diff --git a/helm/easyhaproxy/templates/clusterrole.yaml b/helm/easyhaproxy/templates/clusterrole.yaml index 04ac23e..ca784ab 100644 --- a/helm/easyhaproxy/templates/clusterrole.yaml +++ b/helm/easyhaproxy/templates/clusterrole.yaml @@ -28,12 +28,11 @@ rules: - list - watch - apiGroups: - - "extensions" - "networking.k8s.io" resources: - ingresses # - ingresses/status - # - ingressclasses + - ingressclasses verbs: - get - list diff --git a/helm/easyhaproxy/templates/ingressclass.yaml b/helm/easyhaproxy/templates/ingressclass.yaml new file mode 100644 index 0000000..af9fa11 --- /dev/null +++ b/helm/easyhaproxy/templates/ingressclass.yaml @@ -0,0 +1,14 @@ +{{- if .Values.ingressClass.create -}} +apiVersion: networking.k8s.io/v1 +kind: IngressClass +metadata: + name: easyhaproxy + labels: + {{- include "easyhaproxy.labels" . | nindent 4 }} + {{- with .Values.ingressClass.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + controller: byjg.com/easyhaproxy +{{- end }} diff --git a/helm/easyhaproxy/values.yaml b/helm/easyhaproxy/values.yaml index 835151d..cf85445 100644 --- a/helm/easyhaproxy/values.yaml +++ b/helm/easyhaproxy/values.yaml @@ -31,6 +31,13 @@ serviceAccount: annotations: {} name: "" +# IngressClass configuration +ingressClass: + # Create IngressClass resource + create: true + # Additional annotations for the IngressClass + annotations: {} + podAnnotations: {} podSecurityContext: {} diff --git a/src/processor/__init__.py b/src/processor/__init__.py index 0fb29fb..9ba6248 100644 --- a/src/processor/__init__.py +++ b/src/processor/__init__.py @@ -241,16 +241,21 @@ class Kubernetes(ProcessorInterface): for ingress in ret.items: # Support both new spec.ingressClassName and deprecated annotation for backward compatibility ingress_class = None + is_match = False # Check new spec.ingressClassName first (preferred) if hasattr(ingress.spec, 'ingress_class_name') and ingress.spec.ingress_class_name is not None: ingress_class = ingress.spec.ingress_class_name + # Modern spec uses 'easyhaproxy' + is_match = (ingress_class == "easyhaproxy") # Fall back to deprecated annotation elif ingress.metadata.annotations and 'kubernetes.io/ingress.class' in ingress.metadata.annotations: ingress_class = ingress.metadata.annotations['kubernetes.io/ingress.class'] + # Deprecated annotation uses 'easyhaproxy-ingress' for backward compatibility + is_match = (ingress_class == "easyhaproxy-ingress") # Skip if no ingress class is defined or it doesn't match - if ingress_class != "easyhaproxy-ingress": + if not is_match: continue ssl_hosts = []