かんがるーさんの日記

最近自分が興味をもったものを調べた時の手順等を書いています。今は Spring Boot をいじっています。

serverless-domain-manager プラグインを利用して独自ドメインで API Gateway にアクセスする

概要

記事一覧はこちらです。

API Gateway にアクセスする時には deploy 時に表示される ServiceEndpoint(https://~.execute-api.ap-northeast-1.amazonaws.com/dev/... の URL)を使用していましたが、独自ドメインでアクセスする方法を試してみます。

Lambda を deploy する時に独自ドメインを定義できる serverless-domain-manager プラグインというものがあるので、今回はこれを利用します。

構成は以下のようになるようです(ELB と API Gateway のどちらが先にアクセスされるのかが分からない。。。)。

f:id:ksby:20200624141707p:plain:w450

  • SSL証明書は東京リージョン(ap-northeast-1)の ACM で発行します。
  • 独自ドメインは rest.ksbyzero.com にします。Route 53 に登録します。
  • Lambda は Serverless Framework でプロジェクトを作成した時にできる hello をそのまま使い、https://rest.ksbyzero.com/hello でアクセスできるようにします。独自ドメインを使用する方式にすると stage 名を URL からなくせます。
  • 独自ドメインでアクセスできるようにする場合、ELB が作成されて ACM で発行した SSL証明書が ELB に関連付けられます。ACM で作成した SSL証明書を削除しようとすると ELB で使用されているので削除できないというメッセージが表示されて気づきました(API Gateway を削除してから 20~30分程度経過しないと削除できませんでした)。

参照したサイト・書籍

  1. REST API のカスタムドメイン名の設定
    https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/how-to-custom-domains.html

  2. How to set up a custom domain name for API Gateway in your Serverless app
    https://seed.run/blog/how-to-set-up-a-custom-domain-name-for-api-gateway-in-your-serverless-app.html

  3. amplify-education / serverless-domain-manager
    https://www.npmjs.com/package/serverless-domain-manager
    https://github.com/amplify-education/serverless-domain-manager

  4. アプリケーションロードバランサー(ALB)のターゲットにAWS Lambdaが選択可能になりました
    https://aws.amazon.com/jp/blogs/news/lambda-functions-as-targets-for-application-load-balancers/

    • API Gateway を経由しなくても ALB から直接 Lambda を実行できるとのこと。
    • 今回の記事とは関係ありませんが、見かけたのでメモ書きとして残しておきます。

目次

  1. custom-domain-api-project プロジェクトを作成する
  2. serverless-domain-manager プラグインをインストールする
  3. hello_service サブプロジェクト作成し serverless.yml を変更する
  4. Terraform を使用して ACM で SSL証明書を作成する
  5. sls create_domain を実行して独自ドメインを利用できるようにする
  6. deploy する
  7. 動作確認する
  8. ACM の SSL証明書は関連リソースがなくならないと削除できない

手順

custom-domain-api-project プロジェクトを作成する

以下の手順で custom-domain-api-project プロジェクトを作成します。具体的な手順は IntelliJ IDEA+Node.js+npm+serverless framework+Python の組み合わせで開発環境を構築して AWS Lambda を作成してみる 参照。

  • custom-domain-api-project の Empty Project を作成する。
  • Python の仮想環境を作成する。
  • Serverless Framework をローカルインストールする。
  • .envrc を作成する。

serverless-domain-manager プラグインをインストールする

npm install --save-dev serverless-domain-manager を実行してプラグインをインストールします。

f:id:ksby:20200624152732p:plain

hello_service サブプロジェクト作成し serverless.yml を変更する

プロジェクトのルートディレクトリの下で npx sls create --template aws-python3 --path hello_service を実行して hello_service サブプロジェクトを作成します。

f:id:ksby:20200624153418p:plain

hello_service/severless.yml を以下の内容に変更します。

service: hello-service

plugins:
  - serverless-domain-manager

custom:
  customDomain:
    domainName: rest.ksbyzero.com
    # stage を書かなければ provider.stage の設定が使用される
    # stage: dev
    # basePath を書くと https://<domainName>/<basePath>/hello がアクセスする URL になる
    # basePath: base
    certificateName: ksbyzero.com
    createRoute53Record: true
    # endpointType に edge を指定すると CloudFront ディストリビューションを設定する
    # 今回は東京リージョンで設定するので regional を指定する
    endpointType: regional
    securityPolicy: tls_1_2
    apiType: rest

provider:
  name: aws
  runtime: python3.8

  stage: dev
  region: ap-northeast-1

functions:
  hello:
    handler: handler.hello
    events:
      - http:
          path: hello
          method: get
          cors: true
  • plugins を追加して serverless-domain-manager を記述します。
  • custom.customDomain を追加し、serverless-domain-manager の設定を記述します。
  • provider.stage、provider.region を追加します。
  • functions.hello.events.http を追加し、API Gateway にリクエストが来たら Lambda が実行されるよう設定します。

Terraform を使用して ACMSSL証明書を作成する

Terraform は tfenv+aws-vault+direnv を組み合わせて Windows 上に Terraform の実行環境を構築する で構築した環境を使用します。バージョンは 0.12.26 を使用します。

f:id:ksby:20200624154913p:plain

プロジェクトのルートディレクトリ直下に .terraform-version というファイルを作成し、以下の内容を記述します。

0.12.26

プロジェクトのルートディレクトリ直下に terraform というディレクトリを作成し、その下に acm.tf というファイルを作成して以下の内容を記述します。

terraform {
  required_version = "0.12.26"
}

provider "aws" {
  region = "ap-northeast-1"
}

///////////////////////////////////////////////////////////////////////////////
// Route53 の Public Zone
// ※Route53 でドメインを取得したので作成済、resource ではなく data で定義する
//
data "aws_route53_zone" "dns_zone_apex" {
  name = "ksbyzero.com"
}

///////////////////////////////////////////////////////////////////////////////
// ACM で SSL証明書を作成する
//
resource "aws_acm_certificate" "dns_zone_apex" {
  domain_name               = data.aws_route53_zone.dns_zone_apex.name
  subject_alternative_names = ["*.${data.aws_route53_zone.dns_zone_apex.name}"]
  validation_method         = "DNS"

  tags = {
    Name = data.aws_route53_zone.dns_zone_apex.name
  }

  lifecycle {
    create_before_destroy = true
  }
}
resource "aws_route53_record" "cert_validation_0" {
  name    = aws_acm_certificate.dns_zone_apex.domain_validation_options.0.resource_record_name
  type    = aws_acm_certificate.dns_zone_apex.domain_validation_options.0.resource_record_type
  records = [aws_acm_certificate.dns_zone_apex.domain_validation_options.0.resource_record_value]
  zone_id = data.aws_route53_zone.dns_zone_apex.id
  ttl     = 60
}
resource "aws_acm_certificate_validation" "cert" {
  certificate_arn = aws_acm_certificate.dns_zone_apex.arn

  validation_record_fqdns = [
    aws_route53_record.cert_validation_0.fqdn,
  ]
}

以上で設定は完了です。ACMSSL証明書を作成します。

tf init を実行してから、

f:id:ksby:20200624160227p:plain

tf plantf apply を実行します(画面キャプチャは tf apply のみ)。

f:id:ksby:20200624160730p:plain f:id:ksby:20200624160957p:plain

マネジメントコンソールで ACM を見ると ksbyzero.com の証明書が追加されており、「状況」が「発行済み」になっています。

f:id:ksby:20200624171935p:plain

Route 53 には DNS検証用の CNAME のレコードが1件追加されています。

f:id:ksby:20200624172054p:plain

sls create_domain を実行して独自ドメインを利用できるようにする

deploy の前に sls create_domain を実行して serverless.yml の custom.customDomain.domainName に定義した rest.ksbyzero.com を設定します。

f:id:ksby:20200624163113p:plain

New domains may take up to 40 minutes to be initialized. というメッセージが表示されており、使用可能になるまで最大 40分かかるようです。ただし、今回試していた時は結構すぐに使えるようになりました。

マネジメントコンソールから Route 53 を見ると rest.ksbyzero.com の A、AAAA レコードの2件が追加されています。

f:id:ksby:20200624172156p:plain

deploy する

hello_service を deploy します。

f:id:ksby:20200624164408p:plain f:id:ksby:20200624164554p:plain

動作確認する

Postman で GET メソッドにしてから https://rest.ksbyzero.com/hello にアクセスすると 200 OK が返ってきます。

f:id:ksby:20200624164809p:plain

sls logs -f hello コマンドでログを確認すると1回しか実行していないのに7件ログが出力されていました。ELB のヘルスチェックでしょうか?

f:id:ksby:20200624165250p:plain

以下のコマンドを実行して作成したリソースを削除します。

  • npx sls remove -v
  • npx sls delete_domain
  • terraform ディレクトリに移動してから tf destroy

ACMSSL証明書は関連リソースがなくならないと削除できない

tf destroy コマンドで ACMSSL証明書を削除しようとしてもすぐには削除できません。API Gateway を削除してもしばらくの間 ELB がSSL証明書に関連付けられているためです。20~30分程度経つと関連リソースはなくなります。

f:id:ksby:20200624171653p:plain

履歴

2020/06/24
初版発行。