← Back to list

KodeKloud Engineer Day 98: Launch EC2 in Private VPC Subnet Using Terraform.

Hey Everyone! I have taken up the kodekloud engineer daily challenge [100 days of Devops] and through this series, we shall slowly but…

Jane Mils · 2026-06-01 16:58 · 0 claps · 12.7 min read
#kodekloud #kodekloudengineer #devops #terraform #aws
Open on Medium ↗
Wiki topics: ☁️ · DevOps & Cloud

KodeKloud Engineer Day 98: Launch EC2 in Private VPC Subnet Using Terraform.

Hey Everyone! I have taken up the kodekloud engineer daily challenge [100 days of Devops] and through this series, we shall slowly but steadily start solving the daily challenges.

Here’s the link to get started with the challenge: https://engineer.kodekloud.com/practice

Day #98 Task: Launch EC2 in Private VPC Subnet Using Terraform.

The Nautilus DevOps team is expanding their AWS infrastructure and requires the setup of a private Virtual Private Cloud (VPC) along with a subnet. This VPC and subnet configuration will ensure that resources deployed within them remain isolated from external networks and can only communicate within the VPC. Additionally, the team needs to provision an EC2 instance under the newly created private VPC. This instance should be accessible only from within the VPC, allowing for secure communication and resource management within the AWS environment.

  • Create a VPC named nautilus-priv-vpc with the CIDR block 10.0.0.0/16.
  • Create a subnet named nautilus-priv-subnet inside the VPC with the CIDR block 10.0.1.0/24 and auto-assign IP option must not be enabled.
  • Create an EC2 instance named nautilus-priv-ec2 inside the subnet and instance type must be t2.micro.
  • Ensure the security group of the EC2 instance allows access only from within the VPC’s CIDR block.
  • Create the main.tf file (do not create a separate .tf file) to provision the VPC, subnet and EC2 instance.
  • Use variables.tf file with the following variable names:

-- KKE_VPC_CIDR for the VPC CIDR block.

-- KKE_SUBNET_CIDR for the subnet CIDR block.

  • Use the outputs.tf file with the following variable names:

-- KKE_vpc_name for the name of the VPC.

-- KKE_subnet_name for the name of the subnet.

-- KKE_ec2_private for the name of the EC2 instance.

Notes:

  • The Terraform working directory is /home/bob/terraform.
  • Right-click under the EXPLORER section in VS Code and select Open in Integrated Terminal to launch the terminal.
  • Before submitting the task, ensure that terraform plan returns No changes. Your infrastructure matches the configuration.

Day #98 Task: Launch EC2 in Private VPC Subnet Using Terraform.

Day #98 Task: Launch EC2 in Private VPC Subnet Using Terraform.

Step-1: Verify the existing files in /home/bob/terraform.

Let’s check out the existing files in the */home/bob/terraform*path.

# Execute these commands from the terminal of the IDE.
bob@iac-server ~/terraform via 💠 default ✖ ls
README.MD  provider.tf

There’s a README.MD file and a provider.tf file, that has all the values required to create the VPC in the AWS account such as the region details, resource providers, etc.

Step-2: Create the variables.tf, outputs.tf and main.tf file in /home/bob/terraform.

Let’s first start with the variables.tf with the details defined in the problem statement.

# Create the variables.tf file in the /home/bob/terraform path
bob@iac-server ~/terraform via 💠 default ➜  vi variables.tf

# Content of the variables.tf file.
# For the VPC CIDR block.
  variable "KKE_VPC_CIDR" {
    default = "10.0.0.0/16"
  }

  # For the subnet CIDR block.
  variable "KKE_SUBNET_CIDR" {
    default = "10.0.1.0/24"
  }

Let’s now move on to the outputs.tf file with the details defined in the problem statement.

# Create the outputs.tf file in the /home/bob/terraform path
bob@iac-server ~/terraform via 💠 default ➜  vi outputs.tf

# Content of the outputs.tf file.
# For the name of the VPC.
output "KKE_vpc_name" {
  value = aws_vpc.nautilus_priv_vpc.tags["Name"]
}

# For the name of the subnet.
output "KKE_subnet_name" {
  value = aws_subnet.nautilus_priv_subnet.tags["Name"]
}

