(AWS) Terraform: "no matching Route53Zone found" - amazon-web-services

Im currently trying to set up an AWS EC2 Instance & integrated API-Gateway with terraform.
I watched the tutorial of Anton Putra: https://www.youtube.com/watch?v=XhS2JbPg8jA&t=287s
and also cloned his code: https://github.com/antonputra/tutorials/tree/main/lessons/118
I simply wanted to rename some of the resources and apply the terraform.
"terraform init" works but when i run "terraform apply", i get this message:
CMD Error Message
This is the code from the file its complaining about:
resource "aws_acm_certificate" "gradebook" {
    domain_name          = "gradebook.bmeisn.com"
    validation_method = "DNS"
} 
data "aws_route53_zone" "gradebook-r53z" {
    name              = "bmeisn.com"
    private_zone      = false
} 
resource "aws_route53_record" "gradebook-r53r" {
    for_each = {
        for dvo in aws_acm_certificate.gradebook.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.gradebook-r53z.zone_id
} 
resource "aws_acm_certificate_validation" "gradebook" {
    certificate_arn            = aws_acm_certificate.gradebook.arn
    validation_record_fqdns    = [for record in aws_route53_record.gradebook-r53r : record.fqdn ]
}
I read that it might be because of the domain so heres the tf file for that aswell:
resource "aws_apigatewayv2_domain_name" "gradebook" {
  domain_name = "gradebook.bmeisn.com"   domain_name_configuration {
    certificate_arn = aws_acm_certificate.gradebook.arn
    endpoint_type   = "REGIONAL"
    security_policy = "TLS_1_2"
  }  
depends_on = [aws_acm_certificate_validation.gradebook]
} 
resource "aws_route53_record" "gradebook-r53r-02" {
  name    = aws_apigatewayv2_domain_name.gradebook.domain_name
  type    = "A"
  zone_id = data.aws_route53_zone.gradebook-r53z.zone_id   alias {
    name                   = aws_apigatewayv2_domain_name.gradebook.domain_name_configuration[0].target_domain_name
    zone_id                = aws_apigatewayv2_domain_name.gradebook.domain_name_configuration[0].hosted_zone_id
    evaluate_target_health = false
  }
} 
resource "aws_apigatewayv2_api_mapping" "gradebook-map" {
  api_id      = aws_apigatewayv2_api.gradebook-agw.id
  domain_name = aws_apigatewayv2_domain_name.gradebook.id
  stage       = aws_apigatewayv2_stage.dev.id
} 
output "custom_domain_api-v2" {
  value = "https://${aws_apigatewayv2_api_mapping.gradebook-map.domain_name}/health"
}
The whole setup around it seems to work so im assuming i did something wrong here, i just cant figure out what exactly as im not very experienced with this technology.
Also if this question is missing any important info, let me know.

As pointed out in the comments, you aren't exactly creating your Route 53 zone. If you're committed to do it via Terraform (I'd personally advise against it but it's your choice to make) aws_route53_zone resource is what you seek, it also has example on how to reference a zone you're to create.
In case you still get messages about it being absent AFTER referencing zone resource you are creating (Terraform borking the resource creating order), then just use depends_on and call it a day.

Related

Terraform - issue with aws_acm_certificate_validation

I am trying to generate a certificate and make it validate via DNS... all seems to work, until the last steps when I use resource "aws_acm_certificate_validation"
my code is the following:
# Create Certificate
resource "aws_acm_certificate" "ic_cert" {
provider = aws.us-east-1
domain_name = aws_s3_bucket.ic_bucket_main.bucket
subject_alternative_names = [aws_s3_bucket.ic_bucket_redirect.bucket]
validation_method = "DNS"
tags = {
Billing = "company X"
}
lifecycle {
create_before_destroy = true
}
}
# Validate Certificate via DNS
# get zone_id
data "aws_route53_zone" "selected" {
provider = aws.us-east-1
name = aws_s3_bucket.ic_bucket_main.bucket
}
# Generate DNS Records
resource "aws_route53_record" "ic_DNS_validation" {
provider = aws.us-east-1
for_each = {
for dvo in aws_acm_certificate.ic_cert.domain_validation_options : dvo.domain_name => {
name = dvo.resource_record_name
record = dvo.resource_record_value
type = dvo.resource_record_type
zone_id = data.aws_route53_zone.selected.zone_id
}
}
allow_overwrite = true
name = each.value.name
records = [each.value.record]
ttl = 60
type = each.value.type
zone_id = each.value.zone_id
}
# Confirm certificate creation
resource "aws_acm_certificate_validation" "ic_cert_validation" {
certificate_arn = aws_acm_certificate.ic_cert.arn
#validation_record_fqdns = [for record in aws_route53_record.ic_DNS_validation : record.fqdn]
#validation_record_fqdns = [aws_route53_record.ic_DNS_validation.fqdn]
validation_record_fqdns = [for record in aws_route53_record.ic_DNS_validation : record.fqdn]
}
and I get the following error:
Error: reading ACM Certificate (arn:aws:acm:us-east-1:xxxxxxxxxxxxxxxxxxxxx8:certificate/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx): couldn't find resource
│ with aws_acm_certificate_validation.ic_cert_validation,
│ on certificates.tf line 45, in resource "aws_acm_certificate_validation" "ic_cert_validation":
│ 45: resource "aws_acm_certificate_validation" "ic_cert_validation" {
would anybody spot what is the issue?
Since ACM is a regional serivce and the certificate was created using provider = aws.us-east-1 the resource used for certificate validation should also use the same configuration (as the certificates were already created in that region):
resource "aws_acm_certificate_validation" "ic_cert_validation" {
provider = aws.us-east-1
certificate_arn = aws_acm_certificate.ic_cert.arn
#validation_record_fqdns = [for record in aws_route53_record.ic_DNS_validation : record.fqdn]
#validation_record_fqdns = [aws_route53_record.ic_DNS_validation.fqdn]
validation_record_fqdns = [for record in aws_route53_record.ic_DNS_validation : record.fqdn]
}

How Do I Use A Terraform Data Source To Reference A Managed Prefix List?

I'm trying to update a terraform module to add a new security group, which will have an inbound rule populated with two managed prefix lists. The prefix lists are shared to my AWS account from a different account using AWS Resource Access Manager, however I have tried referencing prefix lists created within my own AWS account and am seeing the same error.
Below is the terraform I am using:
resource "aws_security_group" "akamai_sg" {
name = "akamai-pl-sg"
description = "Manage access from Akamai to ${var.environment} alb"
vpc_id = var.vpc_id
tags = merge(var.common_tags, tomap({ "Name" = "akamai-pl-sg" }))
revoke_rules_on_delete = true
}
resource "aws_security_group_rule" "akamai_to_internal_alb" {
for_each = toset(var.domains_inc_akamai)
type = "ingress"
description = "Allow Akamai into ${var.environment}${var.domain_name_suffix}-alb"
from_port = var.alb_listener_port
to_port = var.alb_listener_port
protocol = "tcp"
security_group_id = aws_security_group.akamai_sg.id
prefix_list_ids = [data.aws_prefix_list.akamai-site-shield.id, data.aws_prefix_list.akamai-staging.id]
}
data "aws_prefix_list" "akamai-site-shield" {
filter {
name = "prefix-list-id"
values = ["pl-xxxxxxxxxx"]
}
}
data "aws_prefix_list" "akamai-staging" {
filter {
name = "prefix-list-id"
values = ["pl-xxxxxxxxxx"]
}
}
The terraform error I am revieving reads:
"Error: no matching prefix list found; the prefix list ID or name may be invalid or not exist in the current region"
Is anyone able to help, or see where I am going wrong?
Thanks in advance.
Would not be the following possible?
data "aws_vpc_endpoint" "s3" {
vpc_id = aws_vpc.foo.id
service_name = "com.amazonaws.us-west-2.s3"
}
data "aws_prefix_list" "s3" {
prefix_list_id = aws_vpc_endpoint.s3.prefix_list_id
}
It seems the solution is to use:
data "aws_ec2_managed_prefix_list" "example" {
filter {
name = "prefix-list-name"
values = ["my-prefix-list"]
}
}

Terraform -ssh: handshake failed: ssh: │ unable to authenticate, attempted methods [none publickey], no supported methods remain ╵

I have my terraform code to ssh into a ec2 instance and i keep getting the error as below. Also, I am able to ssh into the instance from my local machine.
timeout - last error: SSH authentication failed (kali#:22): ssh: handshake failed: ssh:
│ unable to authenticate, attempted methods [none publickey], no supported methods remain
here is my code:
resource "aws_key_pair" "public_key" {
  key_name   = "public_key”
  public_key = "ssh-rsa xxxxxxxxxxxxx"
}
data "template_file" "user_data" {
  template = file("../kali_linux_aws/payload.sh")
}
resource "aws_default_subnet" "default" {
    availability_zone = var.availability_zone
}
resource "aws_default_vpc" "default" {
  tags = {
    Name = "Default VPC"
  }
}
resource "aws_security_group" "kali_security_group" {
  name        = "allow_tls"
  description = "Allow TLS inbound traffic"
  vpc_id      = aws_default_vpc.default.id
  ingress {
    description      = "ssh"
    from_port        = 22
    to_port          = 22
    protocol         = "tcp"
    cidr_blocks      = ["0.0.0.0/0"]
  }
  ingress {
    description      = "rdp"
    from_port        = 3389
    to_port          = 3389
    protocol         = "tcp"
    cidr_blocks      = ["0.0.0.0/0"]
  }
  egress {
    from_port        = 0
    to_port          = 0
    protocol         = "-1"
    cidr_blocks      = ["0.0.0.0/0"]
    ipv6_cidr_blocks = ["::/0"]
  }
  tags = {
    Name = "kali_security_group"
  }
}
resource "aws_instance" "kali_linux" {
  ami                         = "ami-0f226738ik68873d1"
  instance_type               = var.instance_type
  availability_zone           = var.availability_zone
  associate_public_ip_address = true
  key_name                    = aws_key_pair.public_key.key_name
  user_data                   = data.template_file.user_data.rendered
  subnet_id                   = var.subnet_id == null ? aws_default_subnet.default.id : var.subnet_id
  vpc_security_group_ids      = [aws_security_group.kali_security_group.id]
 
  root_block_device {
    volume_size = var.volume_size
  }
}
resource "null_resource" "provision"{
  connection {
    type = "ssh"
    user = "kali"
    private_key = "${file("/Users/path/to/id_rsa")}"
    host = aws_instance.kali_linux.public_ip
  }
  provisioner "remote-exec" {
    inline = [
      "sudo apt-get update"
    ]
}
}
All i am trying to do is to create a kali linux EC2 instance on AWS and run some remote-exec commands. Can someone please help? Also if there are any workarounds please suggest as well. Thank you in advance.

How do you declare a gcp rate_limit_options block in terraform

I'm trying to create a gcp cloud armor rate limiting "throttle" resource but i keep getting the error below.
Error: Unsupported block type
│
│ on main.tf line 20, in resource "google_compute_security_policy" "throttle":
│ 172: rate_limit_options {
│
│ Blocks of type "rate_limit_options" are not expected here.
Here is what my resource block looks like;
resource "google_compute_security_policy" "throttle" {
name = "${var.environment_name}-throttle"
description = "rate limits request based on throttle"
rule {
action = "throttle"
preview = true
priority = "1000"
match {
versioned_expr = "SRC_IPS_V1"
config {
src_ip_ranges = ["*"]
}
}
rate_limit_options {
conform_action = "allow"
exceed_action = "deny(429)"
enforce_on_key = "ALL"
rate_limit_threshold {
count = "200"
interval_sec = "300"
}
}
}
}
here is what my provide block look like
provider "google-beta" {
project = var.project[var.environment_name]
region = "us-central1"
}
How do i declare the rate_limit_option block?
This worked for me:
resource "google_compute_security_policy" "throttle" {
name = ${var.environment_name}-throttle"
description = "rate limits"
provider = google-beta
rule {
action = "throttle"
preview = true
priority = "1000"
rate_limit_options {
conform_action = "allow"
exceed_action = "deny(429)"
enforce_on_key = "ALL"
rate_limit_threshold {
count = "200"
interval_sec = "300"
}
}
match {
versioned_expr = "SRC_IPS_V1"
config {
src_ip_ranges = ["*"]
}
}
}
}
The block rate_limit_options is supported by the google-beta provider.
Use this:
provider "google-beta" {
project = "my-project-id"
...
}
Using the google-beta provider

Terraformed AWS API Gateway Custom Domain Names throws 403 Forbidden

I am trying to expose all the stages of my Regional API Gateway through a regional Custom Domain.
Problem
If I curl directly my API Gateway (ie. https://xx.execute-api.eu-west-3.amazonaws.com/default/users), it works, but I get a 403 if I curl de domain name (ie. https://api.acme.com/default/users).
Configuration
My Terraform files looks like that:
data "aws_route53_zone" "acme" {
name = "acme.com."
}
resource "aws_api_gateway_rest_api" "backend" {
name = "acme-backend-api"
description = "Backend API"
body = "SOMETHING"
endpoint_configuration {
types = ["REGIONAL"]
}
}
resource "aws_api_gateway_deployment" "backend" {
rest_api_id = aws_api_gateway_rest_api.backend.id
stage_name = "default"
lifecycle {
create_before_destroy = true
}
}
resource "aws_api_gateway_domain_name" "backend" {
domain_name = "api.acme.com"
regional_certificate_arn = "arn:aws:acm:xx:certificate/xx"
endpoint_configuration {
types = ["REGIONAL"]
}
}
resource "aws_route53_record" "backend" {
name = aws_api_gateway_domain_name.backend.domain_name
type = "A"
zone_id = data.aws_route53_zone.acme.id
alias {
evaluate_target_health = true
name = aws_api_gateway_domain_name.backend.regional_domain_name
zone_id = aws_api_gateway_domain_name.backend.regional_zone_id
}
}
resource "aws_api_gateway_base_path_mapping" "backend" {
api_id = aws_api_gateway_rest_api.backend.id
domain_name = aws_api_gateway_domain_name.backend.domain_name
# No stage_name: expose all stages
}
According to the Terraform api_gateway_domain_name and api_gateway_base_path_mapping examples, it should be ok.
I have also followed many howtos, and I have these elements:
The certificate
The A record to the API custom domain
The mapping to the deployed stage (which works if you call it directly)
What do I miss/do wrong?
This is v2 example working for me as off today, this "aws_apigatewayv2_api_mapping" is key to avoid port 80: Connection refused
or {"message":"Forbidden"} errors which I see you have but I did struggle with.
// ACM
resource "aws_acm_certificate" "cert_api" {
domain_name = var.api_domain
validation_method = "DNS"
tags = {
Name = var.api_domain
}
}
resource "aws_acm_certificate_validation" "cert_api" {
certificate_arn = aws_acm_certificate.cert_api.arn
}
// API Gateway V2
resource "aws_apigatewayv2_api" "lambda" {
name = "serverless_lambda_gw"
protocol_type = "HTTP"
}
resource "aws_apigatewayv2_stage" "lambda" {
api_id = aws_apigatewayv2_api.lambda.id
name = "serverless_lambda_stage"
auto_deploy = true
access_log_settings {
destination_arn = aws_cloudwatch_log_group.api_gw.arn
format = jsonencode({
requestId = "$context.requestId"
sourceIp = "$context.identity.sourceIp"
requestTime = "$context.requestTime"
protocol = "$context.protocol"
httpMethod = "$context.httpMethod"
resourcePath = "$context.resourcePath"
routeKey = "$context.routeKey"
status = "$context.status"
responseLength = "$context.responseLength"
integrationErrorMessage = "$context.integrationErrorMessage"
}
)
}
}
resource "aws_apigatewayv2_integration" "testimonials" {
api_id = aws_apigatewayv2_api.lambda.id
integration_uri = aws_lambda_function.testimonials.invoke_arn
integration_type = "AWS_PROXY"
integration_method = "POST"
}
resource "aws_apigatewayv2_route" "testimonials" {
api_id = aws_apigatewayv2_api.lambda.id
route_key = "GET /testimonials"
target = "integrations/${aws_apigatewayv2_integration.testimonials.id}"
}
resource "aws_cloudwatch_log_group" "api_gw" {
name = "/aws/api_gw/${aws_apigatewayv2_api.lambda.name}"
retention_in_days = 30
}
resource "aws_lambda_permission" "api_gw" {
statement_id = "AllowExecutionFromAPIGateway"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.testimonials.function_name
principal = "apigateway.amazonaws.com"
source_arn = "${aws_apigatewayv2_api.lambda.execution_arn}/*/*"
}
resource "aws_apigatewayv2_domain_name" "api" {
domain_name = var.api_domain
domain_name_configuration {
certificate_arn = aws_acm_certificate.cert_api.arn
endpoint_type = "REGIONAL"
security_policy = "TLS_1_2"
}
}
resource "aws_apigatewayv2_api_mapping" "api" {
api_id = aws_apigatewayv2_api.lambda.id
domain_name = aws_apigatewayv2_domain_name.api.id
stage = aws_apigatewayv2_stage.lambda.id
}
// Route53
resource "aws_route53_zone" "api" {
name = var.api_domain
}
resource "aws_route53_record" "cert_api_validations" {
allow_overwrite = true
count = length(aws_acm_certificate.cert_api.domain_validation_options)
zone_id = aws_route53_zone.api.zone_id
name = element(aws_acm_certificate.cert_api.domain_validation_options.*.resource_record_name, count.index)
type = element(aws_acm_certificate.cert_api.domain_validation_options.*.resource_record_type, count.index)
records = [element(aws_acm_certificate.cert_api.domain_validation_options.*.resource_record_value, count.index)]
ttl = 60
}
resource "aws_route53_record" "api-a" {
name = aws_apigatewayv2_domain_name.api.domain_name
type = "A"
zone_id = aws_route53_zone.api.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
}
}