Tuesday 11 July 2023

Generate KVSet json Format Using appsettings json for Updating Azure App Configurations

 To apply Azure App Configurations including key vault secrets reference key values and normal key values, using a single file requires to use KVSet file as described in the Article here.  With Azure pipelines updating the app config values require, two seperate files to be used in default mode to update, app configs for non secrets and secrets. However, developers of .NET applications would prefer to keep the appsettings file for keeping configurations for development purpose, rather than keeping seperate file to keep references to secret key values. Therefore, in Azure pipline implmentation, it would be required to generate a KVSet file using an app setting file.

For example consider the below appsettings file.

{
  "AppDomainName": "fakeorg.com",
  "Swagger": {
    "AllowAnonymousSwagger": true
  },
  "AzureAdB2C": {
    "Instance": "https://fakeorg.b2clogin.com",
    "Tenant": "fakeorg.onmicrosoft.com",
    "TenantId": "fake-tenatid",
    "ClientId": "fake-clientid",
    "Domain": "fakeorg.onmicrosoft.com",
    "SignedOutCallbackPath": "/signout/B2C_1A_AD_SIGNUP_SIGNIN",
    "SignUpSignInPolicyId": "B2C_1A_AD_SIGNUP_SIGNIN",
    "ClientSecret": "fakeclientsecret",
    "Scope": "https://fakeorg.onmicrosoft.com/fake-id/access_as_user",
    "ShouldCreateNewAzureB2CUserWhenCreatingNewApplicationUser": true
  },
  "DocuSignClmConfiguration": {
    "BaseUrl": "https://fakeapi.springcm.com/v2",
    "UploadBaseUrl": "https://fakeuploadapi.springcm.com",
    "Authentication": {
      "Audience": "account-d.docusign.com",
      "ClientId": "fake-clientid"
    }
  }
}

In above appsettings below should be considered as secrets.

AzureAdB2C.ClientId
AzureAdB2C.ClientSecret
DocuSignClmConfiguration.Authentication.ClientId

.NET application should be able to use appsettings file for local runs and should load configurations from Azure App Configuration service for deployed app in Azure.

To generate the KVSet file as specified in the Article here we can write a PowerShell script as show below. We can use the script in Azure DevOps pipelines to apply the app configs to Azure App Configuration service, which we are going to discuss in the next post.

The script requires appsetting json (hierarchy of app setting defined sperated with dots) and a variable group defined with secret list .

For example, above ClientId of  AzureAdB2C   represnted in variable group with value for it as  AzureAdB2C.ClientId


Same name AzureAdB2C.ClientId is used in secret list variable group as well to define as a secret.

If we have no secrets we can create secret list with just a dummy variable name.


For our case we can define three secret variable names.


Script will identyfy secrets based on secret-list variable group (in below case variable group with id 27) file and will generate the KVSet file with the correct content type.

$appSettingsFile = 'C:\temp\appsettingstokvset\appsettings.json';
$kvSecretsFile = 'C:\temp\appsettingstokvset\secretlist.txt';
$configLabel = 'demo001';
$token = 'pattoken';
$azdoAccoutName= 'chamindac';
$teamProjectName='YAML_CICD';
$User='';
$secretListVarGroupId='27';


function Get-PropValue {
    param (
        $props,
        $propNamePrefix,
        $KVSetItems
    )

    foreach($prop in $props)
    {
   
        if($prop.TypeNameOfValue -eq 'System.Management.Automation.PSCustomObject')
        {
            $originalPropNamePrefix = $propNamePrefix;
            $propNamePrefix = $propNamePrefix + '.' + $prop.Name;
            
            $KVSetItems = Get-PropValue -props $prop.Value.psObject.Properties -propNamePrefix $propNamePrefix -KVSetItems $KVSetItems
            
            $propNamePrefix = $originalPropNamePrefix;
        }
        else
        {
            [string]$fullPropName = ($propNamePrefix + '.' + $prop.Name).Substring(1)
            #$fullPropName
            #$prop.Value
            if ($kvSecrets.Contains($fullPropName))
            {
                #Write-Host 'secret'
                $KVSetItem ='
                {
                  "key": "' + $fullPropName.Replace('.',':') + '",
                  "value": "{\"uri\":\"' + $prop.Value + '\"}",
                  "label": "' + $configLabel +'",
                  "content_type": "application/vnd.microsoft.appconfig.keyvaultref+json;charset=utf-8",
                  "tags": {}
                }';
                
            }
            else
            {
                $KVSetitem ='
                {
                  "key": "' + $fullPropName.Replace('.',':') + '",
                  "value": "' + $prop.Value + '",
                  "label": "' + $configLabel +'",
                  "content_type": null,
                  "tags": {}
                }';
            }

            $KVSetItems = $KVSetItems + ',' + $KVSetitem;
            #Write-Host '------------------'
            #$KVSetItem
            #Write-Host '++++++++++++++++++'
        }
    }
    return $KVSetItems;
}


$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $User,$token)));
$header = @{Authorization=("Basic {0}" -f $base64AuthInfo)};

$Uri = 'https://dev.azure.com/' + $azdoAccoutName + '/' + $teamProjectName + '/_apis/distributedtask/variablegroups/' + $secretListVarGroupId + '?api-version=7.1-preview.2'

$kvSecrets = (Invoke-RestMethod -Method Get -ContentType application/json -Uri $Uri -Headers $header).variables.psObject.Properties.Name

Write-Host '------------------'
Write-Host 'secret-list'
Write-Host '------------------'
$kvSecrets
Write-Host '------------------'


$appSettings = Get-Content -Path $appSettingsFile | ConvertFrom-Json

$KVSetItems = '';

$KVSetItems = Get-PropValue -props $appSettings.psObject.Properties -propNamePrefix '' -KVSetItems $KVSetItems

$KVSet = '{
  "items": ['+ $KVSetItems.Substring(1) +'
  ]
}
';

$KVSet

$KVSet | Out-File -FilePath 'C:\temp\kvset.json'

Once the script is executed it will generate the KVSet file content as shown below.



No comments:

Popular Posts