# For the name of the EC2 instance.
output "KKE_ec2_private" {
  value = aws_instance.nautilus_priv_ec2.tags["Name"]
}

Let’s create the main.tf file now, which uses these variables for creating the respective resources.

# Create the main.tf file in the /home/bob/terraform path
bob@iac-server ~/terraform via 💠 default ➜  vi main.tf

# Content of the main.tf file.

# 1. Create VPC.
resource "aws_vpc" "nautilus_priv_vpc" {
  cidr_block = var.KKE_VPC_CIDR

  tags = {
    Name = "nautilus-priv-vpc"
  }
}

# 2. Create Subnet.
resource "aws_subnet" "nautilus_priv_subnet" {
  vpc_id                  = aws_vpc.nautilus_priv_vpc.id
  cidr_block              = var.KKE_SUBNET_CIDR
  map_public_ip_on_launch = false

  tags = {
    Name = "nautilus-priv-subnet"
  }
}

# 3. Create Security Group.
resource "aws_security_group" "nautilus_priv_sg" {
  name        = "nautilus-priv-sg"
  description = "Allow traffic only within VPC"
  vpc_id      = aws_vpc.nautilus_priv_vpc.id

  ingress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = [var.KKE_VPC_CIDR]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = [var.KKE_VPC_CIDR]
  }
}

# 4. Create EC2 Instance.
resource "aws_instance" "nautilus_priv_ec2" {
  ami           = "ami-0c101f26f147fa7fd"
  instance_type = "t2.micro"

  subnet_id = aws_subnet.nautilus_priv_subnet.id

  vpc_security_group_ids = [
    aws_security_group.nautilus_priv_sg.id
  ]

  tags = {
    Name = "nautilus-priv-ec2"
  }
}

As per this main.tf file, we are creating a VPC, a private subnet in the VPC created, a security group and the ec2 instance.

We are using protocol value as ‘-1’ in the security group rules as our problem statement tells us to ‘Allow access only from within the VPC CIDR block’, which means allow all internal VPC communication within 10.0.0.0/16.

Step-3: Execute the terraform file and validate if the EC2 instance got created and launched in the private subnet successfully.

# Run 'terraform init' to initalize the working directory with the Terraform configurations.
bob@iac-server ~/terraform via 💠 default ➜  terraform init

Initializing the backend...
Initializing provider plugins...
- Finding hashicorp/aws versions matching "5.91.0"...
- Installing hashicorp/aws v5.91.0...
- Installed hashicorp/aws v5.91.0 (signed by HashiCorp)
Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

# Let's preview, what and all are getting created before actually creating the infra for validation by executing 'terraform plan'.

bob@iac-server ~/terraform via 💠 default ➜  terraform plan

Terraform used the selected providers to generate the following
execution plan. Resource actions are indicated with the following
symbols:
  + create

