💡

CFnでタグ付与をIf文を使用して複数付与する方法

に公開

背景・目的

開発環境ではタグ付与はなし
検証環境、本番環境では複数のタグを付与したいとの要望があった。
この場合、Conditionsを使用して開発環境の判定後にタグを付与したいが、そもそもIf文を使用したタグ付与の方法や、
タグを複数渡したいときのテンプレート記述方法の情報が見当たらなかった。

早く知りたい方向け

その場合、以下の記述で実現できた。(S3バケット作成)

AWSTemplateFormatVersion: 2010-09-09
Description: Add multi tag with condition

Parameters:
  Env:
    Type: String
    AllowedValues:
      - dev
      - stg
      - prod
    Default: dev

Conditions:
  IsDev: !Equals [!Ref Env, dev]

Resources:
  S3Hosting:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub "${Env}-s3-bucket-${AWS::Region}"
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      Tags:
        !If
          - IsDev
          - - !Ref AWS::NoValue
          - - Key: tag1
              Value: value1
            - Key: tag2
              Value: value2
            - Key: tag3
              Value: value3

詳しく

どうしてその記述なのか知りたい方は以下参考にしてください。

まずは公式ドキュメント

公式ドキュメントを見るとCloudFormationテンプレートによるAWSリソースタグを付与したい場合は以下の記述で可能
公式ドキュメント:AWS::S3::Bucket

Tags:
  - Key: String
    Value: String

初めのハイフンがリスト形式で渡すことを表し、その後のKey,Valueのセットがオブジェクトを表す。
ちなみにJSONで見るとわかりやすい

"Tags" : [
  {
    "Key" : String,
    "Value" : String
  }
],

次にタグを複数渡したいときの実装

これは簡単ですね。いろいろな方が書かれています。

Tags:
  - Key: String
    Value: String
  - Key: String2
    Value: String2
  - Key: String3
    Value: String3

本題

ではこれにIf文による条件分岐があった場合どのように書けばいいでしょうか。
今回条件分岐含めて、1行での書き方もあるのでしょうが可読性のために改行して記述したいです。
そのためCFn上でIf文は以下のようになります

!If
  - <条件>
  - <trueの場合>
  - <falseの場合>

この書き方を踏まえると以下のようにしてテンプレートに記述すると目的を達成できそうです!!

AWSTemplateFormatVersion: 2010-09-09
Description: Add multi tag with condition

Parameters:
  Env:
    Type: String
    AllowedValues:
      - dev
      - stg
      - prod
    Default: dev

Conditions:
  IsDev: !Equals [!Ref Env, dev]

Resources:
  S3Hosting:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub "${Env}-s3-bucket-${AWS::Region}"
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      Tags:
        !If
          - IsDev
          - - !Ref AWS::NoValue
          - - Key: tag1
              Value: value1
            - Key: tag2
              Value: value2
            - Key: tag3
              Value: value3

長くなってしまったので必要な部分のみ取り出すと以下です。

Tags:
  !If
    - IsDev
    - - !Ref AWS::NoValue
    - - Key: tag1
        Value: value1
      - Key: tag2
        Value: value2
      - Key: tag3
        Value: value3

Conditionsで記述した環境を判定するIsDev(開発環境)の場合は擬似パラメータ"!Ref AWS::NoValue"を使用します。
このときTagsプロパティにはリスト形式で渡す必要があるので-(ハイフン)を忘れないようにしましょう。
※もしかしたらハイフンいらないかもです。

またIsDevでない場合は複数のタグを渡す必要があります。
1つ目のハイフンはIf文の条件分岐を、2つめのハイフンはリストで渡すことを表しています。
もしかしたら以下のように記述するほうが見やすい方もいるかも知れません。

Tags:
  !If
    - IsDev
    - - !Ref AWS::NoValue
    -
      - Key: tag1
        Value: value1
      - Key: tag2
        Value: value2
      - Key: tag3
        Value: value3

ちなみにChatgptに1行で書いてとお願いすると以下のように返ってきました。
実際試していないので試した方は結果を教えて下さい。(個人的には見にくいです。。。)

Tags: !If [IsDev, [{Key: tag1, Value: value1}, {Key: tag2, Value: value2}], !Ref AWS::NoValue]

実際に実行してみると

簡単なテンプレートになりますが、実際にスタック作成してみました。
使用したテンプレートはこちら

開発環境想定

  1. パラメータにdevを指定して作成
  2. 作成されたS3バケット
    タグが付与されていないことが確認できた。

本番環境想定

  1. パラメータにprodを指定して作成
  2. 作成されたS3バケット
    タグが複数付与されていることが確認できた。

おわりに

いかがだったでしょうか
恥ずかしながら実務ではこんな簡単なことに苦しんでしまい、時間を溶かしてしまいました。
ハイフンつける場所をまちがえてエラー起こしたりと・・・
CFnでは記述するハイフンが何を意味しているのかをしっかり考える必要がありそうですね。

ちなみにLambda関数のSAM形式ではこちらの記述ではうまくいきませんでした。
こちらについてはまた別の記事で解説したいと考えています。

テンプレートに誤りありましたら、ご指摘をお願いいたします。
最後まで読んでくれてありがとうございました。

GitHubで編集を提案

Discussion