Kyverno Ingress TLS Templates¶
Enforces TLS encryption requirements for Ingress resources. Ensures production workloads use HTTPS with valid certificates and automated renewal.
HTTP Ingress Exposes Unencrypted Traffic
Ingress without TLS sends credentials and data in plaintext. Enforce TLS on all production ingress resources.
Template 4: Ingress TLS Requirements¶
Enforces TLS encryption on all Ingress resources in production namespaces. Prevents cleartext HTTP traffic to production applications.
Complete Policy¶
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-ingress-tls
namespace: kyverno
spec:
validationFailureAction: enforce
background: true
rules:
- name: validate-tls-configuration
match:
resources:
kinds:
- Ingress
exclude:
resources:
namespaces:
- kube-system
- local-dev
- dev
- test
validate:
message: "Ingress in production namespaces must define TLS configuration"
pattern:
spec:
tls:
- hosts:
- "?*"
secretName: "?*"
- name: validate-tls-secret-exists
match:
resources:
kinds:
- Ingress
exclude:
resources:
namespaces:
- kube-system
- local-dev
context:
- name: tlsSecrets
apiCall:
urlPath: "/api/v1/namespaces/{{ request.namespace }}/secrets"
jmesPath: "items[?type=='kubernetes.io/tls'].metadata.name"
validate:
message: "TLS secret referenced in Ingress must exist as type kubernetes.io/tls"
deny:
conditions:
any:
- key: "{{ request.object.spec.tls[].secretName }}"
operator: AnyNotIn
value: "{{ tlsSecrets }}"
- name: enforce-tls-hostname-match
match:
resources:
kinds:
- Ingress
exclude:
resources:
namespaces:
- kube-system
validate:
message: "TLS hosts must match at least one rule host"
deny:
conditions:
any:
- key: "{{ request.object.spec.tls[].hosts[] }}"
operator: AnyNotIn
value: "{{ request.object.spec.rules[].host }}"
- name: block-http-redirect-annotation-removal
match:
resources:
kinds:
- Ingress
exclude:
resources:
namespaces:
- kube-system
- local-dev
validate:
message: "Production ingress must include SSL redirect annotation"
pattern:
metadata:
annotations:
(nginx.ingress.kubernetes.io/ssl-redirect): "true"
- name: require-cert-manager-annotation
match:
resources:
kinds:
- Ingress
exclude:
resources:
namespaces:
- kube-system
selector:
matchLabels:
cert-manager.io/issuer: "manual"
validate:
message: "Ingress must specify cert-manager.io/cluster-issuer for automated certificate management"
pattern:
metadata:
annotations:
cert-manager.io/cluster-issuer: "?*"
Customization Variables¶
| Variable | Default | Purpose |
|---|---|---|
production-namespaces |
All except dev, test, local-dev |
Namespaces requiring TLS |
validationFailureAction |
enforce |
Use audit for gradual rollout |
cert-manager-issuer |
Required unless manual label present |
Automated certificate provisioning |
ssl-redirect |
true |
Force HTTP to HTTPS redirection |
Validation Commands¶
# Apply policy
kubectl apply -f ingress-tls-policy.yaml
# Create TLS secret
kubectl create secret tls app-tls-secret \
--cert=./tls.crt \
--key=./tls.key \
-n default
# Test ingress with TLS (should pass)
kubectl apply -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress-tls
namespace: default
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: nginx
tls:
- hosts:
- app.example.com
secretName: app-tls-secret
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app-service
port:
number: 80
EOF
# Test ingress without TLS in production (should fail)
kubectl apply -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress-no-tls
namespace: production
spec:
ingressClassName: nginx
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app-service
port:
number: 80
EOF
# Audit ingress without TLS
kubectl get ingress -A -o json | jq -r '.items[] | select(.spec.tls == null) | "\(.metadata.namespace)/\(.metadata.name)"'
# Check TLS secret types
kubectl get secrets -A -o json | jq -r '.items[] | select(.metadata.name | endswith("-tls")) | "\(.metadata.namespace)/\(.metadata.name): \(.type)"'
# Audit cert-manager coverage
kubectl get ingress -A -o json | jq -r '.items[] | select(.metadata.annotations["cert-manager.io/cluster-issuer"] == null) | "\(.metadata.namespace)/\(.metadata.name)"'
# Check for expired certificates
kubectl get secrets -A -o json | jq -r '.items[] | select(.type == "kubernetes.io/tls") | "\(.metadata.namespace)/\(.metadata.name): \(.data."tls.crt" | @base64d)"' | openssl x509 -noout -enddate
Use Cases¶
- Encryption in Transit: Prevent credential and data exposure via unencrypted HTTP
- PCI-DSS Compliance: Enforce TLS for all cardholder data transmission
- Certificate Management: Ensure automated certificate renewal via cert-manager
- Security Auditing: Track TLS configuration and certificate expiration
- HTTPS Enforcement: Block accidental deployment of HTTP-only ingress resources
Related Resources¶
- Kyverno Ingress Class → - IngressClass requirements
- Kyverno Network Security → - NetworkPolicy and egress requirements
- Kyverno Network Services → - Service type restrictions
- Kyverno Labels → - Mandatory metadata
- Template Library Overview → - Back to main page