Refactor LocalStack configuration and add Terraform scripts for AWS resources

This commit is contained in:
Elmar Kresse
2025-08-12 11:54:54 +02:00
parent 149b10a643
commit 2c6cde91b9
13 changed files with 664 additions and 54 deletions

View File

@@ -7,7 +7,7 @@ services:
- "127.0.0.1:4510-4559:4510-4559" # external services port range
environment:
# LocalStack configuration: https://docs.localstack.cloud/references/configuration/
- DEBUG=${DEBUG:-0}
DEBUG: ${DEBUG:-0}
volumes:
- "${LOCALSTACK_VOLUME_DIR:-./volume}:/var/lib/localstack"
- "/var/run/docker.sock:/var/run/docker.sock"

47
readme.md Normal file
View File

@@ -0,0 +1,47 @@
# LocalStack
LocalStack is a fully functional local AWS cloud stack. This project is designed to help you develop and test cloud applications offline.
## Features
- Fully functional local AWS cloud stack
- Supports a wide range of AWS services
- Easy to use and deploy
- Fast and reliable
## Installation
To install LocalStack, you can use the docker compose setup and run the following command:
```bash
docker-compose up
```
This starts the LocalStack services in the background.
There is also a second service named terraform that can be used to manage Terraform configurations onto the LocalStack environment.
```bash
docker-compose exec terraform /bin/sh
```
The terraform container already mounted the terraform folder the includes basic terraform configurations.
To run the Terraform commands, you can use the following command:
```bash
docker-compose exec terraform /bin/sh
```
This will give you access to a shell inside the terraform container, where you can run Terraform commands as needed.
```bash
terraform init
```
```bash
terraform apply
```
```bash
terraform destroy
```

View File

@@ -0,0 +1,11 @@
resource "aws_instance" "web" {
ami = var.ami_id
instance_type = var.instance_type
subnet_id = aws_subnet.public_a.id
vpc_security_group_ids = [aws_security_group.web_sg.id]
associate_public_ip_address = true
tags = {
Name = "${var.project_name}-web"
}
}

14
terraform/scripts/dns.tf Normal file
View File

@@ -0,0 +1,14 @@
resource "aws_route53_zone" "primary" {
name = var.hosted_zone_name
comment = "primary hosted zone for ${var.project_name} localstack"
}
# In real AWS you'd use alias to ALB; LocalStack may not fully resolve alias, but we include it.
resource "aws_route53_record" "web" {
zone_id = aws_route53_zone.primary.zone_id
name = var.domain_name
type = "A"
ttl = 60
# direct connect to instance because alb is not supported in free localstack
records = [aws_instance.web.private_ip]
}

View File

@@ -1,27 +0,0 @@
provider "aws" {
region = "us-west-2"
access_key = "anaccesskey"
secret_key = "asecretkey"
s3_use_path_style = true
skip_credentials_validation = true
skip_metadata_api_check = true
skip_requesting_account_id = true
endpoints {
ec2 = "http://localstack:4566"
s3 = "http://localstack:4566"
lambda = "http://localstack:4566"
dynamodb = "http://localstack:4566"
# Add more services as needed
}
}
resource "aws_instance" "app_server" {
# LocalStack doesn't validate real AMI IDs; use a dummy ID
ami = "ami-12345678"
instance_type = "t2.micro"
tags = {
Name = "hashicorp-learn"
}
}

View File

@@ -0,0 +1,20 @@
output "instance_id" {
value = aws_instance.web.id
}
output "instance_private_ip" {
value = aws_instance.web.private_ip
description = "Private IP"
}
output "domain_record" {
value = aws_route53_record.web.fqdn
}
output "security_group_id" {
value = aws_security_group.web_sg.id
}
output "vpc_id" {
value = aws_vpc.main.id
}

View File

@@ -0,0 +1,28 @@
terraform {
required_version = ">= 1.5.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.0"
}
}
}
provider "aws" {
region = var.region
access_key = "test"
secret_key = "test"
s3_use_path_style = true
skip_credentials_validation = true
skip_metadata_api_check = true
skip_requesting_account_id = true
endpoints {
ec2 = var.localstack_endpoint
s3 = var.localstack_endpoint
route53 = var.localstack_endpoint
iam = var.localstack_endpoint
acm = var.localstack_endpoint
sts = var.localstack_endpoint
}
}

View File

