Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

README.md

cloudflare-access-webhook-redirect

Version: 2.1.11 Type: application AppVersion: v0.3.21

A Helm chart for deploying the Cloudflare Access Webhook Redirect service. This service acts as an authentication proxy that validates requests using Cloudflare Access Service Auth tokens before forwarding them to target backend services.

Use Case

This is particularly useful for protecting webhook endpoints or APIs that don't have built-in authentication, by leveraging Cloudflare Access for secure authentication and authorization.

Prerequisites

  • Kubernetes 1.19+
  • Helm 3.0+
  • A Cloudflare Access application with Service Auth credentials
  • Target backend service to proxy requests to

Get Repository Info

helm repo add timschoenle https://timschoenle.github.io/helm-charts
helm repo update

Install Chart

helm install [RELEASE_NAME] timschoenle/cloudflare-access-webhook-redirect \
  --namespace [NAMESPACE] \
  --create-namespace \
  --set application.handler.targetBase="http://backend:8080" \
  --set application.cloudflareAccess.clientId="your-client-id" \
  --set application.cloudflareAccess.clientSecret="your-client-secret"

Upgrade Chart

helm upgrade [RELEASE_NAME] timschoenle/cloudflare-access-webhook-redirect \
  --namespace [NAMESPACE]

Uninstall Chart

helm uninstall [RELEASE_NAME] --namespace [NAMESPACE]

Configuration

The following table lists the configurable parameters of the chart and their default values.

Values

