836 words
4 minutes
Set up default certificate with the Application Routing add-on

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 and spec.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.

  1. 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}
  1. 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)
  1. 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.

  1. 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)
  1. Attach Azure Key Vault to Application Routing add-on
az aks approuting update -n ${aks} -g ${rG} --enable-kv --attach-kv ${kvURI}
  1. 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
NOTE

If you are asked to set certificate password and you don’t want to set the password, you can ignore them by pressing Enter twice.

  1. 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/')
NOTE

If 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.

  1. 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

See also: Enable and disable auto-rotation certificate with Azure Key Vault provider for Secrets Store CSI Driver.

  1. 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
  1. 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.

  1. 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
  1. Import certificate into secret in Azure Kubernetes Service
kubectl create secret tls defaultcert \
--cert=${cert_name}-local.crt --key=${cert_name}-local.key
  1. 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
  1. 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
NOTE

If 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
Set up default certificate with the Application Routing add-on
https://blog.joeyc.dev/posts/aks-approuting-defaultcert/
Author
Joey Chen
Published at
2024-07-24