This guide demonstrates steps required to setup Secrets Store CSI driver and Azure Key Vault Provider to enable applications to work with NGINX Ingress Controller with TLS stored in Key Vault. For more information on securing an Ingress with TLS, refer to: https://kubernetes.io/docs/concepts/services-networking/ingress/#tls
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"
Create a namespace
kubectl create ns ingress-test
Helm install ingress-controller
helm install stable/nginx-ingress --generate-name \
--namespace ingress-test \
--set controller.replicaCount=2 \
--set controller.nodeSelector."beta\.kubernetes\.io/os"=linux \
--set defaultBackend.nodeSelector."beta\.kubernetes\.io/os"=linux
- To provide identity to access key vault, refer to the following section.
- Set the
tenantId
andkeyvaultName
- Use
objectType: secret
foringresscert
as this is the only way to retrieve the certificate and private key from azure key vault as documented here - Set secret type to
kubernetes.io/tls
$ cat <<EOF | kubectl apply -n ingress-test -f -
apiVersion: secrets-store.csi.x-k8s.io/v1alpha1
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: ingresscert
key: tls.key
- objectName: ingresscert
key: tls.crt
parameters:
usePodIdentity: "false"
keyvaultName: "azkv" # the name of the KeyVault
objects: |
array:
- |
objectName: ingresscert
objectType: secret
tenantId: "xx-xxxxxxxx-xx" # the tenant ID of the KeyVault
EOF
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.
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
Deploy the test apps
kubectl apply -f sample/ingress-controller-tls/deployment-app-one.yaml -n ingress-test
kubectl apply -f sample/ingress-controller-tls/deployment-app-two.yaml -n ingress-test
kubectl get secret -n ingress-test
NAME TYPE DATA AGE
ingress-tls-csi kubernetes.io/tls 2 1m34s
NOTE: The ingress resource references the Kubernetes secret
ingress-tls-csi
created by the CSI driver as a result of the app creation.
tls:
- hosts:
- demo.test.com
secretName: ingress-tls-csi
kubectl apply -f sample/ingress-controller-tls/ingress.yaml -n ingress-test
kubectl get service -l app=nginx-ingress --namespace ingress-test
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.