GitHub Actions and Azure key vault

We all know that we shouldn’t put any passwords into our code and check them into source control, but many guides (including my own) often reference a password variable or parameter. The parameter option is actually OK, in my opinion, as long as you then reference a secure password from either an Azure DevOps library, GitHub Secret, or using an Azure key vault. In this post, I want to show you how to reference secrets stored in the Azure key vault and use them in a GitHub action and pass the value to a Bicep deployment. I have written a blog series on using GitHub actions and Bicep. If you haven’t read it yet, have a look here .

First, I will need to create an Azure key vault and add my secrets into the key vault. I will go to the Azure portal and click on “Add a resource”.

I will search for “Key Vault” and press enter.

I can then click on “Create”

I will create a new resource group called “rg-keyvault-001” and provide the name “BlogPostDemo”, and I want the location to be in West Europe.

I will allow ARM access to the key vault for template deployments and click on “Review and create”, this permission isn’t strictly needed in this demo, but I like to have that permission set so I can use it inside ARM templates.

The validation passed so I will click on “Create”

When the deployment has completed, I can go to the resource and add my secrets. In the navigation pane on my key vault, I click on “Secrets”, and I can then click on “Generate/Import” in the midsection.

I choose the manual option for upload and provide a name for my secret. Here, I am creating the domain join password, so I will call it “DomainJoinPassword” and I will type in the password I am using for my service account. I could choose to set dates for activation and expiration, but I will leave those unchecked and ensure that the secret is enabled.

I am using three secrets in this demo so the picture below matches my needs in this setup.

Next, I need to allow my service principal access to the key vault. Otherwise, it won’t be able to retrieve the secrets and use them in the pipeline. I provide this access by using Azure CLI and the command below. You can find the client id under “Azure Active Directory” and “App registrations,” find the service principal you are using in GitHub actions, and in the overview, the client id is listed. I have pasted an example on the app registration below.

az keyvault set-policy -n BlogPostDemo --secret-permissions get list --spn <clientId>

With the key vault created and the updated permissions, I can update my GitHub action workflow to fetch and pass these secrets. Below I have pasted a section from my YAML file which logs into Azure with my service principal, and then it retrieves the secrets in the key vault I have created.

    - name: Login to Azure
      uses: azure/login@v1
      with:
        creds: ${{ secrets.AZURE\_CREDENTIALS\_BLOGSERIES }}

    - uses: Azure/get-keyvault-secrets@v1
      with:
        keyvault: "BlogPostDemo"
        secrets: 'VMPassword, DomainJoinPassword, VPNSharedSecret'
      id: KeyVaultSecrets

To use the secrets, I reference the id from the key vault section above and point to the secret I need. Below is an example of this configuration.

    - name: Deploy Citrix Cloud Connectors
      uses: azure/arm-deploy@v1
      with:
        scope: resourcegroup
        resourceGroupName: rg-bicep-citrix-vm-001
        subscriptionId: ${{ secrets.AZURE\_SUBSCRIPTION }}
        region: westeurope
        template: ./VirtualMachine/DeployCCCVM.bicep
        deploymentMode: incremental
        parameters: 
          DomainJoinPassword=${{ steps.KeyVaultSecrets.outputs.DomainJoinPassword }}
          VMPassword=${{ steps.KeyVaultSecrets.outputs.VMPassword }} 

For the above to work the bicep file needs to take the secrets as parameters and below I have an example of this.

param companyPrefix string = 'bicep'
@secure()
param VMPassword string
@secure()
param DomainJoinPassword string

module citrixcloudconnector './Templates/CitrixCloudConnector.bicep' = {
  name: 'CitrixCloudConnector'
  params: {
    availabilitySetName: 'as-citrix-001'
    availabilitySetPlatformFaultDomainCount: 2
    availabilitySetPlatformUpdateDomainCount: 5
    CCVMPrefix: 'vm-ctx-cc'
    domainFQDN: 'InsertDomain'
    domainJoinUserName: 'domainjoin'
    domainJoinUserPassword: DomainJoinPassword
    location: resourceGroup().location
    OS: 'Server2019'
    ouPath: 'InsertOUPath'
    SubnetName: 'snet-citrix-vm-001'
    virtualMachineCount: 2
    VMPassword: VMPassword
    VMSize: 'Standard\_B2ms'
    VMUserName: 'azureadmin'
    vNetName: 'vnet-${companyPrefix}-citrix-001'
    vNetResourceGroup: 'rg-${companyPrefix}-citrix-network-001'
  }
}

By using Azure key vault, I have secured my deployment and ensured that no password is stored in my source code and that no password will be shown in any deployment logs in GitHub actions.

You can find the complete source code for my Bicep deployment here .

I hope this post was useful, and do provide any feedback you might have.

Comments