AWS には API Gateway っていう、その名の通り API を作るのに便利なサービスがあるのですが、最近ちょっと用事があって利用しようとしたら、v2 としてHTTP対応されていたので飛びついてみました。
今回はそれをTerraformで構築したのですが、どうも v2 に関してあまり情報がまとまっていなかったので、まずはベースとなるリソースのコードを記載して、次回にどんな感じで扱ったかという中身について触れていければと思います。
API Gateway とは
この辺を読んでおくとよいと思います。私のとこは実戦叩き上げ野郎によるコピペ用コードがウリなので、細かい説明はすっ飛ばして他に任せるスタイルです。- 高速、低コストで、より良いAPIの構築 – HTTP APIが利用可能(GA)になりました | Amazon Web Services ブログ
- よくある質問 – Amazon API Gateway | AWS
- Amazon API Gateway は何をしてるのか | Developers.IO
目的
大きく2つあり、今回は1つ目の、任意のFQDNでアクセス確認できればOKって内容になります。
FQDN 設計例
例えば、こんな感じのFQDNが登場するということにしておきます。こんな感じで、少なくとも3箇所で証明書が必要になる想定なので、ワイルドカードにしてやりくりするとよいでしょう。(ゆーても CloudFrontは us-east-1 で別ACMになるけど)
ACM作成
とりあえず、証明書が必要なのでACMを作ります。これについては過去記事にあるので冗長を避けるためにリンク貼っておきます。ちょっとコード記法が古臭いのは勘弁してください。- AWSで学ぶコンテナの基礎 (3) サービス起動 | 外道父の匠 の DNSとSSL/TLS証明書を準備する
API用DNS登録
この辺から若干ややこしくて、管理画面とにらめっこしてもリソースの関係性がいまいちピンとこなくて、管理画面とTerraformドキュメントとBBSの雑談を拾ってきてなんとかなりました。まず、APIで使うFQDNを宣言し、ACMと紐付けます。
1 2 3 4 5 6 7 8 9 10 11 |
resource "aws_apigatewayv2_domain_name" "example" { domain_name = local.example_api_fqdn domain_name_configuration { certificate_arn = aws_acm_certificate.example.arn endpoint_type = "REGIONAL" security_policy = "TLS_1_2" } depends_on = [aws_acm_certificate_validation.example] } |
このリソースを作ることで、例えば “d-01234abcde.execute-api.ap-northeast-1.amazonaws.com” みたいなAWS臭いFQDNが割り当てられるので、DNSレコードでエイリアスとして任意の運用FQDNと紐付けます。
1 2 3 4 5 6 7 8 9 10 11 |
resource "aws_route53_record" "example" { name = aws_apigatewayv2_domain_name.example.domain_name type = "A" zone_id = data.aws_route53_zone.example.zone_id alias { name = aws_apigatewayv2_domain_name.example.domain_name_configuration.0.target_domain_name zone_id = aws_apigatewayv2_domain_name.example.domain_name_configuration.0.hosted_zone_id evaluate_target_health = false } } |
Lambda作成
コードは次記事で軽く書きますが、いったん適当な lambda を作ったことにします。return {“statusCode”: 200, “body”: “OK”}
だけの lambda_handler だけで全然OK。
environment は次回使うので書いてますが、いらんです。
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 |
resource "aws_lambda_function" "example" { function_name = "api-gateway" handler = "api-gateway.lambda_handler" s3_bucket = local.lambda_bucket s3_key = local.lambda_main_key s3_object_version = data.aws_s3_bucket_object.lambda_main.version_id layers = [aws_lambda_layer_version.system-lib[0].arn] memory_size = 128 timeout = 30 runtime = local.lambda_runtime role = data.terraform_remote_state.common.outputs.aws_iam_role_lambda_arn environment { variables = { ON_SIMPLE_AUTH = true AUTH_KEY = local.auth_key AUTH_VALUE = local.auth_value } } } resource "aws_cloudwatch_log_group" "example" { name = format("%s%s", local.lambda_log_group_prefix, "api-gateway") retention_in_days = 7 } |
API作成
ここから関連付くので1つ1つ記述しますが、まずLambdaに紐づくAPI本体を作ります。name はわかりやすいからFQDNと同名にしてるだけです。
1 2 3 4 5 |
resource "aws_apigatewayv2_api" "example" { name = local.example_api_fqdn protocol_type = "HTTP" target = aws_lambda_function.example.arn } |
API Gateway から実行のお許しをLambdaにもらいます。
1 2 3 4 5 6 7 |
resource "aws_lambda_permission" "example" { function_name = aws_lambda_function.example.arn principal = "apigateway.amazonaws.com" action = "lambda:InvokeFunction" source_arn = "${aws_apigatewayv2_api.example.execution_arn}/*/*" } |
APIと任意のFQDNを結びつけて完成です。
1 2 3 4 5 |
resource "aws_apigatewayv2_api_mapping" "example" { api_id = aws_apigatewayv2_api.example.id domain_name = aws_apigatewayv2_domain_name.example.id stage = "$default" } |
動作確認
ここまでTerraform突っ込んで、いきなりAPIのURLぶっ叩いて確認してもよいのですが、シンプルなようでわかりづらいので1つ1つ丁寧に、Terraform と管理画面を追って理解したほうがよいと思います。その上で、リソースを全部作り終わった後に、
API Domain に割り振られた AWS用FQDN の名前解決をしてみて、
1 |
host "d-01234abcde.execute-api.ap-northeast-1.amazonaws.com" |
任意で割り当てたFQDNでも名前解決してみて、
1 |
host "api.example.com" |
API にアクセスしてみます。
1 |
curl -s https://api.example.com/ |
lambda で書いた return値が返れば成功ですし、もしダメなら CloudWatchLogs の lambda ログに何か残っているかもしれません。ログすらなければ、そもそもアクセスすら届いていないでしょう。
成功したら、def lambda_handler(event, context): の event をガバっと print して、どんな項目が扱えるのか確認していくと、どういう風に設計するか浮かんでくると思います。
この土台さえやっちまえば、あとは楽しいPythonコーディング!って思えば、微妙な面倒くささも吹っ飛ぶぜ:-9
てことで、もうちょっとだけ続くんじゃ
To Be Continued ⇨