【AWS】CloudFormation ~ 条件分岐 ~

■ はじめに

AWS CloudFormation で、Booleanの入力パラメータで
Roleを付与するかしないかを扱った。

その中で、Conditions セクションや条件関数(!IF、!Equals)を
やったのでメモっておく。

目次

【1】条件関数
 1)Fn::Equals(!Equals)
 2)Fn::If(!If)
 3)Fn::Not(!Not)
 4)Fn::And(!And)
 5)Fn::Or(!Or)
【2】条件分岐で関連するセクション
 1)Parametersセクション
 2)Conditionsセクション
 3)Resourcesセクション
【3】サンプル

【1】条件関数

* 条件付きでスタックリソースを作成
* 条件関数は、以下の5つ。

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-conditions.html

1)Fn::Equals(!Equals)

* 2 つの値が等しいかどうかを比較

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-conditions.html#intrinsic-function-reference-conditions-equals

構文

# 完全名関数の構文
Fn::Equals: [<value_1>, <value_2>]

# 短縮形の構文
# <value_1> = <value_2> だったら、True
!Equals [<value_1>, <value_2>]

# 書き方1
IsProdCondition:
  !Equals [!Ref EnvironmentType, prod]

# 書き方2:「【3】サンプル」より抜粋
HasNormalRole: !Equals
  - !Ref IsAddedNormalRole
  - true

2)Fn::If(!If)

* IF文(今回のメイン)
 => 指定された条件が true に評価された場合は 1 つの値を返却
 => 指定された条件が false に評価された場合はもう 1 つの値を返却

構文

# 完全名関数の構文
Fn::If: [<条件式>, <trueの場合の値>, <falseの場合の値>]

# 短縮形の構文
!If [<条件式>, <trueの場合の値>, <falseの場合の値>]

!If
- 条件式
- trueの場合の処理
- falseの場合の処理


https://stackoverflow.com/questions/41752007/conditionally-create-codepipeline-actions-based-on-cloudformation-conditions

- !If
  - IsProdCondition
  - InputArtifacts: []
    Name: !Join ["",[!Ref GitHubRepository, "-prd-approval"]]
    ActionTypeId:
      Category: Approval
      Owner: AWS
      Version: '1'
      Provider: Manual
    OutputArtifacts: []
    Configuration:
      NotificationArn: !GetAtt ["SNSApprovalNotification", "Outputs.SNSTopicArn"]
      ExternalEntityLink: OutputTestUrl
    RunOrder: 3
  - !Ref AWS::NoValue

例2:環境ごとにEC2インスタンスタイプを変える
https://oreout.hatenablog.com/entry/aws/cloudformation/6

Resources:
  # EC2作成
  DemoEC2:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: ami-e99f4896
      InstanceType: !If [IsProduction, "t2.micro", "t2.nano"]

補足:AWS::NoValue

* 以下の関連記事を参照のこと。

https://dk521123.hatenablog.com/entry/2021/12/05/134313

3)Fn::Not(!Not)

* Not句
=> false だったら、true を返す
=> true だったら、false を返す

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-conditions.html#intrinsic-function-reference-conditions-not

4)Fn::And(!And)

* AND句
 => すべての条件が true に評価された場合は true を返す

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-conditions.html#intrinsic-function-reference-conditions-and
構文

!And [<条件1>, <条件2>, ...]

5)Fn::Or(!Or)

* OR句
 => 指定された条件のいずれかが true に評価された場合は true を返却

構文

# 完全名関数の構文
Fn::Or: [<条件1>, <条件2>, ...]

# 短縮形の構文
!Or [<条件1>, <条件2>, ...]

# EnviromentType が、stage or prod だった場合、MyOrCondition に true
MyOrCondition:
  !Or [!Equals [stage, !Ref EnviromentType], !Equals [prod, !Ref EnviromentType]]

【2】条件分岐で関連するセクション

* 条件分岐で関連するセクションは、以下の通り。

1)Parametersセクション
2)Conditionsセクション
3)Resourcesセクション

1)Parametersセクション

* 切替に必要な入力パラメータを設定

Parameters:
  IsReadonly:
    Description: Whether you should create role (true/false).
    Default: false
    Type: String
    AllowedValues: [true, false]

2)Conditionsセクション

* 条件によりリソースを作成する際に利用
* 1)のパラメータを評価して条件(論理値)を作成
* 指定した値は、「Resources」「Outputs」で使用できる

