とことんDevOps | 日本仮想化技術のDevOps技術情報メディア

DevOpsに関連する技術情報を幅広く提供していきます。

日本仮想化技術がお届けする「とことんDevOps」では、DevOpsに関する技術情報や、日々のDevOps業務の中での検証結果、TipsなどDevOpsのお役立ち情報をお届けします。
主なテーマ: DevOps、CI/CD、コンテナ開発、IaCなど
読者登録と各種SNSのフォローもよろしくお願いいたします。

CFnテンプレートをHCLにコンバート

私はCloudFormationテンプレートが苦手です。CloudFormationが悪いツールだとは思いませんが、どうも慣れないというかなんというか。Terraformの方が簡単に書ける印象です。書くのが苦手ならば、もちろん読むのも苦手でして。たまにCFnテンプレートを渡されて、Terraformにしといてちょっと言われるのですが、よくわからないので渡されたテンプレートからCFnスタックを作成し、それをTerraformのimportでTerraform化していました。が、ちょっと検索するとcf2tfなるツールが・・・

cf2tf

github.com

CFnテンプレートをTerraformのコードにコンバートしてくれるツールです。できることはそれだけですが大変便利。

試す

簡単なCFnテンプレートを用意しました。

---
Resources:
  IAMUser:
    Type: AWS::IAM::User
    Properties:
      Path: /
      UserName: "test-user"

  IAMUserAccessKey:
    Type: AWS::IAM::AccessKey
    Properties:
      UserName: !Ref IAMUser

  IAMUserAccessKeySecret:
    Type: AWS::SecretsManager::Secret
    Properties:
      Name: !Sub credentials/${IAMUser}
      SecretString: !Sub "{\"accessKeyId\":\"${IAMUserAccessKey}\",\"secretAccessKey\":\"${IAMUserAccessKey.SecretAccessKey}\"}"

このコードでは、IAMユーザーを作成し、そのIAMユーザーで発行したクレデンシャルをSecrets Managerに登録します。

このコードをiam.amlというファイルに保存し、cf2tfに食わせてみましょう。

$ cf2tf iam.yaml

// Converting iam.yaml to Terraform!
// Existing Terraform src code found at /var/folders/ys/ql50h491259ft68p_sf6qfjc0000gn/T/terraform_src.

resource "aws_iam_user" "iam_user" {
  path = "/"
  name = "test-user"
}

resource "aws_iam_access_key" "iam_user_access_key" {
  user = aws_iam_user.iam_user.arn
}

resource "aws_secretsmanager_secret" "iam_user_access_key_secret" {
  name = "credentials/${aws_iam_user.iam_user.arn}"
  force_overwrite_replica_secret = "{"accessKeyId":"${aws_iam_access_key.iam_user_access_key.create_date}","secretAccessKey":"${aws_iam_access_key.iam_user_access_key.secret}"}"
}

見事にTerraformのコードが生成されました。

デフォルトの動作では、コンバートしたHCLが標準出力されます。cf2tfに-oオプションで出力先のディレクトリを指定してあげると、指定のディレクトリに出力できます。

$ cf2tf iam.yaml -o test            

// Converting iam.yaml to Terraform!
// Existing Terraform src code found at /var/folders/ys/ql50h491259ft68p_sf6qfjc0000gn/T/terraform_src.
Saving converted terraform objects to /path/to/test

$ ls test
                                                      
resource.tf

今回はresource.tfしかありませんが、変数を使っていればvariable.tf、データソースを使用する場面があればdata.tfなど、いい感じにファイルを分割してくれます。

terraform validateコマンドを実行してみると微妙にエラーが出ました。

$ terraform validate

╷
│ Error: Missing newline after argument
│ 
│   on resource.tf line 12, in resource "aws_secretsmanager_secret" "iam_user_access_key_secret":
│   12:   force_overwrite_replica_secret = "{"accessKeyId":"${aws_iam_access_key.iam_user_access_key.create_date}","secretAccessKey":"${aws_iam_access_key.iam_user_access_key.secret}"}"
│ 
│ An argument definition must end with a newline.
╵
╷
│ Error: Invalid character
│ 
│   on resource.tf line 12, in resource "aws_secretsmanager_secret" "iam_user_access_key_secret":
│   12:   force_overwrite_replica_secret = "{"accessKeyId":"${aws_iam_access_key.iam_user_access_key.create_date}","secretAccessKey":"${aws_iam_access_key.iam_user_access_key.secret}"}"
│ 
│ This character is not used within the language.
╵
╷
│ Error: Invalid character
│ 
│   on resource.tf line 12, in resource "aws_secretsmanager_secret" "iam_user_access_key_secret":
│   12:   force_overwrite_replica_secret = "{"accessKeyId":"${aws_iam_access_key.iam_user_access_key.create_date}","secretAccessKey":"${aws_iam_access_key.iam_user_access_key.secret}"}"
│ 
│ This character is not used within the language.
╵

Secrets Managerに設定するJSONがうまくコンバートできなかったみたいです。

diff --git a/resource.tf b/resource.tf
index ef81a3e..380c0a0 100644
--- a/resource.tf
+++ b/resource.tf
@@ -9,6 +9,8 @@ resource "aws_iam_access_key" "iam_user_access_key" {
 
 resource "aws_secretsmanager_secret" "iam_user_access_key_secret" {
   name = "credentials/${aws_iam_user.iam_user.arn}"
-  force_overwrite_replica_secret = "{"accessKeyId":"${aws_iam_access_key.iam_user_access_key.create_date}","secretAccessKey":"${aws_iam_access_key.iam_user_access_key.secret}"}"
+  force_overwrite_replica_secret = jsonencode({
+    accessKeyId     = aws_iam_access_key.iam_user_access_key.create_date,
+    secretAccessKey = aws_iam_access_key.iam_user_access_key.secret
+  })
 }
-

このように修正して再度バリデートしてあげると

$ terraform validate

Success! The configuration is valid.

成功です。

$ 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:

  # aws_iam_access_key.iam_user_access_key will be created
  + resource "aws_iam_access_key" "iam_user_access_key" {
      + create_date                    = (known after apply)
      + encrypted_secret               = (known after apply)
      + encrypted_ses_smtp_password_v4 = (known after apply)
      + id                             = (known after apply)
      + key_fingerprint                = (known after apply)
      + secret                         = (sensitive value)
      + ses_smtp_password_v4           = (sensitive value)
      + status                         = "Active"
      + user                           = (known after apply)
    }

  # aws_iam_user.iam_user will be created
  + resource "aws_iam_user" "iam_user" {
      + arn           = (known after apply)
      + force_destroy = false
      + id            = (known after apply)
      + name          = "test-user"
      + path          = "/"
      + tags_all      = (known after apply)
      + unique_id     = (known after apply)
    }

  # aws_secretsmanager_secret.iam_user_access_key_secret will be created
  + resource "aws_secretsmanager_secret" "iam_user_access_key_secret" {
      + arn                            = (known after apply)
      + force_overwrite_replica_secret = (sensitive value)
      + id                             = (known after apply)
      + name                           = (known after apply)
      + name_prefix                    = (known after apply)
      + policy                         = (known after apply)
      + recovery_window_in_days        = 30
      + tags_all                       = (known after apply)
    }

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

───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now.

terraform planも大丈夫そうでした。

まとめ

CFnテンプレートをわざわざ実環境にデプロイしなくてHCL化できるのは大変便利です。ただし、完璧にコンバードができるわけではなさそうなので、terraform validateなどと組み合わせて修正しつつ進める必要がありました。