はじめに
我々tdiはお客様社内の業務システムを開発することがほとんどです。
AWSでサーバーレスな構成を組む時に、フロントエンドをS3とCloudFrontで配信し、バックエンドをAPI Gateway経由のLambdaで、データベースはDynamoDBで・・・というのはよくある構成ですね。
しかし、社内の業務システムとなると、
- インターネット経由でシステムにアクセスしたくない
- Lambdaのローカル開発に慣れていない
- データベースはやっぱりRDBMSで構成したい
などといった様々な外的要因も無視できません。
そこで今回は、Reactで動いているフロントエンドとSpring Bootで動いているバックエンドを1つのALBから振り分けるようなAWS Fargateの構成をCDKで構築して動かしていきたいと思います。
分量が非常に多くなってしまうので、何回かに分けて連載していく予定です。
最後までお付き合いください。
構成の概要
最終的に動かしていく構成は以下の通りです。
フロントエンド用とバックエンド用のFargateサービスを分け、パスベースルーティングで1つのALBから振り分けます。
今回は「インターネット経由でシステムにアクセスしたくない」という要件は外しましたが、もしその要件を入れる場合はALBをプライベートサブネットで構成するようにしてください。
また、認証にはCognitoを使用しGoogleとフェデレーションします。
そして、Cognitoで認証されたトークンを持っているユーザのみが、バックエンドのAPIを使用できるように認可制御も実装します。
これらの構成の開発手順とCDKでの構築手順をお届けしていきます!
Google認証のためのCognitoをCDKで構築する
第1回となる今回はGoogleとフェデレーションするCognitoをCDKで構築していきます。
前提として、
- 開発環境はWindows
- AWS CLIのインストール
- Node.jsのインストール
- CDKのインストール
- CDKのデプロイ権限を持ったAWSのプロファイル設定
- VSCodeのインストール
- Google認証のためのGoogle Cloud側の設定(OAuthクライアント、同意画面)
は完了していることを想定しています。
早速、CDKプロジェクトを作成していきましょう。
適当なフォルダで以下のコマンドを実行して、プロジェクトを作成します。
1 2 3 |
mkdir -p miso-cdk\miso-auth cd miso-cdk\miso-auth cdk init --language typescript |
構築する環境ごとに設定を切り分けたいため、dotenvをインストールします。
1 |
npm install dotenv |
.envから設定を読み込みようにmiso-auth.tsを編集します。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#!/usr/bin/env node import 'source-map-support/register'; import * as cdk from 'aws-cdk-lib'; import { MisoAuthStack } from '../lib/miso-auth-stack'; import * as dotenv from 'dotenv'; dotenv.config({ path: `.env.${process.env.NODE_ENV}` }); const app = new cdk.App(); new MisoAuthStack(app, 'MisoAuthStack', { }); |
とりあえず開発環境ということで、.env.devファイルを作成します。
ステージング環境なら.env.stg、本番環境なら.env.prdのように作成してください。
1 2 |
GOOGLE_CLIENT_ID=your-google-client-id GOOGLE_CLIENT_SECRET=your-google-client-secret |
your-google-client-idおよびyour-google-client-secretの値は、Google Cloud側で設定したOAuthクライアントのクライアントIDとクライアントシークレットの値を設定してください。
また、.envがGitリポジトリに保存されないように忘れずに.gitignoreに追加しておきましょう。
1 2 3 4 5 6 7 8 9 |
*.js !jest.config.js *.d.ts node_modules # CDK asset staging directory .cdk.staging cdk.out .env.* |
メインとなるCognitoを設定するCDKコードをmiso-auth-stack.tsに記述します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
import * as cdk from 'aws-cdk-lib'; import { Construct } from 'constructs'; import * as cognito from 'aws-cdk-lib/aws-cognito'; export class MisoAuthStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); // 環境変数から情報を取得 const googleClientId = process.env.GOOGLE_CLIENT_ID ?? (() => { throw new Error('GOOGLE_CLIENT_IDが取得できませんでした'); })(); const googleClientSecret = process.env.GOOGLE_CLIENT_SECRET ?? (() => { throw new Error('GOOGLE_CLIENT_SECRETが取得できませんでした'); })(); const callbackUrls = process.env.CALLBACK_URLS?.split(',') ?? (() => { throw new Error('CALLBACK_URLSが取得できませんでした'); })(); const logoutUrls = process.env.LOGOUT_URLS?.split(',') ?? (() => { throw new Error('LOGOUT_URLSが取得できませんでした'); })(); // Cognito User Poolの作成 const userPool = new cognito.UserPool(this, 'CognitoUserPool', { userPoolName: `miso-${process.env.NODE_ENV}`, selfSignUpEnabled: true, signInAliases: { email: true, }, autoVerify: { email: true }, }); // Cognito User Poolアプリクライアントの作成 const userPoolClient = new cognito.UserPoolClient(this, 'CognitoAppClient', { userPool, authFlows: { userPassword: true, userSrp: true, }, oAuth: { flows: { authorizationCodeGrant: true, }, scopes: [ cognito.OAuthScope.OPENID, cognito.OAuthScope.EMAIL, cognito.OAuthScope.PROFILE, cognito.OAuthScope.COGNITO_ADMIN, ], callbackUrls: callbackUrls, logoutUrls: logoutUrls, }, supportedIdentityProviders: [ cognito.UserPoolClientIdentityProvider.GOOGLE, ] }); // Googleをフェデレーションに設定 const googleProvider = new cognito.UserPoolIdentityProviderGoogle(this, 'Google', { clientId: googleClientId, clientSecretValue: cdk.SecretValue.unsafePlainText(googleClientSecret), userPool, attributeMapping: { email: cognito.ProviderAttribute.GOOGLE_EMAIL, fullname: cognito.ProviderAttribute.GOOGLE_NAME, profilePicture: cognito.ProviderAttribute.GOOGLE_PICTURE, givenName: cognito.ProviderAttribute.GOOGLE_GIVEN_NAME, }, scopes: ['profile', 'email', 'openid'], }); // AWSが管理するドメインの設定 const cognitoDomain = userPool.addDomain('CognitoDomain', { cognitoDomain: { domainPrefix: `miso-${process.env.NODE_ENV}`, }, }); // User Pool ClientにGoogleプロバイダーを関連付ける userPoolClient.node.addDependency(googleProvider); // CDK出力にUserPoolとAppClientのIDを追加 new cdk.CfnOutput(this, 'UserPoolId', { value: userPool.userPoolId, }); new cdk.CfnOutput(this, 'UserPoolClientId', { value: userPoolClient.userPoolClientId, }); } } |
コードが完成したので、あとはデプロイするだけ!NODE_ENVをセットするのを忘れずに。
1 2 3 |
set NODE_ENV=dev cdk bootstrap cdk deploy |
デプロイが完了すると、以下のようなメッセージ表示され、UserPoolIdとUserPoolClientIdが表示されているのが分かります。
1 2 3 4 5 6 7 8 9 10 11 |
✅ MisoAuthStack ✨ Deployment time: 18.35s Outputs: MisoAuthStack.UserPoolClientId = abcdefghijklmnop0123456789 MisoAuthStack.UserPoolId = ap-northeast-1_XXXXXXXXX Stack ARN: arn:aws:cloudformation:ap-northeast-1:nnnnnnnnnnnn:stack/MisoAuthStack/00000000-0000-0000-0000-000000000000 ✨ Total time: 32.85s |
これでGoogle認証を行うCognitoをCDKで構築することができました。
次回は、構築したCognitoで認証するReactのアプリケーションを作成していこうと思います。
それでは、また次回に👋
執筆者プロフィール
-
昔も今も新しいものが大好き!
インフラからアプリまで縦横無尽にトータルサポートや新技術の探求を行っています。
週末はときどきキャンプ場に出没します。