Terraform will perform the following actions:

  # aws_instance.nautilus_priv_ec2 will be created
  + resource "aws_instance" "nautilus_priv_ec2" {
      + ami                                  = "ami-0c101f26f147fa7fd"
      + arn                                  = (known after apply)
      + associate_public_ip_address          = (known after apply)
      + availability_zone                    = (known after apply)
      + cpu_core_count                       = (known after apply)
      + cpu_threads_per_core                 = (known after apply)
      + disable_api_stop                     = (known after apply)
      + disable_api_termination              = (known after apply)
      + ebs_optimized                        = (known after apply)
      + enable_primary_ipv6                  = (known after apply)
      + get_password_data                    = false
      + host_id                              = (known after apply)
      + host_resource_group_arn              = (known after apply)
      + iam_instance_profile                 = (known after apply)
      + id                                   = (known after apply)
      + instance_initiated_shutdown_behavior = (known after apply)
      + instance_lifecycle                   = (known after apply)
      + instance_state                       = (known after apply)
      + instance_type                        = "t2.micro"
      + ipv6_address_count                   = (known after apply)
      + ipv6_addresses                       = (known after apply)
      + key_name                             = (known after apply)
      + monitoring                           = (known after apply)
      + outpost_arn                          = (known after apply)
      + password_data                        = (known after apply)
      + placement_group                      = (known after apply)
      + placement_partition_number           = (known after apply)
      + primary_network_interface_id         = (known after apply)
      + private_dns                          = (known after apply)
      + private_ip                           = (known after apply)
      + public_dns                           = (known after apply)
      + public_ip                            = (known after apply)
      + secondary_private_ips                = (known after apply)
      + security_groups                      = (known after apply)
      + source_dest_check                    = true
      + spot_instance_request_id             = (known after apply)
      + subnet_id                            = (known after apply)
      + tags                                 = {
          + "Name" = "nautilus-priv-ec2"
        }
      + tags_all                             = {
          + "Name" = "nautilus-priv-ec2"
        }
      + tenancy                              = (known after apply)
      + user_data                            = (known after apply)
      + user_data_base64                     = (known after apply)
      + user_data_replace_on_change          = false
      + vpc_security_group_ids               = (known after apply)

      + capacity_reservation_specification (known after apply)

      + cpu_options (known after apply)

      + ebs_block_device (known after apply)

      + enclave_options (known after apply)

      + ephemeral_block_device (known after apply)

      + instance_market_options (known after apply)

      + maintenance_options (known after apply)

      + metadata_options (known after apply)

      + network_interface (known after apply)

      + private_dns_name_options (known after apply)

      + root_block_device (known after apply)
    }

  # aws_security_group.nautilus_priv_sg will be created
  + resource "aws_security_group" "nautilus_priv_sg" {
      + arn                    = (known after apply)
      + description            = "Allow traffic only within VPC"
      + egress                 = [
          + {
              + cidr_blocks      = [
                  + "10.0.0.0/16",
                ]
              + from_port        = 0
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "-1"
              + security_groups  = []
              + self             = false
              + to_port          = 0
                # (1 unchanged attribute hidden)
            },
        ]
      + id                     = (known after apply)
      + ingress                = [
          + {
              + cidr_blocks      = [
                  + "10.0.0.0/16",
                ]
              + from_port        = 0
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "-1"
              + security_groups  = []
              + self             = false
              + to_port          = 0
                # (1 unchanged attribute hidden)
            },
        ]
      + name                   = "nautilus-priv-sg"
      + name_prefix            = (known after apply)
      + owner_id               = (known after apply)
      + revoke_rules_on_delete = false
      + tags_all               = (known after apply)
      + vpc_id                 = (known after apply)
    }

  # aws_subnet.nautilus_priv_subnet will be created
  + resource "aws_subnet" "nautilus_priv_subnet" {
      + arn                                            = (known after apply)
      + assign_ipv6_address_on_creation                = false
      + availability_zone                              = (known after apply)
      + availability_zone_id                           = (known after apply)
      + cidr_block                                     = "10.0.1.0/24"
      + enable_dns64                                   = false
      + enable_resource_name_dns_a_record_on_launch    = false
      + enable_resource_name_dns_aaaa_record_on_launch = false
      + id                                             = (known after apply)
      + ipv6_cidr_block_association_id                 = (known after apply)
      + ipv6_native                                    = false
      + map_public_ip_on_launch                        = false
      + owner_id                                       = (known after apply)
      + private_dns_hostname_type_on_launch            = (known after apply)
      + tags                                           = {
          + "Name" = "nautilus-priv-subnet"
        }
      + tags_all                                       = {
          + "Name" = "nautilus-priv-subnet"
        }
      + vpc_id                                         = (known after apply)
    }

  # aws_vpc.nautilus_priv_vpc will be created
  + resource "aws_vpc" "nautilus_priv_vpc" {
      + arn                                  = (known after apply)
      + cidr_block                           = "10.0.0.0/16"
      + default_network_acl_id               = (known after apply)
      + default_route_table_id               = (known after apply)
      + default_security_group_id            = (known after apply)
      + dhcp_options_id                      = (known after apply)
      + enable_dns_hostnames                 = (known after apply)
      + enable_dns_support                   = true
      + enable_network_address_usage_metrics = (known after apply)
      + id                                   = (known after apply)
      + instance_tenancy                     = "default"
      + ipv6_association_id                  = (known after apply)
      + ipv6_cidr_block                      = (known after apply)
      + ipv6_cidr_block_network_border_group = (known after apply)
      + main_route_table_id                  = (known after apply)
      + owner_id                             = (known after apply)
      + tags                                 = {
          + "Name" = "nautilus-priv-vpc"
        }
      + tags_all                             = {
          + "Name" = "nautilus-priv-vpc"
        }
    }

