ふり返る暇なんて無いね

日々のメモ書きをつらつらと。メインブログに書くほどでもないことを流してます

CDKTFでリソースのアトリビュートに対して文字列処理がうまくできなかった件

リソースのアトリビュートを文字列処理しようとしたらうまく動かなかったという現象に出会ったのですが、 結論としては、リソースのアトリビュートはStringではなくTokensという型なので、Stringのメソッドは使えないという話しです。

Tokens - CDK for Terraform | Terraform | HashiCorp Developer

現象

こんな感じでIAM Policyを定義しようとしていました。 タスク定義ARNの末尾には :${リビジョン番号} が付与されてるので、これを削除するためにreplace()を使ってるつもりですが、これはうまく動きません。 意図通りreplaceされることはなく、タスク定義ARNがそのままの値でResourceに渡されてしまいます。

    const taskDefinition = new EcsTaskDefinition(this, "ecs_task_definition", {
      // 省略
    });

    new IamPolicy(this, "ecs_deploy_policy", {
      name: getResourceName("ecs-deploy-policy"),
      policy: JSON.stringify({
        Version: "2012-10-17",
        Statement: [
          {
            Sid: "RegisterTaskDefinitionWithTag",
            Effect: "Allow",
            Action: ["ecs:TagResource"],
            Condition: {
              StringEquals: {
                "ecs:CreateAction": "RegisterTaskDefinition",
              },
            },
            Resource: taskDefinition.arn.replace("/:[1-9][0-9]*$/", ""),
          },
        ],
      })

原因

Tokens - CDK for Terraform | Terraform | HashiCorp Developer

タスク定義ARNの型はStringではなく、Tokens型です。Tokensはモジュールのoutputやリソースのアトリビュートに使われる型で、terraformがapplyされるまで不定の値を示します。

Tokensを文字列として扱うためにはFnを利用してterraformの組み込み関数を呼び出すか、asString()メソッドを呼び出して、Stringに変換してから文字列処理をしてあげる必要があります。

解としては以下の通りになります。

    import { Fn } from "cdktf";

    new IamPolicy(this, "ecs_deploy_policy", {
      name: getResourceName("ecs-deploy-policy"),
      policy: JSON.stringify({
        Version: "2012-10-17",
        Statement: [
          {
            Sid: "RegisterTaskDefinitionWithTag",
            Effect: "Allow",
            Action: ["ecs:TagResource"],
            Condition: {
              StringEquals: {
                "ecs:CreateAction": "RegisterTaskDefinition",
              },
            },
            Resource: Fn.replace(taskDefinition.arn, "/:[1-9][0-9]*$/", ""),
          },
        ],
      }),
    });