APC 技術ブログ

株式会社エーピーコミュニケーションズの技術ブログです。

株式会社 エーピーコミュニケーションズの技術ブログです。

Azure Container AppsでKeyVaultからSecretを取得する

はじめに

Azure Container Appsでアプリケーションを実行する際、KeyVaultからContainer Appsにシークレット値を格納したり、ボリュームとしてマウントしたいということが多々あると思います。

2023年7月20日現在、KeyVaultからシークレットを参照する機能はPreviewとなっていますが、今回は先取りして実際に使ってみたいと思います。

指定方法

Bicepファイルの内容は以下のようになります。

resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31'existing = {
  name: managedIdentityName
}

resource environment 'Microsoft.App/managedEnvironments@2023-04-01-preview' existing = {
  name: acaEnvironmentName
}

resource app 'Microsoft.App/containerApps@2023-04-01-preview' = {
  name: appName
  location: location
  identity: {
    type: 'UserAssigned'
    userAssignedIdentities: {
      '${managedIdentity.id}': {}
    }
  }
  properties: {
    managedEnvironmentId: environment.id
    configuration: {
      // 〜〜省略〜〜
      secrets: [
        {
          // ${kv.properties.vaultUri} は末尾に '/' を含んでいます
          keyVaultUrl: '${kv.properties.vaultUri}secrets/appSecret1'
          name: 'appenv1'
          identity: managedIdentity.id          
        }
        {
          keyVaultUrl: '${kv.properties.vaultUri}secrets/appSecret2'
          name: 'appenv2'
          identity: managedIdentity.id          
        }
        {
          keyVaultUrl: '${kv.properties.vaultUri}secrets/secretConfig'
          name: 'secretfile'
          identity: managedIdentity.id          
        }
      ]
      // 〜〜省略〜〜
    }
    template: {
      containers: [
        {
          image: '${appImageName}:${appImageTag}'
          name: appName
          env:[
            {
              name: 'APP_ENV_1'
              secretRef: 'appenv1'
            }
            {
              name: 'APP_ENV_2'
              secretRef: 'appenv2'
            }
          ]
          // 〜〜省略
          volumeMounts: [
            {
              volumeName: 'secret-config'
              mountPath: '/mnt/config'
            }
          ]
        }
      ]
      volumes: [
        {
          name: 'secret-config'
          storageType: 'Secret'
          secrets: [
             {
               secretRef: 'secretconfig'
               path: 'secret-config.yaml'
             }
          ]
        }
      ]
  // 〜〜省略〜〜
  tags: tags
}

参照するシークレット情報の指定

KeyVaultからシークレットを取得するために必要となるのが properties.configration.secrets です。 ここに環境変数として参照するもの、ファイルとしてマウントするもの、双方の項目情報をすべて列挙しなければなりません。

指定内容は以下のようになります。

        {
          keyVaultUrl: '${kv.properties.vaultUri}secrets/appSecret2'
          name: 'appenv2' 
          identity: managedIdentity.id
        }

name はこのアプリケーションリソース内におけるシークレットのキーです。キーは小文字の英数字、'_'または'.'が使用可能です。また先頭と末尾は英数字を使用しなければなりません。

identity はKeyVault へのアクセスする際にmanaged identityを利用する場合に指定します。このmanaged identityはBicep中の identity のところで指定してある必要があります。またここではUser managed identitiyを使用していますが、System managed identityを使用する場合は 'System' と指定します。

keyVaultUrl は参照するシークレット値のURLです。 secretの場合、https:///secrets/<secret名>(/[version) という形式になります。Azure PortalでKeyVaultのシークレットを参照したときに表示されるシークレット識別子をコピーするか、上記の例のように ${kv.properties.vaultUri} とkeyvaultのリソース情報を参照するとよいでしょう。このとき${kv.properties.vaultUri}の末尾には '/' が含まれていることに注意してURLを指定してください。 なお、指定の際、末尾にバージョン情報をつけることができます。バージョン情報を省略した場合、最新バージョンの値を参照します。バージョンを指定していない場合、新しいバージョンがKeyVault上で有効になると、30分以内にアプリケーションは最新バージョンを取得します。また、環境変数でシークレットを参照している場合は自動的に再起動されます。

シークレット値の環境変数への格納

まずは環境変数に格納してみましょう。 properties.template.containers[].env で環境変数を指定します。

            {
              name: 'APP_ENV_1'
              secretRef: 'appenv1'
            }

name には環境変数名を指定します。

secretRef には さきほどの secrets のところで指定した name のキーを指定します。 これだけで終了です。

シークレットファイルのマウント

KeyVaultのシークレットにファイルを登録することもあると思います。そうした場合はボリュームとしてマウントして利用します。まずは properties.template.volumes[]` への指定です。

       {
          name: 'secret-config'
          storageType: 'Secret'
          secrets: [
            {
              secretRef: 'secretconfig'
              path: 'secret-config.yaml'
            }
          ]
       }

name にはあとでvolumeMount時に使用するためのキー名を記述します。

storageType は今回KeyVaultを利用してるため 'Secret' と指定します。

secrets[] にはシークレットに格納されているファイルの情報を記述します。secretRef には さきほどの secrets のところで指定した name のキーを指定します。pathには マウントする際のファイル名を記述します。

続いて properties.template.containers[].volumeMounts です。ここからは通常のvolumeMountと同じです。

            {
              volumeName: 'secret-config'
              mountPath: '/mnt/config'
            }

volumeName はさきほどvolumesで指定したボリュームのキー名を指定します。mountPathはマウントする際のディレクトリ名を指定します。

以上で完了です。

今後の課題

シークレットの更新時の動作として以下のようになっていると記載しました。

バージョンを指定していない場合、新しいバージョンがKeyVault上で有効になると、30分以内にアプリケーションは最新バージョンを取得します。また、環境変数でシークレットを参照している場合は自動的に再起動されます。

確かに環境変数で指定されている場合、自動的に再起動するのですが、ボリュームマウントの場合は再起動されないのではないかと思われます。(再起動されなかったように見えた)

このあたりは今後も詳細を確認する必要があります。

ただ、実際の運用では、アプリケーションリビジョンのロールバックなどを行うことを考えると明示的にバージョン名をつけるべきではないかと考えており、大きな問題にはならないのではとも思います。

おまけ

今回の話題とは直接関係ありませんが、Container Appsでmanaged identityを利用したアプリケーションを実行する場合、環境変数として AZURE_CLIENT_ID を指定しておく必要があるそうです。

AKSのWorkload Identityの場合、このあたりの環境変数は自動的に設定されていたのですが、Container Appsの場合はそうなっていませんでした。今回のシークレットと合わせてこちらも設定しておくとよいかもしれません。

github.com

最後に

いかがだったでしょうか。まだPreviewではありますが、シークレット情報を直接Bicep等に記載する必要のない本機能は非常に有用なものなので積極的に活用していきたいところですが、まだまだ情報も少ないこともあり、ドキュメント等をみても指定方法に戸惑うこともあるかと思います。そうした場合に今回の例を参考にしていただければ幸いです。

また、これまでのAzure Container Appsの記事でも様々な情報を提供しております。ぜひご活用ください。

techblog.ap-com.co.jp

ACS事業部のご紹介

私たちACS事業部はAzure・AKSなどのクラウドネイティブ技術を活用した内製化のご支援をしております。 ぜひお声がけください。

www.ap-com.co.jp