Управление секретами с помощью Bicep

Для развертываний часто требуется безопасно хранить секреты и распространять их в среде Azure. В Bicep и Azure есть множество функций, которые помогут вам управлять секретами в развертываниях.

При возможности не используйте секреты

Во многих случаях секреты можно вообще не использовать. Многие ресурсы Azure поддерживают управляемые удостоверения, позволяющие им выполнять проверку подлинности и получать разрешение на доступ к другим ресурсам в Azure без обработки учетных данных и управления ими. Кроме того, некоторые службы Azure могут автоматически создавать сертификаты HTTPS, чтобы не обрабатывать сертификаты и закрытые ключи. По возможности используйте управляемые удостоверения и сертификаты, управляемые службами.

Используйте защищенные параметры

Если вам нужно предоставить секреты в развертывания Bicep в качестве параметров, используйте декоратор @secure(). Если пометить параметр как безопасный, Azure Resource Manager не будет вносить значение в журнал или отображать его на портале Azure, в Azure CLI или Azure PowerShell.

Не используйте выходных данных для секретов

Не используйте выходные данные Bicep для защищенных данных. Выходные данные регистрируются в журнале развертывания, и любой человек, у кого есть доступ к развертыванию, может просмотреть значения выходных данных развертывания.

Если вам нужно создать секрет в развертывании Bicep и сделать его доступным для вызывающего или других ресурсов, рассмотрите один из описанных ниже подходов.

Ищите секреты динамически

Иногда для настройки одного ресурса требуется доступ к секрету другого ресурса.

Например, если вы создали учетную запись хранения в другом развертывании и вам нужно получить доступ к ее первичному ключу для настройки приложения решения "Функции Azure". С помощью ключевого слова existing вы можете получить строго типизированную ссылку на предварительно созданную учетную запись хранения, а затем с помощью метода listKeys() учетной записи хранения создать строку подключения с первичным ключом:

Следующий пример является частью большего примера. Для файла Bicep, который вы можете развернуть, см. полный файл.

param location string = resourceGroup().location
param storageAccountName string
param functionAppName string = 'fn-${uniqueString(resourceGroup().id)}'

var appServicePlanName = 'MyPlan'
var applicationInsightsName = 'MyApplicationInsights'

resource storageAccount 'Microsoft.Storage/storageAccounts@2021-06-01' existing = {
  name: storageAccountName
}

var storageAccountConnectionString = 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${listKeys(storageAccount.id, storageAccount.apiVersion).keys[0].value}'

resource functionApp 'Microsoft.Web/sites@2023-12-01' = {
  name: functionAppName
  location: location
  kind: 'functionapp'
  properties: {
    httpsOnly: true
    serverFarmId: appServicePlan.id
    siteConfig: {
      appSettings: [
        {
          name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
          value: applicationInsights.properties.InstrumentationKey
        }
        {
          name: 'AzureWebJobsStorage'
          value: storageAccountConnectionString
        }
        {
          name: 'FUNCTIONS_EXTENSION_VERSION'
          value: '~3'
        }
        {
          name: 'FUNCTIONS_WORKER_RUNTIME'
          value: 'dotnet'
        }
        {
          name: 'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING'
          value: storageAccountConnectionString
        }
      ]
    }
  }
}

resource appServicePlan 'Microsoft.Web/serverfarms@2023-12-01' = {
  name: appServicePlanName
  location: location
  sku: {
    name: 'Y1' 
    tier: 'Dynamic'
  }
}

resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = {
  name: applicationInsightsName
  location: location
  kind: 'web'
  properties: { 
    Application_Type: 'web'
    publicNetworkAccessForIngestion: 'Enabled'
    publicNetworkAccessForQuery: 'Enabled'
  }
}

Использование этого метода позволяет избежать передачи секретов в файл Bicep или из него.

Этот способ также можно использовать для хранения секретов в хранилище ключей.

Использование Key Vault