@@ -0,0 +1,32 @@
resource "aws_security_group" "web_sg" {
name = "${var.project_name}-web-sg"
description = "Allow HTTP/HTTPS only"
vpc_id = aws_vpc.main.id
ingress {
description = "HTTP"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "HTTPS"
from_port = 443
to_port = 443
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"]
}
tags = {
Name = "${var.project_name}-web-sg"
}
}

View File

@@ -1,10 +0,0 @@
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.92"
}
}
required_version = ">= 1.2"
}

View File

@@ -1,21 +1,42 @@
{
"version": 4,
"terraform_version": "1.12.2",
"serial": 1,
"serial": 38,
"lineage": "d4b3ead1-bf36-0a61-6b2a-8097a03862ed",
"outputs": {},
"outputs": {
"domain_record": {
"value": "example.local",
"type": "string"
},
"instance_id": {
"value": "i-9b3990d5fe7ddabd2",
"type": "string"
},
"instance_private_ip": {
"value": "10.0.1.4",
"type": "string"
},
"security_group_id": {
"value": "sg-ff0700449b3f0c236",
"type": "string"
},
"vpc_id": {
"value": "vpc-d2369b36584be2923",
"type": "string"
}
},
"resources": [
{
"mode": "managed",
"type": "aws_instance",
"name": "app_server",
"name": "web",
"provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
"instances": [
{
"schema_version": 1,
"attributes": {
"ami": "ami-12345678",
"arn": "arn:aws:ec2:us-west-2::instance/i-ff8f884d048fb6dba",
"arn": "arn:aws:ec2:us-west-2::instance/i-9b3990d5fe7ddabd2",
"associate_public_ip_address": true,
"availability_zone": "us-west-2a",
"capacity_reservation_specification": [],
@@ -35,7 +56,7 @@
"host_id": "",
"host_resource_group_arn": null,
"iam_instance_profile": "",
"id": "i-ff8f884d048fb6dba",
"id": "i-9b3990d5fe7ddabd2",
"instance_initiated_shutdown_behavior": "stop",
"instance_lifecycle": "",
"instance_market_options": [],
@@ -61,12 +82,12 @@
"password_data": "",
"placement_group": "",
"placement_partition_number": 0,
"primary_network_interface_id": "eni-671b9b667332dd817",
"private_dns": "ip-10-108-71-135.us-west-2.compute.internal",
"primary_network_interface_id": "eni-4095f018ac52e4592",
"private_dns": "ip-10-0-1-4.us-west-2.compute.internal",
"private_dns_name_options": [],
"private_ip": "10.108.71.135",
"public_dns": "ec2-54-214-139-172.us-west-2.compute.amazonaws.com",
"public_ip": "54.214.139.172",
"private_ip": "10.0.1.4",
"public_dns": "ec2-54-214-5-174.us-west-2.compute.amazonaws.com",
"public_ip": "54.214.5.174",
"root_block_device": [
{
"delete_on_termination": true,
@@ -77,7 +98,7 @@
"tags": {},
"tags_all": {},
"throughput": 0,
"volume_id": "vol-7f697cf5342910fce",
"volume_id": "vol-ebbf4bf49122eb0ce",
"volume_size": 8,
"volume_type": "gp2"
}
@@ -86,12 +107,12 @@
"security_groups": [],
"source_dest_check": true,
"spot_instance_request_id": "",
"subnet_id": "subnet-46507f191da09e9e5",
"subnet_id": "subnet-fabb34e9dcee4e10c",
"tags": {
"Name": "hashicorp-learn"
"Name": "web-demo-web"
},
"tags_all": {
"Name": "hashicorp-learn"
"Name": "web-demo-web"
},
"tenancy": "default",
"timeouts": null,
@@ -99,11 +120,391 @@
"user_data_base64": null,
"user_data_replace_on_change": false,
"volume_tags": null,
"vpc_security_group_ids": []
"vpc_security_group_ids": [
"sg-ff0700449b3f0c236"
]
},
"sensitive_attributes": [],
"identity_schema_version": 0,
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjo2MDAwMDAwMDAwMDAsImRlbGV0ZSI6MTIwMDAwMDAwMDAwMCwicmVhZCI6OTAwMDAwMDAwMDAwLCJ1cGRhdGUiOjYwMDAwMDAwMDAwMH0sInNjaGVtYV92ZXJzaW9uIjoiMSJ9"
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjo2MDAwMDAwMDAwMDAsImRlbGV0ZSI6MTIwMDAwMDAwMDAwMCwicmVhZCI6OTAwMDAwMDAwMDAwLCJ1cGRhdGUiOjYwMDAwMDAwMDAwMH0sInNjaGVtYV92ZXJzaW9uIjoiMSJ9",
"dependencies": [
"aws_security_group.web_sg",
"aws_subnet.public_a",
"aws_vpc.main"
]
}
]
},
{
"mode": "managed",
"type": "aws_internet_gateway",
"name": "gw",
"provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"arn": "arn:aws:ec2:us-west-2:000000000000:internet-gateway/igw-137a64d5ace66fd05",
"id": "igw-137a64d5ace66fd05",
"owner_id": "000000000000",
"tags": {
"Name": "web-demo-igw"
},
"tags_all": {
"Name": "web-demo-igw"
},
"timeouts": null,
"vpc_id": "vpc-d2369b36584be2923"
},
"sensitive_attributes": [],
"identity_schema_version": 0,
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjEyMDAwMDAwMDAwMDAsInVwZGF0ZSI6MTIwMDAwMDAwMDAwMH19",
"dependencies": [
"aws_vpc.main"
]
}
]
},
{
"mode": "managed",
"type": "aws_route",
"name": "default_inet",
"provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"carrier_gateway_id": "",
"core_network_arn": "",
"destination_cidr_block": "0.0.0.0/0",
"destination_ipv6_cidr_block": "",
"destination_prefix_list_id": "",
"egress_only_gateway_id": "",
"gateway_id": "igw-137a64d5ace66fd05",
"id": "r-rtb-9cd3766ac0d2a3d2a1080289494",
"instance_id": "",
"instance_owner_id": "",
"local_gateway_id": "",
"nat_gateway_id": "",
"network_interface_id": "",
"origin": "CreateRoute",
"route_table_id": "rtb-9cd3766ac0d2a3d2a",
"state": "active",
"timeouts": null,
"transit_gateway_id": "",
"vpc_endpoint_id": "",
"vpc_peering_connection_id": ""
},
"sensitive_attributes": [],
"identity_schema_version": 0,
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjozMDAwMDAwMDAwMDAsImRlbGV0ZSI6MzAwMDAwMDAwMDAwLCJ1cGRhdGUiOjEyMDAwMDAwMDAwMH19",
"dependencies": [
"aws_internet_gateway.gw",
"aws_route_table.public",
"aws_vpc.main"
]
}
]
},
{
"mode": "managed",
"type": "aws_route53_record",
"name": "web",
"provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
"instances": [
{
"schema_version": 2,
"attributes": {
"alias": [],
"allow_overwrite": null,
"cidr_routing_policy": [],
"failover_routing_policy": [],
"fqdn": "example.local",
"geolocation_routing_policy": [],
"geoproximity_routing_policy": [],
"health_check_id": "",
"id": "4CSYFAR2Y8XOXVAYMXEYVJ_example.local_A",
"latency_routing_policy": [],
"multivalue_answer_routing_policy": false,
"name": "example.local",
"records": [
"10.0.1.4"
],
"set_identifier": "",
"timeouts": null,
"ttl": 60,
"type": "A",
"weighted_routing_policy": [],
"zone_id": "4CSYFAR2Y8XOXVAYMXEYVJ"
},
"sensitive_attributes": [],
"identity_schema_version": 0,
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxODAwMDAwMDAwMDAwLCJkZWxldGUiOjE4MDAwMDAwMDAwMDAsInVwZGF0ZSI6MTgwMDAwMDAwMDAwMH0sInNjaGVtYV92ZXJzaW9uIjoiMiJ9",
"dependencies": [
"aws_instance.web",
"aws_route53_zone.primary",
"aws_security_group.web_sg",
"aws_subnet.public_a",
"aws_vpc.main"
]
}
]
},
{
"mode": "managed",
"type": "aws_route53_zone",
"name": "primary",
"provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"arn": "arn:aws:route53:::hostedzone/4CSYFAR2Y8XOXVAYMXEYVJ",
"comment": "primary hosted zone for web-demo localstack",
"delegation_set_id": "",
"force_destroy": false,
"id": "4CSYFAR2Y8XOXVAYMXEYVJ",
"name": "example.local",
"name_servers": [
"ns-2048.awsdns-64.com",
"ns-2049.awsdns-65.net",
"ns-2050.awsdns-66.org",
"ns-2051.awsdns-67.co.uk"
],
"primary_name_server": "ns-2048.awsdns-64.com",
"tags": null,
"tags_all": {},
"timeouts": null,
"vpc": [],
"zone_id": "4CSYFAR2Y8XOXVAYMXEYVJ"
},
"sensitive_attributes": [],
"identity_schema_version": 0,
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxODAwMDAwMDAwMDAwLCJkZWxldGUiOjE4MDAwMDAwMDAwMDAsInVwZGF0ZSI6MTgwMDAwMDAwMDAwMH19"
}
]
},
{
"mode": "managed",
"type": "aws_route_table",
"name": "public",
"provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"arn": "arn:aws:ec2:us-west-2:000000000000:route-table/rtb-9cd3766ac0d2a3d2a",
"id": "rtb-9cd3766ac0d2a3d2a",
"owner_id": "000000000000",
"propagating_vgws": [],
"route": [],
"tags": {
"Name": "web-demo-public-rt"
},
"tags_all": {
"Name": "web-demo-public-rt"
},
"timeouts": null,
"vpc_id": "vpc-d2369b36584be2923"
},
"sensitive_attributes": [],
"identity_schema_version": 0,
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjozMDAwMDAwMDAwMDAsImRlbGV0ZSI6MzAwMDAwMDAwMDAwLCJ1cGRhdGUiOjEyMDAwMDAwMDAwMH19",
"dependencies": [
"aws_vpc.main"
]
}
]
},
{
"mode": "managed",
"type": "aws_route_table_association",
"name": "public_a",
"provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"gateway_id": "",
"id": "rtbassoc-c573a733d31cd9074",
"route_table_id": "rtb-9cd3766ac0d2a3d2a",
"subnet_id": "subnet-fabb34e9dcee4e10c",
"timeouts": null
},
"sensitive_attributes": [],
"identity_schema_version": 0,
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjozMDAwMDAwMDAwMDAsImRlbGV0ZSI6MzAwMDAwMDAwMDAwLCJ1cGRhdGUiOjEyMDAwMDAwMDAwMH19",
"dependencies": [
"aws_route_table.public",
"aws_subnet.public_a",
"aws_vpc.main"
]
}
]
},
{
"mode": "managed",
"type": "aws_security_group",
"name": "web_sg",
"provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
"instances": [
{
"schema_version": 1,
"attributes": {
"arn": "arn:aws:ec2:us-west-2:000000000000:security-group/sg-ff0700449b3f0c236",
"description": "Allow HTTP/HTTPS only",
"egress": [
{
"cidr_blocks": [
"0.0.0.0/0"
],
"description": "",
"from_port": 0,
"ipv6_cidr_blocks": [],
"prefix_list_ids": [],
"protocol": "-1",
"security_groups": [],
"self": false,
"to_port": 0
}
],
"id": "sg-ff0700449b3f0c236",
"ingress": [
{
"cidr_blocks": [
"0.0.0.0/0"
],
"description": "HTTP",
"from_port": 80,
"ipv6_cidr_blocks": [],
"prefix_list_ids": [],
"protocol": "tcp",
"security_groups": [],
"self": false,
"to_port": 80
},
{
"cidr_blocks": [
"0.0.0.0/0"
],
"description": "HTTPS",
"from_port": 443,
"ipv6_cidr_blocks": [],
"prefix_list_ids": [],
"protocol": "tcp",
"security_groups": [],
"self": false,
"to_port": 443
}
],
"name": "web-demo-web-sg",
"name_prefix": "",
"owner_id": "000000000000",
"revoke_rules_on_delete": false,
"tags": {
"Name": "web-demo-web-sg"
},
"tags_all": {
"Name": "web-demo-web-sg"
},
"timeouts": null,
"vpc_id": "vpc-d2369b36584be2923"
},
"sensitive_attributes": [],
"identity_schema_version": 0,
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjo2MDAwMDAwMDAwMDAsImRlbGV0ZSI6OTAwMDAwMDAwMDAwfSwic2NoZW1hX3ZlcnNpb24iOiIxIn0=",
"dependencies": [
"aws_vpc.main"
]
}
]
},
{
"mode": "managed",
"type": "aws_subnet",
"name": "public_a",
"provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
"instances": [
{
"schema_version": 1,
"attributes": {
"arn": "arn:aws:ec2:us-west-2:000000000000:subnet/subnet-fabb34e9dcee4e10c",
"assign_ipv6_address_on_creation": false,
"availability_zone": "us-west-2a",
"availability_zone_id": "usw2-az2",
"cidr_block": "10.0.1.0/24",
"customer_owned_ipv4_pool": "",
"enable_dns64": false,
"enable_lni_at_device_index": 0,
"enable_resource_name_dns_a_record_on_launch": false,
"enable_resource_name_dns_aaaa_record_on_launch": false,
"id": "subnet-fabb34e9dcee4e10c",
"ipv6_cidr_block": "",
"ipv6_cidr_block_association_id": "",
"ipv6_native": false,
"map_customer_owned_ip_on_launch": false,
"map_public_ip_on_launch": true,
"outpost_arn": "",
"owner_id": "000000000000",
"private_dns_hostname_type_on_launch": "ip-name",
"tags": {
"Name": "web-demo-public-a"
},
"tags_all": {
"Name": "web-demo-public-a"
},
"timeouts": null,
"vpc_id": "vpc-d2369b36584be2923"
},
"sensitive_attributes": [],
"identity_schema_version": 0,
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjo2MDAwMDAwMDAwMDAsImRlbGV0ZSI6MTIwMDAwMDAwMDAwMH0sInNjaGVtYV92ZXJzaW9uIjoiMSJ9",
"dependencies": [
"aws_vpc.main"
]
}
]
},
{
"mode": "managed",
"type": "aws_vpc",
"name": "main",
"provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
"instances": [
{
"schema_version": 1,
"attributes": {
"arn": "arn:aws:ec2:us-west-2:000000000000:vpc/vpc-d2369b36584be2923",
"assign_generated_ipv6_cidr_block": false,
"cidr_block": "10.0.0.0/16",
"default_network_acl_id": "acl-c5ff179f0c8ec1efb",
"default_route_table_id": "rtb-44a01b63149b9fc2e",
"default_security_group_id": "sg-2f93b45397ffd42cf",
"dhcp_options_id": "default",
"enable_dns_hostnames": true,
"enable_dns_support": true,
"enable_network_address_usage_metrics": false,
"id": "vpc-d2369b36584be2923",
"instance_tenancy": "default",
"ipv4_ipam_pool_id": null,
"ipv4_netmask_length": null,
"ipv6_association_id": "",
"ipv6_cidr_block": "",
"ipv6_cidr_block_network_border_group": "",
"ipv6_ipam_pool_id": "",
"ipv6_netmask_length": 0,
"main_route_table_id": "rtb-44a01b63149b9fc2e",
"owner_id": "000000000000",
"tags": {
"Name": "web-demo-vpc"
},
"tags_all": {
"Name": "web-demo-vpc"
}
},
"sensitive_attributes": [],
"identity_schema_version": 0,
"private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ=="
}
]
}

