ci/cd pipeline with azure devops to deploy any apps on kubernetes
Back in October 1st 2018, I published Azure DevOps to deploy your apps/services into a Kubernetes cluster, then I updated it on October 12th 2018 with Helm charts repository with Azure Container Registry, to finally published on November 27th 2018 a more generic and professional one in the official Microsoft Open Source blog: Tutorial: Using Azure DevOps to setup a CI/CD pipeline and deploy to Kubernetes. Enventually the latter got a major refresh on November 2019 (few information of this current blog article may differ though).
I got great feedback from customers and colleagues which brought to my attention few ideas of improvements.
Today, I would like to walk you through 4 improvements I have made:
- Helm chart versioning improvement
- Specific Service Principal to deploy apps in AKS
- YAML definition for both the Build and the Release pipelines
- Azure Key Vault to store and retrieve secrets throughout the CI/CD pipeline
The workflow is now:
1. Helm chart versioning improvement
Again I got great feedback from my original blog article, here is the story about how I have improved the Helm chart versioning: Helm chart management in CI/CD with ACR and Azure DevOps.
2. Specific Service Principal to deploy apps in AKS
From Azure DevOps pipelines we need to get access to the AKS cluster to be able then to deploy our Helm chart. Typically we will get the kubeconfig file to be able to run the helm upgrade command. To do so we will need to do az login and then az aks get-credendials. Furthermore, we would like to respect the Least privilege Security Principle by restricting the role and scope of the associated Service Principal. Here is how you will achieve that:
aksSpSecret=$(az ad sp create-for-rbac -n aks-sp --skip-assignment --query password -o tsv) aksSpId=$(az ad sp show --id http://aks-sp --query appId -o tsv) aks=_<your-aks-cluster-name>_ aksId=$(az aks show -g $aks -n $aks --query id) az role assignment create --assignee $aksSpId --role "Azure Kubernetes Service Cluster User Role" --scope aksId aksSpTenantId=$(az account show --query tenantId -o tsv)
We will use those values later.
Note: previously we were using a Kubernetes Service Endpoint which typically allows you to provide the kubeconfig or create for you a Service Principal but Contributor on a specific Resource Group or at the Subscription level.
3. YAML definition for both the Build and the Release pipelines
Since Multi-Stage pipeline is supported with the YAML definition we could now integrate our Release definition and our Build definition with our Azure pipelines. On that regard, we will have 4 files:
- ci-pipeline.yml and cd-pipeline.yml, which will define the entire CI/CD pipeline with 3 Stages: Build, Development and Production
- ci-steps-template.yml, acting as the template for the Build steps (CI)
- cd-steps-template.yml, acting as the template for the Release steps (CD - Development and Production)
TIPS: you could leverage the Azure DevOps CLI to create your Azure pipeline definition based on this YAML file:
az pipelines create --yml-path.
4. Azure Key Vault to store and retrieve the secrets
Here the goal is to store secrets needed throughout the CI/CD pipeline in Azure Key Vault to be more secure.
rg=<your-rg> kv=<your-kv> subscriptionId=$(az account show --query id -o tsv) tenantId=$(az account show --query tenantId -o tsv) # Create an Azure Key Vault instance az group create -n $rg -l $location az keyvault create -l $location -n $kv -g $rg # Create a Service Principal which will be able to read the secrets from that specific Azure Key Vault kvSpSecret=$(az ad sp create-for-rbac -n $kv --skip-assignment --query password -o tsv) kvSpId=$(az ad sp show --id http://$kv --query appId -o tsv) kvId=$(az keyvault show -n $kv --query id -o tsv) az role assignment create --assignee $kvSpId --role Reader --scope $kvId # Add the specific policies to this Service Principal az keyvault set-policy -n $kv --spn $kvSpId --secret-permissions get list
TIPS: you could leverage the Azure DevOps CLI to create your Service Endpoint based on this specific Service Principal created for your Azure Key Vault:
az devops service-endpoint create \ --authorization-scheme ServicePrincipal \ --service-endpoint-type azurerm \ --azure-rm-service-principal-id $kvSpId \ --azure-rm-subscription-id $subscriptionId \ --azure-rm-tenant-id $tenantId # Now let's add our secrets into our Azure Key Vault for our Development Environment (for other Environments like Production, you could repeat the exact same way accordingly) az keyvault secret set --vault-name $kv -n dev-aksSpTenantId --value $tenantId az keyvault secret set --vault-name $kv -n dev-aksSpId --value $aksSpId az keyvault secret set --vault-name $kv -n dev-aksSpSecret --value $aksSpSecret
Note: You could also store your Azure Container Registry login and password (see the original blog article to see how to get them).
From there, you could now create a Variable Group in Azure DevOps linked to this Azure Key Vault by leveraging this Service Principal just created.
And voila, for today!
Throughout this blob article, we were able to add more security in our CI/CD pipeline by storing our Secrets into Azure Key Vault and by following the Least Privilege Security Principle, we rigorously improved our Helm chart versioning as well as we leveraged the multi-stage definition as YAML file to gain in automation with Configuration-as-Code.
Hope you enjoyed this blog article and hope you are able to leverage and adapt it for your own needs and context.