ASOS Tech Blog
Published in

ASOS Tech Blog

How auto rotating certificates reduces toil for our engineering teams

Hosting technologies at ASOS

Controlling access to certificates in Azure Key Vault

Azure App Service

  1. Enable System Assigned identity
  2. Include a step in your provisioning pipeline to reference the Key Vault to obtain a certificate reference — this will ‘import’ the certificate into the App Service
  3. Setup the TLS SNI binding as normal by referencing the imported certificate
az account set --subscription subscriptionNameaz webapp config ssl import --resource-group rename 
--name appServiceName
--key-vault /subscriptions/subscriptionId/resourceGroups/rgName/providers/Microsoft.KeyVault/vaults/keyVaultName
--key-vault-certificate-name certificateName

Azure Application Gateway

  1. Create a User Assigned Managed Identity
  2. Assign the identity to the Application Gateway
az network application-gateway identity assign -g rgName --gateway-name gatewayName --identity resourceIdForManagedIdentity
az network application-gateway ssl-cert create -n 'sslCertName' -g rgName --gateway-name gatewayName --key-vault-secret-id certificateSecretUrl

Kubernetes — Traefik and Nginx

apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
name: {{ .Values.ingressCertificateName }}
namespace: {{ .Values.ingressNamespace }}
spec:
provider: azure
secretObjects:
- secretName: {{ .Values.secretName }}
type: kubernetes.io/tls
data:
- objectName: {{ .Values.ingressCertificateName }}
key: tls.key
- objectName: {{ .Values.ingressCertificateName }}
key: tls.crt
parameters:
usePodIdentity: "false"
useVMManagedIdentity: "true"
userAssignedIdentityID: {{ .Values.managedIdentityClientId }}
keyvaultName: {{ .Values.ingressCertificateKeyVaultName }}
objects: |
array:
- |
objectName: {{ .Values.ingressCertificateName }}
objectType: secret
tenantId: {{ .Values.tenantId }}
volumes:
- name: tls-volume
csi:
driver: secrets-store.csi.k8s.io
readOnly: true
volumeAttributes:
secretProviderClass: {{ .Values.ingressCertificateName }}
volumeMounts:
- name: tls-volume
mountPath: /etc/ssl/private
readOnly: true
  1. you need to configure how often the CSI driver polls the Key Vault for updates and if mounts will be updated when the secret changes
  2. binding the volume directly to a ingress pod adds a runtime dependency to the availability of the Key Vault — therefore we choose not to mount it to the ingress pod and instead mount it to a pod which only exists for this purpose
  3. The setup of point 2 allows the ingress pods to scale or restart because they consume the Kubernetes secret which remains available during this scenario
apiVersion: traefik.containo.us/v1alpha1
kind: TLSStore
metadata:
name: default
annotations:
helm.sh/hook: "post-install,post-upgrade"
spec:
defaultCertificate:
secretName: {{ .Values.ingress_certificate_name }}
extraArgs: default-ssl-certificate: "{{ nginx_namespace }}/{{ secret_name }}"

Conclusions and Shout Outs

Useful Links

About Me

--

--

A collective effort from ASOS's Tech Team, driven and directed by our writers. Learn about our engineering, our culture, and anything else that's on our mind.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store