Azure Key Vault используется для хранения защищенных данных и управления ими. Используйте хранилище ключей для управления секретами, сертификатами, ключами и другими данными, которые необходимо защитить и совместно использовать.

С помощью Bicep можно создавать хранилища ключей и секреты и управлять ими. Определите свои хранилища, создав ресурс с типом Microsoft.KeyVault/vaults.

При создании хранилища ключей необходимо определить, кто и что могут получать доступ к его данным. Если вы планируете считывать секреты хранилища ключей из файла Bicep, установите для свойства enabledForTemplateDeployment значение true.

Добавление секретов в хранилище ключей

Секрет — это дочерний ресурс, который можно создавать с помощью типа Microsoft.KeyVault/vaults/secrets. В следующем примере показано создание хранилища ключей и секрета:

Следующий пример является частью большего примера. Для файла Bicep, который вы можете развернуть, см. полный файл.

param location string = resourceGroup().location
param keyVaultName string = 'mykv${uniqueString(resourceGroup().id)}'

resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' = {
  name: keyVaultName
  location: location
  properties: {
    enabledForTemplateDeployment: true
    tenantId: tenant().tenantId
    accessPolicies: [
    ]
    sku: {
      name: 'standard'
      family: 'A'
    }
  }
}

resource keyVaultSecret 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = {
  parent: keyVault
  name: 'MySecretName'
  properties: {
    value: 'MyVerySecretValue'
  }
}

Совет

При использовании автоматизированных конвейеров развертываний иногда бывает сложно определить, как выполнить начальную загрузку секретов хранилища ключей для развертываний. Например, если вам предоставлен ключ API для связи с внешним API, перед использованием в развертываниях секрет нужно добавить в хранилище ключей.

При работе с секретами от третьей стороны может потребоваться вручную добавить их в хранилище ключей, а затем ссылаться на них для всех последующих использований.

Использование хранилища ключей с модулями

При использовании модулей Bicep можно предоставить защищенные параметры с помощью функции getSecret.

Вы также можете ссылаться на хранилище ключей, определенное в другой группе ресурсов, используя вместе ключевые слова existing и scope вместе. В следующем примере файл Bicep развертывается в группе ресурсов с именем Networking. Значение параметра mySecret модуля определяется в хранилище ключей contosonetworkingsecrets, расположенном в группе ресурсов Secret:

resource networkingSecretsKeyVault 'Microsoft.KeyVault/vaults@2023-07-01' existing = {
  scope: resourceGroup('Secrets')
  name: 'contosonetworkingsecrets'
}

module exampleModule 'module.bicep' = {
  name: 'exampleModule'
  params: {
    mySecret: networkingSecretsKeyVault.getSecret('mySecret')
  }
}

Использование хранилища ключей в файле Bicepparam

При использовании .bicepparam формата файла можно предоставить безопасные значения параметрам с помощью getSecret функции.

Наведите ссылку на KeyVault, указав идентификатор подписки, имя группы ресурсов и имя хранилища ключей. Значение секрета можно получить, указав имя секрета. При необходимости можно указать версию секрета. Если вы не предоставляете секретную версию, используется последняя версия.

using './main.bicep'

param secureUserName = az.getSecret('<subscriptionId>', '<resourceGroupName>', '<keyVaultName>', '<secretName>', '<secretVersion>')
param securePassword = az.getSecret('<subscriptionId>', '<resourceGroupName>', '<keyVaultName>', '<secretName>')

Работа с секретами в конвейерах

При развертывании ресурсов Azure с помощью конвейера необходимо обеспечить правильную обработку секретов.

  • Избегайте хранения секретов в репозитории кода. Например, не добавляйте секрет к файлам параметров или YAML-файлам определения конвейера.
  • В GitHub Actions используйте зашифрованные секреты для хранения защищенных данных. Используйте сканирование секретов, чтобы обнаружить любые случайные фиксации секретов.
  • В Azure Pipelines используйте секретные переменные для хранения защищенных данных.