{"id":12976,"date":"2019-11-11T08:39:37","date_gmt":"2019-11-11T07:39:37","guid":{"rendered":"https:\/\/www.dbi-services.com\/blog\/a-simple-terraform-script-to-create-an-aws-ec2-playground\/"},"modified":"2019-11-11T08:39:37","modified_gmt":"2019-11-11T07:39:37","slug":"a-simple-terraform-script-to-create-an-aws-ec2-playground","status":"publish","type":"post","link":"https:\/\/www.dbi-services.com\/blog\/a-simple-terraform-script-to-create-an-aws-ec2-playground\/","title":{"rendered":"A simple Terraform script to create an AWS EC2 playground"},"content":{"rendered":"<p>When I started to write the blog about <a href=\"https:\/\/www.dbi-services.com\/blog\/avoiding-patching-madness-by-using-aws-ssm\/\" target=\"_blank\" rel=\"noopener noreferrer\">AWS SSM<\/a> I quickly realized that I need a way to bring up and destroy my AWS EC2 playground in an easy and reproducible way. There are several options for this: I could have used the <a href=\"https:\/\/aws.amazon.com\/cli\/\" target=\"_blank\" rel=\"noopener noreferrer\">AWS command line interface<\/a> or <a href=\"https:\/\/aws.amazon.com\/cloudformation\/\" target=\"_blank\" rel=\"noopener noreferrer\">AWS CloudFormation<\/a>. Both work pretty well and would have been more than enough for my simple requirements. In the end I decided to use <a href=\"https:\/\/www.terraform.io\/\" target=\"_blank\" rel=\"noopener noreferrer\">Terraform<\/a> for one simple reason: With Terraform you can not only provision on <a href=\"https:\/\/www.aws.com\" target=\"_blank\" rel=\"noopener noreferrer\">AWS<\/a> but also on <a href=\"https:\/\/azure.microsoft.com\/en-us\/\" target=\"_blank\" rel=\"noopener noreferrer\">Azure<\/a>, <a href=\"https:\/\/cloud.google.com\/\" target=\"_blank\" rel=\"noopener noreferrer\">GCP<\/a> and <a href=\"https:\/\/www.terraform.io\/docs\/providers\/index.html\" target=\"_blank\" rel=\"noopener noreferrer\">many others<\/a>. So, instead of using a tool which is limited to AWS, using a tool which is vendor independent make much more sense. <\/p>\n<p><!--more--><\/p>\n<p>For the <a href=\"https:\/\/www.dbi-services.com\/blog\/avoiding-patching-madness-by-using-aws-ssm\/\" target=\"_blank\" rel=\"noopener noreferrer\">AWS SSM blog<\/a> I had several requirements I wanted to address:<\/p>\n<ul>\n<li>The playground should run in my on <a href=\"https:\/\/aws.amazon.com\/vpc\/\">VPC<\/a> so I will not affect any other people doing tests at the same time<\/li>\n<li>Because I had Windows and Linux EC2 instances two <a href=\"https:\/\/docs.aws.amazon.com\/vpc\/latest\/userguide\/VPC_SecurityGroups.html\" target=\"_blank\" rel=\"noopener noreferrer\">security groups<\/a> should get created, one allowing SSH and one allowing RDP into the EC2 machines<\/li>\n<li>Both security groups should allow outbound connections to the internet by using an <a href=\"https:\/\/docs.aws.amazon.com\/vpc\/latest\/userguide\/VPC_Internet_Gateway.html\" target=\"_blank\" rel=\"noopener noreferrer\">internet gateway<\/a><\/li>\n<li>Finally two Windows, two Ubuntu, two Red Hat, two SLES and two CentOS instances should get provisioned<\/li>\n<\/ul>\n<p>Using Terraform all of this is actually quite simple. The first information you&#8217;ll need to tell Terraform is the provider you want to use. In my case this is AWS and I am using my &#8220;test&#8221; <a href=\"https:\/\/docs.aws.amazon.com\/cli\/latest\/userguide\/cli-configure-profiles.html\" target=\"_blank\" rel=\"noopener noreferrer\">AWS profile<\/a> which is configured for my AWS command line interface, the <a href=\"https:\/\/docs.aws.amazon.com\/AWSEC2\/latest\/UserGuide\/using-regions-availability-zones.html\" target=\"_blank\" rel=\"noopener noreferrer\">AWS region<\/a> I want to use is Frankfurt:<\/p>\n<pre class=\"brush: bash; gutter: true; first-line: 1\">\n\/\/ set the provider to AWS and the AWS region to eu-central-1\nprovider \"aws\" {\n  profile    = \"test\"\n  region     = \"eu-central-1\"\n}\n<\/pre>\n<p>Because I want to limit direct access to the EC2 instances to my own IP address for security reasons I am defining a local variable I am changing each time I am setting this up from a different network. <a href=\"https:\/\/www.terraform.io\/docs\/configuration-0-11\/variables.html\" target=\"_blank\" rel=\"noopener noreferrer\">Input variables<\/a> could also be used for that but in my case a local variable is just fine:<\/p>\n<pre class=\"brush: bash; gutter: true; first-line: 1\">\nlocals {\n  my_ip        = [\"37.201.6.8\/32\"]\n}\n<\/pre>\n<p>The first component that actually gets provisioned on AWS is the VPC usinf the <a href=\"https:\/\/www.terraform.io\/docs\/providers\/aws\/r\/vpc.html\" target=\"_blank\" rel=\"noopener noreferrer\">aws_vpc<\/a> resource::<\/p>\n<pre class=\"brush: bash; gutter: true; first-line: 1\">\n\/\/ create the virtual private network\nresource \"aws_vpc\" \"dwe-vpc\" {\n  cidr_block = \"10.0.0.0\/16\"\n  enable_dns_hostnames = true\n  enable_dns_support = true\n\n  tags = {\n    Name = \"dwe-vpc\"\n  }\n}\n<\/pre>\n<p>This defines the IP range I&#8217;ll be using, switches the dns parameters to on and gets a tag. As I want my EC2 instances to be able to connect to the internet an internet gateway gets provisioned in the next step, which is attached to the VPC that was created in the step before:<\/p>\n<pre class=\"brush: bash; gutter: true; first-line: 1\">\n\/\/ create the internet gateway\nresource \"aws_internet_gateway\" \"dwe-igw\" {\n  vpc_id = \"${aws_vpc.dwe-vpc.id}\"\n\n  tags = {\n    Name = \"dwe-igw\"\n  }\n}\n<\/pre>\n<p>Next we need a subnet, again attached to the VPC:<\/p>\n<pre class=\"brush: bash; gutter: true; first-line: 1\">\n\/\/ create a dedicated subnet\nresource \"aws_subnet\" \"dwe-subnet\" {\n  vpc_id            = \"${aws_vpc.dwe-vpc.id}\"\n  cidr_block        = \"10.0.1.0\/24\"\n  availability_zone = \"eu-central-1a\"\n\n  tags = {\n    Name = \"dwe-subnet\"\n  }\n}\n<\/pre>\n<p><a href=\"https:\/\/docs.aws.amazon.com\/vpc\/latest\/userguide\/VPC_Route_Tables.html\" target=\"blank\" rel=\"noopener noreferrer\">Routing tables<\/a> are an important concept in AWS and define how traffic is routed in the VPC. The routing table below enables traffic to the internet through the internet gateway:<\/p>\n<pre class=\"brush: bash; gutter: true; first-line: 1\">\n\/\/ create routing table which points to the internet gateway\nresource \"aws_route_table\" \"dwe-route\" {\n  vpc_id = \"${aws_vpc.dwe-vpc.id}\"\n\n  route {\n    cidr_block = \"0.0.0.0\/0\"\n    gateway_id = \"${aws_internet_gateway.dwe-igw.id}\"\n  }\n\n  tags = {\n    Name = \"dwe-igw\"\n  }\n}\n<\/pre>\n<p>Once the routing table is defined it needs to be attached to the subnet:<\/p>\n<pre class=\"brush: bash; gutter: true; first-line: 1\">\n\/\/ associate the routing table with the subnet\nresource \"aws_route_table_association\" \"subnet-association\" {\n  subnet_id      = \"${aws_subnet.dwe-subnet.id}\"\n  route_table_id = \"${aws_route_table.dwe-route.id}\"\n}\n<\/pre>\n<p>For ssh and rdp access to the EC2 instances two security groups get provisioned:<\/p>\n<pre class=\"brush: bash; gutter: true; first-line: 1\">\n\/\/ create a security group for ssh access to the linux systems\nresource \"aws_security_group\" \"dwe-sg-ssh\" {\n  name        = \"dwe-sg-ssh\"\n  description = \"Allow SSH inbound traffic\"\n  vpc_id      = \"${aws_vpc.dwe-vpc.id}\"\n\n  ingress {\n    from_port   = 22\n    to_port     = 22\n    protocol    = \"tcp\"\n    cidr_blocks = local.my_ip\n  }\n\n  \/\/ allow access to the internet\n  egress {\n    from_port   = 0\n    to_port     = 0\n    protocol    = \"-1\"\n    cidr_blocks = [\"0.0.0.0\/0\"]\n  }\n\n  tags = {\n    Name = \"dwe-sg-ssh\"\n  }\n}\n\n\/\/ create a security group for rdp access to the windows systems\nresource \"aws_security_group\" \"dwe-sg-rdp\" {\nname        = \"dwe-sg-rdp\"\nvpc_id      = \"${aws_vpc.dwe-vpc.id}\"\ndescription = \"Allow RDP inbound traffic\"\n\n  ingress {\n    from_port   = 3389\n    to_port     = 3389\n    protocol    = \"tcp\"\n    cidr_blocks = local.my_ip\n  }\n\n  \/\/ allow access to the internet\n  egress {\n    from_port   = 0\n    to_port     = 0\n    protocol    = \"-1\"\n    cidr_blocks = [\"0.0.0.0\/0\"]\n  }\n\n\n  tags = {\n    Name = \"dwe-sg-rdp\"\n  }\n}\n<\/pre>\n<p>Both define an inbound rule (ssh and rdp) and an outbound rule for being able to connect the internet. Now, as all the basics are there the EC2 instances itself get provisioned based on the building blocks from above:<\/p>\n<pre class=\"brush: bash; gutter: true; first-line: 1\">\n\/\/ create two Ubuntu instances\nresource \"aws_instance\" \"i-ubuntu-linux-prod\" {\n  ami                         = \"ami-0cc0a36f626a4fdf5\"\n  instance_type               = \"t2.micro\"\n  key_name                    = \"dwe-key-pair\"\n  vpc_security_group_ids      = [\"${aws_security_group.dwe-sg-ssh.id}\"]\n  subnet_id                   = \"${aws_subnet.dwe-subnet.id}\"\n  associate_public_ip_address = \"true\"\n\n  root_block_device {\n    volume_size           = \"10\"\n    volume_type           = \"standard\"\n    delete_on_termination = \"true\"\n  }\n  \n  tags = {\n    Name = \"i-ubuntu-linux-prod\"\n  }  \n}\n\nresource \"aws_instance\" \"i-ubuntu-linux-test\" {\n  ami                         = \"ami-0cc0a36f626a4fdf5\"\n  instance_type               = \"t2.micro\"\n  key_name                    = \"dwe-key-pair\"\n  vpc_security_group_ids      = [\"${aws_security_group.dwe-sg-ssh.id}\"]\n  subnet_id                   = \"${aws_subnet.dwe-subnet.id}\"\n  associate_public_ip_address = \"true\"\n\n  root_block_device {\n    volume_size           = \"10\"\n    volume_type           = \"standard\"\n    delete_on_termination = \"true\"\n  }\n\n  tags = {\n    Name = \"i-ubuntu-linux-test\"\n  } \n}\n\n\/\/ create two Amazon linux instances\nresource \"aws_instance\" \"i-amazon-linux-prod\" {\n  ami                         = \"ami-0f3a43fbf2d3899f7\"\n  instance_type               = \"t2.micro\"\n  key_name                    = \"dwe-key-pair\"\n  vpc_security_group_ids      = [\"${aws_security_group.dwe-sg-ssh.id}\"]\n  subnet_id                   = \"${aws_subnet.dwe-subnet.id}\"\n  associate_public_ip_address = \"true\"\n\n  root_block_device {\n    volume_size           = \"10\"\n    volume_type           = \"standard\"\n    delete_on_termination = \"true\"\n  }\n\n  tags = {\n    Name = \"i-amazon-linux-prod\"\n  } \n}\n\nresource \"aws_instance\" \"i-amazon-linux-test\" {\n  ami                         = \"ami-0f3a43fbf2d3899f7\"\n  instance_type               = \"t2.micro\"\n  key_name                    = \"dwe-key-pair\"\n  vpc_security_group_ids      = [\"${aws_security_group.dwe-sg-ssh.id}\"]\n  subnet_id                   = \"${aws_subnet.dwe-subnet.id}\"\n  associate_public_ip_address = \"true\"\n\n  root_block_device {\n    volume_size           = \"10\"\n    volume_type           = \"standard\"\n    delete_on_termination = \"true\"\n  }\n\n  tags = {\n    Name = \"i-amazon-linux-test\"\n  } \n}\n\n\/\/ create two Red Hat linux instances\nresource \"aws_instance\" \"i-redhat-linux-prod\" {\n  ami                         = \"ami-0badcc5b522737046\"\n  instance_type               = \"t2.micro\"\n  key_name                    = \"dwe-key-pair\"\n  vpc_security_group_ids      = [\"${aws_security_group.dwe-sg-ssh.id}\"]\n  subnet_id                   = \"${aws_subnet.dwe-subnet.id}\"\n  associate_public_ip_address = \"true\"\n\n  root_block_device {\n    volume_size           = \"10\"\n    volume_type           = \"standard\"\n    delete_on_termination = \"true\"\n  }\n\n  tags = {\n    Name = \"i-redhat-linux-prod\"\n  } \n}\n\nresource \"aws_instance\" \"i-redhat-linux-test\" {\n  ami                         = \"ami-0badcc5b522737046\"\n  instance_type               = \"t2.micro\"\n  key_name                    = \"dwe-key-pair\"\n  vpc_security_group_ids      = [\"${aws_security_group.dwe-sg-ssh.id}\"]\n  subnet_id                   = \"${aws_subnet.dwe-subnet.id}\"\n  associate_public_ip_address = \"true\"\n  \n  root_block_device {     \n    volume_size           = \"10\"\n    volume_type           = \"standard\"\n    delete_on_termination = \"true\"\n  }\n  \n  tags = { \n    Name = \"i-redhat-linux-test\"\n  }\n}\n\n\/\/ create two SUSE linux instances\nresource \"aws_instance\" \"i-suse-linux-prod\" {\n  ami                         = \"ami-03b86a97a8f02d44e\"\n  instance_type               = \"t2.micro\"\n  key_name                    = \"dwe-key-pair\"\n  vpc_security_group_ids      = [\"${aws_security_group.dwe-sg-ssh.id}\"]\n  subnet_id                   = \"${aws_subnet.dwe-subnet.id}\"\n  associate_public_ip_address = \"true\"\n\n  root_block_device { \n    volume_size           = \"10\"\n    volume_type           = \"standard\"\n    delete_on_termination = \"true\"\n  }\n\n  tags = { \n    Name = \"i-suse-linux-prod\"\n  }\n}\n\nresource \"aws_instance\" \"i-suse-linux-test\" {\n  ami                         = \"ami-03b86a97a8f02d44e\"\n  instance_type               = \"t2.micro\"\n  key_name                    = \"dwe-key-pair\"\n  vpc_security_group_ids      = [\"${aws_security_group.dwe-sg-ssh.id}\"]\n  subnet_id                   = \"${aws_subnet.dwe-subnet.id}\"\n  associate_public_ip_address = \"true\"\n  \n  root_block_device {     \n    volume_size           = \"10\"\n    volume_type           = \"standard\"\n    delete_on_termination = \"true\"\n  }\n  \n  tags = { \n    Name = \"i-suse-linux-test\"\n  }\n}\n\n\/\/ create two CentOS linux instances\nresource \"aws_instance\" \"i-centos-linux-prod\" {\n  ami                         = \"ami-04cf43aca3e6f3de3\"\n  instance_type               = \"t2.micro\"\n  key_name                    = \"dwe-key-pair\"\n  vpc_security_group_ids      = [\"${aws_security_group.dwe-sg-ssh.id}\"]\n  subnet_id                   = \"${aws_subnet.dwe-subnet.id}\"\n  associate_public_ip_address = \"true\"\n\n  root_block_device { \n    volume_size           = \"10\"\n    volume_type           = \"standard\"\n    delete_on_termination = \"true\"\n  }\n\n  tags = { \n    Name = \"i-centos-linux-prod\"\n  }\n}\n\nresource \"aws_instance\" \"i-centos-linux-test\" {\n  ami                         = \"ami-04cf43aca3e6f3de3\"\n  instance_type               = \"t2.micro\"\n  key_name                    = \"dwe-key-pair\"\n  vpc_security_group_ids      = [\"${aws_security_group.dwe-sg-ssh.id}\"]\n  subnet_id                   = \"${aws_subnet.dwe-subnet.id}\"\n  associate_public_ip_address = \"true\"\n  \n  root_block_device {     \n    volume_size           = \"10\"\n    volume_type           = \"standard\"\n    delete_on_termination = \"true\"\n  }\n  \n  tags = { \n    Name = \"i-centos-linux-test\"\n  }\n}\n\n\/\/ create two Windows instances\nresource \"aws_instance\" \"i-windows-prod\" {\n  ami           = \"ami-034937fd7f621ba85\"\n  instance_type = \"t2.micro\"\n  key_name                    = \"dwe-key-pair\"\n  vpc_security_group_ids      = [\"${aws_security_group.dwe-sg-rdp.id}\"]\n  subnet_id                   = \"${aws_subnet.dwe-subnet.id}\"\n  associate_public_ip_address = \"true\"\n\n  root_block_device { \n    volume_size           = \"30\"\n    volume_type           = \"standard\"\n    delete_on_termination = \"true\"\n  }\n\n  tags = { \n    Name = \"i-windows-prod\"\n  }\n}\n\nresource \"aws_instance\" \"i-windows-test\" {\n  ami           = \"ami-034937fd7f621ba85\"\n  instance_type = \"t2.micro\"\n  key_name                    = \"dwe-key-pair\"\n  vpc_security_group_ids      = [\"${aws_security_group.dwe-sg-rdp.id}\"]\n  subnet_id                   = \"${aws_subnet.dwe-subnet.id}\"\n  associate_public_ip_address = \"true\"\n\n  root_block_device { \n    volume_size           = \"30\"\n    volume_type           = \"standard\"\n    delete_on_termination = \"true\"\n  }\n\n  tags = {\n    Name = \"i-windows-test\"\n  }\n}\n<\/pre>\n<p>And that&#8217;s it. To check what actually will be done by Terraform there is the <a href=\"https:\/\/www.terraform.io\/docs\/commands\/plan.html\" target=\"_blank\" rel=\"noopener noreferrer\">&#8220;plan&#8221;<\/a> command. As the output is quite long I&#8217;ll skip most of it and just present the last few lines:<\/p>\n<pre class=\"brush: bash; gutter: true; first-line: 1\">\ndwe@dwe:~\/Documents\/aws\/ssm_demo$ terraform plan\n\n...\n\nPlan: 19 to add, 0 to change, 0 to destroy.\n\n------------------------------------------------------------------------\n\nNote: You didn't specify an \"-out\" parameter to save this plan, so Terraform\ncan't guarantee that exactly these actions will be performed if\n\"terraform apply\" is subsequently run.\n<\/pre>\n<p>Once you are happy with that you can <a href=\"https:\/\/www.terraform.io\/docs\/github-actions\/actions\/apply.html\" target=\"_blank\" rel=\"noopener noreferrer\">&#8220;apply&#8221;<\/a> the execution plan and everything will get provisioned and you confirmed by &#8220;yes&#8221;:<\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1; highlight: [7]\">\ndwe@dwe:~\/Documents\/aws\/ssm_demo$ terraform apply\n\nPlan: 19 to add, 0 to change, 0 to destroy.\n\nDo you want to perform these actions?\n  Terraform will perform the actions described above.\n  Only 'yes' will be accepted to approve.\n\n  Enter a value: yes\n<\/pre>\n<p>Sit back, relax and one or two minutes later your AWS playground is ready:<\/p>\n<pre class=\"brush: bash; gutter: true; first-line: 1\">\naws_vpc.dwe-vpc: Creating...\naws_vpc.dwe-vpc: Creation complete after 2s [id=vpc-026cdc481d5365074]\naws_internet_gateway.dwe-igw: Creating...\naws_subnet.dwe-subnet: Creating...\naws_security_group.dwe-sg-ssh: Creating...\naws_security_group.dwe-sg-rdp: Creating...\naws_subnet.dwe-subnet: Creation complete after 0s [id=subnet-028e27fef8df3b963]\naws_internet_gateway.dwe-igw: Creation complete after 0s [id=igw-0656108a04d5ea0a5]\naws_route_table.dwe-route: Creating...\naws_security_group.dwe-sg-rdp: Creation complete after 1s [id=sg-0764508e3a5234393]\naws_route_table.dwe-route: Creation complete after 1s [id=rtb-07691bc54b40af0ae]\naws_route_table_association.subnet-association: Creating...\naws_instance.i-windows-prod: Creating...\naws_instance.i-windows-test: Creating...\naws_security_group.dwe-sg-ssh: Creation complete after 1s [id=sg-053995952f558a4ff]\naws_instance.i-centos-linux-test: Creating...\naws_instance.i-amazon-linux-prod: Creating...\naws_instance.i-amazon-linux-test: Creating...\naws_instance.i-redhat-linux-prod: Creating...\naws_instance.i-centos-linux-prod: Creating...\naws_instance.i-redhat-linux-test: Creating...\naws_instance.i-ubuntu-linux-test: Creating...\naws_route_table_association.subnet-association: Creation complete after 0s [id=rtbassoc-07c7d4282033c4a71]\naws_instance.i-ubuntu-linux-prod: Creating...\naws_instance.i-windows-prod: Still creating... [10s elapsed]\naws_instance.i-windows-test: Still creating... [10s elapsed]\naws_instance.i-centos-linux-test: Still creating... [10s elapsed]\naws_instance.i-amazon-linux-test: Still creating... [10s elapsed]\naws_instance.i-amazon-linux-prod: Still creating... [10s elapsed]\naws_instance.i-redhat-linux-prod: Still creating... [10s elapsed]\naws_instance.i-centos-linux-prod: Still creating... [10s elapsed]\naws_instance.i-redhat-linux-test: Still creating... [10s elapsed]\naws_instance.i-ubuntu-linux-test: Still creating... [10s elapsed]\naws_instance.i-ubuntu-linux-prod: Still creating... [10s elapsed]\naws_instance.i-amazon-linux-test: Creation complete after 13s [id=i-02706717c3440723a]\naws_instance.i-suse-linux-test: Creating...\naws_instance.i-ubuntu-linux-test: Creation complete after 16s [id=i-0d2999aa319a90a3d]\naws_instance.i-centos-linux-test: Creation complete after 16s [id=i-03923fcf9d5881421]\naws_instance.i-suse-linux-prod: Creating...\naws_instance.i-ubuntu-linux-prod: Creation complete after 16s [id=i-00967725bc758f3ef]\naws_instance.i-redhat-linux-test: Creation complete after 16s [id=i-02a705327fb0acb61]\naws_instance.i-windows-prod: Creation complete after 16s [id=i-09c3fcc90491ef2cf]\naws_instance.i-redhat-linux-prod: Creation complete after 16s [id=i-0161726dfe1ed890b]\naws_instance.i-windows-test: Creation complete after 16s [id=i-02f567d11d32444fd]\naws_instance.i-amazon-linux-prod: Still creating... [20s elapsed]\naws_instance.i-centos-linux-prod: Still creating... [20s elapsed]\naws_instance.i-suse-linux-test: Still creating... [10s elapsed]\naws_instance.i-amazon-linux-prod: Creation complete after 23s [id=i-0b799879e77ce8b33]\naws_instance.i-suse-linux-prod: Still creating... [10s elapsed]\naws_instance.i-centos-linux-prod: Still creating... [30s elapsed]\naws_instance.i-centos-linux-prod: Creation complete after 32s [id=i-0482d958849f86483]\naws_instance.i-suse-linux-test: Still creating... [20s elapsed]\naws_instance.i-suse-linux-prod: Still creating... [20s elapsed]\naws_instance.i-suse-linux-test: Still creating... [30s elapsed]\naws_instance.i-suse-linux-test: Creation complete after 32s [id=i-0b35d559853f9f0d6]\naws_instance.i-suse-linux-prod: Still creating... [30s elapsed]\naws_instance.i-suse-linux-prod: Creation complete after 33s [id=i-062df970b894a23da]\n\nApply complete! Resources: 19 added, 0 changed, 0 destroyed.\n<\/pre>\n<p>Once you&#8217;re done with your tests, simply destroy the whole stuff by usinf the <a href=\"https:\/\/www.terraform.io\/docs\/commands\/destroy.html\" target=\"_blank\" rel=\"noopener noreferrer\">&#8220;destroy&#8221;<\/a> command:<\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1; highlight: [9]\">\ndwe@dwe:~\/Documents\/aws\/ssm_demo$ terraform destroy\n...\nPlan: 0 to add, 0 to change, 19 to destroy.\n\nDo you really want to destroy all resources?\n  Terraform will destroy all your managed infrastructure, as shown above.\n  There is no undo. Only 'yes' will be accepted to confirm.\n\n  Enter a value: yes\n...\naws_security_group.dwe-sg-rdp: Destroying... [id=sg-0764508e3a5234393]\naws_security_group.dwe-sg-rdp: Destruction complete after 1s\naws_security_group.dwe-sg-ssh: Destruction complete after 1s\naws_subnet.dwe-subnet: Destruction complete after 1s\naws_vpc.dwe-vpc: Destroying... [id=vpc-026cdc481d5365074]\naws_vpc.dwe-vpc: Destruction complete after 0s\n\nDestroy complete! Resources: 19 destroyed.\n<\/pre>\n<p>Quite easy, always reproducible and fast.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>When I started to write the blog about AWS SSM I quickly realized that I need a way to bring up and destroy my AWS EC2 playground in an easy and reproducible way. There are several options for this: I could have used the AWS command line interface or AWS CloudFormation. Both work pretty well [&hellip;]<\/p>\n","protected":false},"author":29,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[955,229],"tags":[133,1340],"type_dbi":[],"class_list":["post-12976","post","type-post","status-publish","format-standard","hentry","category-cloud","category-database-administration-monitoring","tag-aws","tag-terraform"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.2 (Yoast SEO v27.5) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>A simple Terraform script to create an AWS EC2 playground - dbi Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.dbi-services.com\/blog\/a-simple-terraform-script-to-create-an-aws-ec2-playground\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"A simple Terraform script to create an AWS EC2 playground\" \/>\n<meta property=\"og:description\" content=\"When I started to write the blog about AWS SSM I quickly realized that I need a way to bring up and destroy my AWS EC2 playground in an easy and reproducible way. There are several options for this: I could have used the AWS command line interface or AWS CloudFormation. Both work pretty well [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.dbi-services.com\/blog\/a-simple-terraform-script-to-create-an-aws-ec2-playground\/\" \/>\n<meta property=\"og:site_name\" content=\"dbi Blog\" \/>\n<meta property=\"article:published_time\" content=\"2019-11-11T07:39:37+00:00\" \/>\n<meta name=\"author\" content=\"Daniel Westermann\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@westermanndanie\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Daniel Westermann\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"11 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/a-simple-terraform-script-to-create-an-aws-ec2-playground\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/a-simple-terraform-script-to-create-an-aws-ec2-playground\\\/\"},\"author\":{\"name\":\"Daniel Westermann\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#\\\/schema\\\/person\\\/8d08e9bd996a89bd75c0286cbabf3c66\"},\"headline\":\"A simple Terraform script to create an AWS EC2 playground\",\"datePublished\":\"2019-11-11T07:39:37+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/a-simple-terraform-script-to-create-an-aws-ec2-playground\\\/\"},\"wordCount\":608,\"commentCount\":0,\"keywords\":[\"AWS\",\"Terraform\"],\"articleSection\":[\"Cloud\",\"Database Administration &amp; Monitoring\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/a-simple-terraform-script-to-create-an-aws-ec2-playground\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/a-simple-terraform-script-to-create-an-aws-ec2-playground\\\/\",\"url\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/a-simple-terraform-script-to-create-an-aws-ec2-playground\\\/\",\"name\":\"A simple Terraform script to create an AWS EC2 playground - dbi Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#website\"},\"datePublished\":\"2019-11-11T07:39:37+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#\\\/schema\\\/person\\\/8d08e9bd996a89bd75c0286cbabf3c66\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/a-simple-terraform-script-to-create-an-aws-ec2-playground\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/a-simple-terraform-script-to-create-an-aws-ec2-playground\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/a-simple-terraform-script-to-create-an-aws-ec2-playground\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Accueil\",\"item\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"A simple Terraform script to create an AWS EC2 playground\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/\",\"name\":\"dbi Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#\\\/schema\\\/person\\\/8d08e9bd996a89bd75c0286cbabf3c66\",\"name\":\"Daniel Westermann\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/31350ceeecb1dd8986339a29bf040d4cd3cd087d410deccd8f55234466d6c317?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/31350ceeecb1dd8986339a29bf040d4cd3cd087d410deccd8f55234466d6c317?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/31350ceeecb1dd8986339a29bf040d4cd3cd087d410deccd8f55234466d6c317?s=96&d=mm&r=g\",\"caption\":\"Daniel Westermann\"},\"description\":\"Daniel Westermann is Principal Consultant and Technology Leader Open Infrastructure at dbi services. He has more than 15 years of experience in management, engineering and optimization of databases and infrastructures, especially on Oracle and PostgreSQL. Since the beginning of his career, he has specialized in Oracle Technologies and is Oracle Certified Professional 12c and Oracle Certified Expert RAC\\\/GridInfra. Over time, Daniel has become increasingly interested in open source technologies, becoming \u201cTechnology Leader Open Infrastructure\u201d and PostgreSQL expert. \u00a0Based on community or EnterpriseDB tools, he develops and installs complex high available solutions with PostgreSQL. He is also a certified PostgreSQL Plus 9.0 Professional and a Postgres Advanced Server 9.4 Professional. He is a regular speaker at PostgreSQL conferences in Switzerland and Europe. Today Daniel is also supporting our customers on AWS services such as AWS RDS, database migrations into the cloud, EC2 and automated infrastructure management with AWS SSM (System Manager). He is a certified AWS Solutions Architect Professional. Prior to dbi services, Daniel was Management System Engineer at LC SYSTEMS-Engineering AG in Basel. Before that, he worked as Oracle Developper &amp;\u00a0Project Manager at Delta Energy Solutions AG in Basel (today Powel AG). Daniel holds a diploma in Business Informatics (DHBW, Germany). His branch-related experience mainly covers the pharma industry, the financial sector, energy, lottery and telecommunications.\",\"sameAs\":[\"https:\\\/\\\/x.com\\\/westermanndanie\"],\"url\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/author\\\/daniel-westermann\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"A simple Terraform script to create an AWS EC2 playground - dbi Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.dbi-services.com\/blog\/a-simple-terraform-script-to-create-an-aws-ec2-playground\/","og_locale":"en_US","og_type":"article","og_title":"A simple Terraform script to create an AWS EC2 playground","og_description":"When I started to write the blog about AWS SSM I quickly realized that I need a way to bring up and destroy my AWS EC2 playground in an easy and reproducible way. There are several options for this: I could have used the AWS command line interface or AWS CloudFormation. Both work pretty well [&hellip;]","og_url":"https:\/\/www.dbi-services.com\/blog\/a-simple-terraform-script-to-create-an-aws-ec2-playground\/","og_site_name":"dbi Blog","article_published_time":"2019-11-11T07:39:37+00:00","author":"Daniel Westermann","twitter_card":"summary_large_image","twitter_creator":"@westermanndanie","twitter_misc":{"Written by":"Daniel Westermann","Est. reading time":"11 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.dbi-services.com\/blog\/a-simple-terraform-script-to-create-an-aws-ec2-playground\/#article","isPartOf":{"@id":"https:\/\/www.dbi-services.com\/blog\/a-simple-terraform-script-to-create-an-aws-ec2-playground\/"},"author":{"name":"Daniel Westermann","@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/8d08e9bd996a89bd75c0286cbabf3c66"},"headline":"A simple Terraform script to create an AWS EC2 playground","datePublished":"2019-11-11T07:39:37+00:00","mainEntityOfPage":{"@id":"https:\/\/www.dbi-services.com\/blog\/a-simple-terraform-script-to-create-an-aws-ec2-playground\/"},"wordCount":608,"commentCount":0,"keywords":["AWS","Terraform"],"articleSection":["Cloud","Database Administration &amp; Monitoring"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.dbi-services.com\/blog\/a-simple-terraform-script-to-create-an-aws-ec2-playground\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.dbi-services.com\/blog\/a-simple-terraform-script-to-create-an-aws-ec2-playground\/","url":"https:\/\/www.dbi-services.com\/blog\/a-simple-terraform-script-to-create-an-aws-ec2-playground\/","name":"A simple Terraform script to create an AWS EC2 playground - dbi Blog","isPartOf":{"@id":"https:\/\/www.dbi-services.com\/blog\/#website"},"datePublished":"2019-11-11T07:39:37+00:00","author":{"@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/8d08e9bd996a89bd75c0286cbabf3c66"},"breadcrumb":{"@id":"https:\/\/www.dbi-services.com\/blog\/a-simple-terraform-script-to-create-an-aws-ec2-playground\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.dbi-services.com\/blog\/a-simple-terraform-script-to-create-an-aws-ec2-playground\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.dbi-services.com\/blog\/a-simple-terraform-script-to-create-an-aws-ec2-playground\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Accueil","item":"https:\/\/www.dbi-services.com\/blog\/"},{"@type":"ListItem","position":2,"name":"A simple Terraform script to create an AWS EC2 playground"}]},{"@type":"WebSite","@id":"https:\/\/www.dbi-services.com\/blog\/#website","url":"https:\/\/www.dbi-services.com\/blog\/","name":"dbi Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.dbi-services.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/8d08e9bd996a89bd75c0286cbabf3c66","name":"Daniel Westermann","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/31350ceeecb1dd8986339a29bf040d4cd3cd087d410deccd8f55234466d6c317?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/31350ceeecb1dd8986339a29bf040d4cd3cd087d410deccd8f55234466d6c317?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/31350ceeecb1dd8986339a29bf040d4cd3cd087d410deccd8f55234466d6c317?s=96&d=mm&r=g","caption":"Daniel Westermann"},"description":"Daniel Westermann is Principal Consultant and Technology Leader Open Infrastructure at dbi services. He has more than 15 years of experience in management, engineering and optimization of databases and infrastructures, especially on Oracle and PostgreSQL. Since the beginning of his career, he has specialized in Oracle Technologies and is Oracle Certified Professional 12c and Oracle Certified Expert RAC\/GridInfra. Over time, Daniel has become increasingly interested in open source technologies, becoming \u201cTechnology Leader Open Infrastructure\u201d and PostgreSQL expert. \u00a0Based on community or EnterpriseDB tools, he develops and installs complex high available solutions with PostgreSQL. He is also a certified PostgreSQL Plus 9.0 Professional and a Postgres Advanced Server 9.4 Professional. He is a regular speaker at PostgreSQL conferences in Switzerland and Europe. Today Daniel is also supporting our customers on AWS services such as AWS RDS, database migrations into the cloud, EC2 and automated infrastructure management with AWS SSM (System Manager). He is a certified AWS Solutions Architect Professional. Prior to dbi services, Daniel was Management System Engineer at LC SYSTEMS-Engineering AG in Basel. Before that, he worked as Oracle Developper &amp;\u00a0Project Manager at Delta Energy Solutions AG in Basel (today Powel AG). Daniel holds a diploma in Business Informatics (DHBW, Germany). His branch-related experience mainly covers the pharma industry, the financial sector, energy, lottery and telecommunications.","sameAs":["https:\/\/x.com\/westermanndanie"],"url":"https:\/\/www.dbi-services.com\/blog\/author\/daniel-westermann\/"}]}},"_links":{"self":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/12976","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/users\/29"}],"replies":[{"embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/comments?post=12976"}],"version-history":[{"count":0,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/12976\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/media?parent=12976"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/categories?post=12976"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/tags?post=12976"},{"taxonomy":"type","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/type_dbi?post=12976"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}