SNS/SQSで始めるCloudFormation

AWS CloudFormation

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

丹内です。

SNSのドキュメントで、CloudFormation(CFn)テンプレートのサンプルが提供されています(リンク)。

個人的にCFnは敷居が高い印象だったのですが、SNS/SQSのサンプルなら簡単そうかつ実用的だったので、このテンプレートでCFnに入門してみました。

サンプルをコピペして実行してみる

中身は後でじっくり見るとして、とりあえず動かしてみましょう。

リンク先のドキュメントをコピペしてmain.jsonという名前で保存して、準備完了です。(事前にAWS CLIの設定をしておいてください)

このファイル名の規約は特に無いので、お好きなものをどうぞ。

まずは、テンプレートのバリデーションをしてみます。

$ aws cloudformation validate-template --template-body file://main.json
{
    "CapabilitiesReason": "The following resource(s) require capabilities: [AWS::IAM::User, AWS::IAM::Group, AWS::IAM::UserToGroupAddition, AWS::IAM::AccessKey]",
    "Description": "This Template creates an Amazon SNS topic that can send messages to two Amazon SQS queues with appropriate permissions for one IAM user to publish to the topic and another to read messages from the queues. MySNSTopic is set up to publish to two subscribed endpoints, which are two Amazon SQS queues (MyQueue1 and MyQueue2). MyPublishUser is an IAM user that can publish to MySNSTopic using the Publish API. MyTopicPolicy assigns that permission to MyPublishUser. MyQueueUser is an IAM user that can read messages from the two Amazon SQS queues. MyQueuePolicy assigns those permissions to MyQueueUser. It also assigns permission for MySNSTopic to publish its notifications to the two queues. The template creates access keys for the two IAM users with MyPublishUserKey and MyQueueUserKey.  Note that you will be billed for the AWS resources used if you create a stack from this template.",
    "Parameters": [
        {
            "NoEcho": true,
            "Description": "Password for the IAM user MyPublishUser",
            "ParameterKey": "MyPublishUserPassword"
        },
        {
            "NoEcho": true,
            "Description": "Password for the IAM user MyQueueUser",
            "ParameterKey": "MyQueueUserPassword"
        }
    ],
    "Capabilities": [
        "CAPABILITY_IAM"
    ]
}

名前の通り、テンプレートのJSONに記述されている内容が正しいかどうかを確認します。

ここでvalidationでエラーが出なくても、その他の理由でCFn実行時にエラーになることもあるのでその点を頭に入れておきましょう。

