【Terraform】手を動かしながら理解するEphemeralリソースとWrite-only arguments

記事タイトルとURLをコピーする

はじめに

サービス開発課のくればやしです。『鬼滅の刃 無限城編』を観てきました。これはぜひ映画館で観たい映画でしたね。上映が終わる前に、もう一度観たいと思います☺️

本記事では、TerraformのEphemeralリソースが一つ一つサンプルコードを交えながら説明してみたいと思います。

Ephemeralリソース

Ephemeralリソースを使わない場合

例として、AWSの認証情報(アクセスキー、シークレットアクセスキー)をAWS Secrets Managerから安全に取得したいケースを考えたいと思います。具体的には、デフォルトとは別のAWSのプロバイダの認証情報を利用して、そちらにVPCをデプロイする構成を考えたいと思います。

できるだけ認証情報はソースコードやその他のファイルに残さないようにしたいところです。

Ephemeralリソース無しで、普通のデータリソースを使って構成すると以下のようになると思います。

data "aws_secretsmanager_secret_version" "access_key" {
  secret_id = "access_key"
}
    
data "aws_secretsmanager_secret_version" "secret_key" {
  secret_id = "secret_key"
}    
    
provider "aws" {
  alias  = "sub-account"
  region = "ap-northeast-1"
  access_key = data.aws_secretsmanager_secret_version.access_key.secret_string
  secret_key = data.aws_secretsmanager_secret_version.secret_key.secret_string
}    
    
resource aws_vpc vpc1 {
  provider = aws.sub-account
  cidr_block = "10.0.0.0/16"
}

この構成でもソースコード中に認証情報は残りませんが、 .tfstate ファイルに認証情報が残ってしまいます( secret_string キーのところ)。 もし、要件として、 .tfstate ファイルに機密情報を残さないことを考える場合は要件を満たすことができません。

{
  "resources": [
    {
      "mode": "data",
      "type": "aws_secretsmanager_secret_version",
      "name": "access_key",
      "instances": [
        {
          "attributes": {
            "secret_id": "handson1",
            "secret_string": "xxxxxxxxxxxxxxxxx"
          }
        }
      ]
    },
    {
      "mode": "data",
      "type": "aws_secretsmanager_secret_version",
      "name": "secret_key",
      "instances": [
        {
          "attributes": {
            "secret_id": "handson1-s",
            "secret_string": "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
          }
        }
      ]
    }
  ]
}

Ephemeralリソースを使った場合

そこで、Ephemeral リソースを使ってみましょう。 Ephemeral リソースを使った場合は、 .tf ファイルは以下のようになります。

ephemeral "aws_secretsmanager_secret_version" "ephemeral_access_key" {
  secret_id = "ephemeral_access_key"
}
    
ephemeral "aws_secretsmanager_secret_version" "ephemeral_secret_key" {
  secret_id = "ephemeral_secret_key"
}
    
provider "aws" {
  alias  = "sub-account"
  region = "ap-northeast-1"
  access_key = ephemeral.aws_secretsmanager_secret_version.ephemeral_access_key.secret_string
  secret_key = ephemeral.aws_secretsmanager_secret_version.ephemeral_secret_key.secret_string
}
    
resource aws_vpc ephemeral_account {
  provider = aws.sub-account
  cidr_block = "10.34.0.0/16"
}

上記のようにEphemeral リソースを使った場合は、 .tfstate ファイルに認証情報は残りません。 resources のブロックの中に aws_secretsmanager_secret_version の項目自体が残りませんでした。

これにより、機密情報をより安全に参照することが可能となります。

ちなみに、 Ephemeral リソースが使えるのは、一部の項目のみで、どのリソースの属性に対してでも使えるというわけではありません。

You can only reference ephemeral resources in specific ephemeral contexts or Terraform throws an error. The following are valid contexts for referencing ephemeral resources:

  • In a write-only argument
  • In another ephemeral resource
  • In local values
  • In ephemeral variables
  • In ephemeral outputs
  • Configuring providers in the provider block
  • In provisioner and connection blocks

