Condividi tramite


Gestire i segreti con Bicep

Le distribuzioni richiedono spesso che i segreti vengano archiviati e propagati in modo sicuro in tutto l'ambiente Azure. Bicep e Azure offrono molte funzionalità per facilitare la gestione dei segreti nelle distribuzioni.

Evitare segreti in cui è possibile

In molte situazioni, è possibile evitare di usare segreti. Molte risorse di Azure supportano le identità gestite, che consentono loro di eseguire l'autenticazione e di essere autorizzate ad accedere ad altre risorse all'interno di Azure, senza dover gestire o gestire le credenziali. Inoltre, alcuni servizi di Azure possono generare automaticamente certificati HTTPS, evitando di gestire certificati e chiavi private. Usare le identità gestite e i certificati gestiti dal servizio laddove possibile.

Usare parametri protetti

Quando è necessario fornire segreti alle distribuzioni Bicep come parametri, usare il @secure() decorator. Quando si contrassegna un parametro come sicuro, Azure Resource Manager evita di registrare il valore o visualizzarlo nel portale di Azure, nell'interfaccia della riga di comando di Azure o in Azure PowerShell.

Evitare output per i segreti

Non usare output Bicep per i dati sicuri. Gli output vengono registrati nella cronologia di distribuzione e chiunque abbia accesso alla distribuzione può visualizzare i valori degli output di una distribuzione.

Se è necessario generare un segreto all'interno di una distribuzione Bicep e renderlo disponibile al chiamante o ad altre risorse, è consigliabile usare uno degli approcci seguenti.

Cercare i segreti in modo dinamico

In alcuni casi, è necessario accedere a un segreto da una risorsa per configurare un'altra risorsa.

Ad esempio, potrebbe essere stato creato un account di archiviazione in un'altra distribuzione ed è necessario accedere alla relativa chiave primaria per configurare un'app funzioni di Azure. È possibile usare la parola chiave existing per ottenere un riferimento fortemente tipizzato all'account di archiviazione precedentemente creato e quindi usare il metodo listKeys() dell'account di archiviazione per creare una stringa di connessione con la chiave primaria:

L'esempio seguente fa parte di un esempio più ampio. Per un file Bicep che è possibile distribuire, vedere il file completo.

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'
  }
}

Usando questo approccio, è possibile evitare di passare segreti all'esterno o al file Bicep.

È anche possibile usare questo approccio per archiviare i segreti in un insieme di credenziali delle chiavi.

Usare Key Vault

Azure Key Vault è progettato per archiviare e gestire i dati sicuri. Usare un insieme di credenziali delle chiavi per gestire segreti, certificati, chiavi e altri dati che devono essere protetti e condivisi.

È possibile creare e gestire insiemi di credenziali e segreti usando Bicep. Definire gli insiemi di credenziali creando una risorsa con il tipo Microsoft.KeyVault/vaults.

Quando si crea un insieme di credenziali, è necessario determinare chi e cosa può accedere ai dati. Se si prevede di leggere i segreti dell'insieme di credenziali dall'interno di un file Bicep, impostare la proprietà enabledForTemplateDeployment su true.

Aggiungere segreti a un insieme di credenziali delle chiavi

I segreti sono una risorsa figlio e possono essere creati usando il tipo Microsoft.KeyVault/vaults/secrets. L'esempio seguente illustra come creare un insieme di credenziali e un segreto:

L'esempio seguente fa parte di un esempio più ampio. Per un file Bicep che è possibile distribuire, vedere il file completo.

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'
  }
}

Suggerimento

Quando si usano pipeline di distribuzione automatizzate, a volte può essere difficile determinare come eseguire il bootstrap dei segreti dell'insieme di credenziali delle chiavi per le distribuzioni. Ad esempio, se è stata fornita una chiave API da usare durante la comunicazione con un'API esterna, il segreto deve essere aggiunto a un insieme di credenziali prima che possa essere usato nelle distribuzioni.

Quando si usano segreti provenienti da terze parti, potrebbe essere necessario aggiungerli manualmente all'insieme di credenziali e quindi fare riferimento al segreto per tutti gli usi successivi.

Usare un insieme di credenziali delle chiavi con i moduli

Quando si usano i moduli Bicep, è possibile fornire parametri sicuri usando la funzione getSecret.

È anche possibile fare riferimento a un insieme di credenziali delle chiavi definito in un altro gruppo di risorse usando le parole chiave existing e scope insieme. Nell'esempio seguente il file Bicep viene distribuito in un gruppo di risorse denominato Networking. Il valore del parametro del modulo mySecret viene definito in un insieme di credenziali delle chiavi denominato contosonetworkingsecrets che si trova nel gruppo di risorse Segreti:

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')
  }
}

Usare un insieme di credenziali delle chiavi in un file con estensione bicepparam

Quando si usa il formato di file .bicepparam, è possibile fornire valori sicuri ai parametri usando la getSecret funzione.

Fare riferimento all'insieme di credenziali delle chiavi specificando l'ID sottoscrizione, il nome del gruppo di risorse e il nome dell'insieme di credenziali delle chiavi. È possibile ottenere il valore del segreto specificando il nome del segreto. Facoltativamente, è possibile specificare la versione del segreto. Se non si specifica la versione privata, viene usata la versione più recente.

using './main.bicep'

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

Usare i segreti nelle pipeline

Quando si distribuiscono le risorse di Azure usando una pipeline, è necessario occuparsi di gestire i segreti in modo appropriato.

  • Evitare di archiviare segreti nel repository di codice. Ad esempio, non aggiungere segreti ai file dei parametri o ai file YAML di definizione della pipeline.
  • In GitHub Actions usare segreti crittografati per archiviare dati sicuri. Usare l'analisi dei segreti per rilevare eventuali commit accidentali dei segreti.
  • In Azure Pipelines usare variabili segrete per archiviare dati sicuri.