CFnテンプレートの記述に基づいて、以下の内容が出力されます。

  • CapabilitiesReason: IAMなど一部の操作では、CFn実行時にCAPABILITY_IAMの指定が必要なのですが、その理由です
  • Capabilities: ここで指定されたCapabilityを指定する必要があります(現在はCAPABILITY_IAMのみです)
  • Parameters: テンプレート内ではパスワードをCFn実行時に引数で指定させています
  • 次に、CFnを実行してstackを作ってみましょう。

    $ aws cloudformation create-stack --stack-name SampleStack --template-body file://main.json 
    --parameters ParameterKey=MyPublishUserPassword,ParameterValue=password 
    ParameterKey=MyQueueUserPassword,ParameterValue=password 
    --capabilities CAPABILITY_IAM
    {
        "StackId": "arn:aws:cloudformation:us-east-1:404956753679:stack/SampleStack/d31e6390-020e-11e5-8f77-500162a66cb4"
    }
    

    create-stackを実行した結果、すぐにStackIdが返されます。

    ただ、この時点ではまだ完了していません。

    少し時間をあけてマネジメントコンソールのCFn画面でStackを確認すると、作成されていることがわかります。

    CloudFormation_Management_Console

    マネジメントコンソールの下部で様々な内容を見れます。

    以下、重要な箇所を見て行きましょう。

    Overview

    overview

    設定したStack NameとDescription、それと生成されたStackIdが記載されています。

    Outputs

    outputs

    テンプレートのOutputsに書いた項目が出力されています。

    他の画面では表示1回きりのSecret Access Keyもここに表示されているので、SDKを使うときなどはここを参照します。

    Resources

    resources

    作成されたリソースが記載されています。

    Events

    events

    実施された操作(イベント)の詳細が記載されています。

    Parameters

    parameters

    create-stack時に指定した引数の内容が記載されています。

    以下のようにサンプルのテンプレートでNoEchoをtrueに設定しているので、入力内容はマスクされています。

    "Parameters":{
      "MyPublishUserPassword":{
        "NoEcho":"true",
        "Type":"String",
        "Description":"Password for the IAM user MyPublishUser",
        "MinLength":"1",
        "MaxLength":"41",
        "AllowedPattern":"[a-zA-Z0-9]*",
        "ConstraintDescription":"must contain only alphanumeric characters."
      },
    

    最後に、delete-stackで後片付けをしておきましょう。

    $ aws cloudformation delete-stack --stack-name SampleStack
    

    サンプルのテンプレートを読む

    ここまでで挙動はおおまかに把握できたので、次はテンプレートを読んでみましょう。

    AWSTemplateFormatVersion

    まず、サンプルテンプレートの最上部にはこの記載があります。

    "AWSTemplateFormatVersion":"2010-09-09",
    

    名前の通り、テンプレートのバージョンを指定します。

    Description

    "Description":"This Template creates an Amazon SNS topic that can send ...(省略)"
    

    テンプレートの詳細です。

    AWS CLIでのdescribe-stacksやマネジメントコンソールで確認できます。

    Parameters

    "Parameters":{
      "MyPublishUserPassword":{
        "NoEcho":"true",
        "Type":"String",
        "Description":"Password for the IAM user MyPublishUser",
        "MinLength":"1",
        "MaxLength":"41",
        "AllowedPattern":"[a-zA-Z0-9]*",
        "ConstraintDescription":"must contain only alphanumeric characters."
      },
      "MyQueueUserPassword":{
        "NoEcho":"true",
        "Type":"String",
        "Description":"Password for the IAM user MyQueueUser",
        "MinLength":"1",
        "MaxLength":"41",
        "AllowedPattern":"[a-zA-Z0-9]*",
        "ConstraintDescription":"must contain only alphanumeric characters."
      }
    },
    

    テンプレート内で必要になるパラメータを記載します。

    AWS CLIの場合はcreate-stack時に引数で渡します。マネジメントコンソールからだと、stack作成時に値を設定する画面があります。

    パスワードなどログに残したりマネジメントコンソールに記載したくない値は、NoEchoをTrueに設定します。

    Resources

    実際に作成するものです。ここが主役になります(?)。

    指定したResourceのTypeにあわせて、ドキュメントを参照しながら値を記述していきます。

    サンプルの一部を見てみましょう。

    IAM Userの作成

    "MyPublishUser":{
     "Type":"AWS::IAM::User",
     "Properties":{
       "LoginProfile":{
         "Password":{"Ref":"MyPublishUserPassword"}
       }
     }
    },
    

    アクセスキーの作成

    "MyQueueUserKey":{
     "Type":"AWS::IAM::AccessKey",
     "Properties":{
          "UserName":{"Ref":"MyQueueUser"}
      }
    },
    

    IAMユーザをGroupに追加

    "AddUserToMyPublishTopicGroup":{
      "Type":"AWS::IAM::UserToGroupAddition",
      "Properties":{
        "GroupName":{"Ref":"MyPublishTopicGroup"},
        "Users":[{"Ref":"MyPublishUser"}]
      }
    },
    

    SNSトピックの作成

    "MySNSTopic":{
      "Type":"AWS::SNS::Topic",
      "Properties":{
        "Subscription":[
          {
            "Endpoint":{"Fn::GetAtt":["MyQueue1","Arn"]},
            "Protocol":"sqs"
          },
          {
            "Endpoint":{"Fn::GetAtt":["MyQueue2","Arn"]},
            "Protocol":"sqs"
          }
        ]
      }
    },
    

    ここでは以下の組み込み関数が使われています。

  • Fn::GetApp
  • Ref
  • これらの関数を使うことで、CFnで事前に作成されたリソースのランダムな名前を参照できます。

    まとめ

    敷居が高いCFnですが、その名の通りSimpleなSNS/SQSは設定項目が少なく、CFnの入門に最適だと思います。

    また、AccessKeyやEndpointなどのリソースがCFnの画面で一覧表示できることも、非常に便利です。

    これ以外にもたくさん公式ドキュメントでサンプルが提供されているので、参照しながら手を動かしていくといずれはCFnマスターになれそうです!