Task: Configure Route 53 to return different database endpoints to internal versus external users. Internal users are routed to an internal RDS instance, while external users are routed to a publicly accessible one. Name the zones "private" and "public", the databases "internal" and "public", and the subnet group "main"

Specification:
Has one "aws_vpc" resource
    with a specified "cidr_block"

Has multiple "aws_subnet" resources
    with "vpc_id" referencing the "aws_vpc" resource
    with specified "cidr_block" for each
    with "availability_zone" set

Has one "aws_db_subnet_group" resource
    with "subnet_ids" referencing the IDs of "aws_subnet" resources

Has one "aws_route53_zone" resource
    with "name"

Has one "aws_route53_zone" resource
    with "name"
    with a "vpc" block with "vpc_id" referencing the "aws_vpc" resource


Has one "aws_db_instance" resource for internal use
    with "allocated_storage" set to a specific size
    with a specified "engine" 
    with a specified "instance_class"
    with "username" and "password"
    with "skip_final_snapshot" set to true
    with "identifier"
    with "password"
    with "db_subnet_group_name" referencing the "aws_db_subnet_group" resource

Has one "aws_db_instance" resource for public use
    with "allocated_storage" set to a specific size
    with a specified "engine"
    with a specified "instance_class"
    with "username" and "password"
    with "skip_final_snapshot" set to true
    with "identifier"
    with "password"
    with "publicly_accessible" set to true

Has two "aws_route53_record" resources
    with "zone_id" referencing one of the "aws_route53_zone" resources
    with "type"
    with "ttl"
    with "records" referencing one of the "aws_db_instance" resources 


Terraform configuration (main.tf):
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">= 5.75"
    }
  }

  required_version = ">= 1.9.0"
}


provider "aws" {
  region = "us-east-1" 
}

# Create a VPC for internal resources
resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/24"
}


# RDS instances
resource "aws_db_instance" "internal" {
  # Internal DB configuration
  allocated_storage    = 20
  engine               = "mysql"
  instance_class       = "db.t3.micro"
  identifier =  "internal"
  username             = "user"
  password             = "password"
  db_subnet_group_name = aws_db_subnet_group.main.name
  skip_final_snapshot  = true
}

resource "aws_db_instance" "public" {
  # Public DB configuration
  publicly_accessible  = true
  allocated_storage    = 20
  engine               = "mysql"
  instance_class       = "db.t3.micro"
  identifier = "public"
  username             = "user"
  password             = "password"
  skip_final_snapshot  = true
}

resource "aws_db_subnet_group" "main" {
  name       = "mydb-subnet-group"
  subnet_ids = [aws_subnet.maina.id, aws_subnet.mainb.id]
}

data "aws_availability_zones" "available" {}

# Subnet for RDS
resource "aws_subnet" "maina" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.0.0/25"
  availability_zone = data.aws_availability_zones.available.names[0]
}

resource "aws_subnet" "mainb" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.0.128/25"
  availability_zone = data.aws_availability_zones.available.names[1]
}

# Route 53 Public Hosted Zone for external users
resource "aws_route53_zone" "public" {
  name = "example53.com"
}

# Route 53 Private Hosted Zone for internal users
resource "aws_route53_zone" "private" {
  name = "example53.com"
  vpc {
    vpc_id = aws_vpc.main.id
  }
}

# Route 53 Record for Public DB (External Endpoint)
resource "aws_route53_record" "public_db" {
  zone_id = aws_route53_zone.public.zone_id
  name    = "public-db.example.com"
  type    = "CNAME"
  ttl     = "300"
  records = [aws_db_instance.public.address]
}

# Route 53 Record for Internal DB (Internal Endpoint)
resource "aws_route53_record" "internal_db" {
  zone_id = aws_route53_zone.private.zone_id
  name    = "internal-db.example.com"
  type    = "CNAME"
  ttl     = "300"
  records = [aws_db_instance.internal.address]
}

Validation policy (checks.rego):
package terraform.validation

default is_configuration_valid = false

default is_valid_r53_zone = false

default is_valid_r53_record = false

default is_valid_db_instance = false

default is_valid_vpc = false

default is_valid_subnet = false

default is_valid_subnet_group = false