View File

@@ -0,0 +1,9 @@
{
"version": 4,
"terraform_version": "1.12.2",
"serial": 27,
"lineage": "d4b3ead1-bf36-0a61-6b2a-8097a03862ed",
"outputs": {},
"resources": [],
"check_results": null
}

View File

@@ -0,0 +1,42 @@
variable "region" {
description = "AWS region"
type = string
default = "us-west-2"
}
variable "localstack_endpoint" {
description = "base url"
type = string
default = "http://localstack:4566"
}
variable "project_name" {
description = "name for tagging resources"
type = string
default = "web-demo"
}
variable "instance_type" {
description = "ec2 type"
type = string
default = "t2.micro"
}
variable "ami_id" {
description = "ami id for LocalStack EC2"
type = string
default = "ami-12345678"
}
variable "domain_name" {
description = "domain name to simulate in Route53 (LocalStack)"
type = string
default = "example.local"
}
variable "hosted_zone_name" {
description = "hosted zone name (must end with a dot)"
type = string
default = "example.local."
}

43
terraform/scripts/vpc.tf Normal file
View File

@@ -0,0 +1,43 @@
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_support = true
enable_dns_hostnames = true
tags = {
Name = "${var.project_name}-vpc"
}
}
resource "aws_subnet" "public_a" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
map_public_ip_on_launch = true
availability_zone = "us-west-2a"
tags = {
Name = "${var.project_name}-public-a"
}
}
resource "aws_internet_gateway" "gw" {
vpc_id = aws_vpc.main.id
tags = {
Name = "${var.project_name}-igw"
}
}
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
tags = {
Name = "${var.project_name}-public-rt"
}
}
resource "aws_route" "default_inet" {
route_table_id = aws_route_table.public.id
destination_cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.gw.id
}
resource "aws_route_table_association" "public_a" {
subnet_id = aws_subnet.public_a.id
route_table_id = aws_route_table.public.id
}