やりたかったこと
以前投稿した SSMドキュメントでCloudFormation Stackを作成してみた の続きです。
作成済みのSSMドキュメントを複数アカウントに展開するにあたり、各アカウント用にSSMドキュメントを書き換える手間を減らすために環境固有の情報を外部化することになりました。
AWSのユーザーガイド を見ても分かりづらい部分があったので手順をメモしておきます。
もともとのSSMドキュメントの内容
一時サーバ用EC2インスタンスのCFn Stackを作成することで、自動で起動するためのSSMドキュメントです。
定期的に一時サーバ起動の処理が必要になるため、SSMドキュメント化することで同じ処理を繰り返し実行しやすくしています。
以下のSSMドキュメントのyamlファイルのうち、①「サービスロールのARNに含まれるアカウントID」②「作成したいCFn Stackの名前」③「CFn Template格納先のS3バケットのURL」の3つをアカウントごとに変える必要がありました。
description: Launch temporary server by creating CloudFormation stack
schemaVersion: '0.3'
#assumeRoleではドキュメント実行時に利用するサービスロールのARNを指定。ARNの「account-id」の箇所はドキュメントを作成するAWSアカウントごとに変更する必要がある(①)
assumeRole: 'arn:aws:iam::account-id:role/SSMServiceRole'
mainSteps:
- name: CreateStackForTemporaryServer
action: 'aws:createStack'
inputs:
#StackNameでは作成したいCFn Stackの名前を指定。アカウントの識別子(Devなど)を含めたいため、ドキュメントを作成するAWSアカウントごとに変更する必要がある(②)
StackName: TempServerForDev
#TemplateURLでは作成したいCFn Template格納先のS3バケットのURLを指定。格納先バケットはSSMドキュメントを実行するアカウントで作成するため、ドキュメントを作成するAWSアカウントごとに変更する必要がある(③)
TemplateURL: 'https://bucket-name.s3.ap-northeast-1.amazonaws.com/test/temporary-server.yaml'
Capabilities:
- CAPABILITY_IAM
環境固有の情報の外部化の手順
##1. SSMパラメーターストアの値を参照
②「作成したいCFn Stackの名前」③「CFn Template格納先のS3バケットのURL」の値はSSMパラメーターストアに保管して、SSMドキュメント側から参照できるようにします。
##1-1. SSMパラメーストアに値を登録
②「作成したいCFn Stackの名前」用に、Stringタイプのパラメーター /tmp-server/stack-name
を作成し、値 TempServerForDev
を保管します。
③「CFn Template格納先のS3バケットのURL」用にStringタイプのパラメーター /tmp-server/cfn-template-url
を作成し、値 https://bucket-name.s3.ap-northeast-1.amazonaws.com/test/temporary-server.yaml
を保管します。
SSMパラメーターストアへの値の登録手順詳細は CloudFormationを使ってSystems Managerのパラメータストアの値を登録し、取得する を参照ください。
##1-2. SSMドキュメントにパラメーターを追加
SSMドキュメント自体のパラメーターを追加して、許容される値として1-1で追加したSSMのパラメーター名を指定します。
②「作成したいCFn Stackの名前」用に、1-1で作成したパラメーター /tmp-server/stack-name
を参照するためにSSMドキュメントのパラメーター StackNameForTempServer
を追加します。
SSMドキュメントをGUIで編集する場合は以下のようなイメージです。
「Allowed values」のSSMパラメーターの値は {{ssm:parameter-name}}
のように指定してあげます。
ドキュメントのパラメーターのデータタイプを「String」にした場合は ['{{ssm:parameter-name}}']
と入力しないと怒られます。
入力後は画像のように - '{{ssm:parameter-name}}'
と表示されるようになります。
③「CFn Template格納先のS3バケットのURL」用にも、1-1で作成したパラメーター /tmp-server/cfn-template-url
を参照するためにSSMドキュメントのパラメーター CFnTemplateURL
を追加します。
##1-3. SSMドキュメントの該当箇所にパラメーターを指定
SSMドキュメントの該当箇所に、1-2で追加したSSMドキュメント自体のパラメーター名を指定します。
StackNameForTempServer
を「Stack name」に、 CFnTemplateURL
を「Template URL」に指定します。
以下のようなイメージです。
パラメーター名を {{
と }}
で囲うのが注意点です。
##2. Automation system variablesを利用
①「サービスロールのARNに含まれるアカウントID」は、SSMドキュメント用に提供されているAutomation system variables利用して外部化します。
SSMドキュメント実行時のIAMユーザーまたはIAMロールのアカウントIDを参照できる変数 global:ACCOUNT_ID
を使います。
Automation system variablesの一覧は、冒頭にも掲載した AWSのユーザーガイド に載っています。
##2-1. SSMドキュメントにパラメーターを追加
SSMドキュメント自体のパラメーター AutomationAssumeRole
を追加して、許容される値としてサービスロールのARNを指定します。
1-2の手順とほぼ同じで、以下のようなイメージです。
「Allowed values」で指定するサービスロールのARNは arn:aws:iam::{{global:ACCOUNT_ID}}:role/SSMServiceRole
のように指定してあげます。
2-2と同じで、ドキュメントのパラメーターのデータタイプを「String」にした場合は ['arn:aws:iam::{{global:ACCOUNT_ID}}:role/SSMServiceRole']
と入力しないと怒られます。
##2-2. SSMドキュメントの該当箇所にパラメーターを指定
2-1で追加したドキュメントのパラメーター AutomationAssumeRole
をSSMドキュメントの該当箇所「ロールを想定」に指定します。
1-3と同じで、パラメーター名を {{
と }}
で囲うのが注意点です。
これで①「サービスロールのARNに含まれるアカウントID」②「作成したいCFn Stackの名前」③「CFn Template格納先のS3バケットのURL」の3つ全ての外部化が完了です。
#更新後のSSMドキュメントの内容
更新後のSSMドキュメントのyamlは以下のようになります。
このように書き換えておけば、他のアカウントにSSMドキュメントを展開する際もこのyamlをそのままコピーできます。
description: Launch temporary server by creating CloudFormation stack
schemaVersion: '0.3'
assumeRole: '{{ AutomationAssumeRole }}'
parameters:
StackNameForTempServer:
type: String
allowedValues:
- '{{ssm:/tmp-server/stack-name}}'
description: ' (Required) CFn Stack name for temporary server.'
CFnTemplateURL:
type: String
allowedValues:
- '{{ssm:/tmp-server/cfn-template-url}}'
description: (Required) CFn Template URL for temporary server.
AutomationAssumeRole:
type: String
allowedValues:
- 'arn:aws:iam::{{global:ACCOUNT_ID}}:role/SSMServiceRole'
description: (Required) The ARN of the role that allows Automation to perform the actions on your behalf.
mainSteps:
- name: CreateStackForTemporaryServer
action: 'aws:createStack'
inputs:
StackName: '{{ StackNameForTempServer }}'
TemplateURL: '{{ CFnTemplateURL }}'
Capabilities:
- CAPABILITY_IAM
後日追記
環境固有の情報をパラメーターとして与える場合、パラメーターの値を固定値としていいのであれば、 allowedValues
より default
を使用するのが適していることに気づきました。
allowedValues
の場合、実行時に毎回パラメーターの値を allowedValues
のままとするか、上書きするかを明示指定する必要がありますが、default
は毎回明示指定する必要がないのでちょっと楽です。
ただ、2020年8月時点ではSSMコンソールのドキュメントビルダーでは default
の指定はできないので、yamlファイルを用意して作成する必要があります。