For more information on securing an Ingress with TLS, refer to this guide
Importing the ingress TLS certificate to the cluster can be included in the following deployments:
export CERT_NAME=ingresscert
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-out ingress-tls.crt \
-keyout ingress-tls.key \
-subj "/CN=demo.test.com/O=ingress-tls"
Convert the .crt certificate to pfx format and import it to Azure Key Vault. For example:
export AKV_NAME="[YOUR AKV NAME]"
openssl pkcs12 -export -in ingress-tls.crt -inkey ingress-tls.key -out $CERT_NAME.pfx
# skip Password prompt
az keyvault certificate import --vault-name $AKV_NAME -n $CERT_NAME -f $CERT_NAME.pfx
Deploy the Azure Key Vault Provider and Secrets Store CSI Driver components:
helm repo add csi-secrets-store-provider-azure https://azure.github.io/secrets-store-csi-driver-provider-azure/charts
helm install csi csi-secrets-store-provider-azure/csi-secrets-store-provider-azure --set secrets-store-csi-driver.syncSecret.enabled=true
Refer to installation for more details and validation.
If using AAD pod identity to access Azure Keyvault, make sure it is configured properly in the cluster. Refer to doc on how to use AAD Pod identity to access keyvault.
export AAD_POD_IDENTITY_NAME=azure-kv
export NAMESPACE=ingress-test
kubectl create ns $NAMESPACE
tenantID
and keyvaultName
usePodIdentity: "true"
objectType: secret
for the certificate, as this is the only way to retrieve the certificate and private key from azure key vault as documented herekubernetes.io/tls
export TENANT_ID=[YOUR TENANT ID]
cat <<EOF | kubectl apply -n $NAMESPACE -f -
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
name: azure-tls
spec:
provider: azure
secretObjects: # secretObjects defines the desired state of synced K8s secret objects
- secretName: ingress-tls-csi
type: kubernetes.io/tls
data:
- objectName: $CERT_NAME
key: tls.key
- objectName: $CERT_NAME
key: tls.crt
parameters:
usePodIdentity: "false"
keyvaultName: $AKV_NAME # the name of the KeyVault
objects: |
array:
- |
objectName: $CERT_NAME
objectType: secret
tenantID: $TENANT_ID # the tenant ID of the KeyVault
EOF
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
Depending on the TLS certificate lifecycle, follow one of the following steps:
Application’s deployment will reference the csi store provider.
helm install ingress-nginx/ingress-nginx --generate-name \
--namespace $NAMESPACE \
--set controller.replicaCount=2 \
--set controller.nodeSelector."beta\.kubernetes\.io/os"=linux \
--set defaultBackend.nodeSelector."beta\.kubernetes\.io/os"=linux
Next, Deploy the application.
NOTE: Ingress controller references a Secrets Store CSI volume and a
secretProviderClass
object created earlier. A Kubernetes secretingress-tls-csi
will be created by the CSI driver as a result of ingress controller creation.
helm install ingress-nginx/ingress-nginx --generate-name \
--namespace $NAMESPACE \
--set controller.replicaCount=2 \
--set controller.nodeSelector."beta\.kubernetes\.io/os"=linux \
--set defaultBackend.nodeSelector."beta\.kubernetes\.io/os"=linux \
--set controller.podLabels.aadpodidbinding=$AAD_POD_IDENTITY_NAME \
-f - <<EOF
controller:
extraVolumes:
- name: secrets-store-inline
csi:
driver: secrets-store.csi.k8s.io
readOnly: true
volumeAttributes:
secretProviderClass: "azure-tls"
nodePublishSecretRef:
name: secrets-store-creds
extraVolumeMounts:
- name: secrets-store-inline
mountPath: "/mnt/secrets-store"
readOnly: true
EOF
If not using service principal mode, remove the following snippet from the script:
nodePublishSecretRef:
name: secrets-store-creds
kubectl get secret -n $NAMESPACE
NAME TYPE DATA AGE
ingress-tls-csi kubernetes.io/tls 2 1m34s
Next, Deploy the application.
Depending on the TLS certificate lifecycle, follow one of the following steps:
NOTE: These apps reference a Secrets Store CSI volume and a
secretProviderClass
object created earlier. A Kubernetes secretingress-tls-csi
will be created by the CSI driver as a result of the app creation in the same namespace.
volumes:
- name: secrets-store-inline
csi:
driver: secrets-store.csi.k8s.io
readOnly: true
volumeAttributes:
secretProviderClass: "azure-tls"
nodePublishSecretRef:
name: secrets-store-creds
If not using service principal mode, remove the following snippet from deployment-app-one.yaml and deployment-app-two.yaml
nodePublishSecretRef:
name: secrets-store-creds
kubectl apply -f https://raw.githubusercontent.com/Azure/secrets-store-csi-driver-provider-azure/master/docs/sample/ingress-controller-tls/deployment-app-one.yaml -n $NAMESPACE
kubectl apply -f https://raw.githubusercontent.com/Azure/secrets-store-csi-driver-provider-azure/master/docs/sample/ingress-controller-tls/deployment-app-two.yaml -n $NAMESPACE
kubectl get secret -n $NAMESPACE
NAME TYPE DATA AGE
ingress-tls-csi kubernetes.io/tls 2 1m34s
Next, Deploy the ingress resource
remove the following snippet from deployment-app-one.yaml and deployment-app-two.yaml
volumeMounts:
- name: secrets-store-inline
mountPath: "/mnt/secrets-store"
readOnly: true
volumes:
- name: secrets-store-inline
csi:
driver: secrets-store.csi.k8s.io
readOnly: true
volumeAttributes:
secretProviderClass: "azure-tls"
nodePublishSecretRef:
name: secrets-store-creds
kubectl apply -f https://raw.githubusercontent.com/Azure/secrets-store-csi-driver-provider-azure/master/docs/sample/ingress-controller-tls/deployment-app-one.yaml -n $NAMESPACE
kubectl apply -f https://raw.githubusercontent.com/Azure/secrets-store-csi-driver-provider-azure/master/docs/sample/ingress-controller-tls/deployment-app-two.yaml -n $NAMESPACE
Next, Deploy the ingress resource
NOTE: The ingress resource references the Kubernetes secret
ingress-tls-csi
created by the CSI driver as a result of the app creation.
The following snippet shows the code which makes this happen:
tls:
- hosts:
- demo.test.com
secretName: ingress-tls-csi
kubectl apply -f https://raw.githubusercontent.com/Azure/secrets-store-csi-driver-provider-azure/master/docs/sample/ingress-controller-tls/ingress.yaml -n $NAMESPACE
kubectl get service -l app=nginx-ingress --namespace $NAMESPACE
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-ingress-1588032400-controller LoadBalancer 10.0.255.157 52.xx.xx.xx 80:31293/TCP,443:31265/TCP 19m
nginx-ingress-1588032400-default-backend ClusterIP 10.0.223.214 <none> 80/TCP 19m
Using curl
to verify ingress configuration using TLS.
Replace the public IP with the external IP of the ingress controller service from the previous step.
curl -v -k --resolve demo.test.com:443:52.xx.xx.xx https://demo.test.com
# You should see the following in your output
* subject: CN=demo.test.com; O=ingress-tls
* start date: Apr 15 04:23:46 2020 GMT
* expire date: Apr 15 04:23:46 2021 GMT
* issuer: CN=demo.test.com; O=ingress-tls
* SSL certificate verify result: self signed certificate (18), continuing anyway.
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.