[アップデート] CloudFormation の Fn::FindInMap でより簡潔なマッピング定義が可能になるように機能が拡張されました

2023.01.15

いわさです。

先日のアップデートで Fn::FindInMap に便利な機能がいくつか追加されました。
アナウンスは以下です。

私は普段 FindInMap をそこまで使い倒してこなかったからか、最初このアナウンスを見てもよくわかりませんでした。
そこで、今まで出来なかったことと今回出来るようになったことを整理しつつ実際に使ってみましたので紹介します。

アップデート内容サマリ

Fn::FindInMap は CloudFormation の Mappings 句で定義した値を取得する際に使用します。
非常に便利な機能ではあるのですが、Mappings を定義するために使用されるキーを網羅した定義が必要になり冗長な記述になってしまうことがありました。

そこで今回のアップデートで Mappings 定義をスマートに出来るように以下の 2 つのアップデートが行われました。

  • デフォルト値の設定が可能に
  • Fn::FindInMap 内で利用がサポートされる関数が追加された

一点注意点があり、こちらは通常の Fn::FindInMap の機能が強化されたわけではなく、言語拡張の変換を使った際に利用出来る機能となっています。

言語拡張の変換はテンプレートの Transform にAWS::LanguageExtensionsの記述を行うことで CloudFormation の機能を強化出来るもので、2022 年 9 月ごろに登場しました。

デフォルト機能

リージョンごとに Mappings 句で値やフラグを定義するシーンがあると思いますが、AMI の ID などリージョン固有なものはともかく、一部のリージョンだけ別のパラメータを設定したいシーンがあるとします。
以下の場合だと ap-northeast-1 と ap-northeast-2 だけ固有の値で、それ以外のリージョンは共通の値を利用することを想定していますが、Mappings 句にはデプロイ対象となりえるリージョンの数だけ定義が必要です。

AWSTemplateFormatVersion: 2010-09-09
Description: ---
Mappings: 
  HogeValue:
    ap-northeast-1:
      tagvalue: hoge1
    ap-northeast-2:
      tagvalue: hoge2
    ap-northeast-3:
      tagvalue: defaultvalue
    us-east-1:
      tagvalue: defaultvalue

:

    us-west-1:
      tagvalue: defaultvalue
Resources: 
  myVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsSupport: true
      Tags:
        - Key: HogeKey
          Value: !FindInMap
            - HogeValue
            - !Ref AWS::Region
            - tagvalue

こちらを ap-northeast-1 でデプロイすると以下のようにタグにマップした値が設定された VPC が作成されます。

上記のデプロイすれば ap-northeast-3 だと defaultvalue という値が設定されますが、もし ap-northeast-1 と ap-northeast-2 以外に定義を行わなかった場合はデプロイ自体が失敗してしまいます。

% rain deploy hoge1.yaml hoge1 --region ap-northeast-3
error creating changeset: Template error: Unable to get mapping for HogeValue::ap-northeast-3::tagvalue

ここでのデプロイは Rain を使っています。

拡張機能を使う

今回追加された拡張機能を使うと以下のように定義することが出来るようになります。

AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::LanguageExtensions
Description: ---
Mappings: 
  HogeValue:
    ap-northeast-1:
      tagvalue: hoge1
    ap-northeast-2:
      tagvalue: hoge2
Resources: 
  myVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsSupport: true
      Tags:
        - Key: HogeKey
          Value: !FindInMap
            - HogeValue
            - !Ref AWS::Region
            - tagvalue
            - DefaultValue: defaultvalue

Mappings 句には個別の値のみを設定し、Fn::FindInMap に共通のその他デフォルト値を設定します。
こちらを ap-northeast-3 にてデプロイしてみましょう。

iwasa.takahito@HL01200 hoge0115cfn % rain deploy hoge1.yaml hoge1 --region ap-northeast-3
CloudFormation will make the following changes:
Stack hoge1:
  + AWS::EC2::VPC myVPC
Do you wish to continue? (Y/n) 
Deploying template 'hoge1.yaml' as stack 'hoge1' in ap-northeast-3.
Stack hoge1: CREATE_COMPLETE
Successfully deployed hoge1

以下のように defaultvalue が設定されました。

ap-northeast-2 でデプロイした場合も期待どおり個別の値がマッピングされています。

このように共通の値が大部分を占めておりいくつかのマップキーの分だけ定義できれば済むような場合はコードがかなり少なくなりますね。
従来でも Condition や If などを使うことで実現自体は出来ていたようですが、複雑な分岐をかかずに直感的な記述が出来るようになりました。

Fn::FindInMap 内で使える関数の追加

言語拡張を使わない場合に Fn::FindInMap 内で使える関数は Fn::FindInMap と Ref のみが利用可能でした。

Supported functions
You can use the following functions in a Fn::FindInMap function:
- Fn::FindInMap
- Ref

Fn::FindInMap - AWS CloudFormation より

言語拡張を使う場合に以下が追加で Fn::FindInMap 内で利用出来るようになっています。

  • Fn::Join
  • Fn::Sub
  • Fn::If
  • Fn::Select
  • Fn::Length
  • Fn::ToJsonString
  • Fn::Split

参考 : Fn::FindInMap enhancements - AWS CloudFormation

アップデートアナウンスではユースケースとして AWS::KMS::Key の KeyUsage で利用するケースが挙げられていました。
こちらは適用例のコードを見たほうがわかりやすいと思うので先に拡張機能を使ったコードを見てみましょう。

AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::LanguageExtensions
Description: ---
Parameters:
  KeySpec:
    Type: String
    AllowedValues:
      - ECC_NIST_P256
      - ECC_NIST_P384
      - ECC_NIST_P521
      - ECC_SECG_P256K1
      - HMAC_224
      - HMAC_256
      - HMAC_384
      - HMAC_512
      - RSA_2048
      - RSA_3072
      - RSA_4096
      - SYMMETRIC_DEFAULT
    Default: SYMMETRIC_DEFAULT
Mappings:
  KeyPrefix:
    ECC:
      usage: SIGN_VERIFY
    HMAC:
      usage: GENERATE_VERIFY_MAC
    SYMMETRIC:
      usage: ENCRYPT_DECRYPT
Resources:
  Key:
    Type: AWS::KMS::Key
    Properties:
      KeySpec: !Ref KeySpec
      KeyUsage: !FindInMap
        - KeyPrefix
        - !Select [0, !Split [_, !Ref KeySpec]]
        - usage

KeyUsage に設定可能な値は KeySpec プロパティで設定するキータイプによっていくつかに分類されます。
KeySpec への設定値は ECC_NIST_P256 のような形式となっており、このプレフィックスで分類することが出来ます。
そこで、上記では KeySpec の値を Split と Select を使ってプレフィックだけ取得し、その値を使って FindInMap を利用しています。

これによって Mapping 句が 3 パターンだけの定義でよくなります。
プレフィックスを使わない場合だと KeySpec の数だけ定義が必要なことがわかると思います。(実際には Mapping 句に使えるキーのバリデーションで別の問題が起きるのですが)

さいごに

本日は CloudFormation の Fn::FindInMap でいくつか機能強化されていたのでアップデート情報を整理し、いくつか実際に使ってみました。

私はリージョンをキーに AMI を取得する程度しか普段 Mapping を使ってこなかったので、恩恵を感じきることが出来ず勉強不足だなと反省しましたが、CloudFormation 職人の皆様には嬉しいアップデートなのかもしれませんね。