Skip to main content

Azure Bicepのセキュリティの基本

著者
Headshot of Mark Johnson

Mark Johnson

feature bicep security

2022年12月13日

0 分で読めます

この記事は、Snyk AmbassadorのMark Johnson(@tazmainiandevil)が執筆しました。Snykをいち早く体験するには、 Snyk Ambassadorに登録してください。

Azure Bicepの人気は日々高まっており、Azure Resource Manager(ARM)テンプレートに急速に取って代わりつつあります。この記事では、Bicepを使用する際のセキュリティの基本をいくつか紹介します。Bicepについて詳しくない方は、Microsoft Learnのドキュメントをご覧ください。

シークレットをソース管理に含めない

シークレットをソース管理に含めないことは誰もが理解していますが、特にローカルでBicepの構成をテストしていると、ファイルにシークレットを誤って残してしまうことは簡単に起こります。

シークレットをコミットしないための方法をいくつか紹介します。

  • コマンドラインからパラメーターを渡す。

  • ソース管理の対象外にするパラメーターJSONファイルを使用する。Gitを使用している場合は、たとえば.gitignoreファイルに追加します。

入力を保護する

外部からパラメーターを渡すのは一つの方法ですが、シークレットが安全に保護され、出力に表示されないようにするにはどうすればよいでしょうか。Bicepには、String型とObject型のパラメーターに使用できる@secureデコレーターが用意されています。例を示します。

@secure()
param adminPassword string

@secure()
param adminCredentials object

出力の扱いに注意する

Bicepモジュールに出力を追加すると便利ですが、注意すべき点もいくつかあります。シークレットのように見える値を出力に設定すると、Bicepはシークレットが漏えいする可能性があるという警告を表示します。ストレージアカウントの接続文字列を次のように出力すると、この警告が表示されます。

output connection string = 'DefaultEndpointsProtocol=https;AccountName=${storageaccount.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${listKeys(storageaccount.id, storageaccount.apiVersion).keys[0].value}'

ただし、出力に割り当てる前に値を変数に追加しておくと、警告が表示されず、見落としやすくなります。

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

output connection string = connectionString

では、次の構成を使ってストレージアカウントのリソースをAzureにデプロイするとどうなるか見てみましょう。

deploy.bicep
param location string = resourceGroup().location
param tags object = {}
param storageName string = 'stsecureteststore'
param sku string = 'Standard_LRS'

module storageModule 'modules/storage.bicep' = {
  name: 'StorageDeploy'
  params: {
    location: location
    storageName: storageName
    tags: tags
    sku: sku
  }
}

modules/storage.bicep

@description('The storage account name')
@minLength(3)
@maxLength(24)
param storageName string
@description('The storage account location')
param location string
@description('The tags for the storage account')
param tags object
@description('The storage account sku') 
@allowed([ 'Standard_LRS', 'Standard_GRS', 'Standard_GZRS', 'Standard_RAGRS', 'Standard_RAGZRS', 'Standard_ZRS', 'Premium_LRS', 'Premium_ZRS' ])
param sku string = 'Standard_LRS'
@description('The access tier for the blob services') 
@allowed([ 'Hot', 'Cool' ]) 
param accessTier string = 'Hot' 
@description('Allow public access to blobs') 
param allowBlobPublicAccess bool = false 

resource storageaccount 'Microsoft.Storage/storageAccounts@2022-05-01' = {
  name: storageName
  location: location
  kind: 'StorageV2'
  tags: tags
  sku: {
    name: sku
  }
  properties: {
    supportsHttpsTrafficOnly: true
    minimumTlsVersion: 'TLS1_2'
    accessTier: accessTier
    allowBlobPublicAccess: allowBlobPublicAccess
  }
}

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

Bicepで定義した出力は、リソースのデプロイ先であるリソースグループのデプロイから確認できます。

rg-security-exampleリソースグループのAzureポータルのデプロイページ。StorageDeployとmainのデプロイが表示され、ステータスはいずれも「成功」

StorageDeployの出力を見ると、接続文字列にアカウントキーが平文で表示されていることがわかります。

ストレージアカウントの接続文字列の出力が表示された、AzureポータルのStorageDeploy Outputsページ。

つまり、Azure Portalでリソースを閲覧できる人なら誰でも、これらの出力を確認できます。セキュリティ態勢を適切に保つには、Bicepでシークレットを出力しないことをおすすめします。

今後、Bicepの出力にも@secureデコレーターが使えるようになれば、シークレットを安全に返せるようになるでしょう。

リソースからシークレットを取得する

Bicepからシークレットを返すことが問題となる場合、あるモジュールから別のモジュールへシークレットを渡すにはどうすればよいでしょうか。一つの方法は、existingキーワードを使って既存のリソースにアクセスすることです。例を示します。

