APC 技術ブログ

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

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

Terraform v1.11 で追加された write-only attributes の機能と移行手順の紹介

こんにちは、ACS 事業部の埜下です。

先日リリースされた Terraform の v1.11.0write-only attributes という機能が追加されました。

今回は「write-only attributes とはなにか」と「既存のパラメータから write-only attributes に移行する手順」について紹介します。

なお、本記事では Terraform で Azure リソースを管理する AzureRM プロバイダーにフォーカスしています。 細かい挙動はプロバイダーごとに異なる可能性があるため、詳細は各プロバイダーのドキュメントをご確認ください。

1. write-only attributes とは

Terraform では v1.10 からシークレット情報を安全に取り扱うための機能追加がされてきました。

  • Ephemeral input variables / output variables
  • Ephemeral resources

write-only attributes もその一環の機能追加で、ステートファイルにシークレット情報を記録せずにリソースを作成できるパラメータです。 今までのバージョンの Terraform と比較しながら write-only attributes を見ていきましょう。

1.1 今までの Terraform の課題

Terraform で Azure 等にリソースを作成すると、Terraform は「ステートファイル」にリソースの情報を記録します。 デフォルトではステートファイルは terraform.tfstate という名前です。

パスワード等のシークレット情報を使ってリソースを作成することがありますが、今までの Terraform ではステートファイルにパスワードが平文で記録されていました。

Terraform を実行した際の標準出力にはシークレット情報は (sensitive value) とマスクされて平文は見れないようになっています。 たとえば、Terraform を使って Azure Database for MySQL Flexible Server を作るリソース azurerm_mysql_flexible_server は管理者のパスワードを administrator_password に設定します。

resource "azurerm_mysql_flexible_server" "example" {
  name                = "mysql-tf-write-only"
  resource_group_name = azurerm_resource_group.example.name
  location            = azurerm_resource_group.example.location
  version             = "8.0.21"
  sku_name            = "B_Standard_B1ms"

  administrator_login    = "mysqladmin"
  administrator_password = "H@Sh1CoR3!"    # 管理者パスワードを設定
}

この構成を使って terraform plan を実行すると、パスワード部分はマスクされて値が表示されないようになっています。