Plan: 4 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + KKE_ec2_private = "nautilus-priv-ec2"
  + KKE_subnet_name = "nautilus-priv-subnet"
  + KKE_vpc_name    = "nautilus-priv-vpc"

──────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform
can't guarantee to take exactly these actions if you run "terraform
apply" now.

# Let's actually create the resources by running 'terraform apply'.
bob@iac-server ~/terraform via 💠 default ➜  terraform apply

Terraform used the selected providers to generate the following
execution plan. Resource actions are indicated with the following
symbols:
  + create

Terraform will perform the following actions:

  # aws_instance.nautilus_priv_ec2 will be created
  + resource "aws_instance" "nautilus_priv_ec2" {
      + ami                                  = "ami-0c101f26f147fa7fd"
      + arn                                  = (known after apply)
      + associate_public_ip_address          = (known after apply)
      + availability_zone                    = (known after apply)
      + cpu_core_count                       = (known after apply)
      + cpu_threads_per_core                 = (known after apply)
      + disable_api_stop                     = (known after apply)
      + disable_api_termination              = (known after apply)
      + ebs_optimized                        = (known after apply)
      + enable_primary_ipv6                  = (known after apply)
      + get_password_data                    = false
      + host_id                              = (known after apply)
      + host_resource_group_arn              = (known after apply)
      + iam_instance_profile                 = (known after apply)
      + id                                   = (known after apply)
      + instance_initiated_shutdown_behavior = (known after apply)
      + instance_lifecycle                   = (known after apply)
      + instance_state                       = (known after apply)
      + instance_type                        = "t2.micro"
      + ipv6_address_count                   = (known after apply)
      + ipv6_addresses                       = (known after apply)
      + key_name                             = (known after apply)
      + monitoring                           = (known after apply)
      + outpost_arn                          = (known after apply)
      + password_data                        = (known after apply)
      + placement_group                      = (known after apply)
      + placement_partition_number           = (known after apply)
      + primary_network_interface_id         = (known after apply)
      + private_dns                          = (known after apply)
      + private_ip                           = (known after apply)
      + public_dns                           = (known after apply)
      + public_ip                            = (known after apply)
      + secondary_private_ips                = (known after apply)
      + security_groups                      = (known after apply)
      + source_dest_check                    = true
      + spot_instance_request_id             = (known after apply)
      + subnet_id                            = (known after apply)
      + tags                                 = {
          + "Name" = "nautilus-priv-ec2"
        }
      + tags_all                             = {
          + "Name" = "nautilus-priv-ec2"
        }
      + tenancy                              = (known after apply)
      + user_data                            = (known after apply)
      + user_data_base64                     = (known after apply)
      + user_data_replace_on_change          = false
      + vpc_security_group_ids               = (known after apply)

      + capacity_reservation_specification (known after apply)

      + cpu_options (known after apply)

      + ebs_block_device (known after apply)

      + enclave_options (known after apply)

      + ephemeral_block_device (known after apply)

      + instance_market_options (known after apply)

      + maintenance_options (known after apply)

      + metadata_options (known after apply)

      + network_interface (known after apply)

      + private_dns_name_options (known after apply)

      + root_block_device (known after apply)
    }

  # aws_security_group.nautilus_priv_sg will be created
  + resource "aws_security_group" "nautilus_priv_sg" {
      + arn                    = (known after apply)
      + description            = "Allow traffic only within VPC"
      + egress                 = [
          + {
              + cidr_blocks      = [
                  + "10.0.0.0/16",
                ]
              + from_port        = 0
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "-1"
              + security_groups  = []
              + self             = false
              + to_port          = 0
                # (1 unchanged attribute hidden)
            },
        ]
      + id                     = (known after apply)
      + ingress                = [
          + {
              + cidr_blocks      = [
                  + "10.0.0.0/16",
                ]
              + from_port        = 0
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "-1"
              + security_groups  = []
              + self             = false
              + to_port          = 0
                # (1 unchanged attribute hidden)
            },
        ]
      + name                   = "nautilus-priv-sg"
      + name_prefix            = (known after apply)
      + owner_id               = (known after apply)
      + revoke_rules_on_delete = false
      + tags_all               = (known after apply)
      + vpc_id                 = (known after apply)
    }

  # aws_subnet.nautilus_priv_subnet will be created
  + resource "aws_subnet" "nautilus_priv_subnet" {
      + arn                                            = (known after apply)
      + assign_ipv6_address_on_creation                = false
      + availability_zone                              = (known after apply)
      + availability_zone_id                           = (known after apply)
      + cidr_block                                     = "10.0.1.0/24"
      + enable_dns64                                   = false
      + enable_resource_name_dns_a_record_on_launch    = false
      + enable_resource_name_dns_aaaa_record_on_launch = false
      + id                                             = (known after apply)
      + ipv6_cidr_block_association_id                 = (known after apply)
      + ipv6_native                                    = false
      + map_public_ip_on_launch                        = false
      + owner_id                                       = (known after apply)
      + private_dns_hostname_type_on_launch            = (known after apply)
      + tags                                           = {
          + "Name" = "nautilus-priv-subnet"
        }
      + tags_all                                       = {
          + "Name" = "nautilus-priv-subnet"
        }
      + vpc_id                                         = (known after apply)
    }

  # aws_vpc.nautilus_priv_vpc will be created
  + resource "aws_vpc" "nautilus_priv_vpc" {
      + arn                                  = (known after apply)
      + cidr_block                           = "10.0.0.0/16"
      + default_network_acl_id               = (known after apply)
      + default_route_table_id               = (known after apply)
      + default_security_group_id            = (known after apply)
      + dhcp_options_id                      = (known after apply)
      + enable_dns_hostnames                 = (known after apply)
      + enable_dns_support                   = true
      + enable_network_address_usage_metrics = (known after apply)
      + id                                   = (known after apply)
      + instance_tenancy                     = "default"
      + ipv6_association_id                  = (known after apply)
      + ipv6_cidr_block                      = (known after apply)
      + ipv6_cidr_block_network_border_group = (known after apply)
      + main_route_table_id                  = (known after apply)
      + owner_id                             = (known after apply)
      + tags                                 = {
          + "Name" = "nautilus-priv-vpc"
        }
      + tags_all                             = {
          + "Name" = "nautilus-priv-vpc"
        }
    }

