Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
CDKアプリとしてのAmplify Gen2 - @aws-amplify/backendの...
Search
MURAKAMI Masahiko
July 06, 2024
Technology
3.7k
3
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
CDKアプリとしてのAmplify Gen2 - @aws-amplify/backendのアーキテクチャにみるCDKベストプラクティス -
MURAKAMI Masahiko
July 06, 2024
More Decks by MURAKAMI Masahiko
See All by MURAKAMI Masahiko
AmplifyHostingConstructからSSRフレームワークのためのホスティング設計を考察する/amplify-hosting-construct
fossamagna
1
250
AWS Blocks を触ってみた/first-tach-aws-blocks
fossamagna
2
170
AWS Amplifyをもっと便利に使うための取り組み/amplify-tools-and-contributions
fossamagna
1
160
Amazon Verified Permissions実践入門 〜Cedar活用とAppSync導入事例/Practical Introduction to Amazon Verified Permissions
fossamagna
2
410
Amplify Gen2から知るAWS CDK Toolkit Libraryの使い方/How to use the AWS CDK Toolkit Library as known from Amplify Gen2
fossamagna
1
940
AWS Amplify Gen2向けのVSCode拡張を作って公開してみた話/lts-techday-2024
fossamagna
0
60
Amplify Gen2の 新機能と実践的な使用例 AWS Amplify Gen 2 Festival in Japan/New features and practical use cases in Amplify Gen2
fossamagna
0
850
Amplify Gen2を 拡張してみよう JAWS-UG北陸新幹線 ( 福井開催 ) 2024-04-06/Let's extend Amplify Gen2
fossamagna
0
1.1k
みんな本当に AWS Amplify を知っている?/do-you-really-know-aws-amplify
fossamagna
0
200
Other Decks in Technology
See All in Technology
ruby.wasmとPicoRuby.wasmに対応した仮想DOMライブラリを作ってる話 #kaigieffect_kaigi
sue445
PRO
0
150
最適な自走を最小限の支援で — M&Aで拡大する組織で少人数SREが挑んだ1年 / SRE NEXT 2026
genda
0
1.5k
大量データに対しても、生成AIを用いてリーズナブルにデータ加工をしたい!Databricksのai_queryについて調べてみた
kamoshika
1
220
Oracle Base Database Service 技術詳細
oracle4engineer
PRO
15
110k
凡エンジニアがこの先生きのこるためには。〜TypeScript完全に理解したい〜
alchemy1115
2
310
AI時代の闇と光
tatsuya1970
0
110
Claude Code公式skillで 自分の仕事を少しずつ手放そう!(Claude Code開発ノウハウ大公開スペシャル by クラスメソッド)
kaym
1
500
DMM.com 購入改善推進チーム におけるCodeRabbitを用いた レビューフロー改善の一例
ysknsid25
2
670
「AIに依存している」と 「AIを使いこなしている」の違い
k8yasuma
0
120
タスクの複雑さでモデルを選ぶ ── Thompson Samplingで動かす“トークン/コスト最適化
satohy0323
0
570
OPENLOGI Company Profile for engineer
hr01
1
74k
CIで使うClaude
iwatatomoya
0
290
Featured
See All Featured
A brief & incomplete history of UX Design for the World Wide Web: 1989–2019
jct
2
420
The #1 spot is gone: here's how to win anyway
tamaranovitovic
3
1.1k
SEO in 2025: How to Prepare for the Future of Search
ipullrank
3
3.6k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
162
16k
Imperfection Machines: The Place of Print at Facebook
scottboms
270
14k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.5k
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
Leveraging Curiosity to Care for An Aging Population
cassininazir
1
390
Designing Experiences People Love
moore
143
24k
Measuring Dark Social's Impact On Conversion and Attribution
stephenakadiri
2
240
Done Done
chrislema
186
16k
Site-Speed That Sticks
csswizardry
13
1.3k
Transcript
CDKアプリとしての Amplify Gen2 - @aws-amplify/backendのアーキテク チャにみる CDKベストプラクティス - AWS CDK
Conference Japan 2024 presented by JAWS-UG 2024-07-06 株式会社永和システムマネジメント 村上雅彦 (a.k.a @fossamagna)
村上 雅彦 株式会社永和システムマネジメント Amplify Japan User Group 運営メンバー AWS Community
Builder (Front-End Web & Mobile since 2022) GitHub: https://github.com/fossamagna X(旧Twitter): https://x.com/fossamagna 自己紹介
• AWS CDKをベースとする次世代のAmplifyのバックエン ド構築ツール • TypeScriptによるバックエンド定義を提供 • CoC(設定より規約を優先する) • GitのブランチとAWS環境を1:1でマッピング
• 開発者毎の独立したsandbox環境を提供 Amplify Gen2
• AWS CDKをベースとする次世代のAmplifyのバックエン ド構築ツール • TypeScriptによるバックエンド定義を提供 • ファイルベース規約(設定より規約を優先する) • GitのブランチとAWS環境を1:1でマッピング
• 開発者毎の独立したsandbox環境を提供 Amplify Gen2の新機能
ファイルベース規約 amplify ├── auth // 認証のカテゴリ │ └── resource.ts ├──
data // GraphQL APIのカテゴリ │ └── resource.ts ├── backend.ts // バックエンド全体 ├── package.json └── tsconfig.json • Amplifyが提供する機能 毎のディレクトリ内の resource.tsに定義する • backend.tsにバックエン ド全体を定義する • どの機能のリソース定義 がどこにあるのか予測で きる
TypeScriptによる 定義 // amplify/data/resource.ts const schema = a.schema({ Todo: a
.model({ content: a.string(), }) .authorization((allow) => [allow.publicApiKey()]), }); export type Schema = ClientSchema<typeof schema>; export const data = defineData({ schema, authorizationModes: { defaultAuthorizationMode: "apiKey", // API Key is used for a.allow.public() rules apiKeyAuthorizationMode: { expiresInDays: 30, }, }, }); • defineData関数でリ ソースを宣言的に定義 • TypeScriptで GraphQLのSchemaと APIの認証設定を記述 するのみ • この例ではAppSync, DynamoDBによる GraphQL APIが構築さ れる
TypeScriptによる 定義 // amplify/backend.ts import { defineBackend } from '@aws-amplify/backend'
; import { auth } from './auth/resource'; import { data } from './data/resource'; defineBackend({ auth, data, }); • defineBackendでバッ クエンド全体を定義 • 機能毎の定義をimport してアプリのバックエド ン全体を構成する
• prodcutionやstagingといった環境がGitのブランチと 1 : 1 で対応 • Gitのブランチへpushすることで自動でデプロイされる https://docs.amplify.aws/react/how-amplify-works/concepts/#faster-local-development Gitベースのフルスタック環境
• 開発者毎の独立した sandbox環境を提供 • npx ampx sandboxコマン ド一発で環境構築完了 • hot
swapデプロイ対応で 迅速にデプロイ可能 https://docs.amplify.aws/react/how-amplify-works/concepts/#faster-local-development sandbox環境
Amplify Gen2バックエンドの内側
• Gitブランチに対応するフルスタック環境 ◦ npx ampx pipeline-deploy --branch $AWS_BRANCH --app-id $AWS_APP_ID
• sandbox環境 ◦ npx ampx sandbox Amplify Gen2バックエンドのデプロイ
• CDKアプリとして見ると Amplify Gen2 CLIプロセスは aws-cdkプロセスを呼び出す ラッパー • 赤枠部分はAWS CDKそのも
の Amplify Gen2 バックエンドのプロセス構成 https://github.com/aws-amplify/amplify-backend/blob/main/PROJECT_ARCHITECTURE.md から引用
• Best practices for developing and deploying cloud infrastructure with
the AWS CDK (AWS CDKを使用したクラウドイン フラストラクチャの開発とデプロイのベストプラ クティス) • Best practices for using the AWS CDK in TypeScript to create IaC projects - AWS Prescriptive Guidance (AWS 規範ガ イダンス AWS CDK で TypeScript を使用し て IaC プロジェクトを作成するためのベストプ ラクティス) AWS CDKのベストプラクティスの参考資料
L3 Constructの作成
• dataとauthの2つのL3 Construct ◦ @aws-amplify/data-construct ◦ @aws-amplify/auth-construct • @aws-amplify/<feature>-construct という規則のパッケージ名
• 素早く簡単にAmplifyライクなリソースを 構築できる • Amplifyから独立しても使える L3 Constructsの作成 パッケージ構造の依存関係図: https://github.com/aws-amplify/amplify-backend/blob/main/PROJECT_ARCHITECTURE.md から引用
@aws-amplify/ data-construct // Cognito ユーザープールベースの認証を使用したシンプルな Todo リスト import { App,
Stack } from 'aws-cdk-lib'; import { UserPool } from 'aws-cdk-lib/aws-cognito'; import { AmplifyData, AmplifyDataDefinition } from '@aws-amplify/data-construct'; const app = new App(); const stack = new Stack(app, 'TodoStack'); new AmplifyData(stack, 'TodoApp', { definition: AmplifyDataDefinition.fromString(/* GraphQL */ ` type Todo @model @auth(rules: [{ allow: owner }]) { description: String! completed: Boolean } `), authorizationModes: { userPoolConfig: { userPool: UserPool.fromUserPoolId(stack, 'ImportedUserPool', '<YOUR_USER_POOL_ID>'), }, }, }); • GraphQLのスキーマ定 義がTypeScriptではな いこと以外はほぼ Amplify Gen2と同じ • AppSync+DynamoDB というパターンに対して特 化した効果的なインタ フェース
@aws-amplify/ auth-construct // SMSを使ったMFA設定を使用したEメールログイン import { App, Stack } from
"aws-cdk-lib"; import { AmplifyAuth } from "@aws-amplify/auth-construct"; const app = new App(); const stack = new Stack(app, "AuthStack"); new AmplifyAuth(stack, "Auth", { loginWith: { email: true, }, multifactor: { mode: "OPTIONAL", sms: { smsMessage: (code: string) => `Your verification code is ${code}`, }, totp: false, }, }); • 設定オブジェクトによる宣 言的な設定 • Amplify の auth が提 供するWebアプリ、モバ イル向けのAmplify ライ クな認証設定を簡単に設 定可能
Abstract Factoryパターン を利用する *万人向けではありません
ConstructFactory // amplify-backend/packages/plugin-types/src/construct_factory.ts /** * Functional interface for construct factories.
All objects in the backend-engine definition must implement this interface. */ export type ConstructFactory<T extends ResourceProvider = ResourceProvider> = { readonly provides?: string; getInstance: (props: ConstructFactoryGetInstanceProps) => T; }; // amplify-backend/packages/plugin-types/src/resource_provider.ts /** * Provides reference to underlying CDK resources. */ export type ResourceProvider<T extends object = object> = { resources: T; }; • @aws-amplify/backen dでのCDKコンストラクトの 構築を担うクラス • synthプロセス内で呼び出 される • 機能間で依存するコンスト ラクトの解決(DIコンテナ) に利用される • 依存するコンストラクトの具 体的な構築方法を知らなく てよい
https://github.com/aws-amplify/amplify-backend/blob/main/PROJECT_ARCHITECTURE.md から引用 ConstructFactoryの実装 Amplify Gen2 バックエンドのプロセス構成の詳細
Aspectsを使ってセキュリティプ ロパティに関する アサーションを行う
Cognito IdPの 信頼ポリシー { "Version": "2012-10-17", "Statement": [ { "Effect":
"Allow", "Principal": { "Federated": "cognito-identity.amazonaws.com" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "cognito-identity.amazonaws.com:aud": "us-west-2:abcdefg-1234-5678-910a-0e8443553f95" }, "ForAnyValue:StringLike": { "cognito-identity.amazonaws.com:amr": "authenticated" } } } ] } • sts:AssumeRoleWithWebIden tity を許可する信頼ポリシーには 適切な条件が設定されている必要 がある ◦ モバイルやWebアプリなどWebベースのIDプロ バイダーを使用して認証されたユーザーに、 IAM Roleの一時的なセキュリティ認証情報を 発行するAPIリクエスト ◦ cognito-identity.amazonaws.com:aud で 特定のCognito IdentityPoolからのオペレー ションに制限する ◦ cognito-identity.amazonaws.com:amr で ロールの付与を認証済みもしくはゲストユー ザーに制限する
Aspectsによるポリ シーの条件チェック // packages/backend/src/engine/amplify_stack.ts から一部抜粋 class CognitoRoleTrustPolicyValidator implements IAspect {
visit = (node: IConstruct ) => { ... const assumeRolePolicyDocument = node.assumeRolePolicy ?.toJSON(); assumeRolePolicyDocument .Statement .forEach( this.cognitoTrustPolicyStatementValidator ); }; private cognitoTrustPolicyStatementValidator = ({ Action: action, Condition: condition , Effect: effect, Principal: principal , }: { // These property names come from the IAM policy document which we do not control Action: string; Condition ?: Record<string, Record<string, string>>; Effect: 'Allow' | 'Deny'; Principal ?: { Federated ?: string }; }) => { ... const audCondition = condition ?.StringEquals ?.['cognito-identity.amazonaws.com:aud' ]; if (typeof audCondition !== 'string' || audCondition .length === 0) { throw new AmplifyFault ('InvalidTrustPolicyFault' , { message: 'Cannot create a Role trust policy with Cognito that does not have a StringEquals condition for cognito-identity.amazonaws.com:aud' , }); } ... }; } • Aspectsを使ってセキュリティに関する チェックを実施している • CognitoRoleTrustPolicyValidatorと いうAspectでCognito Idpの sts:AssumeRoleWithWebIdentity のActionを付与するロールに条件が 含まれているのかを検証している • 特定のCognito IdentityPoolからの オペレーションに制限する指定がある か、ロールの付与を認証済みもしくは ゲストユーザーに制限する指定がある をチェック。
カスタムリソース
secrets import { defineAuth, secret } from '@aws-amplify/backend' ; export
const auth = defineAuth({ loginWith: { email: true, externalProviders: { facebook: { // fooという名前のシークレットを利用 clientId: secret('foo'), clientSecret: secret('bar') } } } }); • Amplify Gen2でのシーク レット値を管理する機能 • secret関数にシークレット の名前を指定するだけで参 照可能。 • シークレット値はアプリ全 体、ブランチ毎にシークレッ ト値を設定できる • SSM Parameter Storeに 登録される
secrets export const handler = async ( event: CloudFormationCustomResourceEvent ):
Promise<CloudFormationCustomResourceSuccessResponse > => { console.info(`Received ' ${event.RequestType }' event` ); const physicalId = event.RequestType === 'Create' ? randomUUID () : event.PhysicalResourceId ; let data: { secretValue : string } | undefined = undefined ; if (event.RequestType === 'Update' || event.RequestType === 'Create' ) { // SSM からシークレットを取得する const val = await handleCreateUpdateEvent (secretClient , event); data = { secretValue: val, }; } return { RequestId: event.RequestId , LogicalResourceId: event.LogicalResourceId , PhysicalResourceId: physicalId , Data: data, StackId: event.StackId, NoEcho: true, Status: 'SUCCESS' , } as CloudFormationCustomResourceSuccessResponse ; }; • SSMから対象ブランチまたは アプリ全体のシークレット値 を取得する CustomResourceProvide rとして実装されている • シークレットを参照する側が Lambdaの場合、シークレッ ト値を取得して環境変数に設 定するランタイムコードが ユーザーコードの先頭に挿 入されデプロイされる
• AWS::DynamoDB::Tableを置き換えるAmplify用DynamoDBTableカ スタムリソース • 一度で複数のGSIの更新をサポート ◦ isCompleteはDynamoDBへの変更処理行う。 WaiterStateMachineはisCompleteがエラーを返さなくまで(複数 のDynamoDBへの更新処理が完了するまで)retryする Custom::AmplifyDynamoDBTable
• Amplify Gen2 で使われているベストプラクティス、L3 ConstructやAbstract Factoryパターンにより利用する 側はより宣言的にリソースを定義できる。 • AWS CDK
をベースにしたプラットフォームを提供する場 合の参考になる。 まとめ
ご清聴ありがとうございました!