Key Type Default Description
affinity object {} Pod affinity rules
application.cloudflareAccess.secretName string "" Existing secret name containing Cloudflare Access credentials Must contain client_id and client_secret keys
application.handler.paths object {} Path configurations with allowed HTTP methods Example: api/webhook: - ALL test: - GET - POST
application.handler.targetBase string "" Base URL for redirect targets
application.logLevel string "info" Application log level
application.sentryDsn string "" Sentry DSN for error tracking (empty disables)
application.server.host string "0.0.0.0" Server bind address
application.server.port int 8080 HTTP server port
autoscaling.enabled bool false Enable Horizontal Pod Autoscaler (HPA)
autoscaling.maxReplicas int 5 Maximum replicas
autoscaling.minReplicas int 1 Minimum replicas
autoscaling.targetCPUUtilizationPercentage int 80 Target CPU utilization (%)
autoscaling.targetMemoryUtilizationPercentage int 80 Target memory utilization (%)
fullnameOverride string "" Override the full release name
image.pullPolicy string "IfNotPresent" Image pull policy
image.repository string "timmi6790/cloudflare-access-webhook-redirect" Container image repository (e.g. docker.io/user/image)
image.tag string "v0.3.21@sha256:e5607cedf22b71b8835146aaa1c3e274102888d3d85890224ace3bf088aa646a" Container image tag (version)
imagePullSecrets list [] Optional image pull secrets for private registries
ingress.annotations object {} Additional ingress annotations Example: cert-manager.io/cluster-issuer: letsencrypt-prod nginx.ingress.kubernetes.io/rate-limit: "100"
ingress.enabled bool false Enable ingress resource
ingress.hosts list [] Host definitions for ingress Example: - host: example.local paths: - path: / pathType: Prefix
ingress.ingressClassName string "nginx" Ingress class name (e.g. nginx)
ingress.tls list [] TLS configuration for ingress Example: - secretName: example-tls hosts: - example.local
livenessProbe.enabled bool true Enable liveness probe
livenessProbe.failureThreshold int 3 Failure threshold
livenessProbe.httpGet.path string "/health" Health check path
livenessProbe.httpGet.port string "http" Health check port
livenessProbe.initialDelaySeconds int 10 Initial delay before probe starts
livenessProbe.periodSeconds int 10 Probe frequency
livenessProbe.timeoutSeconds int 5 Probe timeout
nameOverride string "" Override the chart name
networkPolicy object {"egress":{"customRules":[],"dns":{"enabled":true},"enabled":true,"http":{"enabled":false},"https":{"enabled":false},"sentry":{"enabled":true}},"enabled":false,"ingress":{"controller":{"enabled":true,"namespace":"traefik","selector":{"app.kubernetes.io/name":"traefik"}},"customRules":[],"enabled":true,"monitoring":{"enabled":true,"namespace":"monitoring"}}} Network policy configuration
networkPolicy.egress object {"customRules":[],"dns":{"enabled":true},"enabled":true,"http":{"enabled":false},"https":{"enabled":false},"sentry":{"enabled":true}} Egress configuration
networkPolicy.egress.customRules list [] Custom egress rules
networkPolicy.egress.dns object {"enabled":true} DNS configuration for egress
networkPolicy.egress.dns.enabled bool true Allow egress to DNS
networkPolicy.egress.enabled bool true Enable egress rules
networkPolicy.egress.http object {"enabled":false} HTTP configuration for egress
networkPolicy.egress.http.enabled bool false Allow egress to HTTP (TCP/80)
networkPolicy.egress.https object {"enabled":false} HTTPS configuration for egress
networkPolicy.egress.https.enabled bool false Allow egress to HTTPS (TCP/443)
networkPolicy.egress.sentry object {"enabled":true} Sentry configuration for egress
networkPolicy.egress.sentry.enabled bool true Allow egress to Sentry (HTTPS)
networkPolicy.enabled bool false Enable network policies
networkPolicy.ingress object {"controller":{"enabled":true,"namespace":"traefik","selector":{"app.kubernetes.io/name":"traefik"}},"customRules":[],"enabled":true,"monitoring":{"enabled":true,"namespace":"monitoring"}} Ingress configuration
networkPolicy.ingress.controller object {"enabled":true,"namespace":"traefik","selector":{"app.kubernetes.io/name":"traefik"}} Ingress Controller configuration
networkPolicy.ingress.controller.enabled bool true Allow ingress from Ingress Controller
networkPolicy.ingress.controller.namespace string "traefik" Namespace where Ingress Controller is running (default: traefik)
networkPolicy.ingress.controller.selector object {"app.kubernetes.io/name":"traefik"} Pod selector for Ingress Controller (default: Traefik label)
networkPolicy.ingress.customRules list [] Custom ingress rules
networkPolicy.ingress.enabled bool true Enable ingress rules
networkPolicy.ingress.monitoring object {"enabled":true,"namespace":"monitoring"} Monitoring configuration for ingress
networkPolicy.ingress.monitoring.enabled bool true Allow ingress from monitoring namespace
networkPolicy.ingress.monitoring.namespace string "monitoring" Namespace where monitoring tools are running
nodeSelector object {} Node selector labels for scheduling
podAnnotations object {} Additional annotations for the Pod metadata
podDisruptionBudget.enabled bool false Enable PodDisruptionBudget
podDisruptionBudget.maxUnavailable int 1 Maximum unavailable pods
podDisruptionBudget.minAvailable int 1 Minimum available pods
podLabels object {} Additional labels for the Pod metadata
podSecurityContext.fsGroup int 10001 Group ID for file system access
podSecurityContext.runAsNonRoot bool true Run pod as non-root user
podSecurityContext.runAsUser int 10001 User ID to run as
priorityClassName string "" Optional Kubernetes PriorityClass name
readinessProbe.enabled bool true Enable readiness probe
readinessProbe.failureThreshold int 3 Failure threshold
readinessProbe.httpGet.path string "/health" Health check path
readinessProbe.httpGet.port string "http" Health check port
readinessProbe.initialDelaySeconds int 5 Initial delay before probe starts
readinessProbe.periodSeconds int 5 Probe frequency
readinessProbe.timeoutSeconds int 3 Probe timeout
replicaCount int 1 Number of replicas to deploy
resources.limits.cpu string "100m" Maximum CPU usage (e.g. 100m = 0.1 core)
resources.limits.memory string "50Mi" Maximum memory usage (e.g. 64Mi)
resources.requests.cpu string "10m" Guaranteed CPU request
resources.requests.memory string "35Mi" Guaranteed memory request
securityContext.allowPrivilegeEscalation bool false Allow privilege escalation
securityContext.capabilities.drop list ["ALL"] Linux capabilities to drop
securityContext.readOnlyRootFilesystem bool false Mount root filesystem as read-only
service.annotations object {} Additional service annotations
service.port int 80 Service port
service.type string "ClusterIP" Kubernetes service type
serviceAccount.annotations object {} Additional annotations for the service account
serviceAccount.automountToken bool false Whether to automount the service account token
serviceAccount.create bool true Whether to create a dedicated service account
serviceAccount.name string "" Custom service account name (auto-generated if empty)
startupProbe.enabled bool true Enable startup probe
startupProbe.failureThreshold int 30 Failure threshold
startupProbe.httpGet.path string "/health" Health check path
startupProbe.httpGet.port string "http" Health check port
startupProbe.initialDelaySeconds int 2 Initial delay before probe starts
startupProbe.periodSeconds int 5 Probe frequency
startupProbe.successThreshold int 1 Success threshold
startupProbe.timeoutSeconds int 3 Probe timeout
tolerations list [] Tolerations for taints
topologySpreadConstraints list [] Pod topology spread constraints for availability
volumeMounts list [] Additional volume mounts (e.g., /cache)
volumes list [] Additional volumes (e.g., cache, tmp)

Cloudflare Access Configuration

Option 1: Using Existing Secret

Create a Kubernetes secret with your Cloudflare Access Service Auth credentials:

