Slide 1

Slide 1 text

Stripeを組み込む際の CDK実装Tips AWS エバンジェリストシリーズ  AWSの基礎を学ぼう Hidetaka Okamoto(@hide__dev) 2022/02/26

Slide 2

Slide 2 text

岡本 秀高 ( @hide__dev ) ● Stripe Developer Advocate (ex-developer in Digitalcube) ● JavaScript / TypeScript developer ● AWS / Next.js / WordPress / etc… ● WordCamp Kyoto 2017 / JP_Stripes Connect 2019 / AWS Samurai 2017 / etc… ● 🐈(猫フラご容赦󰢛) 2 ジャムジャム!!Jamstack_5 #awsbasics

Slide 3

Slide 3 text

3 https://jawsug.connpass.com/event/240422/

Slide 4

Slide 4 text

4 https://stripe.com/jp

Slide 5

Slide 5 text

サーバーサイドSDKで、簡単に決済系の組み込みが可能 5 AWS エバンジェリストシリーズ  AWSの基礎を学ぼう #awsbasics const session = await stripe.checkout.sessions.create({ mode: "payment", success_url: `${req.headers.origin}`, cancel_url: `${req.headers.origin}`, line_items:[{ price: req.body.price_id, quantity: 1 }] }) return session.url

Slide 6

Slide 6 text

6 そのコード、どこにどうやってデプロイしよう? AWS エバンジェリストシリーズ  AWSの基礎を学ぼう

Slide 7

Slide 7 text

7 https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html

Slide 8

Slide 8 text

AWS CDKでServerless Functionを実装 8 AWS エバンジェリストシリーズ  AWSの基礎を学ぼう #awsbasics # アプリをセットアップ % mkdir new-cdk-app % cd new-cdk-app % cdk init –language typescript # ライブラリのインストールやファイルの配置 % npm install stripe % mkdir -p resources/functions/ % touch resources/functions/stripe.js # デプロイ % cdk deploy –watch

Slide 9

Slide 9 text

料金データを返すLambdaの例 9 AWS エバンジェリストシリーズ  AWSの基礎を学ぼう #awsbasics const stripe = require('stripe')(process.env.STRIPE_SECRET_API_KEY); exports.main = async function(event, context) { try { const { data } = await stripe.prices.list({ lookup_keys: [process.env.STRIPE_PRICE_LOOKUP_KEY] }) return { statusCode: 200, body: JSON.stringify(data) }; } catch(error) { const body = error.stack || JSON.stringify(error, null, 2); return { statusCode: 400, body: JSON.stringify(body) }; } }

Slide 10

Slide 10 text

LambdaをCDKで定義 10 AWS エバンジェリストシリーズ  AWSの基礎を学ぼう #awsbasics import { Stack, StackProps } from 'aws-cdk-lib'; import { Construct } from "constructs"; import * as lambda from "aws-cdk-lib/aws-lambda"; export class AwsCdkStack extends Stack { constructor(scope: Construct, id: string, props?: StackProps) { super(scope, id, props); const handler = new lambda.Function(this, "StripeHandler", { runtime: lambda.Runtime.NODEJS_14_X, // So we can use async in widget.js code: lambda.Code.fromAsset("resources/functions"), handler: "stripe.main", environment: { STRIPE_PRICE_LOOKUP_KEY: ‘lookup-key’, STRIPE_SECRET_API_KEY: 'sk_xxx' } }); }}

Slide 11

Slide 11 text

環境変数を何処に置こう? 11 AWS エバンジェリストシリーズ  AWSの基礎を学ぼう #awsbasics import { Stack, StackProps } from 'aws-cdk-lib'; import { Construct } from "constructs"; import * as lambda from "aws-cdk-lib/aws-lambda"; export class AwsCdkStack extends Stack { constructor(scope: Construct, id: string, props?: StackProps) { super(scope, id, props); const handler = new lambda.Function(this, "StripeHandler", { runtime: lambda.Runtime.NODEJS_14_X, // So we can use async in widget.js code: lambda.Code.fromAsset("resources/functions"), handler: "stripe.main", environment: { STRIPE_PRICE_LOOKUP_KEY: ‘lookup-key’, STRIPE_SECRET_API_KEY: 'sk_xxx' } }); } }

Slide 12

Slide 12 text

12 Secrets Managerの値を読み取る AWS エバンジェリストシリーズ  AWSの基礎を学ぼう

Slide 13

Slide 13 text

Secrets Managerの値を環境変数に渡す例 13 AWS エバンジェリストシリーズ  AWSの基礎を学ぼう #awsbasics import * as sm from "aws-cdk-lib/aws-secretsmanager"; export class AwsCdkStack extends Stack { constructor(scope: Construct, id: string, props?: StackProps) { super(scope, id, props); const secret = sm.Secret.fromSecretAttributes(this, "ImportedSecret", { secretCompleteArn: "登録したSecretのARN" }); const handler = new lambda.Function(this, "StripeHandler", { environment: { STRIPE_PRICE_LOOKUP_KEY: secret.secretValueFromJson('lookup-key').toString(), STRIPE_SECRET_API_KEY: ‘sk_xxx’ } …

Slide 14

Slide 14 text

14 もっと安全に管理したい AWS エバンジェリストシリーズ  AWSの基礎を学ぼう

Slide 15

Slide 15 text

LambdaにSecrets Managerへのアクセス権限を設定 15 AWS エバンジェリストシリーズ  AWSの基礎を学ぼう #awsbasics const handler = new lambda.Function(this, "StripeHandler", { runtime: lambda.Runtime.NODEJS_14_X, // So we can use async in widget.js code: lambda.Code.fromAsset("resources/functions"), handler: "stripe.main", environment: { STRIPE_PRICE_LOOKUP_KEY: secret.secretValueFromJson('lookup-key').toString(), } }); handler.addToRolePolicy(new iam.PolicyStatement({ resources: [secret.secretArn], actions: ['secretsManager:GetSecretValue'], }))

Slide 16

Slide 16 text

Secrets Managerの値を取得して、利用する 16 AWS エバンジェリストシリーズ  AWSの基礎を学ぼう #awsbasics const AWS = require('aws-sdk'); const Stripe = require('stripe'); exports.main = async function(event, context) { try { const secretsmanager = new AWS.SecretsManager(); const secrets = await secretsmanager.getSecretValue({ SecretId: 'secret-id' }) const secretsJSON = JSON.parse(secrets.SecretString) const stripe = new Stripe(secretsJSON.STRIPE_SECRET_API_KEY)

Slide 17

Slide 17 text

まとめ ● AWS CDKを利用すると、アプリの実装言語でAWSインフラも定義できる ● StripeなどのAPIキーを利用するSaaSを使う場合、 Secrets Manager / Systems ManagerとCDKを組み合わせて、 テンプレートからキー情報を秘匿できる ● テスト環境・本番環境の切り替えまでやりたい場合は、 CDKのContextを活用しよう https://docs.aws.amazon.com/cdk/v2/guide/get_context_var.html 17 AWS エバンジェリストシリーズ  AWSの基礎を学ぼう

Slide 18

Slide 18 text

Thanks! ● Twitterハッシュタグでシェア #awsbasics #JP_Stripes ● Twitterアカウント: @hide__dev @StripeJapan ● QiitaでStripeに関する 開発ブログ更新中 https://qiita.com/organizations/stripe 18 AWS エバンジェリストシリーズ  AWSの基礎を学ぼう