$ terraform plan

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # azurerm_mysql_flexible_server.example will be created
  + resource "azurerm_mysql_flexible_server" "example" {
      + administrator_login           = "mysqladmin"
      + administrator_password        = (sensitive value)      <- パスワードは表示されない
(省略)

terraform apply でこのリソースを作成すると、センシティブなデータを含めた構成情報が記録されたステートファイルが作成されます。

{
(省略)
  "resources": [
    {
      "mode": "managed",
      "type": "azurerm_mysql_flexible_server",
      "name": "example",
      "provider": "provider[\"registry.terraform.io/hashicorp/azurerm\"]",
      "instances": [
        {
          "schema_version": 0,
          "attributes": {
            "administrator_login": "mysqladmin",
            "administrator_password": "H@Sh1CoR3!",      <- パスワードが平文で記録されている
(省略)

このようにステートファイルにはパスワードなどのシークレット情報が平文で記録されてしまいます。 そのため、ステートファイルを参照する権限さえがあれば誰でもシークレット情報を取得できてしまうので、ステートファイルの取り扱いには最新の注意が必要です。

1.2 write-only attributes のメリット

Terraform v1.11.0 で追加された write-only attributes を使うことで、ステートファイルにシークレット情報を格納しなくてもリソースを作成できるようになります。

どのリソースで write-only attributes がサポートされるかは各プロバイダー次第となっており、AzureRM プロバイダーは v4.21.0 から次のリソースで write-only attributes のサポートが始まりました。

  • azurerm_mssql_job_credential
  • azurerm_mssql_server
  • azurerm_mysql_flexible_server
  • azurerm_postgresql_flexible_server
  • azurerm_postgresql_server

write-only attributes は今までのパスワードを設定していたパラメータとは別のパラメータとして実装されています。 先ほどの azurerm_mysql_flexible_server リソースでは管理者パスワードを administrator_password というパラメータに設定していましたが、代わりに administrator_password_wo というパラメータにパスワードを設定することで write-only attributes を使うことになります。

resource "azurerm_mysql_flexible_server" "example" {
  name                = "mysql-tf-write-only"
  resource_group_name = azurerm_resource_group.example.name
  location            = azurerm_resource_group.example.location
  version             = "8.0.21"
  sku_name            = "B_Standard_B1ms"

  administrator_login               = "mysqladmin"
  administrator_password_wo         = "H@Sh1CoR3!"    # 管理者パスワードを設定する write-only attributes
  administrator_password_wo_version = 1
}

また、新たに administrator_password_wo_version というパラメータも追加されています。 このバージョンパラメータは write-only attributes で作成されたリソースの値を更新するために使うもので、バージョンパラメータの値を変更することで Terraform が write-only attributes の値が更新されたと検出します。

言い換えると、バージョンパラメータを更新していない場合は write-only attributes の更新が反映されません。

上記の write-only attributes に書き換えた構成で terraform plan してみると、以前のように (write-only attribute) とマスクされてシークレット情報は表示されません。

$ terraform plan

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # azurerm_mysql_flexible_server.example will be created
  + resource "azurerm_mysql_flexible_server" "example" {
      + administrator_login               = "mysqladmin"
      + administrator_password_wo         = (write-only attribute)      <- パスワードは表示されない
      + administrator_password_wo_version = 1
(省略)

terraform apply でリソース作成後に確認してもステートファイルには write-only attributes の administrator_password_wo に設定したパスワードは記録されていません。

{
(省略)
  "resources": [
    {
      "mode": "managed",
      "type": "azurerm_mysql_flexible_server",
      "name": "example",
      "provider": "provider[\"registry.terraform.io/hashicorp/azurerm\"]",
      "instances": [
        {
          "schema_version": 0,
          "attributes": {
            "administrator_login": "mysqladmin",
            "administrator_password": null,
            "administrator_password_wo": null,      <- write-only attributes のパスワードは記録されない
            "administrator_password_wo_version": 1,
(省略)

試しに write-only attributes を使って作成した MySQL にログインしてみましたが、問題なくログインできました。

$ mysql -h mysql-tf-write-only.mysql.database.azure.com -P 3306 -u mysqladmin -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 12
Server version: 8.0.40-azure Source distribution

Copyright (c) 2000, 2025, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

ステートファイルにシークレット情報が含まれていなければ、万が一ステートファイルが漏洩してもシークレット情報が公開されることはありません。 このように、write-only attributes を使えばシークレット情報をステートファイルに記録せずに済み、ステートファイルの安全性が高まります。

2. write-only attributes への移行

それでは、既存のパラメータで管理しているパスワードを write-only attributes のパラメータに移行していきましょう。

今回は次の環境で実施しました。

  • Terraform v1.11.0
  • AzureRM プロバイダー v4.20.0 で MySQL Flexible Server を作成済み
  • ローカルステートを使用

2.1 プロバイダーのアップグレード

まずはプロバイダーのバージョンを write-only attirbutes に対応したものにアップグレードします。 AzureRM プロバイダーでは v4.21.0 以上にしてください。

terraform ブロックでバージョン制約している場合は対応するバージョンを使えるようにします。

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "4.20.0"    # これを
      version = "4.21.0"    # これに変更

      version = ">=4.20"    # 最新のマイナーバージョンが使われるこちらでも可
    }
  }
  required_version = "1.11.0"
}

その後、terraform init -upgrade コマンドでローカルのプロバイダーをアップグレードします。

$ terraform init -upgrade
Initializing the backend...
Initializing provider plugins...
- Finding hashicorp/azurerm versions matching "4.21.0"...
- Installing hashicorp/azurerm v4.21.0...
- Installed hashicorp/azurerm v4.21.0 (signed by HashiCorp)
Terraform has made some changes to the provider dependency selections recorded
in the .terraform.lock.hcl file. Review those changes and commit them to your
version control system if they represent changes you intended to make.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

これで Terraform の構成ファイルに write-only attribures のパラメータを使えるようになりました。

2.2 パラメータの置き換え

次に、既存のパラメータを削除して write-only attributes の administrator_password_woadministrator_password_wo_version を追加します。

resource "azurerm_mysql_flexible_server" "example" {
  name                = "mysql-tf-write-only"
  resource_group_name = azurerm_resource_group.example.name
  location            = azurerm_resource_group.example.location
  version             = "8.0.21"

  administrator_login               = "mysqladmin"
  # administrator_password          = "H@Sh1CoR3!"    # いままで使っていたパラメータは削除
  administrator_password_wo         = "H@Sh1CoR3!"    # write-only attributes に管理者パスワードを設定
  administrator_password_wo_version = 1               # write-only attributes のバージョンを設定
}

この例では構成ファイルに直接パスワードを記述していますが、実際に扱う際は variables からシークレット情報を渡すようにしてファイルに直接シークレット情報を記述しないようにしてください。

2.3 リソースを更新

write-only attributes に置き換えた構成ファイルを使ってリソースを更新します。

まずは terraform plan でリソースの変更内容を確認します。 既存のパラメータ administrator_password が null になって、administrator_password_wo_version が更新されます。 パスワードを指定した administrator_password_wo は更新されません。

$ terraform plan

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # azurerm_mysql_flexible_server.example will be updated in-place
  ~ resource "azurerm_mysql_flexible_server" "example" {
      - administrator_password            = (sensitive value) -> null
      ~ administrator_password_wo_version = 0 -> 1

      (省略)
    }

Plan: 0 to add, 1 to change, 0 to destroy.

内容に問題なければ terraform apply します。

$ terraform apply -auto-approve

(省略)

Apply complete! Resources: 0 added, 1 changed, 0 destroyed.

無事に Apply が完了すれば write-only attributes への移行は完了です。 管理者パスワードを使って MySQL にログインできるか確認しておきましょう。

ステートファイルにもシークレット情報が記録されていないことを確認します。 平文でパスワードが記録されていた administrator_password は空文字になっています。 また、構成ファイルでパスワードを設定した administrator_password_wo にもパスワードは記録されていません。

{
(省略)
  "resources": [
    {
      "mode": "managed",
      "type": "azurerm_mysql_flexible_server",
      "name": "example",
      "provider": "provider[\"registry.terraform.io/hashicorp/azurerm\"]",
      "instances": [
        {
          "schema_version": 0,
          "attributes": {
            "administrator_login": "mysqladmin",
            "administrator_password": "",
            "administrator_password_wo": null,
            "administrator_password_wo_version": 1,

このように、パスワードを維持したまま既存のパラメータから write-only attributes に移行して、ステートファイルからシークレット情報を削除できます。

2.3 移行の注意点

write-only attributes に移行する際の注意点があります。 それは、移行時に administrator_password_wo_version = 0 としてしまうと管理者パスワードでログインできなくなってしまう、という点です。

AzurRM プロバイダー固有の話かもしれませんが、write-only attributes で追加された _wo_version というパラメータの初期値は 0 になっています。 パスワードが設定されていた administrator_password を削除する際に administrator_password_wo_version = 0 を設定していると、 administrator_password_wo で設定したパスワードが更新されたと判断されずに administrator_password の変更(パスワードの削除)だけが実行されてしまうようです。

今後のバージョンで改善される可能性もありますが、write-only attributes へ移行する際はご注意ください。

3. まとめ

今回は Terraform の write-only attributes について紹介しました。

  • Terraform の v1.11.0 以上で利用可能
  • ステートファイルにシークレット情報が記録せずにリソース作成可能
  • write-only attributes を使えるパラメータはプロバイダー依存

write-only attributes を使うことで、より安全にシークレット情報を扱えるようになります。 ご利用されているプロバイダーのサポート状況をご確認いただきつつ、write-only attributes を使ってみてください。