diff --git a/eng/common/TestResources/build-test-resource-config.yml b/eng/common/TestResources/build-test-resource-config.yml index b363f85afb9e..5633b12ac94f 100644 --- a/eng/common/TestResources/build-test-resource-config.yml +++ b/eng/common/TestResources/build-test-resource-config.yml @@ -12,6 +12,12 @@ parameters: - name: SubscriptionConfigurationFilePaths type: object default: null + - name: EnvFromKeyvault + type: string + default: '' + - name: KeyvaultEnvPrefix + type: string + default: '' steps: - task: AzurePowerShell@5 @@ -34,20 +40,36 @@ steps: Write-Host "Setting pipeline subnet env variable PoolSubnet to '$poolSubnet'" Write-Host "##vso[task.setvariable variable=PoolSubnet;]$poolSubnet" - - pwsh: | - . ./eng/common/TestResources/SubConfig-Helpers.ps1 + - ${{ if not(parameters.EnvFromKeyvault) }}: + - pwsh: | + . ./eng/common/TestResources/SubConfig-Helpers.ps1 + + $baseSubConfigJson = @' + ${{ parameters.SubscriptionConfiguration }} + '@.Trim() - $baseSubConfigJson = @' - ${{ parameters.SubscriptionConfiguration }} - '@.Trim() + $additionalSubConfigsJson = @' + ${{ convertToJson(parameters.SubscriptionConfigurations) }} + '@.Trim() -replace '"{', '{' -replace '}"', '}' - $additionalSubConfigsJson = @' - ${{ convertToJson(parameters.SubscriptionConfigurations) }} - '@.Trim() -replace '"{', '{' -replace '}"', '}' + $subConfigFilesJson = @' + ${{ convertToJson(parameters.SubscriptionConfigurationFilePaths) }} + '@.Trim() - $subConfigFilesJson = @' - ${{ convertToJson(parameters.SubscriptionConfigurationFilePaths) }} - '@.Trim() + BuildAndSetSubscriptionConfig $baseSubConfigJson $additionalSubConfigsJson $subConfigFilesJson + displayName: Merge subscription configurations + - ${{ else }}: + - task: AzurePowerShell@5 + displayName: Set env vars from ${{ parameters.EnvFromKeyvault }} Keyvault + inputs: + azureSubscription: ${{ parameters.EnvFromKeyvault }} # service connection name must match keyvault name + azurePowerShellVersion: LatestVersion + pwsh: true + ScriptType: InlineScript + Inline: | + . ./eng/common/scripts/Helpers/Keyvault-Helpers.ps1 + Export-KeyvaultSecrets ` + -Keyvault ${{ parameters.EnvFromKeyvault }} ` + -Prefix ${{ parameters.KeyvaultEnvPrefix }} ` + -CI - BuildAndSetSubscriptionConfig $baseSubConfigJson $additionalSubConfigsJson $subConfigFilesJson - displayName: Merge subscription configurations diff --git a/eng/common/scripts/Helpers/Keyvault-Helpers.ps1 b/eng/common/scripts/Helpers/Keyvault-Helpers.ps1 new file mode 100644 index 000000000000..e77ec4ab00f5 --- /dev/null +++ b/eng/common/scripts/Helpers/Keyvault-Helpers.ps1 @@ -0,0 +1,65 @@ +$ErrorActionPreference = 'Stop' +$PSNativeCommandUseErrorActionPreference = $true + +function downloadKeyvaultSecretsAzCli([string]$keyvault) { + $result = @{} + $secrets = @((az keyvault secret list --vault-name $keyvault -o json ` + | ConvertFrom-Json -AsHashtable).name) + foreach ($key in $secrets) { + Write-Host "Fetching secret $key" + $value = az keyvault secret show --vault-name $keyvault --name $key --query value -o tsv + $result[$key] = $value + } + return $result +} + +function downloadKeyvaultSecretsAzPowershell([string]$keyvault) { + $initialContext = if (!$CI) { Get-AzContext } + + $result = @{} + try { + $secrets = @(Get-AzKeyvaultSecret -VaultName $keyvault) + foreach ($obj in $secrets) { + Write-Host "Fetching secret $($obj.Name)" + $value = Get-AzKeyvaultSecret -VaultName $keyvault -Name $obj.Name -AsPlainText + $result[$obj.name] = $value + } + } finally { + if ($initialContext) { + Write-Verbose "Restoring initial context: $($initialContext.Account)" + $null = $initialContext | Select-AzContext + } + } + + return $result +} + +function Export-KeyvaultSecrets { + param( + [string]$Keyvault, + [string]$Prefix, + [switch]$AzCli, + [switch]$CI = ($null -ne $env:SYSTEM_TEAMPROJECTID) + ) + + $secrets = if ($AzCli) { + downloadKeyvaultSecretsAzCli $Keyvault + } else { + downloadKeyvaultSecretsAzPowershell $Keyvault + } + + foreach ($secret in $secrets.GetEnumerator()) { + $envKey = ($secret.key -replace '-','_').ToUpper() + if (!$prefix -or $secret.name -like "${prefix}*" -or $envKey -like "${prefix}*") { + if ($envKey -eq $secret.key) { + Write-Host "Setting variable '$envKey' from keyvault '$Keyvault' as secret" + } else { + Write-Host "Setting variable '$envKey' from '$($secret.key)' in keyvault '$Keyvault' as secret" + } + [Environment]::SetEnvironmentVariable($envKey, $secret.value) + if ($CI) { + Write-Host "##vso[task.setvariable variable=$envKey;issecret=true;]$($secret.value)" + } + } + } +} diff --git a/eng/pipelines/templates/jobs/archetype-sdk-client.yml b/eng/pipelines/templates/jobs/archetype-sdk-client.yml index c5d6e7796bc7..0a678f0d077a 100644 --- a/eng/pipelines/templates/jobs/archetype-sdk-client.yml +++ b/eng/pipelines/templates/jobs/archetype-sdk-client.yml @@ -87,6 +87,12 @@ parameters: - name: PersistOidcToken type: boolean default: false + - name: EnvFromKeyvault + type: string + default: '' + - name: KeyvaultEnvPrefix + type: string + default: '' extends: template: /eng/pipelines/templates/stages/1es-redirect.yml @@ -183,6 +189,8 @@ extends: - ${{ parameters.PostSteps }} UseFederatedAuth: ${{ parameters.UseFederatedAuth }} PersistOidcToken: ${{ parameters.PersistOidcToken }} + EnvFromKeyvault: ${{ parameters.EnvFromKeyvault }} + KeyvaultEnvPrefix: ${{ parameters.KeyvaultEnvPrefix }} MatrixConfigs: # Enumerate platforms and additional platforms based on supported clouds (sparse platform<-->cloud matrix). - ${{ each config in parameters.MatrixConfigs }}: diff --git a/eng/pipelines/templates/jobs/live.tests.yml b/eng/pipelines/templates/jobs/live.tests.yml index 222177cf8449..3a5641e82348 100644 --- a/eng/pipelines/templates/jobs/live.tests.yml +++ b/eng/pipelines/templates/jobs/live.tests.yml @@ -39,6 +39,12 @@ parameters: - name: PersistOidcToken type: boolean default: false + - name: EnvFromKeyvault + type: string + default: '' + - name: KeyvaultEnvPrefix + type: string + default: '' jobs: - job: @@ -78,6 +84,8 @@ jobs: - template: /eng/common/TestResources/build-test-resource-config.yml parameters: + EnvFromKeyvault: ${{ parameters.EnvFromKeyvault }} + KeyvaultEnvPrefix: ${{ parameters.KeyvaultEnvPrefix }} SubscriptionConfiguration: ${{ parameters.CloudConfig.SubscriptionConfiguration }} SubscriptionConfigurations: ${{ parameters.CloudConfig.SubscriptionConfigurations }} SubscriptionConfigurationFilePaths: ${{ parameters.CloudConfig.SubscriptionConfigurationFilePaths }} diff --git a/sdk/ai/azopenai/ci.yml b/sdk/ai/azopenai/ci.yml index 2724b10fcc21..f55898d20679 100644 --- a/sdk/ai/azopenai/ci.yml +++ b/sdk/ai/azopenai/ci.yml @@ -33,10 +33,8 @@ extends: ServiceDirectory: "ai/azopenai" RunLiveTests: true UsePipelineProxy: false - CloudConfig: - Public: - SubscriptionConfigurations: - - $(sub-config-openai-test-resources) # TestSecrets-openai + EnvFromKeyvault: TestSecrets-openai + KeyvaultEnvPrefix: 'GO' EnvVars: AZURE_TEST_RUN_LIVE: "true" # use when utilizing the New-TestResources Script AZURE_CLIENT_ID: $(AZOPENAI_CLIENT_ID)