kubectl create secret generic cloudflare-access-secret \
  --namespace [NAMESPACE] \
  --from-literal=client_id='your-client-id' \
  --from-literal=client_secret='your-client-secret'

Then reference it in your values:

application:
  cloudflareAccess:
    secretName: "cloudflare-access-secret"

Option 2: Inline Credentials (Not Recommended for Production)

application:
  cloudflareAccess:
    clientId: "your-client-id"
    clientSecret: "your-client-secret"

Path Configuration

Define which paths should be proxied and which HTTP methods are allowed:

application:
  handler:
    paths:
      # Allow all HTTP methods for webhook endpoint
      api/webhook:
        - ALL

      # Allow specific methods
      api/data:
        - GET
        - POST

      # Multiple endpoints
      health:
        - GET
      metrics:
        - GET

Available HTTP methods: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS, or ALL for all methods.

Examples

Minimal Configuration

application:
  handler:
    targetBase: "http://backend-service:8080"
    paths:
      api/webhook:
        - POST

  cloudflareAccess:
    clientId: "your-client-id-here"
    clientSecret: "your-client-secret-here"

With Ingress and TLS

application:
  handler:
    targetBase: "http://backend-service:8080"
    paths:
      api/webhook:
        - POST
      api/status:
        - GET

  cloudflareAccess:
    secretName: "cloudflare-access-secret"

ingress:
  enabled: true
  ingressClassName: "nginx"
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
  hosts:
    - host: webhook.example.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: webhook-tls
      hosts:
        - webhook.example.com

High Availability Setup

replicaCount: 3

application:
  handler:
    targetBase: "http://backend-service:8080"
    paths:
      api/webhook:
        - POST
      api/events:
        - POST
        - GET

  cloudflareAccess:
    secretName: "cloudflare-access-secret"

autoscaling:
  enabled: true
  minReplicas: 3
  maxReplicas: 10
  targetCPUUtilizationPercentage: 70
  targetMemoryUtilizationPercentage: 80

topologySpreadConstraints:
  - maxSkew: 1
    topologyKey: kubernetes.io/hostname
    whenUnsatisfiable: ScheduleAnyway
    labelSelector:
      matchLabels:
        app.kubernetes.io/name: cloudflare-access-webhook-redirect

podDisruptionBudget:
  enabled: true
  minAvailable: 2

resources:
  limits:
    cpu: 200m
    memory: 30Mi
  requests:
    cpu: 50m
    memory: 20Mi

With Network Policy

application:
  handler:
    targetBase: "http://backend-service:8080"
    paths:
      api/webhook:
        - ALL

  cloudflareAccess:
    secretName: "cloudflare-access-secret"

networkPolicy:
  enabled: true
  policyTypes:
    - Ingress
    - Egress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              name: ingress-nginx
      ports:
        - protocol: TCP
          port: 8080
  egress:
    - to:
        - namespaceSelector: {}
      ports:
        - protocol: TCP
          port: 8080
    - to:
        - namespaceSelector: {}
      ports:
        - protocol: TCP
          port: 443

Production Setup with Monitoring

replicaCount: 2

application:
  logLevel: info
  sentryDsn: "https://your-sentry-dsn@sentry.io/project"

  handler:
    targetBase: "http://backend-service:8080"
    paths:
      api/webhook:
        - POST
      api/data:
        - GET
        - POST

  cloudflareAccess:
    secretName: "cloudflare-access-secret"

resources:
  limits:
    cpu: 100m
    memory: 15Mi
  requests:
    cpu: 10m
    memory: 10Mi

startupProbe:
  enabled: true
  initialDelaySeconds: 0
  periodSeconds: 5
  failureThreshold: 30

livenessProbe:
  enabled: true
  initialDelaySeconds: 10
  periodSeconds: 10

readinessProbe:
  enabled: true
  initialDelaySeconds: 5
  periodSeconds: 5

podDisruptionBudget:
  enabled: true
  minAvailable: 1

How It Works

  1. Client sends a request to the service (e.g., via Ingress)
  2. The service validates the request against the configured paths and HTTP methods
  3. It uses Cloudflare Access Service Auth credentials to authenticate the request
  4. If authenticated, the request is proxied to the target backend service
  5. The response from the backend is returned to the client

This provides a zero-trust authentication layer for services that don't have built-in authentication.

Security Considerations

  • Always use secrets for Cloudflare Access credentials in production
  • Enable NetworkPolicy to restrict ingress/egress traffic
  • Use TLS/HTTPS via Ingress with proper certificates
  • Monitor logs and consider enabling Sentry for error tracking
  • Set resource limits to prevent resource exhaustion
  • Use PodDisruptionBudget for high-availability deployments

Source Code

Maintainers

Name Email Url
Tim Schönle https://github.com/TimSchoenle

Autogenerated from chart metadata using helm-docs v1.14.2