Create AWS API Gateway  Custom Domain Route 53 with SSL certificate using Terraform

Create AWS API Gateway Custom Domain Route 53 with SSL certificate using Terraform

Hello readers this article is a continuation of the previous one where we created a AWS Lambda with Terraform API Gateway

So if you are on track with that resource, let get started

To set up a custom domain with terraform, we still need to follow the same workflow. First, we need to issue a TLS certificate.

terraform/7-certificate.tf

resource "aws_acm_certificate" "api" {
  domain_name       = "api.rose-tech.net"
  validation_method = "DNS"
}

data "aws_route53_zone" "public" {
  name         = "rose-tech.net"
  private_zone = false
}

resource "aws_route53_record" "api_validation" {
  for_each = {
    for dvo in aws_acm_certificate.api.domain_validation_options : dvo.domain_name => {
      name   = dvo.resource_record_name
      record = dvo.resource_record_value
      type   = dvo.resource_record_type
    }
  }

  allow_overwrite = true
  name            = each.value.name
  records         = [each.value.record]
  ttl             = 60
  type            = each.value.type
  zone_id         = data.aws_route53_zone.public.zone_id
}

resource "aws_acm_certificate_validation" "api" {
  certificate_arn         = aws_acm_certificate.api.arn
  validation_record_fqdns = [for record in aws_route53_record.api_validation : record.fqdn]
}

The next step is to create a custom domain using terraform. Specify the domain name, which should match the certificate.

terraform/8-custom-domain-name.tf

resource "aws_apigatewayv2_domain_name" "api" {
  domain_name = "api.rose-tech.net"

  domain_name_configuration {
    certificate_arn = aws_acm_certificate.api.arn
    endpoint_type   = "REGIONAL"
    security_policy = "TLS_1_2"
  }

  depends_on = [aws_acm_certificate_validation.api]
}

resource "aws_route53_record" "api" {
  name    = aws_apigatewayv2_domain_name.api.domain_name
  type    = "A"
  zone_id = data.aws_route53_zone.public.zone_id

  alias {
    name                   = aws_apigatewayv2_domain_name.api.domain_name_configuration[0].target_domain_name
    zone_id                = aws_apigatewayv2_domain_name.api.domain_name_configuration[0].hosted_zone_id
    evaluate_target_health = false
  }
}

In the last file, let's create API mapping. The first one is for the base path. And the second one is to map the staging stage with the v1 path.

terraform/9-api-mapping.tf

resource "aws_apigatewayv2_api_mapping" "api" {
  api_id      = aws_apigatewayv2_api.main.id
  domain_name = aws_apigatewayv2_domain_name.api.id
  stage       = aws_apigatewayv2_stage.staging.id
}

resource "aws_apigatewayv2_api_mapping" "api_v1" {
  api_id          = aws_apigatewayv2_api.main.id
  domain_name     = aws_apigatewayv2_domain_name.api.id
  stage           = aws_apigatewayv2_stage.staging.id
  api_mapping_key = "v1"
}

output "custom_domain_api" {
  value = "https://${aws_apigatewayv2_api_mapping.api.domain_name}"
}

output "custom_domain_api_v1" {
  value = "https://${aws_apigatewayv2_api_mapping.api_v1.domain_name}/${aws_apigatewayv2_api_mapping.api_v1.api_mapping_key}"
}

Run terraform

terraform init
terraform apply

scrrr.png

Test with curl or with browser.

curl -X POST \
> -H "Content-Type: application/json" \
> -d '{"name":"Antoine"}' \
> "https://api.rose-tech.net/hello"
curl "https://api.rose-tech.net/hello?Name=Antoine"

alll.png