概要/前提
route53ですでに管理している example.com
を使って、 api.example.com
を割り当てたapiを作成する想定
httpapiなので証明書はapigwと同リージョンに用意されていること
ディレクトリ構造に合わせてhandlerの設定をしているのでそこはよしなに
アプリのソースはpython、cdkのソースはtsで記述
やってることはだいたい以下
- lambda作成
- route53のゾーン参照
- acmの証明書参照
- apigwのカスタムドメイン登録
- サブドメインのレコードを参照したゾーンに書き込み
- apigw作成 & lambda紐付け
環境変数
.env
HOSTED_ZONE_ID=xxxxxxxxxxxxxxxxx
HOSTED_ZONE_NAME=example.com
CERT_ARN=arn:aws:acm:[REGION]:[ID]:certificate/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
API_DOMAIN_NAME=api.example.com
ディレクトリ構造
.
├── .env
├── .envrc
├── ...
└── src/
├── app/
│ ├── pyproject.toml
│ ├── poetry.lock
│ └── handlers/
│ └── hoge.py
└── infra/
├── cdk.json
├── package.json
├── package-lock.json
├── tsconfig.json
├── bin/
└── lib/
└── hoge-stack.ts
CDKソース
lib/hoge-stack.ts
import * as cdk from "@aws-cdk/core";
import { CorsHttpMethod, HttpApi, HttpMethod, DomainName } from "@aws-cdk/aws-apigatewayv2";
import { LambdaProxyIntegration } from "@aws-cdk/aws-apigatewayv2-integrations";
import { Runtime } from "@aws-cdk/aws-lambda";
import { Role, ServicePrincipal, ManagedPolicy } from "@aws-cdk/aws-iam";
import * as path from "path";
import { PythonFunction } from "@aws-cdk/aws-lambda-python";
import { HostedZone, ARecord, RecordTarget } from "@aws-cdk/aws-route53";
import { Certificate } from "@aws-cdk/aws-certificatemanager";
import { ApiGatewayv2DomainProperties } from "@aws-cdk/aws-route53-targets";
export class HogeStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const lambdaExecutionRole = new Role(this, "LambdaExecutionRole", {
roleName: "LambdaExecutionRole",
assumedBy: new ServicePrincipal("lambda.amazonaws.com"),
managedPolicies: [ManagedPolicy.fromAwsManagedPolicyName("service-role/AWSLambdaBasicExecutionRole")],
});
const handler = new PythonFunction(this, "Handler", {
entry: path.resolve(path.join("", "../app")),
index: "handlers/hoge.py",
handler: "handler",
memorySize: 128,
runtime: Runtime.PYTHON_3_8,
timeout: cdk.Duration.seconds(30),
functionName: "Handler",
environment: {},
role: lambdaExecutionRole,
});
const integration = new LambdaProxyIntegration({
handler,
});
const hostedZone = HostedZone.fromHostedZoneAttributes(this, "HostedZone", {
hostedZoneId: process.env.HOSTED_ZONE_ID,
zoneName: process.env.HOSTED_ZONE_NAME, // ゾーンで管理してるドメイン、e.g.) example.com
});
const certificate = Certificate.fromCertificateArn(
this,
"Certificate",
process.env.CERT_ARN // arn:aws:acm:[REGION]:[ID]:certificate/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
);
const domainName = new DomainName(this, "ApiDomainName", {
domainName: process.env.API_DOMAIN_NAME,
certificate,
});
const aRecord = new ARecord(this, "ARecord", {
zone: hostedZone,
recordName: process.env.API_DOMAIN_NAME, // 参照してるゾーンで管理していてこのapiに適用したいドメイン
target: RecordTarget.fromAlias(
new ApiGatewayv2DomainProperties(domainName.regionalDomainName, domainName.regionalHostedZoneId)
),
});
const api = new HttpApi(this, "ApiGateway", {
defaultDomainMapping: {
domainName,
},
apiName: "HOGEAPI",
corsPreflight: {
allowHeaders: ["*"],
allowOrigins: ["*"],
allowMethods: [
CorsHttpMethod.HEAD,
CorsHttpMethod.OPTIONS,
CorsHttpMethod.GET,
CorsHttpMethod.POST,
CorsHttpMethod.PUT,
CorsHttpMethod.DELETE,
],
},
});
api.addRoutes({
path: "/hoge",
methods: [HttpMethod.GET],
integration,
});
}
}