is_valid_r53_zone {
        some i, j
    resource := input.configuration.root_module.resources[i]
    resource.type == "aws_route53_zone"
    resource.expressions.name
    resource2 := input.configuration.root_module.resources[j]
    resource2.type == "aws_route53_zone"
    resource2.expressions.name
    resource2.expressions.vpc[0].vpc_id.references[0]

}

is_valid_vpc {
		some i
    resource := input.configuration.root_module.resources[i]
    resource.type == "aws_vpc"
    resource.expressions.cidr_block
}

is_valid_r53_record {
        some i, j
    resource := input.configuration.root_module.resources[i]
    resource.type == "aws_route53_record"
    resource.expressions.name
    resource.expressions.type
    resource.expressions.ttl
    resource.expressions.zone_id.references[0] == "aws_route53_zone.public.zone_id"
    resource.expressions.records.references[0] == "aws_db_instance.public.address"

    resource2 := input.configuration.root_module.resources[j]
    resource2.type == "aws_route53_record"
    resource2.expressions.name
    resource2.expressions.type
    resource2.expressions.ttl
    resource2.expressions.zone_id.references[0] == "aws_route53_zone.private.zone_id"
    resource2.expressions.records.references[0] == "aws_db_instance.internal.address"
}



is_valid_subnet {
		some i, j
    resource := input.configuration.root_module.resources[i]
    resource.type == "aws_subnet"
    resource.expressions.cidr_block
    resource.expressions.availability_zone
    
    resource2 := input.configuration.root_module.resources[j]
    resource2.type == "aws_subnet"
    resource2.expressions.cidr_block
    resource2.expressions.availability_zone
    resource2.expressions.vpc_id.references[0] == resource.expressions.vpc_id.references[0]

}

is_valid_subnet_group {
		some i
    resource := input.configuration.root_module.resources[i]
    resource.type == "aws_db_subnet_group"
    resource.expressions.subnet_ids.references[0]
}

is_valid_db_instance {
        some i
        resource := input.configuration.root_module.resources[i]
    resource.type == "aws_db_instance"
    has_required_main_db_arguments
}

# Helper rule to check if all required arguments are present and valid
has_required_main_db_arguments {
		some i, j
    resource := input.configuration.root_module.resources[i]
    resource.type == "aws_db_instance"
    resource.expressions.db_subnet_group_name.references[0] == "aws_db_subnet_group.main.name"
    resource2 := input.configuration.root_module.resources[j]
    resource2.type == "aws_db_instance"
    resource2.expressions.publicly_accessible.constant_value == true
    # Check for allocated_storage, engine, instance_class, username, password, and skip_final_snapshot
    requirement1(resource.expressions)
    requirement1(resource2.expressions)
    # Check for instance_class validity
    requirement2(resource.expressions)
    requirement2(resource2.expressions)
}



# 1, allocated_storage and engine or snapshot_identifier or replace_source_db
requirement1(expressions) {
    expressions.allocated_storage
    expressions.engine
    expressions.username
    expressions.password
    is_valid_engine(expressions.engine.constant_value)
}

requirement1(expressions) {
    expressions.snapshot_identifier
}

# Check for instance_class validity
requirement2(expressions) {
    expressions.instance_class
    is_valid_instance_class(expressions.instance_class.constant_value)
}


# Helper rule to validate engine value
is_valid_engine(engine) {
        engine_set := {
        "mysql",
        "postgres",
        "mariadb",
        "oracle-se",
        "oracle-se1",
        "oracle-se2",
        "oracle-ee",
        "sqlserver-ee",
        "sqlserver-se",
        "sqlserver-ex",
        "sqlserver-web"
    }
        engine_set[engine]
}

# Helper rule to validate instance class type
is_valid_instance_class(instance_class) {
        instance_class_starts_with(instance_class, "db.")
}

# Helper rule to check prefix of instance class
instance_class_starts_with(instance_class, prefix) {
        startswith(instance_class, prefix)
}


# Combine all checks into a final rule
is_configuration_valid {
    is_valid_db_instance
    is_valid_vpc
    is_valid_subnet
    is_valid_subnet_group
    is_valid_r53_record
    is_valid_r53_zone
    
}