Estimated Duration: 60 minutes
NOTE: You need to fulfill these requirements and AKS Basic Cluster to complete this exercise.
An Ingress is an API object that defines rules, which allow external access to services in an Azure Kubernetes Service (AKS) cluster. When you create an Ingress object that uses the application routing add-on nginx Ingress classes, the add-on creates, configures, and manages one or more Ingress controllers in your AKS cluster.
This lab shows you how to set up an advanced Ingress configuration to encrypt the traffic with SSL/TLS certificates stored in an Azure Key Vault, and use Azure DNS to manage DNS zones.
- Managed NGINX ingress with the application routing add-on
- Set up a custom domain name and SSL certificate with the application routing add-on
In a terminal, export variables required for this lab (if not already exported):
INITIALS=abc
CLUSTER_NAME=aks-$INITIALS
RG=aks-$INITIALS-rg
LOCATION=eastus2
If not already connected, connect to the cluster from your local client machine.
az aks get-credentials --name $CLUSTER_NAME -g $RG
Run the following command to enable the approuting
add-on if not already enabled
az aks approuting enable --resource-group $RG --name $CLUSTER_NAME
Create a new Azure Key Vault with Azure role-based access control (Azure RBAC) enabled:
AKV_NAME=$INITIALS-kv
az keyvault create --name $AKV_NAME --resource-group $RG --location $LOCATION --enable-rbac-authorization
Retrieve the Azure Key Vault resource id for later use:
KEYVAULT_ID=$(az keyvault show --name $AKV_NAME --resource-group $RG \
--query id --output tsv | tr -d '\r')
Update the app routing add-on to enable the Azure Key Vault secret store CSI driver and apply the role assignment.
az aks approuting update --resource-group $RG --name $CLUSTER_NAME --enable-kv --attach-kv ${KEYVAULT_ID}
Choose a domain name expected to be unique:
DOMAIN_NAME=$INITIALS-azuredemo.com
This step is optional, but without this validation will be only via IP. If you choose to register a domain, you can confirm it is not registered by adding the --dryrun
flag to the command below:
az appservice domain create -g $RG --hostname $DOMAIN_NAME \
--contact-info @manifests/contact-info.json --accept-terms
Create an Azure DNS zone using the az network dns zone create command.
az network dns zone create --resource-group $RG --name $DOMAIN_NAME
Retrieve the resource ID for the DNS zone using this command:
ZONE_ID=$(az network dns zone show -g $RG --name $DOMAIN_NAME --query "id" --output tsv)
Update the add-on to enable the integration with Azure DNS using this command:
az aks approuting zone add -g $RG --name $CLUSTER_NAME --ids=${ZONE_ID} --attach-zones
Export certificate name variable:
CERT_NAME=aks-ingress-cert
This option requires using a registered domain and then issuing a Trusted CA certificate
This certificate is issued by Let's Encrypt CA and requires installing cerbot
see environment setup
Run the following command:
sudo certbot certonly --agree-tos --register-unsafely-without-email --manual \
--preferred-challenges dns -d $DOMAIN_NAME -d *.$DOMAIN_NAME
On a separate terminal run the command below. You will need to export variables and copy challenge value:
CHALLENGE=<challenge_value>
az network dns record-set txt add-record --resource-group $RG --zone-name $DOMAIN_NAME --record-set-name _acme-challenge --value $CHALLENGE
Before confirming challenge, confirm TXT DNS record has been propagated using this command:
nslookup -q=txt _acme-challenge.$DOMAIN_NAME
Once the record is successfully validated, use the command below to export certificate into pfx format (provide sudo password if prompted, but skip export password when prompted):
sudo openssl pkcs12 -export -out $CERT_NAME.pfx -inkey /etc/letsencrypt/live/$DOMAIN_NAME/privkey.pem \
-in /etc/letsencrypt/live/$DOMAIN_NAME/fullchain.pem
Change ownership of exported certificate file:
sudo chown $(whoami) $CERT_NAME.pfx
In this option you will only be able to validate using
curl
command to resolve domain. Generate a TLS certificate using the following command:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-out aks-ingress-tls.crt \
-keyout aks-ingress-tls.key \
-subj "/CN=${DOMAIN_NAME}/O=aks-ingress-tls"
Export the certificate to a PFX file using the following command (skip password prompt):
openssl pkcs12 -export -in aks-ingress-tls.crt -inkey aks-ingress-tls.key -out $CERT_NAME.pfx
Get the user principal name and the key vault ID:
PRINCIPAL_NAME=$(az ad signed-in-user show --query userPrincipalName --output tsv | tr -d '\r')
Grant Key Vault Contributor role to be able to import certificate:
az role assignment create --assignee $PRINCIPAL_NAME --role "Key Vault Certificates Officer" --scope $KEYVAULT_ID
Import the certificate using this command:
az keyvault certificate import --vault-name $AKV_NAME --name $CERT_NAME --file $CERT_NAME.pfx
Create a namespace:
NAMESPACE=tls-managed-nginx
kubectl create namespace $NAMESPACE
Deploy using this command:
kubectl apply -f manifests/aks-helloworld.yaml -n $NAMESPACE
Confirm deployment is successful and pod is in RUNNING
state:
kubectl get pods -n $NAMESPACE
Get the certificate URI to use in the Ingress from Azure Key Vault using this command:
KV_CERT_URI=$(az keyvault certificate show --vault-name $AKV_NAME --name $CERT_NAME --query "id" --output tsv | tr -d '\r')
Before running next command verify required variables are exported:
echo CERT_URI: $KV_CERT_URI, DOMAIN_NAME: $DOMAIN_NAME, NAMESPACE: $NAMESPACE
Create the App Routing Ingress using this command:
cat <<EOF | kubectl apply -n $NAMESPACE -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
kubernetes.azure.com/tls-cert-keyvault-uri: $KV_CERT_URI
name: aks-helloworld
spec:
ingressClassName: webapprouting.kubernetes.azure.com
rules:
- host: $DOMAIN_NAME
http:
paths:
- backend:
service:
name: aks-helloworld
port:
number: 80
path: /
pathType: Prefix
tls:
- hosts:
- $DOMAIN_NAME
secretName: keyvault-aks-helloworld
EOF
Confirm secret was created, pods are running (you should see a new one for keyvault
injection) and ingress has IP ADDRESS
assigned:
kubectl get pods,secret,ingress -n $NAMESPACE
Get the external IP for the nginx-ingress
service:
EXTERNAL_IP=$(kubectl get ingress -n $NAMESPACE -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}')
Verify your ingress is properly configured with TLS using the following command:
curl -v -k --resolve $DOMAIN_NAME:443:$EXTERNAL_IP https://$DOMAIN_NAME
You should see the server certificate (either self-signed or CA issued) in the output
If a domain registration and Trusted Certificate was used, then you can additionally validate using the qualified domain name. Create a DNS record to point to the ingress IP:
az network dns record-set a add-record --ipv4-address $EXTERNAL_IP --record-set-name "@" -g $RG --zone-name $DOMAIN_NAME
Test reaching the fully qualified domain name:
curl -v https://$DOMAIN_NAME
If you are done with all labs and have no plan to continue further, then clean up by deleting the resource group:
az group delete --name $RG --yes --no-wait
Otherwise remove the following resources, keeping the AKS cluster:
kubectl delete namespace $NAMESPACE