Nginx ingress controller offers the option to validate ingresses before they enter the cluster, ensuring controller will generate a valid configuration.
This controller is called, when ValidatingAdmissionWebhook is enabled, by the Kubernetes API server each time a new ingress is to enter the cluster, and rejects objects for which the generated nginx configuration fails to be validated.
This feature requires some further configuration of the cluster, hence it is an optional feature, this section explains how to enable it for your cluster.
Validating webhook must be served using TLS, you need to generate a certificate. Note that kube API server is checking the hostname of the certificate, the common name of your certificate will need to match the service name.
!!! example
To run the validating webhook with a service named ingress-validation-webhook
in the namespace ingress-nginx
, run
```bash
openssl req -x509 -newkey rsa:2048 -keyout certificate.pem -out key.pem -days 365 -nodes -subj "/CN=ingress-validation-webhook.ingress-nginx.svc"
```
Kubernetes also provides primitives to sign a certificate request. Here is an example on how to use it
!!! example ``` #!/bin/bash
SERVICE_NAME=ingress-nginx
NAMESPACE=ingress-nginx
TEMP_DIRECTORY=$(mktemp -d)
echo "creating certs in directory ${TEMP_DIRECTORY}"
cat <<EOF >> ${TEMP_DIRECTORY}/csr.conf
[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
[req_distinguished_name]
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = ${SERVICE_NAME}
DNS.2 = ${SERVICE_NAME}.${NAMESPACE}
DNS.3 = ${SERVICE_NAME}.${NAMESPACE}.svc
EOF
openssl genrsa -out ${TEMP_DIRECTORY}/server-key.pem 2048
openssl req -new -key ${TEMP_DIRECTORY}/server-key.pem \
-subj "/CN=${SERVICE_NAME}.${NAMESPACE}.svc" \
-out ${TEMP_DIRECTORY}/server.csr \
-config ${TEMP_DIRECTORY}/csr.conf
cat <<EOF | kubectl create -f -
apiVersion: certificates.k8s.io/v1beta1
kind: CertificateSigningRequest
metadata:
name: ${SERVICE_NAME}.${NAMESPACE}.svc
spec:
request: $(cat ${TEMP_DIRECTORY}/server.csr | base64 | tr -d '\n')
usages:
- digital signature
- key encipherment
- server auth
EOF
kubectl certificate approve ${SERVICE_NAME}.${NAMESPACE}.svc
for x in $(seq 10); do
SERVER_CERT=$(kubectl get csr ${SERVICE_NAME}.${NAMESPACE}.svc -o jsonpath='{.status.certificate}')
if [[ ${SERVER_CERT} != '' ]]; then
break
fi
sleep 1
done
if [[ ${SERVER_CERT} == '' ]]; then
echo "ERROR: After approving csr ${SERVICE_NAME}.${NAMESPACE}.svc, the signed certificate did not appear on the resource. Giving up after 10 attempts." >&2
exit 1
fi
echo ${SERVER_CERT} | openssl base64 -d -A -out ${TEMP_DIRECTORY}/server-cert.pem
kubectl create secret generic ingress-nginx.svc \
--from-file=key.pem=${TEMP_DIRECTORY}/server-key.pem \
--from-file=cert.pem=${TEMP_DIRECTORY}/server-cert.pem \
-n ${NAMESPACE}
```
To generate the certificate using helm, you can use the following snippet
!!! example
{{- $cn := printf "%s.%s.svc" ( include "nginx-ingress.validatingWebhook.fullname" . ) .Release.Namespace }} {{- $ca := genCA (printf "%s-ca" ( include "nginx-ingress.validatingWebhook.fullname" . )) .Values.validatingWebhook.certificateValidity -}} {{- $cert := genSignedCert $cn nil nil .Values.validatingWebhook.certificateValidity $ca -}}
To enable the feature in the ingress controller, you need to provide 3 flags to the command line.
flag | description | example usage |
---|---|---|
--validating-webhook |
The address to start an admission controller on | :8080 |
--validating-webhook-certificate |
The certificate the webhook is using for its TLS handling | /usr/local/certificates/validating-webhook.pem |
--validating-webhook-key |
The key the webhook is using for its TLS handling | /usr/local/certificates/validating-webhook-key.pem |
Validating webhook feature requires specific setup on the kube API server side. Depending on your kubernetes version, the flag can, or not, be enabled by default. To check that your kube API server runs with the required flags, please refer to the kubernetes documentation.
Once both the ingress controller and the kube API server are configured to serve the webhook, add the you can configure the webhook with the following objects:
apiVersion: v1
kind: Service
metadata:
name: ingress-validation-webhook
namespace: ingress-nginx
spec:
ports:
- name: admission
port: 443
protocol: TCP
targetPort: 8080
selector:
app: nginx-ingress
component: controller
---
apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration
metadata:
name: check-ingress
webhooks:
- name: validate.nginx.ingress.kubernetes.io
rules:
- apiGroups:
- extensions
apiVersions:
- v1beta1
operations:
- CREATE
- UPDATE
resources:
- ingresses
failurePolicy: Fail
clientConfig:
service:
namespace: ingress-nginx
name: ingress-validation-webhook
path: /extensions/v1beta1/ingress
caBundle: <pem encoded ca cert that signs the server cert used by the webhook>