Plan: 4 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + KKE_ec2_private = "nautilus-priv-ec2"
  + KKE_subnet_name = "nautilus-priv-subnet"
  + KKE_vpc_name    = "nautilus-priv-vpc"

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_vpc.nautilus_priv_vpc: Creating...
aws_vpc.nautilus_priv_vpc: Creation complete after 1s [id=vpc-b990f630eb835b304]
aws_subnet.nautilus_priv_subnet: Creating...
aws_security_group.nautilus_priv_sg: Creating...
aws_subnet.nautilus_priv_subnet: Creation complete after 0s [id=subnet-cf85ac19db39315b8]
aws_security_group.nautilus_priv_sg: Creation complete after 0s [id=sg-5ff911a7f6501ceab]
aws_instance.nautilus_priv_ec2: Creating...
aws_instance.nautilus_priv_ec2: Still creating... [10s elapsed]
aws_instance.nautilus_priv_ec2: Creation complete after 10s [id=i-e0da59b6785b44766]

Apply complete! Resources: 4 added, 0 changed, 0 destroyed.

Outputs:

KKE_ec2_private = "nautilus-priv-ec2"
KKE_subnet_name = "nautilus-priv-subnet"
KKE_vpc_name = "nautilus-priv-vpc"

Let’s now verify if the resources are created successfully.

# Run 'terraform state list' to track all the infrastructure created by terraform in the state file.
bob@iac-server ~/terraform via 💠 default ➜  terraform state list

aws_instance.nautilus_priv_ec2
aws_security_group.nautilus_priv_sg
aws_subnet.nautilus_priv_subnet
aws_vpc.nautilus_priv_vpc

# Verify if all the resources are created successfully.