param storageName string

resource storageaccount 'Microsoft.Storage/storageAccounts@2022-05-01' existing = {
  name: storageName  
}

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

この接続文字列は、別のリソースへの入力として使用できます。

Key Vaultからシークレットを取得する

既存のリソースからシークレットを取得する方法のほかに、Key Vaultを使ってシークレットを取得することもできます。

注意:Key Vaultのアクセス構成で「テンプレートのデプロイに Azure Resource Manager を許可する」を有効にしてください。

テンプレートのデプロイにはAzure Resource Managerを使用するリソースアクセス設定。仮想マシンとディスク暗号化は選択されていません。

前のセクションと同様に、existingキーワードを使ってKey Vaultにアクセスします。ただし、getSecretメソッドを使用できるのは、@secureデコレーターが付いたモジュールパラメーターに割り当てる場合のみです。

deploy.bicep
param location string = resourceGroup().location
param tags object
param sqlServerName string
param keyVaultName string
param keyVaultResourceGroupName string
param subscriptionId string = subscription().subscriptionId

resource vaultResource 'Microsoft.KeyVault/vaults@2022-07-01' existing = {
  name: keyVaultName 
  scope: resourceGroup(subscriptionId, keyVaultResourceGroupName  )
}

module sqlModule 'modules/sql.bicep' = {
  name: 'SqlDeploy'
  params: {
    location: location
    tags: tags
    sqlServerName: sqlServerName
    administratorLogin: vaultResource.getSecret('sqlUser')
    administratorLoginPassword: vaultResource.getSecret('sqlPassword')
  }  
}

modules/sql.bicep
@description('The resource location')
param location string
@description('The tags for the resources')
param tags object
@description('The name for the SQL Server')
param sqlServerName string
@secure()
@description('The SQL Administrator Login')
param administratorLogin string
@secure()
@description('The SQL Administrator password')
param administratorLoginPassword string

resource sqlServerResource 'Microsoft.Sql/servers@2022-05-01-preview' = {
  name: sqlServerName
  location: location
  tags:tags
  properties: {
    administratorLogin: administratorLogin
    administratorLoginPassword: administratorLoginPassword
  }
}

Bicepのセキュリティスキャン

Infrastructure as Code(IaC)のスキャンが広く利用されるようになり、セキュリティ上の問題をできるだけ早く見つけようという動きが広がっています。Snykが提供する無料のCLIを使えば、ローカル環境でセキュリティやコンプライアンスの基準に照らしてIaCをスキャンできます。Bicep形式には直接対応していませんが、Bicepのコンパイル先であるARMテンプレートのスキャンには対応しています。

BicepをARMにコンパイルするには、Bicep CLIをインストールする必要があります。Snyk CLIを使い始めるには、無料アカウントを作成し、npmでSnyk CLIをインストールしてください。Node.jsがローカルにインストールされている場合は、次のコマンドを実行してインストールできます。

npm install snyk@latest -g

インストールとセットアップが完了したら、次のコマンドを実行します。

az bicep build -f {file_name}.bicep

Bicepファイルと同じ名前のJSONファイルが生成されます。その後、次のコマンドでSnykスキャンを実行できます。

snyk iac test {file_name}.json

まとめ

セキュリティは誰もが考慮すべきことです。状況は常に変化しますが、学びを重ねることで、リソースの保護に向けてできることも増えていきます。この記事が参考になり、Bicepの構成を保護するためのヒントを得ていただけたなら幸いです。

開発者のために設計されたIaCセキュリティ

Snykは、統合されたポリシー・アズ・コードエンジンにより、SDLCからクラウドでの実行時までInfrastructure as Codeを保護します。すべてのチームが安全に開発、デプロイ、運用できるよう支援します。

続きを読む

feature insights context
Blog

自律型攻撃はすでに始まっている。防御もそのスピードに追いつかなければならない。

自律型攻撃者によって、防御に使える時間は短くなっています。継続的な検出、修復、検証、予防で、セキュリティチームが攻撃に歩調を合わせる方法をご紹介します。

Blog

Evo ADSのエージェント動作ガバナンスが一般提供開始:MCPの利用を管理

Evo ADSのエージェント動作ガバナンスが、MCPガバナンスから一般提供を開始しました。主要なAIコーディングエージェント全体で、MCPサーバーの利用を検出、承認、監視、記録、ブロックできます。

illustration hero ai
Blog

Agentic AppSecとは?

Agentic AppSecが、根拠に基づき、範囲を限定され、独立して検証されるAIエージェントを活用して、アプリケーションセキュリティの一連のプロセスを実行する方法をご紹介します。