Ephemeral block reference for the Terraform configuration language | Terraform | HashiCorp Developer

以上は、 Ephemeralリソース を使ってセキュアにデータを読み出すことを考えました。次に、機密データを設定することを考えます。

Write-only arguments

Write-only arguments を使わない場合

例として、 Secrets Manager のシークレット値を安全に設定することを考えます。

最初に Write-only arguments を使わない場合を考えます。以下のようにシークレット値に入力する値を外部から入力したとしても .tfstate には設定した値が残ってしまいます。

variable "test" {
}
    
resource "aws_secretsmanager_secret" "secret2" {
  name = "secret2"
}
    
resource "aws_secretsmanager_secret_version" "test" {
  secret_id = aws_secretsmanager_secret.secret2.id
  secret_string = var.test
}

Write-only arguments を使う場合

そこで secret_string のかわりに、Write-only arguments の secret_string_wo を使ってみます。以下のように実行すると .tfstate には値は残りません。

variable "test" {
}
    
resource "aws_secretsmanager_secret" "secret3" {
  name = "secret3"
}
    
resource "aws_secretsmanager_secret_version" "test" {
  secret_id = aws_secretsmanager_secret.secret3.id
  secret_string_wo = var.test
  secret_string_wo_version = 1
}

ちなみに .tfstate には以下のように格納されていました。 値が格納されていないために、 .tfstate で値で変更管理できませんので secret_string_wo_version を指定して値を更新するときはこのVersionを更新します。

"secret_string": "",
"secret_string_wo": null,
"secret_string_wo_version": 1,

外部のデータを読み出す時に、 Ephemeral リソースを使わない場合

しかしながら、外部のデータを参照して、値を設定したい場合を考えてみます。例えば、以下のようにデータリソースを使ったとすると、 .tfstate のデータリソースの方にシークレット値が残ってしまいます。

data "aws_secretsmanager_secret_version" "test2" {
  secret_id = "arn:aws:secretsmanager:ap-northeast-1:xxxxxxxxxxxx:secret:test2-xxx"
}
    
resource "aws_secretsmanager_secret" "secret4" {
  name = "secret4"
}
    
resource "aws_secretsmanager_secret_version" "test" {
  secret_id = aws_secretsmanager_secret.secret4.id
  secret_string_wo = data.aws_secretsmanager_secret_version.test2.secret_string
  secret_string_wo_version = 1
}

外部のデータを読み出す時に、 Ephemeral リソースを使う場合

ここで、先程の Ephemeral リソースを使った合せ技が使えます。以下のように設定することで、 .tfstate にデータを残さずにデータを参照しつつ、そのデータを使ってデータを設定できます。

ephemeral "aws_secretsmanager_secret_version" "test2" {
  secret_id = "arn:aws:secretsmanager:ap-northeast-1:xxxxxxxxxxxx:secret:test2-fX8jRA"
}
    
resource "aws_secretsmanager_secret" "secret5" {
  name = "secret5"
}
    
resource "aws_secretsmanager_secret_version" "test" {
  secret_id = aws_secretsmanager_secret.secret5.id
  secret_string_wo = ephemeral.aws_secretsmanager_secret_version.test2.secret_string
  secret_string_wo_version = 1
}

おわりに

TerraformのEphemeralリソースとWrite-only argumentsをアレコレ触りながら、動作を確認してみました。どこかで誰かの御役にたてば幸いです。

関連リンク

developer.hashicorp.com

developer.hashicorp.com

registry.terraform.io

www.hashicorp.com

registry.terraform.io

紅林輝(くればやしあきら)(サービス開発部) 記事一覧

サービス開発部所属。2015年にサーバーワークスにJOIN。クラウドインテグレーション部を経て、現在はCloud Automatorの開発に従事。ドラクエ部。推しナンバーはⅤ、推しモンスターはクックルー。