はじめに
先日、個人開発で作った Alexa Skill をリリースしました!
開発の中でAWS CodeStarによるAlexa Skillプロジェクトの作成を検討しました。
本記事は、その時のメモになります。
AWS CodeStarを使ったAlexa Skill開発
AWS CodeStarとは
AWS CodeStarは、ボイラープレートによるプロジェクトの立ち上げから、コードの構成管理、CI/CDも含めた開発環境までを簡単に構築してくれるツールです。
サービス名にCodeと付いていることもあり、AWSのCode3兄弟(CodeCommit, CodeDeploy, CodePipeline)を組み合わせてCI/CD環境に自動作成してくれるというのが売りです。
AWS CodeStarによるAlexa Skillの作成
CodeStarのコンソール画面にて「プロジェクトの作成」をクリックすると、テンプレートでAlexa Skillのハローワールドスキルが表示されます。これを選択して、指示に従っていけばNode.jsベースのAlexa Skillプロジェクトを立ち上げられます。
- ソースコード管理はCodeCommitもGithubも選択可能
- Alexa Developer Consoleとの連携もGUI上で対応
- Alexa Developer Console上にhello nodeというスキルが作成される
- 作成と同時にCloudformationが走るのを確認。プロビジョニングにかなり時間がかかった。
- CodePipelineが作られていることも確認できる
Tips
- 最初はAlexa Developer Console上でテストを実行できなかった。
=> スキルの状態を「開発中」に変更すれば、実行可能になった。
- 公式ドキュメントより、CodeStarプロジェクトの「アプリケーションの表示」ボタンからAlexa Simulatorを起動できるらしい
- AWS CodeStar コンソールのプロジェクトで、[アプリケーションを表示] を選択します。Alexa Simulator で新しいタブが開きます
- ステップ 1 でプロジェクトに接続したアカウントの Amazon 開発者認証情報を使用してサインインします。
- [Test] (テスト) の下で [Development] (開発) を選択してテストを有効にします。
=> 実際にはシミュレータは起動せず、スキルが実装されているLambdaが表示された
いろいろ調べたが、Alexa Developer Consoleのシミュレータが表示する方法は分からなかった。
- hello nodeというスキル名は、skill.jsonとja-JP.jsonを編集すれば変更できた
- masterブランチへのマージをトリガーにして、デプロイが実行される
DynamoDBとの接続
ローンチしたサービスでは、DynamoDBからデータを読み込む必要があったので、DynamoDBとの接続方法を試しました。
デプロイされるインフラ設定は、Cloudformationテンプレートとしてtemplate.ymlに記載されています。
ここに記載されているLambdaのIAMポリシーに、DynamoDBへのアクセスを許可する記述を追記。
ManagedPolicyArns:
- !Sub "arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
PermissionsBoundary: !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:policy/CodeStar_${ProjectId}_PermissionsBoundary"
Policies:
- PolicyName: "DndbTableAccessPolicy"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- "dynamodb:Get*"
- "dynamodb:Query"
- "dynamodb:Scan"
Resource:
- "Fn::Join":
- ":"
- - "arn:aws:dynamodb"
- Ref: AWS::Region
- Ref: AWS::AccountId
- "table/MyDndbTable-dev"
- "Fn::Join":
- ":"
- - "arn:aws:dynamodb"
- Ref: AWS::Region
- Ref: AWS::AccountId
- "table/MyDndbTable-dev/index/*"
しかし、これだけだとアクセスに失敗します。
INFO Failed to query events; AccessDeniedException: User: arn:aws:sts::xxxxxxxx:assumed-role/CodeStar-alx-cdstar-test-Execution/awscodestar-alx-cdstar-test-lambda-CustomDefaultFunction is not authorized to perform: dynamodb:Query on resource: arn:aws:dynamodb:ap-northeast-1:xxxxxxxxxx:table/MyDndbTable-dev/index/GSI1 because no permissions boundary allows the dynamodb:Query action
at Request.extractError (/var/task/node_modules/aws-sdk/lib/protocol/json.js:52:27)
at Request.callListeners (/var/task/node_modules/aws-sdk/lib/sequential_executor.js:106:20)
at Request.emit (/var/task/node_modules/aws-sdk/lib/sequential_executor.js:78:10)
at Request.emit (/var/task/node_modules/aws-sdk/lib/request.js:686:14)
at Request.transition (/var/task/node_modules/aws-sdk/lib/request.js:22:10)
at AcceptorStateMachine.runTo (/var/task/node_modules/aws-sdk/lib/state_machine.js:14:12)
at /var/task/node_modules/aws-sdk/lib/state_machine.js:26:10
at Request.<anonymous> (/var/task/node_modules/aws-sdk/lib/request.js:38:9)
at Request.<anonymous> (/var/task/node_modules/aws-sdk/lib/request.js:688:12)
at Request.callListeners (/var/task/node_modules/aws-sdk/lib/sequential_executor.js:116:18) {
code: 'AccessDeniedException',
time: 2023-01-30T13:16:51.933Z,
requestId: 'KN8JIRSGDFKNVKJORPN5KM0T6FVV4KQNSO5AEMVJF66Q9ASUAAJG',
statusCode: 400,
retryable: false,
retryDelay: 18.96747783566036
}
Troubleshooting
原因はLambdaのIAMロールについていた~PermissionsBoundaryという記述。
Permissions Boundaryとはサービスに許可するアクセスに事前に範囲(ロールの境界)を指定できるIAMの機能です。つまり、サービスに紐づけるIAMロール自体に制限を設ける機能です。
このPermissionsBoundaryの記述をtemplate.ymlからコメントアウトしてみましたが、その場合はデプロイができなくなりました。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "1",
"Effect": "Allow",
"Action": [
"*"
],
"Resource": [
"arn:aws:cloudformation:ap-northeast-1:xxxxxxxxxxxx:stack/awscodestar-alx-cdstar-test-*",
"arn:aws:codebuild:ap-northeast-1:xxxxxxxxxxxx:project/alx-cdstar-test",
"arn:aws:codecommit:ap-northeast-1:xxxxxxxxxxxx:alexa-codestar-test",
"arn:aws:codedeploy:ap-northeast-1:xxxxxxxxxxxx:application:alx-cdstar-test",
"arn:aws:codedeploy:ap-northeast-1:xxxxxxxxxxxx:deploymentgroup:alx-cdstar-test/*",
"arn:aws:codepipeline:ap-northeast-1:xxxxxxxxxxxx:alx-cdstar-test-Pipeline",
"arn:aws:lambda:ap-northeast-1:xxxxxxxxxxxx:function:awscodestar-alx-cdstar-test-lambda-CustomDefaultFunction",
"arn:aws:s3:::aws-codestar-ap-northeast-1-xxxxxxxxxxxx-alx-cdstar-test-pipe",
"arn:aws:s3:::aws-codestar-ap-northeast-1-xxxxxxxxxxxx-alx-cdstar-test-pipe/*",
"arn:aws:dynamodb:ap-northeast-1:xxxxxxxxxxxx:table/*" // <= 追記★
]
},
そこで上記のように、IAMコンソールからPermissionsBoundaryとして指定されているポリシーにDynamoDBへのアクセスを許可する記述を追記すれば、アクセスできるようになります。
あと、こちらはケアレスミスですが、
最初、IAMポリシー上でのDynamoDBのリソースの記載を以下のように書いてました。
Resource:
- "arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/MyDndbTable-dev"
- "arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/MyDndbTable-dev/index/*"
Serverless Frameworkの場合はこれで通る気がしたのですが、純粋なAWS Cloudformation templateではダメでした。
The policy failed legacy parsing (Service: AmazonIdentityManagement; Status Code: 400; Error Code: MalformedPolicyDocument; Request ID: 0daa4c1a-e614-4550-8a61-696a02a6b73c; Proxy: null)
既に書いたように、Fn::JoinとRefの組み込み関数を使って書いて解決しました。
Alexa Hosted Skillとは異なり、自身のAWSアカウントでAlexa Skillをホスティングすることになるので、上記の設定でDynamoDBからデータを読み込めるようになります。
まとめ
AWS CodeStarを使ってみましたが、小規模な開発で、AWS内でCI/CDを完結させたいなら、利用してみるのもいいかもしれません。
私は、Github Actionsを使いたかったことや、便利な反面、開発の自由度が下がってしまうこと、今回のように全ての設定をプロジェクト内のコード上に記述できない点などを危惧して、今回はCodeStarは使わずにサービスをローンチしました。
しかし、Alexa Skillプロジェクトには、skill.jsonやask-states.jsonといったスキルのステータスを保持するファイルがあり、これにAWSアカウントが記載されてしまいます。
パブリックなレポジトリの場合、AWSアカウントがさらされてしまうので、これらのファイルをGithubリポジトリに格納したくない方はいるでしょう。
その場合、CodeCommitの利用が選択肢に入ってきます。
そしてCodeCommitを使うなら、手軽にCodeCommit上のプロジェクトのセットアップができるCodeStarを検討してみるのがいいでしょう。