Update App Service config from GitHub Actions


During the CI/CD pipeline of a PR request for one of my projects, E2E tests are run in a staging environment of an Azure Static Web App. This results in the staging environment having different URLs each time, giving the API a need to update CORS settings to allow for the app to connect to the API. Thus, came the need to update the settings of an Azure App Service from GitHub Actions.

Connecting to the Azure App Service

First I need to be able to connect from GitHub Actions to the Azure App Service using the Azure Login for GitHub Actions. And for that, as I didn’t already have it, I needed to create credentials. In Azures Cloud Shell, I ran the following command.

 az ad sp create-for-rbac --name $n--role ame contributor --scopes /subscriptions/$subId/resourceGroups/$resourceGroupName --sdk-auth

Where I obviously replace the name $n with a name I could identify the resource with (I used GithubAuthApp) and replace $subId with the subscription id of the resource to access, same with $resourceGroupName.

As a result when running this command, you get a json object output in the format:

{
  "clientId": "xxx",
  "clientSecret": "xxx",
  "subscriptionId": "xxx",
  "tenantId": "xxx",
  "activeDirectoryEndpointUrl": "https://login.microsoftonline.com",
  "resourceManagerEndpointUrl": "https://management.azure.com/",
  "activeDirectoryGraphResourceId": "https://graph.windows.net/",
  "sqlManagementEndpointUrl": "https://management.core.windows.net:8443/",
  "galleryEndpointUrl": "https://gallery.azure.com/",
  "managementEndpointUrl": "https://management.core.windows.net/"
}

Copy that and save it to a temporary document somewhere to keep safe until we need it in the next step. Note that it won’t be recreated, and you will need to repeat this step if you lose it.

Setup GitHub

For GitHub to use the credentials from the previous step, create a GitHub secret name AZURE_API_CREDENTIALS and save the Json object in.

As variables (or secrets but I have a private repository and don’t see the point) save the resource name of the APIs Azure App Service as API_APP_NAME and the name of the Resource group the App Service belongs to as API_RESOURCE_GROUP.

Lastly, the name of the CORS setting in App settings is needed, I saved it as the variable named API_CORS_CONFIG_NAME. I’m pointing out, hopefully without needing to, that obviously the API need to be built with appsettings to be used to configure CORS for this all to work.

App Url

Read about how I handle app url and how it can be created here, https://blog.yellowhousestudio.se/2023/05/10/automate-azure-b2c-redirect-url/#azure-static-web-app-url, as I use this step in the same process.

Create workflow

I use reusable workflows, so I created a new workflow file, named setup-api.yml that looks as follows:

on:
  workflow_call:
    inputs:
      appUrl:
        type: string
        required: true
      environment:
        type: string
        required: true
    secrets:
      AZURE_API_CREDENTIALS:
        required: true

jobs:
  update-api-config:
    name: Update API config to allow for testing
    runs-on: ubuntu-latest
    environment: ${{ inputs.environment }}
    steps:
      - name: Login to Azure
        uses: azure/login@v1
        with:
          creds: ${{ secrets.AZURE_API_CREDENTIALS}}
          allow-no-subscriptions: true
          enable-AzPSSession: true
      - name: Update API config to allow for testing
        uses: azure/powershell@v1
        with:
          azPSVersion: "latest"
          inlineScript: |
            $configCors= az webapp config appsettings list --name ${{ vars.API_APP_NAME }} --resource-group ${{ vars.API_RESOURCE_GROUP }} --query "[?name=='${{ vars.API_CORS_CONFIG_NAME }}'].[value]" --output tsv
            $appUrl= "${{ inputs.appUrl}}"
            if (!$configCors.contains($appUrl)) {
                  $configCors += "," + $appUrl
                  az webapp config appsettings set --name ${{ vars.API_APP_NAME }} --resource-group ${{ vars.API_RESOURCE_GROUP }} --settings ${{ vars.API_CORS_CONFIG_NAME }}=$configCors
            }

First job I log into Azure, and the next job is a PowerShell script that first gets the appsetting for a specific name (CORS Settings). Then I check if the config already contains the url. If not, it tacks it on, writes out the new config string, and sends a command back to update the CORS configuration to the updated config.

Done.

As in other posts about my PR workflow, a new job needed to be created, look like this:

setup-api:
    uses: ./.github/workflows/setup-api.yml
    needs: deploy
    secrets: inherit
    with:
      appUrl: ${{ needs.deploy.outputs.appUrl }}
      environment: Stage

Leave a Reply

Your email address will not be published. Required fields are marked *