Security Hardening¶
This page covers the three security areas that must be configured before a production deployment: encryption keys for data at rest, TLS for data in transit, and authentication for access control.
Encryption Keys¶
The controller uses AES-GCM 256-bit keys to encrypt sensitive data at rest. Providing at least one encryption key is required when developmentMode is set to false.
Generate a 256-bit AES key:
Create the Kubernetes secret:
kubectl create secret generic gateway-encryption-keys \
--namespace <your-namespace> \
--from-file=default-aesgcm256-v1.bin=./default-aesgcm256-v1.bin
Clean up the local key file:
Warning
Do not commit the key file to source control. Remove it immediately after creating the Kubernetes secret.
Reference the secret in values:
gateway:
controller:
encryptionKeys:
enabled: true
secretName: gateway-encryption-keys
mountPath: /app/data/aesgcm-keys
gateway:
config:
controller:
encryption:
providers:
- type: aesgcm
keys:
- version: aesgcm256-v1
file: /app/data/aesgcm-keys/default-aesgcm256-v1.bin
The version field must match the filename stem of the secret key (default-aesgcm256-v1.bin → version aesgcm256-v1).
Key rotation:
- Generate a new key with
openssl rand. - Add it to the Kubernetes secret with an incremented version name.
- Update the
encryption.providerslist in values to include the new key entry. - Run
helm upgradeto redeploy — the controller picks up the new key on startup.
Note
Keep old key versions in the secret until all data encrypted with the previous key has been re-encrypted or is no longer needed.
TLS Configuration¶
TLS must be configured before exposing the gateway externally. Choose one of the options below based on how certificates are managed in your environment.
cert-manager automates TLS certificate provisioning and renewal within the cluster. Install it if you do not already manage certificates externally.
Install cert-manager:
helm repo add jetstack https://charts.jetstack.io --force-update
helm repo update
helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--set crds.enabled=true
Verify all cert-manager pods are running:
Configure the chart to use cert-manager:
gateway:
controller:
tls:
enabled: true
certificateProvider: cert-manager
certManager:
create: true
createIssuer: false # Use your own ClusterIssuer
issuerRef:
name: letsencrypt-prod # Your ClusterIssuer name
kind: ClusterIssuer
commonName: gateway.example.com
dnsNames:
- gateway.example.com
duration: 2160h # 90 days
renewBefore: 720h # Renew 30 days before expiry
Upstream Custom CA Certificates¶
If backend services use certificates signed by a private CA, mount the CA bundle into the controller so it can verify upstream TLS connections.
kubectl create configmap gateway-upstream-certs \
--namespace <your-namespace> \
--from-file=private-ca.crt=./my-ca.crt
Authentication¶
Warning
The default credentials (admin/admin) must be replaced before deploying to any non-development environment. The controller logs a warning at startup if default or no authentication is configured.
Choose an authentication strategy based on your organizational requirements.
This is the safest option. No credentials to manage in the cluster. Authentication is delegated entirely to your identity provider.
gateway:
config:
controller:
auth:
basic:
enabled: false
idp:
enabled: true
jwks_url: "https://idp.example.com/.well-known/jwks.json"
issuer: "https://idp.example.com"
roles_claim: "scope"
role_mapping:
admin: ["gateway:admin"]
developer: ["gateway:developer"]
consumer: ["gateway:consumer"]
Note
Role mapping values must correspond to claims present in the JWT issued by your IDP. See the Gateway Controller OpenAPI reference for the full list of supported roles and their permissions.
If basic auth is required, never store plain-text passwords. The controller supports bcrypt hashes, which are safe to include in Helm values (the hash is not reversible). Store the plain password separately in a Kubernetes secret for rotation reference only.
Generate a bcrypt hash:
Requires apache2-utils (Debian/Ubuntu) or httpd-tools (RHEL/CentOS):
On macOS without htpasswd:
Store the plain password in a Kubernetes secret:
Keep the plain password in a secret for rotation reference. It must never appear in Helm values or ConfigMaps:
kubectl create secret generic gateway-admin-credentials \
--namespace <your-namespace> \
--from-literal=username=admin \
--from-literal=password='your-secure-password'
Configure the chart with the bcrypt hash:
Only the hash goes into the Helm values. This is what ends up in the ConfigMap:
gateway:
config:
controller:
auth:
basic:
enabled: true
users:
- username: "admin"
password: "$2y$10$..." # bcrypt hash — safe to store in ConfigMap
password_hashed: true
roles: ["admin"]
Note
Basic auth users are an array of structs and cannot be overridden via environment variables. The hash must be supplied through Helm values. Rotate credentials by generating a new hash, updating the values, and running helm upgrade.