こんにちは。AWS CLIが好きな福島です。
はじめに
今回は、AWS CLIを使い、CloudFormationの複数のテンプレートで定義したParametersの値を1つのファイルで管理する方法をご紹介いたします。
AWS CLIを使ったCloudformationの操作については、以下にまとめているため、興味がありましたら、ご確認ください。
https://blog.serverworks.co.jp/2020/08/14/190000
概要図
例として、VPCとSubnetを作るケースで概要図を記載いたしました。
※VPCとSubnetは同一テンプレートで作るケースが多いかと存じますが、説明のために分割しました。
Before

赤字の箇所が重複しておりますが、CloudFormationでパラメーターをファイル(以降、パラメーターファイルと記載)で管理するためには、 テンプレートで定義したParametersのみをファイルに記載する必要があります。
Parametersの値が全て同一のテンプレートというのは、ほとんどのないかと存じますため、 基本的にパラメーターファイルは、テンプレートごとに作成する必要が出てきてしまいますが、そうなると管理が煩雑になるかと存じます。
After

上記図のようにパラメーターを1つのファイルで管理できれば、Beforeと比べると管理が楽になるのではないでしょうか。 ということでその方法をここから説明いたします。
結論
冒頭でも記載しましたが、パラメーターファイルには、テンプレートで定義したParametersのみを記載する必要があるため、 パラメーターをまとめたファイルからスクリプトによってテンプレートで使う値のみを抽出し、スタックの作成を行います。
使い方
内容を細かく説明する前にスクリプトの使い方を記載した方がいいかなと思ったため、先に使用方法を記載いたします。
# ./create-stack.sh [テンプレート] [パラメーターファイル]
実行例
VPC
# ./create-stack.sh serverworks-vpc.yml prd-fk-param.json
以下のパラメーターでスタックを作成します。問題ない場合、yesと入力してください。"
##############################################################
CFN_STACK_NAME : prd-fk-serverworks-vpc
## PARAMETERS
EnvironmentName : prd
OwnerName : Serverworks
SystemName : fk
VpcCIDR : 10.0.0.0/16
## 実行コマンド
aws cloudformation create-stack
--stack-name prd-fk-serverworks-vpc
--capabilities CAPABILITY_NAMED_IAM
--template-body file://serverworks-vpc.yml
--parameters ParameterKey=EnvironmentName,ParameterValue=prd ParameterKey=OwnerName,ParameterValue=Serverworks ParameterKey=SystemName,ParameterValue=fk ParameterKey=VpcCIDR,ParameterValue=10.0.0.0/16
##############################################################
yes
{
"StackId": "arn:aws:cloudformation:ap-northeast-1:123456789012:stack/prd-fk-serverworks-vpc/fd6159d0-0951-11ed-bfd7-0650087e107d"
}
#
Subnet
# ./create-stack.sh serverworks-subnet.yml prd-fk-param.json
以下のパラメーターでスタックを作成します。問題ない場合、yesと入力してください。"
##############################################################
CFN_STACK_NAME : prd-fk-serverworks-subnet
## PARAMETERS
EnvironmentName : prd
ImportStackName : prd-fk-serverworks-vpc
OwnerName : Serverworks
PublicSubnet1CIDR : 10.0.1.0/24
PublicSubnet2CIDR : 10.0.2.0/24
SystemName : fk
## 実行コマンド
aws cloudformation create-stack
--stack-name prd-fk-serverworks-subnet
--capabilities CAPABILITY_NAMED_IAM
--template-body file://serverworks-subnet.yml
--parameters ParameterKey=EnvironmentName,ParameterValue=prd ParameterKey=ImportStackName,ParameterValue=prd-fk-serverworks-vpc ParameterKey=OwnerName,ParameterValue=Serverworks ParameterKey=PublicSubnet1CIDR,ParameterValue=10.0.1.0/24 ParameterKey=PublicSubnet2CIDR,ParameterValue=10.0.2.0/24 ParameterKey=SystemName,ParameterValue=fk
##############################################################
yes
{
"StackId": "arn:aws:cloudformation:ap-northeast-1:123456789012:stack/prd-fk-serverworks-subnet/960d5da0-0952-11ed-ac36-0eec3649f2d5"
}
#
詳細
ファイル構成
- ①prd-fk-param.json: パラメーターファイル
※スクリプトの都合、末尾は「-pamarm.json」とする必要があります。 - ②serverworks-vpc.yml: VPC作成のテンプレート
- ③serverworks-subnet.yml: サブネット作成のテンプレート
- ④create-stack.sh: 上記スクリプト
①prd-fk-param.json
[
{
"ParameterKey": "SystemName",
"ParameterValue": "fk"
},
{
"ParameterKey": "OwnerName",
"ParameterValue": "Serverworks"
},
{
"ParameterKey": "EnvironmentName",
"ParameterValue": "prd"
},
{
"ParameterKey": "VpcCIDR",
"ParameterValue": "10.0.0.0/16"
},
{
"ParameterKey": "ImportStackName",
"ParameterValue": "prd-fk-serverworks-vpc"
},
{
"ParameterKey": "PublicSubnet1CIDR",
"ParameterValue": "10.0.1.0/24"
},
{
"ParameterKey": "PublicSubnet2CIDR",
"ParameterValue": "10.0.2.0/24"
}
]
②serverworks-vpc.yml
AWSTemplateFormatVersion: 2010-09-09
Description: This template deploys a VPC
Parameters:
SystemName:
Description: Please specify the system name of the resource
Type: String
OwnerName:
Description: Please specify the owner name of the resource
Type: String
EnvironmentName:
Description: Please specify the environment name of the resource
Type: String
AllowedValues:
- prd
- stg
- dev
- poc
VpcCIDR:
Description: Please enter the IP range (CIDR notation) for this VPC
Type: String
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCIDR
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: !Sub ${SystemName}-${OwnerName}-${EnvironmentName}-vpc
- Key: System
Value: !Sub ${SystemName}
- Key: Owner
Value: !Sub ${OwnerName}
- Key: Environment
Value: !Sub ${EnvironmentName}
Outputs:
VPC:
Description: A reference to the created VPC
Value: !Ref VPC
Export:
Name:
Fn::Sub: ${AWS::StackName}-VPC
③serverworks-subnet.yml
AWSTemplateFormatVersion: 2010-09-09
Description: This template deploys a VPC
Parameters:
SystemName:
Description: Please specify the system name of the resource
Type: String
OwnerName:
Description: Please specify the owner name of the resource
Type: String
EnvironmentName:
Description: Please specify the environment name of the resource
Type: String
AllowedValues:
- prd
- stg
- dev
- poc
ImportStackName:
Description: Please specify the stack name you want to import
Type: String
PublicSubnet1CIDR:
Description: Please enter the IP range (CIDR notation) for the public subnet in the first Availability Zone
Type: String
PublicSubnet2CIDR:
Description: Please enter the IP range (CIDR notation) for the public subnet in the second Availability Zone
Type: String
Resources:
PublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId:
Fn::ImportValue:
!Sub "${ImportStackName}-VPC"
AvailabilityZone: ap-northeast-1a
CidrBlock: !Ref PublicSubnet1CIDR
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub ${SystemName}-${OwnerName}-${EnvironmentName}-public-subnet-1a-001
- Key: System
Value: !Sub ${SystemName}
- Key: Owner
Value: !Sub ${OwnerName}
- Key: Environment
Value: !Sub ${EnvironmentName}
PublicSubnet2:
Type: AWS::EC2::Subnet
Properties:
VpcId:
Fn::ImportValue:
!Sub "${ImportStackName}-VPC"
AvailabilityZone: ap-northeast-1c
CidrBlock: !Ref PublicSubnet2CIDR
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub ${SystemName}-${OwnerName}-${EnvironmentName}-public-subnet-1c-001
- Key: System
Value: !Sub ${SystemName}
- Key: Owner
Value: !Sub ${OwnerName}
- Key: Environment
Value: !Sub ${EnvironmentName}
Outputs:
PublicSubnet1:
Description: A reference to the public subnet in the 1st Availability Zone
Value: !Ref PublicSubnet1
Export:
Name:
Fn::Sub: ${AWS::StackName}-PublicSubnet1
PublicSubnet2:
Description: A reference to the public subnet in the 2nd Availability Zone
Value: !Ref PublicSubnet2
Export:
Name:
Fn::Sub: ${AWS::StackName}-PublicSubnet2
④create-stack.sh
スクリプトを使うためには、AWS CLIおよびjqが導入されている必要があります。
#!/bin/bash
## 1. スクリプトの引数に指定されたテンプレートとパラメーターファイルを変数に定義
CFN_TEMP=${1}
CFN_PARAM=${2}
## 2. スタックの名前をパラメーターファイルおよびテンプレートファイル名から抽出
CFN_STACK_NAME=$(echo ${CFN_PARAM}-${CFN_TEMP##*/} | sed 's/-param.json//g' | awk -F. '{print $1}')
## 3. 変数(引数)がなかった場合、メッセージを出力し、処理を終了
if [[ -z ${CFN_TEMP} || -z ${CFN_PARAM} ]] ; then
echo "第1引数: 使用するテンプレートを指定ください。"
echo "第2引数: 使用するパラメーターを指定ください。"
exit 9
fi
## 5. 4で抽出した値をkey変数に1つずつ代入
while read key
do
## 6. jqコマンドを使い、key変数に定義された情報を基にパラメーターファイルから必要な情報を抽出
temp_value=$(cat ${CFN_PARAM} \
| jq --arg key $key -r '.[] | select(.ParameterKey == $key) | .ParameterValue')
## 7. 6で抽出した情報をparameters変数に代入
parameters+="ParameterKey=$key,ParameterValue=$temp_value "
## 4. テンプレートに定義したParametersのParameterKeyを1つずつ抽出
done << EOL
$(aws cloudformation validate-template \
--template-body file://${CFN_TEMP} \
--query "Parameters[].[ParameterKey]" \
--output text | sort)
EOL
## 8. 抽出したパラメーター,スタック名および実行コマンドを出力
cat << EOF
以下のパラメーターでスタックを作成します。問題ない場合、yesと入力してください。"
##############################################################
CFN_STACK_NAME : ${CFN_STACK_NAME}
## PARAMETERS
$(echo ${parameters} | tr " " "\n" \
| sed -e 's/ParameterKey=//g' -e 's/,ParameterValue=/ : /g' \
| column -t)
## 実行コマンド
aws cloudformation create-stack
--stack-name ${CFN_STACK_NAME}
--capabilities CAPABILITY_NAMED_IAM
--template-body file://${CFN_TEMP}
--parameters ${parameters}
##############################################################
EOF
## 9. 8の内容に問題ないか確認するため、ユーザーから入力を待つ。
read answer
## 10. ユーザーからyesが入力された場合、スタックを作成
if [[ ${answer} == "yes" ]] ; then
aws cloudformation create-stack \
--stack-name ${CFN_STACK_NAME} \
--capabilities CAPABILITY_NAMED_IAM \
--template-body file://${CFN_TEMP} \
--parameters ${parameters}
## 11. yes以外が入力された場合、処理を中断
else
echo "処理を中断しました。"
exit 9
fi
終わりに
今回は複数のテンプレートで定義したParametersの値を1つのファイルで管理する方法をご紹介いたしました。 もう少し簡単に出来れば良かったのですが、これを実現するためにはスクリプトを作らざるを得なそうでした。
どなたかのお役に立てれば幸いです。