Shallow Dive by Dozono

AWS CDKでAppSyncにカスタムドメインを指定する

Posted : 27 May 2020

AWS公式ブログで紹介されているAppSyncのカスタムドメイン設定をAWS CDKで実装する。

環境

  • AWS CDK 1.41.0
  • TypeScript
  • あらかじめRoute 53上にHosted Zoneを作成していること

実装

コード

bin/StackName.ts

1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from '@aws-cdk/core';
import { WorkStack } from '../lib/work-stack';

const app = new cdk.App();
new WorkStack(app, 'WorkStack', {
  env: {
    account: process.env.CDK_DEFAULT_ACCOUNT,  // 追記
    region: process.env.CDK_DEFAULT_REGION     // 追記
  }
});

lib/StackName.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
import * as cdk from '@aws-cdk/core';
import * as acm from '@aws-cdk/aws-certificatemanager';
import * as cloudfront from '@aws-cdk/aws-cloudfront';
import * as appsync from '@aws-cdk/aws-appsync';
import * as route53 from '@aws-cdk/aws-route53';
import * as route53Targets from '@aws-cdk/aws-route53-targets';

export class WorkStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // The code that defines your stack goes here

    const hostedZone = route53.HostedZone.fromLookup(this, 'hostedZone', {
      domainName: process.env.DOMAIN_NAME ? process.env.DOMAIN_NAME : '',
    });

    const certificate = new acm.DnsValidatedCertificate(this, 'certificate', {
      domainName: process.env.DOMAIN_NAME ? process.env.DOMAIN_NAME : '',
      subjectAlternativeNames: [
        process.env.DOMAIN_NAME ? `*.${process.env.DOMAIN_NAME}` : ''
      ],
      hostedZone,
      region: 'us-east-1'
    });

    const graphQLApi = new appsync.GraphQLApi(this, 'graphQLApi', {
      name: 'sample',
      schemaDefinition: `
        type Query {
          todo: String
        }
      `,
    });

    const distribution = new cloudfront.CloudFrontWebDistribution(this, 'distribution', {
      originConfigs: [
        {
          customOriginSource: {
            domainName: cdk.Fn.select(2, cdk.Fn.split('/', graphQLApi.graphQlUrl))
          },
          behaviors: [
            {
              isDefaultBehavior: true,
              allowedMethods: cloudfront.CloudFrontAllowedMethods.ALL
            }
          ]
          // 他のOriginと併用するときはこちら
          // behaviors: [
          //   {
          //     pathPattern: "graphql",
          //     allowedMethods: cloudfront.CloudFrontAllowedMethods.ALL
          //   }
          // ]
        }
      ],
      viewerCertificate: cloudfront.ViewerCertificate.fromAcmCertificate(
        certificate,
        {
          aliases: [
            process.env.DOMAIN_NAME ? process.env.DOMAIN_NAME : '',
            process.env.FQDN ? process.env.FQDN : ''
          ]
        }
      ),
    });

    const ARecord = new route53.ARecord(this, 'ARecord', {
      recordName: process.env.FQDN ? process.env.FQDN : '',
      zone: hostedZone,
      target: route53.RecordTarget.fromAlias(new route53Targets.CloudFrontTarget(distribution))
    });
  }
}

環境変数

コード内で環境変数を使用している箇所が存在するため、環境変数を設定した後にcdk deployコマンドを実行する。
コマンドはLinux OSにおけるサンプルである。

1
2
3
4
5
export CDK_DEFAULT_ACCOUNT=123456789012  // AWSアカウントのID(12桁の数字)
export CDK_DEFAULT_REGION=ap-northeast-1 // 主にリソースを展開するリージョン
export DOMAIN_NAME=example.com           // 既存のRoute 53上に作成されているHosted Zoneの名前
export FQDN=www.example.com              // AppSyncに指定するカスタムドメイン
cdk deploy

生成されたCloudFormationテンプレート(CloudFrontのOrigin部分のみ抜粋)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
        Origins:
          - CustomOriginConfig:
              HTTPPort: 80
              HTTPSPort: 443
              OriginKeepaliveTimeout: 5
              OriginProtocolPolicy: https-only
              OriginReadTimeout: 30
              OriginSSLProtocols:
                - TLSv1.2
            DomainName:
              Fn::Select:
                - 2
                - Fn::Split:
                    - /
                    - Fn::GetAtt:
                        - graphQLApiF94BEEAB
                        - GraphQLUrl
            Id: origin1

動作確認

curlコマンドでGraphQL Endpointとの疎通確認。

1
2
3
4
5
6
7
dozono@ub:work (master)$ curl https://sample.dozono.net/graphql
{
  "errors" : [ {
    "errorType" : "UnauthorizedException",
    "message" : "You are not authorized to make this call."
  } ]
}dozono@ub:work (master)$

Enjoy