- はじめに
- AzureAPI Providerとは
- AzAPI ProviderのドキュメントでContainer Apps環境のパラメータを確認してみる
- AzAPI ProviderでContainer Apps環境の作成にチャレンジ!
- まとめ
はじめに
ACS事業部 安藤です。
以前、Azure Container AppsがTerraformでサポートされたぞ!という記事を書いて1年半以上過ぎたんですが、
皆さんイイ感じに使えているでしょうか?
こんなブログを書いておきながら、私も実はあんまり…な感じだったりします。
というのも、現行のContainer Apps周りのリソースでは一部の機能や設定がTerraformでは、正確にはAzureRM Providerでは設定できないものがあり、
そういった部分はTerraformで出来る範囲の使用に留めるか、手動でやる必要が出てしまったりします。
例を出すと、
- Container Apps EnvironmentのManaged IDの有効化
- Container Apps Environmentの証明書のKey Vault連携
などです。
個人的にはこの辺りの問題がContainer Appsを選択したり、オススメしにくい要因とも感じていました。
AzureRM ProviderもVersion 4系にメジャーアップデートされ、Container Appsもいい感じにサポートされないか?と期待はしたものの未だ来ず、という状態だったので、
おそらくAzureでリリースされている機能であれば全機能対応できるであろうAzureAPI Providerで書いてみてはどうだろう?と思い至りました。
AzureAPI Providerとは
AzureのTerraform Providerといえば先述のAzureRM Providerのことを指すことが一番多いと思いますが、
Azure関連のTerraform Providerには複数あり、Azure AD(現在ではAzure Entra ID)関連のAzureAD ProviderやAzure Stack関連のProviderがあります。
その中でAzureが直々にサポートしているPartner Provederの1つとしてAzAPI Providerがあります。
対象とする領域はAzure Resource Manager (ARM) なのでAzureRM Providerと重複しているのですが、それぞれの特長があるので使い分けが効きます。
AzureRMは様々なリソースタイプが用意されており比較的読み書きしやすいですが、Azure側のAPIのリリースに追従してAzureRM Providerの機能を追加することで新サービスや新機能が扱えるようになるのでタイムラグが発生します。
Container Appsを例にすると、GAされたのが2022/5/25で、AzureRM Providerに追加されたのが8ヶ月半後の2023/2/10でした。
AzAPIはazapi_resourceとごく小数のリソースタイプのみしかありませんが、APIタイプやバージョンを指定することで様々なリソースやサブリソースを管理できます。
ARM TemplateやBicepで利用されているAzure ARM REST API の上にある薄いレイヤーなので、公開されているAPI バージョンならプレビューのものでも利用できるのが特長です。
各リソース・サブリソースに対応した書式はAzureのドキュメントにARM TemplateやBicepと同列で書かれており、HashicorpのドキュメントであるTerraform Registryとは書きっぷりが違うので戸惑うところはありますが、比較的書き初めやすいかと思います。
Microsoft真壁さんもAzureRMとAzAPIを使い分けて使われているとのことなのでご参考ください。
↑のスライドは弊社主催のイベントでご登壇いただきました!(宣伝)
AzAPI ProviderのドキュメントでContainer Apps環境のパラメータを確認してみる
Container Apps環境は microsoft.app/managedenvironments
というAPIタイプで管理できます。↓がそのドキュメントです。
これをしばらく眺めてみたんですが…Managed IDのパラメータがない!?
Microsoft.App managedEnvironments/certificates
の証明書の方も見てみたんですが、こちらもKey Vault連携のパラメータはありませんでした…
ガッカリして1時間ぐらい諦めムードでしたが、ふと他のAPI Versionだとどうなんだろう?とバージョンを弄ってみると…
ありました!!
最新の @2024-03-01
にはなかった identity
のパラメータが @2024-02-02-preview
にはありました!
Change logを見てみると、
Version 2023-11-02-preview
で追加された identity
のパラメータは最新の Version 2024-03-01
ではRemovedになっていました。
経緯は把握できていませんが、何らかの理由で最新のAPIバージョンではidentity
等の一部のパラメータは利用できなくなっていることがわかります。
Microsoft.App/managedEnvironments/certificates
のproperties.certificateKeyVaultProperties
も同様のようです(Change log)
ちなみに、AzureRM ProviderのGitHubのコードを確認してみると、直近のバージョンではMicrosoft.App/managedEnvironments@2024-03-01
を利用していることがわかります。
identity
などのパラメータがTerraformではサポートされていない一因を垣間見えたように思えますね。
ということで思いがけず紆余曲折ありましたが、AzAPI Providerでは任意のAPI Versionを使用することが出来るので、
@2024-02-02-preview
のAPIバージョンを使えばidentity
等のパラメータを使用することができそうです!
AzAPI ProviderでContainer Apps環境の作成にチャレンジ!
それでは早速Container Apps環境を作って、AzureRMではサポートされていない機能を追加してみましょう。
provider関連
まずはAzAPI Providerを使用することを宣言するところから
terraform { required_providers { azapi = { source = "Azure/azapi" } } } provider "azapi" {} provider "azurerm" { subscription_id = "********-****-****-****-************" features {} }
こんな感じになります。
余談ですが、AzureRM Providerでは最近リリースされたv4系からproviderブロック内でsubscription_id
の指定が必要になったのでお忘れなく。
Container Apps 環境 関連
次に本題のContainer Apps 環境を作ります。
Container Apps 環境では現状LogAnaliticsワークスペースを紐づけることが必須なのでその辺りは従来のAzureRM Providerを使用して作成します。
resource "azurerm_resource_group" "main" { name = "ando-demo" location = var.location tags = local.tags } resource "azurerm_log_analytics_workspace" "main" { name = "ando-demo" location = var.location resource_group_name = azurerm_resource_group.main.name tags = local.tags } resource "azurerm_user_assigned_identity" "container" { name = "ando-container-id" location = var.location resource_group_name = azurerm_resource_group.main.name } resource "azapi_resource" "managed_environment" { name = "ando-contaienr-env" location = var.location parent_id = azurerm_resource_group.main.id type = "Microsoft.App/managedEnvironments@2024-02-02-preview" tags = local.tags body = jsonencode({ identity = { type = "UserAssigned" userAssignedIdentities = { "${azurerm_user_assigned_identity.container.id}" : {} } } properties = { appLogsConfiguration = { destination = "log-analytics" logAnalyticsConfiguration = { customerId = azurerm_log_analytics_workspace.main.workspace_id sharedKey = azurerm_log_analytics_workspace.main.primary_shared_key } } } }) }
最後のazapi_resource
がAzAPI Providerのリソースになります。
AzureRMと違って様々なリソースタイプが共通で使える分、ブロック名でどんなリソースなのか見分けがつくようにしたほうが良さそうです。(今回はmanaged_environment
としました)
type
には先述のMicrosoft.App/managedEnvironments@2024-02-02-preview
を指定します。
parent_id
には親となるリソースのIDを渡します。基本的にはリソースグループのIDを渡しておけばよいですが、何かしらのサブリソースの場合は適宜親リソースを指定する必要があります。(後述します)
body
にはJSON形式でパラメータを渡してやる必要がありますが、Terraformの組み込み関数であるjsonencode
関数を使うと、HCLの書式で書いたものをJSONに変換してくれるので、
これを利用してHCLらしく書くのが慣例のようです。
そしてbodyの中で早速identity
を設定しています。typeはSystemAssigned
のほうが個人的には好きなので最初はそうしていたんですが…
いざこのマネージドIDにKeyVaultの権限等を渡そうとしたところ、azapi_resource.managed_environment
のリソースからマネージドIDのオブジェクトIDやプリンシパルIDといった値を取り出せませんでした。
ここは色々なアトリビュート・パラメータを取得できるAzureRMの良さが、翻ってAzAPIの使いにくさになっているように感じます。
ということで、azurerm_user_assigned_identityでマネージドIDを作成してUser Assigned IDとして紐付けました。
その後のuserAssignedIdentities
ではキーに変数を設定していてだいぶ気持ち悪い書き方になっていますが、とりあえずこれで通ったのでOKなはず。。
userAssignedIdentities = { "${azurerm_user_assigned_identity.container.id}" : {} }
Container Apps環境の証明書 関連
次にKey Vaultにある証明書をContainer Apps環境に連携しています。
作成したKey VaultにTerraformで操作している私にAdmin権限を、Container Apps環境のマネージドIDに参照権限を付与しています。
azurerm_key_vault_certificateは長いですが、example.comのいわゆるオレオレ証明書を作っているだけです。
data "azurerm_client_config" "current" {} resource "azurerm_key_vault" "main" { name = "ando-vault" location = var.location resource_group_name = azurerm_resource_group.main.name tenant_id = data.azurerm_client_config.current.tenant_id sku_name = "standard" enable_rbac_authorization = true tags = local.tags } resource "azurerm_role_assignment" "main" { role_definition_name = "Key Vault Administrator" scope = azurerm_key_vault.main.id principal_id = data.azurerm_client_config.current.object_id } resource "azurerm_role_assignment" "container" { role_definition_name = "Key Vault Certificate User" scope = azurerm_key_vault.main.id principal_id = azurerm_user_assigned_identity.container.principal_id } resource "azurerm_key_vault_certificate" "main" { name = "ando-cert" key_vault_id = azurerm_key_vault.main.id certificate_policy { issuer_parameters { name = "Self" } key_properties { exportable = true key_size = 2048 key_type = "RSA" reuse_key = true } lifetime_action { action { action_type = "AutoRenew" } trigger { days_before_expiry = 30 } } secret_properties { content_type = "application/x-pkcs12" } x509_certificate_properties { # Server Authentication = 1.3.6.1.5.5.7.3.1 # Client Authentication = 1.3.6.1.5.5.7.3.2 extended_key_usage = ["1.3.6.1.5.5.7.3.1"] key_usage = [ "cRLSign", "dataEncipherment", "digitalSignature", "keyAgreement", "keyCertSign", "keyEncipherment", ] subject_alternative_names { dns_names = ["example.com"] } subject = "CN=example.com" validity_in_months = 12 } } depends_on = [ azurerm_role_assignment.main, ] } resource "azapi_resource" "cert" { type = "Microsoft.App/managedEnvironments/certificates@2024-02-02-preview" name = "ando-container-cert" location = var.location parent_id = azapi_resource.managed_environment.id tags = local.tags body = jsonencode({ properties = { certificateType = "ServerSSLCertificate" certificateKeyVaultProperties = { identity = azurerm_user_assigned_identity.container.id keyVaultUrl = azurerm_key_vault_certificate.main.versionless_secret_id } } }) }
最後のazapi_resourceではtypeで Microsoft.App/managedEnvironments/certificates@2024-02-02-preview
を使用しているように、Key Vault証明書をContainer Apps環境に連携しています。
こちらはContainer Apps環境のサブリソースなので、parent_id
にはContainer Apps環境のIDを指定しています。
certificateKeyVaultProperties
としてkeyVaultUrlとアクセスするマネージドIDを指定します。
Container Apps 関連
最後にContainer Appsを作成します。Container AppsではPreviewにしかない機能は使ってないので、Microsoft.App/containerApps@2024-03-01
のAPI Versionを使用しています。
なのでAzureRMのほうを使っても問題ないと思いますが、せっかくなのでAzAPIで書いてます。
肝心のconfiguration.customDomains
をコメントアウトしていますが、
example.comのドメインなので諸々NGなのと、正規のドメインであってもドメイン検証のためにDNSのレコード追加などの操作が必要になるので、
完全にTerraformでやるのは結構難しそうなので手作業でやってあとからコードで取り込み、みたいな形のほうが楽だと思ったからです。
resource "azapi_resource" "container_app" { name = "ando-contaienr-apps" location = var.location parent_id = azurerm_resource_group.main.id type = "Microsoft.App/containerApps@2024-03-01" tags = local.tags body = jsonencode({ properties : { managedEnvironmentId = azapi_resource.managed_environment.id template = { "containers" : [ { name : "nginx" image : "nginx:latest" resources = { cpu : 0.25 memory : "0.5Gi" } } ] } configuration = { ingress = { transport = "http" targetPort = 80 external = true # customDomains = [ # { # name = "example.com" # bindingType = "Disabled" # certificateId = azapi_resource.cert.id # } # ] } } } }) }
まとめ
Azure Container Appsがリリースされた当初はAzAPI Providerなら作れる!と言われつつも敷居の高さを感じてAzureRM Providerでのリリースを待ちましたが、
いざリリースされたら一部機能が設定できず、結局AzAPI Providerを触ることになってしまいました。
ですが、実際に調べてみると多少のクセはありますがMicrosoftがドキュメントをしっかり整備してくれており、そこまで辛みなく書くことができました。
これで使いたい機能がAzureRMでサポートされていない時に、AzureRMのアップデートを待つ以外にもAzAPIで書く!という選択肢が増えましたね!!
今回は取り上げませんでしたが、AzAPI2AzureRM という移行ツールもあるようなので、
AzureRMでサポートされたらAzureRMに変換する、なんてことも出来るのかもしれません。(未検証)
azapi_resource_action
というあまりTerraformらしからぬリソースタイプもあり、MS真壁さんによるとそちらも有用とのことなので活用方法を調べていきたいと思います!
【PR】
私達 ACS 事業部は Azure・AKS などのクラウドネイティブ技術を活用した内製化のご支援をしております。
一緒に働いていただける仲間も募集中です!
まだまだ組織規模拡大中なので、ご興味持っていただけましたらぜひお声がけください。
我々の事業部の CultureDeck はコチラ。
私達ACS事業部はAzure・AKSなどのクラウドネイティブ技術を活用した内製化のご支援をしております。