この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
カスタムリソース
CloudFormationカスタムリソースは、テンプレートの中だけでは記述できないリソースタイプなどを外出しして記述する方法です。ユーザーがスタックを作成、更新、削除するたびに AWS CloudFormation がそれを実行します。
今回は、Amazon SNSを使って外部のリソースと連携してみたいと思います。
Amazon SNS-backedカスタムリソース
まず始めにCloudFormationテンプレートを作成したいと思います。カスタムリソース指定の部分に注目してください。このテンプレートは、Custom::HelloWorld型のリソースであるMyCustomLogicを定義しています。このカスタムリソースは、SNSに通知をしますので、このテンプレート内でSNSを作成しています。そして、後からポーリングして取り出せるように、SNSのサブスクライバとしてSQSを指定しています。
{
"AWSTemplateFormatVersion" : "2010-09-09",
"Resources" : {
"MyCustomLogic" : {
"Type": "Custom::HelloWorld",
"Version" : "1.0",
"Properties" : {
"ServiceToken": {"Ref" : "MySNSTopic"}
}
},
"MySNSTopic":{
"Type":"AWS::SNS::Topic",
"Properties":{
"Subscription":[{
"Endpoint":{"Fn::GetAtt":["MyQueue","Arn"]},
"Protocol":"sqs"
}]
}
},
"MyQueue":{
"Type":"AWS::SQS::Queue"
},
"MyQueuePolicy":{
"Type":"AWS::SQS::QueuePolicy",
"Properties":{
"PolicyDocument":{
"Version":"2012-10-17",
"Id":"MyQueuePolicy",
"Statement":[
{
"Sid":"Allow-SendMessage-To-Queues-From-SNS-Topic",
"Effect":"Allow",
"Principal":"*",
"Action":["sqs:SendMessage"],
"Resource":"*",
"Condition":{
"ArnEquals":{
"aws:SourceArn":{"Ref":"MySNSTopic"}
}
}
}
]
},
"Queues":[{"Ref":"MyQueue"}]
}
}
}
}
リソースプロバイダーが受け取るメッセージ
CloudFormation内のテンプレートデベロッパーから送られてきたメッセージは、カスタムリソースプロバイダーで処理されて応答メッセージを返すことになります。ここでは、通知メッセージのボディを見てみたいと思います。Messageブロックには、応答に必要な各種ID情報などが含まれています。
{
"Type" : "Notification",
"MessageId" : "cd211b4f-1dc7-557e-99a1-5553926141df",
"TopicArn" : "arn:aws:sns:ap-northeast-1:XXXXXXXXXXXX:CustomHello6-MySNSTopic-1W0F4LGK7AVL2",
"Subject" : "AWS CloudFormation custom resource request",
"Message" : "{
\"RequestType\":\"Create\",
\"ServiceToken\":\"arn:aws:sns:ap-northeast-1:XXXXXXXXXXXX:CustomHello6-MySNSTopic-1W0F4LGK7AVL2\",
\"ResponseURL\":\"https://cloudformation-custom-resource-response-apnortheast1.s3-ap-northeast-1.amazonaws.com/arn%3Aaws%3Acloudformation%3Aap-northeast-1%XXXXXXXXXXXX%3Astack/CustomHello6/0b8ba5b0-28ae-11e5-8e5c-50fa59279ce0%7CMyCustomLogic%7C27bb6dbe-557a-40f9-8793-85a25a908d71
\"StackId\":\"arn:aws:cloudformation:ap-northeast-1:XXXXXXXXXXXX:stack/CustomHello6/0b8ba5b0-28ae-11e5-8e5c-50fa59279ce0\",
\"RequestId\":\"27bb6dbe-557a-40f9-8793-85a25a908d71\",
\"LogicalResourceId\":\"MyCustomLogic\",
\"ResourceType\":\"Custom::HelloWorld\",
\"ResourceProperties\":{\"ServiceToken\":\"arn:aws:sns:ap-northeast-1:XXXXXXXXXXXX:CustomHello6-MySNSTopic-1W0F4LGK7AVL2\"}}",
"Timestamp" : "2015-07-12T15:53:10.020Z",
"SignatureVersion" : "1",
"Signature" : "Lgtvyeg+sDWbTxHGJrWUNeB1UikS7eMOy2ml+pUhGBAYbyLkpDf7p2mn/06oapDsyV2qIX9y66CI6UuWfsAOTW/+BEjVpJpdx1kux+wuu9165p0MTq0o6c4o5qTaWSOX/IKn0DSLukNKd+5WDSNWwKH3hMs4W0aU7rKh9y5PLep2FtK3wXxFyHWBh4Rsy8Fk6UCDz+HK+K0AORxaRamVL4d4j/vZDXplAw6HbhSaasUnkakzRdllnISiZRd3iiwaaBny3c6M012t8MCVDfq8zUS/JoXRzFXoGmAr9PcExvHUuq+Dy1h/aCOlWHEZu8TmDF2zYyjf7oSkzR0gC2MA1A==",
"SigningCertURL" : "https://sns.ap-northeast-1.amazonaws.com/SimpleNotificationService-d6d679a1d18e95c2f9ffcf11f4f9e198.pem",
"UnsubscribeURL" : "https://sns.ap-northeast-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:ap-northeast-1:XXXXXXXXXXXX:CustomHello6-MySNSTopic-1W0F4LGK7AVL2:d6dec38a-a5f7-4cd8-a419-aa3cad7b1cd1"
}
処理成功の応答をする。
カスタムリソースプロバイダー側の処理が成功したと仮定して、応答を返したいと思います。本来であれば、プログラミング等を結果を返すことになりますが、今回はわかりやすさを優先して、curlコマンドでメッセージを返します。以下は、応答メッセージのボディです。これをresult.jsonという名前で保存しました。
{
"Status" : "SUCCESS",
"PhysicalResourceId" : "MyCustomLogic",
"StackId" : "arn:aws:cloudformation:ap-northeast-1:XXXXXXXXXXXX:stack/CustomHello6/0b8ba5b0-28ae-11e5-8e5c-50fa59279ce0",
"RequestId" : "27bb6dbe-557a-40f9-8793-85a25a908d71",
"LogicalResourceId" : "MyCustomLogic"
}
次に、curlコマンドでS3にPUTします。ここの記述方法でかなりハマりました。HTTPステータスコードが200番になっていることを確認してください。
$ curl -v -X PUT -H 'User-Agent: ' -H 'Content-Type: ' -T body.json "https://cloudformation-custom-resource-response-apnortheast1.s3-ap-northeast-1.amazonaws.com/arn%3Aaws%3Acloudformation%3Aap-northeast-1%3AXXXXXXXXXXXX%3Astack/CustomHello6/0b8ba5b0-28ae-11e5-8e5c-50fa59279ce0%7CMyCustomLogic%7C27bb6dbe-557a-40f9-8793-85a25a908d71
> PUT /arn%3Aaws%3Acloudformation%3Aap-northeast-1%3AXXXXXXXXXXXX%3Astack/CustomHello6/0b8ba5b0-28ae-11e5-8e5c-50fa59279ce0%7CMyCustomLogic%7C27bb6dbe-557a-40f9-8793-85a25a908d71 HTTP/1.1
> Host: cloudformation-custom-resource-response-apnortheast1.s3-ap-northeast-1.amazonaws.com
> Accept: */*
> Content-Length: 285
> Expect: 100-continue
>
< HTTP/1.1 100 Continue
* We are completely uploaded and fine
< HTTP/1.1 200 OK
< x-amz-id-2: IcIFg/AdjYZJ89C/f8YrHjPDTXDvKxS1K3oHtIi4w6lPHkmCed8pVdKoIuSAZ/x7F8oQ6PYmONo=
< x-amz-request-id: 3CCDF82395162625
< Date: Sun, 12 Jul 2015 15:54:41 GMT
< ETag: "60b76cabf261d140b4dbc32a5873973b"
< Content-Length: 0
< Server: AmazonS3
<
* Connection #0 to host cloudformation-custom-resource-response-apnortheast1.s3-ap-northeast-1.amazonaws.com left intact
スタック完了を確認
最後に、CloudFormationが完了したか確認を行います。Custom::HelloWorldのステータスがCREATE_COMPLETEになっていればOKです!
まとめ
今回は、CloudFormationの作成/更新/削除といったスタック操作に合わせて実行する、カスタムリソースについて学びました。環境構築に合わせたテストの実施や、あらかじめCloudFormationで用意されていない処理の実行など、応用範囲はかなり広いと思いました。当初、SNS連携しか用意されていませんでしたが、最近、Lambda対応したことにより、カスタムリソースを使いやすくなりましたので、今後活用が進むと思います。さらに、Service CatalogというCloudFormationを管理するサービスも出てきましたので、CloudFormationから目が離せませんね!
参考資料
Amazon Simple Notification Service-backed カスタムリソース
awslabs/aws-cfn-custom-resource-examples
【新機能】AWS CloudFormationのLambda-Backed Custom Resourcesを使ってBlue-Green Deploymentをより簡単に実現する