#1. Verify if the VPC got created successfully.
bob@iac-server ~/terraform via 💠 default ➜ aws ec2 describe-vpcs
{
    "Vpcs": [
        {
            "OwnerId": "000000000000",
            "InstanceTenancy": "default",
            "Ipv6CidrBlockAssociationSet": [],
            "CidrBlockAssociationSet": [
                {
                    "AssociationId": "vpc-cidr-assoc-a41995711ae492eec",
                    "CidrBlock": "172.31.0.0/16",
                    "CidrBlockState": {
                        "State": "associated"
                    }
                }
            ],
            "IsDefault": true,
            "Tags": [],
            "VpcId": "vpc-e030027e9c2f78498",
            "State": "available",
            "CidrBlock": "172.31.0.0/16",
            "DhcpOptionsId": "default"
        },
        {
            "OwnerId": "000000000000",
            "InstanceTenancy": "default",
            "Ipv6CidrBlockAssociationSet": [],
            "CidrBlockAssociationSet": [
                {
                    "AssociationId": "vpc-cidr-assoc-3bdfa41ab1c64544a",
                    "CidrBlock": "10.0.0.0/16",
                    "CidrBlockState": {
                        "State": "associated"
                    }
                }
            ],
            "IsDefault": false,
            "Tags": [
                {
                    "Key": "Name",
                    "Value": "nautilus-priv-vpc"
                }
            ],
            "VpcId": "vpc-b990f630eb835b304",
            "State": "available",
            "CidrBlock": "10.0.0.0/16",
            "DhcpOptionsId": "default"
        }
    ]
}

#2. Verify if the subnet got created successfully.
bob@iac-server ~/terraform via 💠 default ➜  aws ec2 describe-subnets -
-filters "Name=tag:Name,Values=nautilus-priv-subnet" --region us-east-1
{
    "Subnets": [
        {
            "AvailabilityZoneId": "use1-az2",
            "OwnerId": "000000000000",
            "AssignIpv6AddressOnCreation": false,
            "Ipv6CidrBlockAssociationSet": [],
            "Tags": [
                {
                    "Key": "Name",
                    "Value": "nautilus-priv-subnet"
                }
            ],
            "SubnetArn": "arn:aws:ec2:us-east-1:000000000000:subnet/subnet-cf85ac19db39315b8",
            "Ipv6Native": false,
            "PrivateDnsNameOptionsOnLaunch": {
                "HostnameType": "ip-name"
            },
            "SubnetId": "subnet-cf85ac19db39315b8",
            "State": "available",
            "VpcId": "vpc-b990f630eb835b304",
            "CidrBlock": "10.0.1.0/24",
            "AvailableIpAddressCount": 250,
            "AvailabilityZone": "us-east-1c",
            "DefaultForAz": false,
            "MapPublicIpOnLaunch": false
        }
    ]
}

#3. Verify if the security group got created successfully.
bob@iac-server ~/terraform via 💠 default ➜ aws ec2 describe-security-groups --filters "Name=group-name,Values=nautilus-priv-sg" --region us-e
ast-1
{
    "SecurityGroups": [
        {
            "GroupId": "sg-5ff911a7f6501ceab",
            "IpPermissionsEgress": [
                {
                    "IpProtocol": "-1",
                    "UserIdGroupPairs": [],
                    "IpRanges": [
                        {
                            "CidrIp": "10.0.0.0/16"
                        }
                    ],
                    "Ipv6Ranges": [],
                    "PrefixListIds": []
                }
            ],
            "Tags": [],
            "VpcId": "vpc-b990f630eb835b304",
            "SecurityGroupArn": "arn:aws:ec2:us-east-1:000000000000:security-group/sg-5ff911a7f6501ceab",
            "OwnerId": "000000000000",
            "GroupName": "nautilus-priv-sg",
            "Description": "Allow traffic only within VPC",
            "IpPermissions": [
                {
                    "IpProtocol": "-1",
                    "UserIdGroupPairs": [],
                    "IpRanges": [
                        {
                            "CidrIp": "10.0.0.0/16"
                        }
                    ],
                    "Ipv6Ranges": [],
                    "PrefixListIds": []
                }
            ]
        }
    ]
}