例1:Hello world

Conditions:
  HasWriteRole:
    !Not [!Equals [!Ref IsReadonly, true]]

例2:AWS Region

  IsTokyoRegion: !Equals
    - !Ref AWS::Region
    - ap-northeast-1

例3:空かどうかの判定

  IsEmpty: !Equals
    - !Join
      - ","
      - !Ref DemoCommaDelimtedListValue
    - ""

例4:複数条件

  IsStageOrDev:
    !Or
      - !Equals [!Ref Env, dev]
      - !Equals [!Ref Env, stage]

例5:条件反転(Not)

  IsProd:
    !Not [ Condition: IsStageOrDev]

3)Resourcesセクション

* 2)の条件により、作成するResourceを切り替える


https://dk521123.hatenablog.com/entry/2022/05/25/220037

  MyBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref MyBucket
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Sid: 
          - Action:
              - 's3:GetObject'
              - !If
              - HasWriteRole
                - 's3:PutObject'
                - !Ref 'AWS::NoValue'
            Effect: Allow
            Resource: !Sub arn:aws:s3:::${YourBucketName}/*
            Principal: 'arn:aws:iam::987654321098:user/userA'

【3】サンプル

AWSTemplateFormatVersion: "2010-09-09"
Description: "This is a demo for KMS"

Parameters:
  Env:
    Description: Environment
    Type: String
    Default: dev
    AllowedValues:
      - dev
      - stage
      - prod
  IsAddedNormalRole:
    Description: This is for demo
    Type: String
    Default: false
    AllowedValues:
      - true
      - false

Conditions:
  HasNormalRole: !Equals
    - !Ref IsAddedNormalRole
    - true

Resources:
  # -------
  # KMS Key
  # -------
  DemoKmsKey:
    Type: "AWS::KMS::Key"
    Properties:
      Description: This is a demo key for KMKS
      EnableKeyRotation: true
      KeyPolicy:
        Version: 2012-10-17
        Id: key-demo-1
        Statement:
          - Sid: Enable IAM User Permissions
            Effect: Allow
            Principal:
              AWS: !Sub "arn:aws:iam::${AWS::AccountId}:root"
            Action: kms:*
            Resource:
              AWS:
                - !Sub arn:aws:iam::1111111111:role/demo-key-${Env}-admin
                - !If
                  - HasNormalRole
                  - !Sub arn:aws:iam::1111111111:role/demo-key-${Env}-user
                  - !Ref AWS::NoValue
      Tags:
        - Key: Name
          Value: !Sub demo-key-${Env}-cmk
  # -------
  # KMS Alias
  # -------
  DemoKmsKeyAlias:
    Type: "AWS::KMS::Alias"
    Properties:
      AliasName: !Sub alias/demo-key-${Env}-cmk
      TargetKeyId: !Ref DemoKmsKey
Outputs:
  DemoKmsKey:
    Value: !GetAtt DemoKmsKey.Arn
    Description: "This output is a demo KMS key"
    Export:
      Name: !Sub demo-key-${Env}-cmk

参考文献

https://oreout.hatenablog.com/entry/aws/cloudformation/6
https://blog.denet.co.jp/cloudformation%E3%81%A7%E5%8B%95%E7%9A%84%E3%81%AB%E3%82%BB%E3%82%AD%E3%83%A5%E3%83%AA%E3%83%86%E3%82%A3%E3%82%B0%E3%83%AB%E3%83%BC%E3%83%97%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%90%E3%82%A6%E3%83%B3/

関連記事

CloudFormation ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2021/10/26/224812
CloudFormation ~ 基本編 ~
https://dk521123.hatenablog.com/entry/2021/12/01/170326
CloudFormation ~ Mappings ~
https://dk521123.hatenablog.com/entry/2024/03/09/000428
CloudFormation ~ 組み込み関数 ~
https://dk521123.hatenablog.com/entry/2021/12/04/202519
CloudFormation ~ 疑似パラメータ ~
https://dk521123.hatenablog.com/entry/2021/12/05/134313
CloudFormation ~ AWS CLI
https://dk521123.hatenablog.com/entry/2024/02/23/003010
CloudFormation ~ S3 ~
https://dk521123.hatenablog.com/entry/2022/05/25/220037
CloudFormation ~ KMS ~
https://dk521123.hatenablog.com/entry/2022/05/26/112627