Setting a default certificate is useful when we want to set a certificate for an IP or set a self-signed certificate for internal security purposes.
When deploying the Nginx ingress controller, we can use --default-ssl-certificate
to set a default certificate. However, the application routing plugin has long lacked this feature because we cannot modify the deployment yaml because all services created by the application routing plugin are managed by it. Today, this feature is finally available.
This article shows you how to set a default certificate for application routing, with the certificate stored in Azure Key Vault or Kubernetes secrets.
Supported sources for deploying default certificate
- Certificate URL from Azure Key Vault
- Secrets in Kubernetes
Prerequisites
- The AKS version needs to be gerater than or equal to
1.30
.
TL;DR
- Use
spec.defaultSSLCertificate.keyVaultURI: ${certUrl}
to load default certificate from Azure Key Vault. - Use
spec.defaultSSLCertificate.secret.name
andspec.defaultSSLCertificate.secret.namespace
to load default certificate from Kubernetes secrets. --enable-secret-rotation
is required for auto rotate certificate from Azure Key Vault, but there is no need to enable it if the source is Kubernetes secrets.
Initializing resources
Before the actual configuration, let’s setup our demo with preset parameters.
- Set preset parameters. Configure the AKS version to your desired version.
ranNum=$(echo $RANDOM)
region=westus
rG=aks-approuting-${ranNum}
kv=kvaks${ranNum}
aks=aks-${ranNum}
aksVer=1.30
cert_name=example-meow-${ranNum}
- Create AKS cluster
az group create -n ${rG} -l ${region}
az aks create -n ${aks} -g ${rG} --kubernetes-version ${aksVer} \
--node-vm-size Standard_A4_v2 --node-count 1 --enable-app-routing \
--node-os-upgrade-channel None --no-ssh-key
infra_rG=$(az aks show -n ${aks} -g ${rG} --query nodeResourceGroup -o tsv)
- Get AKS credentials
az aks get-credentials -n ${aks} -g ${rG}
Deploy default certificates
Deploy default certificates through Azure Key Vault
In this section, we will modify the default configuration of Application Routing add-on so that the default Nginx Ingress Controller uses certificates from Azure Key Vault by default.
- Create Azure Key Vault with set-policy mode
az keyvault create -n ${kv} -g ${rG} --enable-rbac-authorization false
kvURI=$(az resource show -n ${kv} -g ${rG} --namespace Microsoft.KeyVault \
--resource-type vaults --query id -o tsv)
- Attach Azure Key Vault to Application Routing add-on
az aks approuting update -n ${aks} -g ${rG} --enable-kv --attach-kv ${kvURI}
- Generate certificate
In the script, I add the keyword “-kv” to the certificate properties, so we will know what certificate is being used later.
openssl req -new -x509 -nodes -subj "/CN=${cert_name}-kv" \
-addext "subjectAltName=DNS:${cert_name}-kv" -out ${cert_name}-kv.crt \
-keyout ${cert_name}-kv.key
openssl pkcs12 -export -in ${cert_name}-kv.crt -inkey ${cert_name}-kv.key \
-out ${cert_name}-kv.pfx
NOTEIf you are asked to set certificate password and you don’t want to set the password, you can ignore them by pressing Enter twice.
- Import certificate into Azure Key Vault
az keyvault certificate import --vault-name ${kv} -n ${cert_name} \
-f ${cert_name}-kv.pfx
certUrl=$(az keyvault certificate show --vault-name ${kv} -n ${cert_name} \
--query id -o tsv | sed -E 's/((.*)([\/]))([a-z0-9]+)/\2/')
NOTEIf you set a certificate password in the previous step, you need to append the parameter
--password <your_password>
when importing the certificate into Azure Key Vault.
- Enable Azure Key Vault secret auto-rotation feature (Optional)
By default, if you import a new version of a certificate into Azure Key Vault, the certificate deployed for Application Routing add-on will not automatically update. You need to enable the certificate auto-rotation feature for the certificates to be automatically updated. To enable certificate auto-rotation feature:
az aks addon update --resource-group ${rG} --name ${aks} \
--addon azure-keyvault-secrets-provider --enable-secret-rotation
- Modify the default configuration of Application Routing to set default certificate
cat <<EOF | kubectl apply -f -
apiVersion: approuting.kubernetes.azure.com/v1alpha1
kind: NginxIngressController
metadata:
name: default
spec:
ingressClassName: webapprouting.kubernetes.azure.com
controllerNamePrefix: nginx
defaultSSLCertificate:
keyVaultURI: ${certUrl}
EOF
- Check the certificate information after certificate being refreshed
sleep 30;
appKv_IP=$(kubectl get svc nginx -n app-routing-system \
-o json | jq -r '.status.loadBalancer.ingress | .[0].ip')
openssl s_client -showcerts -connect ${appKv_IP}:443 </dev/null | grep $"{cert_name}"
The output looks like this:
Can't use SSL_get_servername
depth=0 CN = example-meow-22468-kv
verify error:num=18:self signed certificate
verify return:1
depth=0 CN = example-meow-22468-kv
verify return:1
DONE
Deploy default certificates through Kubernetes secrets
In this section, we will add a new configuration for the Application Routing add-on with a different load balancer IP so that the default Nginx Ingress Controller uses the certificates from the Kubernetes secrets by default.
- Generate certificate
In the script, I add the keyword “-local” to the certificate properties, so we will know what certificate is being used later.
openssl req -new -x509 -nodes -subj "/CN=${cert_name}-local" \
-addext "subjectAltName=DNS:${cert_name}-local" -out ${cert_name}-local.crt \
-keyout ${cert_name}-local.key
- Import certificate into secret in Azure Kubernetes Service
kubectl create secret tls defaultcert \
--cert=${cert_name}-local.crt --key=${cert_name}-local.key
- Modify the default configuration of Application Routing to set default certificate
cat <<EOF | kubectl apply -f -
apiVersion: approuting.kubernetes.azure.com/v1alpha1
kind: NginxIngressController
metadata:
name: default2
spec:
ingressClassName: webapprouting2.kubernetes.azure.com
controllerNamePrefix: nginx2
defaultSSLCertificate:
secret:
name: defaultcert
namespace: default
EOF
- Check the certificate information after certificate being refreshed
sleep 30;
appSec_IP=$(kubectl get svc nginx2-0 -n app-routing-system \
-o json | jq -r '.status.loadBalancer.ingress | .[0].ip')
openssl s_client -showcerts -connect ${appSec_IP}:443 </dev/null | grep $"{cert_name}"
The output looks like this:
Can't use SSL_get_servername
depth=0 CN = example-meow-22468-local
verify error:num=18:self signed certificate
verify return:1
depth=0 CN = example-meow-22468-local
verify return:1
DONE
NOTEIf you want to update the default certificate that references a Kubernetes secret, you do not need to enable certificate auto-rotation feature. Once you update the secret, the default certificate will be automatically updated.
Clean resources
az group delete -n ${rG} --no-wait