#4. Verify if the ec2-instance got created successfully.
bob@iac-server ~/terraform via 💠 default ➜  aws ec2 describe-instances
{
    "Reservations": [
        {
            "ReservationId": "r-825695c8dd224827f",
            "OwnerId": "000000000000",
            "Groups": [],
            "Instances": [
                {
                    "Architecture": "x86_64",
                    "BlockDeviceMappings": [
                        {
                            "DeviceName": "/dev/sda1",
                            "Ebs": {
                                "AttachTime": "2026-05-28T08:25:00Z",
                                "DeleteOnTermination": true,
                                "Status": "in-use",
                                "VolumeId": "vol-55c6f300abb6a9e98"
                            }
                        }
                    ],
                    "ClientToken": "ABCDE0000000000003",
                    "EbsOptimized": false,
                    "Hypervisor": "xen",
                    "NetworkInterfaces": [
                        {
                            "Attachment": {
                                "AttachTime": "2015-01-01T00:00:00Z",
                                "AttachmentId": "eni-attach-01dde7944ad441fce",
                                "DeleteOnTermination": true,
                                "DeviceIndex": 0,
                                "Status": "attached"
                            },
                            "Description": "Primary network interface",
                            "Groups": [
                                {
                                    "GroupId": "sg-5ff911a7f6501ceab",
                                    "GroupName": "nautilus-priv-sg"
                                }
                            ],
                            "MacAddress": "1b:2b:3c:4d:5e:6f",
                            "NetworkInterfaceId": "eni-88ba186b521336f36",
                            "OwnerId": "000000000000",
                            "PrivateIpAddress": "10.0.1.4",
                            "PrivateIpAddresses": [
                                {
                                    "Primary": true,
                                    "PrivateIpAddress": "10.0.1.4"
                                }
                            ],
                            "SourceDestCheck": true,
                            "Status": "in-use",
                            "SubnetId": "subnet-cf85ac19db39315b8",
                            "VpcId": "vpc-b990f630eb835b304"
                        }
                    ],
                    "RootDeviceName": "/dev/sda1",
                    "RootDeviceType": "ebs",
                    "SecurityGroups": [
                        {
                            "GroupId": "sg-5ff911a7f6501ceab",
                            "GroupName": "nautilus-priv-sg"
                        }
                    ],
                    "SourceDestCheck": true,
                    "StateReason": {
                        "Code": "",
                        "Message": ""
                    },
                    "Tags": [
                        {
                            "Key": "Name",
                            "Value": "nautilus-priv-ec2"
                        }
                    ],
                    "VirtualizationType": "paravirtual",
                    "HibernationOptions": {
                        "Configured": false
                    },
                    "MetadataOptions": {
                        "HttpTokens": "optional",
                        "HttpPutResponseHopLimit": 1,
                        "HttpEndpoint": "enabled",
                        "HttpProtocolIpv6": "disabled",
                        "InstanceMetadataTags": "disabled"
                    },
                    "InstanceId": "i-e0da59b6785b44766",
                    "ImageId": "ami-0c101f26f147fa7fd",
                    "State": {
                        "Code": 16,
                        "Name": "running"
                    },
                    "PrivateDnsName": "ip-10-0-1-4.ec2.internal",
                    "PublicDnsName": "None",
                    "StateTransitionReason": "",
                    "AmiLaunchIndex": 0,
                    "InstanceType": "t2.micro",
                    "LaunchTime": "2026-05-28T08:25:00Z",
                    "Placement": {
                        "GroupName": "",
                        "Tenancy": "default",
                        "AvailabilityZone": "us-east-1c"
                    },
                    "KernelId": "None",
                    "Monitoring": {
                        "State": "disabled"
                    },
                    "SubnetId": "subnet-cf85ac19db39315b8",
                    "VpcId": "vpc-b990f630eb835b304",
                    "PrivateIpAddress": "10.0.1.4"
                }
            ]
        }
    ]
}

That’s it for Day #98. Let’s hop on to the next challenge! See you there! Toodaloo!


메타데이터
post_id
d57bf9faaa5d
slug
kodekloud-engineer-day-98-launch-ec2-in-private-vpc-subnet-using-terraform-d57bf9faaa5d
url
https://medium.com/@janemils/kodekloud-engineer-day-98-launch-ec2-in-private-vpc-subnet-using-terraform-d57bf9faaa5d
canonical_url
https://medium.com/@janemils/kodekloud-engineer-day-98-launch-ec2-in-private-vpc-subnet-using-terraform-d57bf9faaa5d
author_url
https://medium.com/@janemils
status
ok
fetched_at
2026-06-21 19:25:17