私はCloudFormationテンプレートが苦手です。CloudFormationが悪いツールだとは思いませんが、どうも慣れないというかなんというか。Terraformの方が簡単に書ける印象です。書くのが苦手ならば、もちろん読むのも苦手でして。たまにCFnテンプレートを渡されて、Terraformにしといてちょっと言われるのですが、よくわからないので渡されたテンプレートからCFnスタックを作成し、それをTerraformのimportでTerraform化していました。が、ちょっと検索するとcf2tfなるツールが・・・
cf2tf
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などと組み合わせて修正しつつ進める必要がありました。
