This example creates an App VPC and a Mgmt VPC and shows how to use the
vpc-app-network-acls and vpc-mgmt-network-acls
modules to add Network ACLs that control what inbound and outbound network traffic is allowed in each subnet
of those VPCs. We also launch a number of EC2 instances in each VPC to test the ACLs.
Quick start
To try these templates out you must have Terraform installed (minimum version: 0.12):
Open vars.tf, set the environment variables specified at the top of the file, and fill in any other variables that
don't have a default.
Run terraform get.
Run terraform plan.
If the plan looks good, run terraform apply.
What's a Network ACL?
Network ACLs provide an extra layer of network
security, similar to a security group.
Whereas a security group controls what inbound and outbound traffic is allowed for a specific resource (e.g. a single
EC2 instance), a network ACL controls what inbound and outbound traffic is allowed for an entire subnet.
Our VPC Structure
To keep this example simple, we create just two VPCs. For a real-world use-case, we recommend following theReference
VPC Architecture and creating three VPCs:
Prod VPC: For production workloads. You can create this type of VPC using the vpc-app module,
as shown in the vpc-app example.
Stage VPC: For non-production workloads. You can create this type of VPC using the vpc-app
module, as shown in the vpc-app example.
Mgmt VPC: Where operators run DevOps tooling and login. You can create this type of VPC using the
vpc-mgmt module, as shown in the templates in the vpc-mgmt example.
VPC Isolation
Each VPC is completely isolated from the other, so if you connect to one VPC, there is no way to access another VPC.
This is part of the "defense-in-depth" philosophy: even if attackers breaches one level of our security, they still
have other problems to deal with at the next level. It's also useful to ensure that changes you make in one VPC don't
accidentally cause problems in another. However, it can be useful to permit limited, controlled access between VPCs,
such as allowing a DevOps tool in the Mgmt VPC to deploy code in the Stage and Prod VPCs. See the
vpc-peering example to learn how this can be done.
Note that to make testing easier in this example, we create all three VPCs in the same Terraform template, but in
real-world usage you should create each VPC in a separate set of templates so that it gets a separate state file. That
way, you get more isolation, and if you somehow corrupt the state file while testing a change in one VPC, it does
not affect the state file for another VPC.
Subnets and Network ACLs
Each VPC defines different "tiers" of subnets, or logical subdivisions of the VPC. The vpc-app
module creates public, private app, and private persistence subnets. The vpc-mgmt module
creates public and private subnets. By default, the only limitations on those subnets are that public subnets are
accessible from the public Internet, while private subnets are not.
The templates in this example show how we can improve security in these subnets by adding Network ACLs. In particular,
the ACLs ensure that each subnet can only receive and send traffic to "adjacent" subnets (e.g. the private persistence
subnet receive requests from the private app subnet, but not the public subnet) as well as the Mgmt VPC. See the
vpc-app-network-acls and vpc-mgmt-network-acls
modules for details.
EC2 instances in this example
This example launches the following resources for demonstration and testing purposes:
App VPC instances: Launch one EC2 Instance in a public subnet, one in a private app subnet, and one in a
private persistence subnet.
Mgmt VPC instances: Launch one EC2 Instance in a public subnet and one in a private subnet.
SSH access
Any instance launched in a private subnet will not have a public IP address. Therefore, the only way to SSH to an
instance in a private subnet is to first SSH to an instance in a public subnet and use it as a "jump host". Note that
the Network ACLs in the templates in this example prevent any connections in the App VPCs between a public
subnet and a private persistence subnet, unless that public subnet is in the Mgmt VPC. Therefore, the only way to SSH
to an instance in the private persistence subnet is to enable VPC peering as shown in the vpc-peering
example and to connect via an instance in the public subnet of the Mgmt VPC. See the Bastion Host
examples for more info.
Known Errors
This terraform template may intermittently trigger certain non-critical errors caused by eventual consistency bugs in
Terraform. These are usually harmless and all you need to do to get around them is to re-run terraform apply.
Questions? Ask away.
We're here to talk about our services, answer any questions, give advice, or just to chat.
{"treedata":{"name":"root","toggled":true,"children":[{"name":".circleci","children":[{"name":"config.yml","path":".circleci/config.yml","sha":"9844f9b2a7c27de7e52ed74739acb0068ea7c945"}]},{"name":".gitignore","path":".gitignore","sha":"32845458602b36a63610885e236aecaf5d0cfb98"},{"name":".pre-commit-config.yaml","path":".pre-commit-config.yaml","sha":"8f0a49e6e74c419dd55216b6397d21c6cc2e1029"},{"name":"CODEOWNERS","path":"CODEOWNERS","sha":"8c24c86ef8447a19436b38826f458c71b4da4f45"},{"name":"LICENSE.txt","path":"LICENSE.txt","sha":"f4e3d9bd4717a044ed31ad847a300eee74371a78"},{"name":"README.md","path":"README.md","sha":"39903688407efa091dc00593faae51b12b3e75e8"},{"name":"examples","children":[{"name":"vpc-app-no-nat-gateway","children":[{"name":"README.md","path":"examples/vpc-app-no-nat-gateway/README.md","sha":"5327b37f00deaf545ac8aeb140841c9bee6a60b5"},{"name":"main.tf","path":"examples/vpc-app-no-nat-gateway/main.tf","sha":"8469afbaf3fac272e23a12b28850c03fa4e64644"},{"name":"outputs.tf","path":"examples/vpc-app-no-nat-gateway/outputs.tf","sha":"e5fe2a9caaa3168dd704ef17ca49fbba76b3ede7"},{"name":"vars.tf","path":"examples/vpc-app-no-nat-gateway/vars.tf","sha":"20dea2995e4f8e7b697b2d7395a7b61ab02261ac"}]},{"name":"vpc-app-with-endpoint","children":[{"name":"README.md","path":"examples/vpc-app-with-endpoint/README.md","sha":"d156678fe7d97d89370b1f95cf0558bf3d2a6430"},{"name":"main.tf","path":"examples/vpc-app-with-endpoint/main.tf","sha":"80a35167e8191382818d45f6c40ddd3ad0760ecb"},{"name":"outputs.tf","path":"examples/vpc-app-with-endpoint/outputs.tf","sha":"36e21a8b972bd561cbc3bdaea7b21b8982d6a662"},{"name":"variables.tf","path":"examples/vpc-app-with-endpoint/variables.tf","sha":"be23cd1bfd3a29beb63724612f6bb9a7e5bd3d25"}]},{"name":"vpc-app","children":[{"name":"README.md","path":"examples/vpc-app/README.md","sha":"5327b37f00deaf545ac8aeb140841c9bee6a60b5"},{"name":"main.tf","path":"examples/vpc-app/main.tf","sha":"4b53b1dd173f1c397c7b448e3a704177c800399e"},{"name":"outputs.tf","path":"examples/vpc-app/outputs.tf","sha":"e5fe2a9caaa3168dd704ef17ca49fbba76b3ede7"},{"name":"vars.tf","path":"examples/vpc-app/vars.tf","sha":"20dea2995e4f8e7b697b2d7395a7b61ab02261ac"}]},{"name":"vpc-custom-cidr-blocks","children":[{"name":"README.md","path":"examples/vpc-custom-cidr-blocks/README.md","sha":"e2387ee9acf039e4bbb6f1094da014d8074ce5f3"},{"name":"main.tf","path":"examples/vpc-custom-cidr-blocks/main.tf","sha":"90055c870e739262a3a3430bfa66586adaaca421"},{"name":"outputs.tf","path":"examples/vpc-custom-cidr-blocks/outputs.tf","sha":"e5fe2a9caaa3168dd704ef17ca49fbba76b3ede7"},{"name":"vars.tf","path":"examples/vpc-custom-cidr-blocks/vars.tf","sha":"56d3e0ca50ded5ea2535c71f3568f3728106a42b"}]},{"name":"vpc-flow-logs","children":[{"name":"README.md","path":"examples/vpc-flow-logs/README.md","sha":"e83626d27ce68cd32c0cec0e2c12446c6dee1dd5"},{"name":"main.tf","path":"examples/vpc-flow-logs/main.tf","sha":"c15ee2681b9ea3313eae292e130306b81044c6b3"},{"name":"outputs.tf","path":"examples/vpc-flow-logs/outputs.tf","sha":"1832dd649235eb4f917497c2772299c761d39dad"},{"name":"vars.tf","path":"examples/vpc-flow-logs/vars.tf","sha":"3ac7ead850b612a5973fd4c58192dc6b856330df"}]},{"name":"vpc-mgmt-no-nat-gateway","children":[{"name":"README.md","path":"examples/vpc-mgmt-no-nat-gateway/README.md","sha":"c3dba0df7f11986dffd3c5bbeab2edf3aa8a8fc7"},{"name":"main.tf","path":"examples/vpc-mgmt-no-nat-gateway/main.tf","sha":"61042a743ec3cdc29f1762c3c9425234b191e336"},{"name":"outputs.tf","path":"examples/vpc-mgmt-no-nat-gateway/outputs.tf","sha":"c11cde7873d030ed8e8e44a726ee2ea19d65fcd6"},{"name":"vars.tf","path":"examples/vpc-mgmt-no-nat-gateway/vars.tf","sha":"bf7cddc01e2b42855c9c435e5c2751e010e6a435"}]},{"name":"vpc-mgmt","children":[{"name":"README.md","path":"examples/vpc-mgmt/README.md","sha":"c3dba0df7f11986dffd3c5bbeab2edf3aa8a8fc7"},{"name":"main.tf","path":"examples/vpc-mgmt/main.tf","sha":"ce909ea1890742b539976338dc42537115a3d67c"},{"name":"outputs.tf","path":"examples/vpc-mgmt/outputs.tf","sha":"c11cde7873d030ed8e8e44a726ee2ea19d65fcd6"},{"name":"vars.tf","path":"examples/vpc-mgmt/vars.tf","sha":"59225eb0320c7af08fa4cade7bbeaf10bdeac295"}]},{"name":"vpc-network-acls","children":[{"name":"README.md","path":"examples/vpc-network-acls/README.md","sha":"f24e234e4e15cd6e87eff7d785256e59110542f9","toggled":true},{"name":"main.tf","path":"examples/vpc-network-acls/main.tf","sha":"8b9a899a799fbc7968a61bdd72dd8040ea8e369f"},{"name":"outputs.tf","path":"examples/vpc-network-acls/outputs.tf","sha":"5f59a828f7128b7bd7e52599fa794abd0f760293"},{"name":"vars.tf","path":"examples/vpc-network-acls/vars.tf","sha":"a19ecd5a9d56e8127d6dbd39ea9594b0ef49a696"}],"toggled":true},{"name":"vpc-peering-external","children":[{"name":"README.md","path":"examples/vpc-peering-external/README.md","sha":"845de39a9e747e109eb5128f86f71292c793c039"},{"name":"main.tf","path":"examples/vpc-peering-external/main.tf","sha":"2041c0004ee1e2378e5f490c23e11d3abb50cb79"},{"name":"outputs.tf","path":"examples/vpc-peering-external/outputs.tf","sha":"5239df47a80d13f33ea58412eb73a83f4ff431ed"},{"name":"vars.tf","path":"examples/vpc-peering-external/vars.tf","sha":"891f648219c644354f932af309fa3dffb0de3bd5"}]},{"name":"vpc-peering","children":[{"name":"README.md","path":"examples/vpc-peering/README.md","sha":"8dc44dcaca1fd832fed57fce29a40ce10dd5e514"},{"name":"main.tf","path":"examples/vpc-peering/main.tf","sha":"471391434c664bc18b79fc86295eedbdea0e4574"},{"name":"outputs.tf","path":"examples/vpc-peering/outputs.tf","sha":"85acf3fc320ca7969f57133d94515e80150f7c79"},{"name":"vars.tf","path":"examples/vpc-peering/vars.tf","sha":"6a8eb9ed4db5427a9eddb3205cfca9fc7386c085"}]}],"toggled":true},{"name":"modules","children":[{"name":"_docs","children":[{"name":"vpc-core-concepts.md","path":"modules/_docs/vpc-core-concepts.md","sha":"6c5780d57f69364b702bbaa5337aa3a1d693370d"},{"name":"vpc_app_architecture.png","path":"modules/_docs/vpc_app_architecture.png","sha":"1cb6d726e1a35614b27be9f3d45b9752589b9683"}]},{"name":"network-acl-inbound","children":[{"name":"README.md","path":"modules/network-acl-inbound/README.md","sha":"95c14fd46389871c3de62f0035d2c96ee05a6a89"},{"name":"main.tf","path":"modules/network-acl-inbound/main.tf","sha":"7c1eac78f96279359b6cb18897f8630a2cff16d9"},{"name":"vars.tf","path":"modules/network-acl-inbound/vars.tf","sha":"afc6a8ae03a4b53a0bf4242b4c3cbbb59093dbca"}]},{"name":"network-acl-outbound","children":[{"name":"README.md","path":"modules/network-acl-outbound/README.md","sha":"8ab75a21400cb74a356d8dc8ccb984b5835c908e"},{"name":"main.tf","path":"modules/network-acl-outbound/main.tf","sha":"ed711e50fb32123e0ed62bb67633df2ec1d9c973"},{"name":"vars.tf","path":"modules/network-acl-outbound/vars.tf","sha":"679d04948306dcdc4e677e8bfee3653b9fb46cc3"}]},{"name":"vpc-app-network-acls","children":[{"name":"README.md","path":"modules/vpc-app-network-acls/README.md","sha":"2047f3b5a6157f6bef300626fd1a5cc914706f13"},{"name":"main.tf","path":"modules/vpc-app-network-acls/main.tf","sha":"ca0c1f5f9ae7a11e130cf988eba0e4755e621d3a"},{"name":"outputs.tf","path":"modules/vpc-app-network-acls/outputs.tf","sha":"525001be9458bc90704667a84f0ac4f784d33129"},{"name":"vars.tf","path":"modules/vpc-app-network-acls/vars.tf","sha":"5f36ba4daf2a65f7b30f037053804395a00deaed"}]},{"name":"vpc-app","children":[{"name":"README.md","path":"modules/vpc-app/README.md","sha":"0c1a23fc7cf7df8045b5dc45def50662d21cac0a"},{"name":"main.tf","path":"modules/vpc-app/main.tf","sha":"d7e1bc08c1a939c0c82ea1cd5a510c5945328308"},{"name":"outputs.tf","path":"modules/vpc-app/outputs.tf","sha":"5901ea4587c3ef057b76b4edf73d402a4dfa8d2e"},{"name":"vars.tf","path":"modules/vpc-app/vars.tf","sha":"04df92e37aa3fb5c0d547c50c3ba7c59f9f571c0"}]},{"name":"vpc-dns-forwarder-rules","children":[{"name":"README.md","path":"modules/vpc-dns-forwarder-rules/README.md","sha":"0bfe6263341fd1d212952149d4c3572785711663"},{"name":"main.tf","path":"modules/vpc-dns-forwarder-rules/main.tf","sha":"3264cb717be99d4f9d3ba8395c44c4b3ba7c5087"},{"name":"variables.tf","path":"modules/vpc-dns-forwarder-rules/variables.tf","sha":"b5baaad0819ce7c23d47d1292fe0798dee12cdf5"}]},{"name":"vpc-dns-forwarder","children":[{"name":"README.md","path":"modules/vpc-dns-forwarder/README.md","sha":"0d0b4fffb15431758fd436c7cdc474bace686b7e"},{"name":"main.tf","path":"modules/vpc-dns-forwarder/main.tf","sha":"98095c1c6b9261ec5d5a0a4fbb0de0d261d6b412"},{"name":"outputs.tf","path":"modules/vpc-dns-forwarder/outputs.tf","sha":"382b7f3ae80e99cfd8325c9b4de404110e4d85ef"},{"name":"variables.tf","path":"modules/vpc-dns-forwarder/variables.tf","sha":"3c27308d90da5517d686c5bfb901801ba65637c0"}]},{"name":"vpc-flow-logs","children":[{"name":"README.md","path":"modules/vpc-flow-logs/README.md","sha":"0c6650434183731aef9332db713d02d06010d470"},{"name":"main.tf","path":"modules/vpc-flow-logs/main.tf","sha":"e9dd44457072efe92e86499f2bf54ee7fe7c864c"},{"name":"outputs.tf","path":"modules/vpc-flow-logs/outputs.tf","sha":"029e23b76b63c324e836a69891a7cb452da99a06"},{"name":"vars.tf","path":"modules/vpc-flow-logs/vars.tf","sha":"bd6957b840f84f331a8011fe0cb669ba41bbaeb3"}]},{"name":"vpc-interface-endpoint","children":[{"name":"README.md","path":"modules/vpc-interface-endpoint/README.md","sha":"bc6a270500a466e45476cce8a20e9ab39d5fccdd"},{"name":"main.tf","path":"modules/vpc-interface-endpoint/main.tf","sha":"dab6e3712b797b934edc1eb2b3e8df3492ebac9d"},{"name":"outputs.tf","path":"modules/vpc-interface-endpoint/outputs.tf","sha":"79d037d3f3ea31cb6981c07f036e9a1704da8945"},{"name":"variables.tf","path":"modules/vpc-interface-endpoint/variables.tf","sha":"e092b663fd6d87615bbb95d42452fa72878d6436"}]},{"name":"vpc-mgmt-network-acls","children":[{"name":"README.md","path":"modules/vpc-mgmt-network-acls/README.md","sha":"c49cc46bcbc09cff6175d7fc47d4eb719331f20f"},{"name":"main.tf","path":"modules/vpc-mgmt-network-acls/main.tf","sha":"7e5e484015cc7b6ded0d28c2b11e0361bf68a79b"},{"name":"outputs.tf","path":"modules/vpc-mgmt-network-acls/outputs.tf","sha":"7dba259d40baeee89c8ee4af63d2b3d1167e92be"},{"name":"vars.tf","path":"modules/vpc-mgmt-network-acls/vars.tf","sha":"559fb01af837e1700fc7fd650a9743f55f92a484"}]},{"name":"vpc-mgmt","children":[{"name":"README.md","path":"modules/vpc-mgmt/README.md","sha":"c36b3f5496f9f9438d6ece5f8616913e89a42230"},{"name":"main.tf","path":"modules/vpc-mgmt/main.tf","sha":"8eefd0bde9f55f54eb6eddd3a29dea11b15f0e73"},{"name":"outputs.tf","path":"modules/vpc-mgmt/outputs.tf","sha":"5c5ff7409ce2687c4c041279cb41717102d4d0a0"},{"name":"vars.tf","path":"modules/vpc-mgmt/vars.tf","sha":"682342efa6eed7bf896181063983ca4b6d6e1ebc"}]},{"name":"vpc-peering-external","children":[{"name":"README.md","path":"modules/vpc-peering-external/README.md","sha":"20b4e1dbadac81d6d5a7a6ce12b705e9d3a03c41"},{"name":"main.tf","path":"modules/vpc-peering-external/main.tf","sha":"aadc0a74ece9e121f07d189de3c6ac7ac4ed006c"},{"name":"vars.tf","path":"modules/vpc-peering-external/vars.tf","sha":"b7a9760c9a22524b8452e83d68495b31e3af18dc"}]},{"name":"vpc-peering","children":[{"name":"README.md","path":"modules/vpc-peering/README.md","sha":"56b1e169cef2f4201c8204611ea0364c5f04bf2c"},{"name":"main.tf","path":"modules/vpc-peering/main.tf","sha":"e9c4d70395e5964ae7c6d72c392dc936f4298d44"},{"name":"vars.tf","path":"modules/vpc-peering/vars.tf","sha":"60502cffac1867fa48a5f68ef6ef0aa566cef21e"}]}]},{"name":"test","children":[{"name":"README.md","path":"test/README.md","sha":"ef26d3851db2fff0b36dfa61379724c0db9ff281"},{"name":"go.mod","path":"test/go.mod","sha":"ec5387da6983f1941480ab52cb56a2227288a594"},{"name":"go.sum","path":"test/go.sum","sha":"099f6d2ad42e905152ac4cc64a480fcb0f0e6dab"},{"name":"test_helpers.go","path":"test/test_helpers.go","sha":"f46a068d884da9a9bd82dff3e2f62585951d61ea"},{"name":"vpc_app_no_nat_gateway_test.go","path":"test/vpc_app_no_nat_gateway_test.go","sha":"c23d6186a6ebb7de534c9dcc73f74a8e278cf4c2"},{"name":"vpc_app_test.go","path":"test/vpc_app_test.go","sha":"d564a91c16fef917f1454f6409ac55f32f1199bb"},{"name":"vpc_app_with_endpoint_test.go","path":"test/vpc_app_with_endpoint_test.go","sha":"1316517e122d2f1a2e935517ebcee90877fda799"},{"name":"vpc_custom_cidr_blocks_test.go","path":"test/vpc_custom_cidr_blocks_test.go","sha":"056710e3d1fc6d6affc28f23caef27cac9042519"},{"name":"vpc_flow_logs_test.go","path":"test/vpc_flow_logs_test.go","sha":"9ba7543acd9d4f40850df419d4bbba56b3703fcb"},{"name":"vpc_mgmt_no_nat_gateway_test.go","path":"test/vpc_mgmt_no_nat_gateway_test.go","sha":"98a5b6189e3651267f7038f906deaa0304fcc699"},{"name":"vpc_mgmt_test.go","path":"test/vpc_mgmt_test.go","sha":"4df8061bd0de902e3ef3d1ff56e4e32758fb8ad8"},{"name":"vpc_network_acls_test.go","path":"test/vpc_network_acls_test.go","sha":"5ed930679340c81ea7549b0a26e94566e18ce660"},{"name":"vpc_peering_external_test.go","path":"test/vpc_peering_external_test.go","sha":"2ce81263d16d2b5f7387993404bea2849ca60698"},{"name":"vpc_peering_test.go","path":"test/vpc_peering_test.go","sha":"ad9bfb95c9e56bcbd9bb69eaaae6619607ad501d"}]}]},"detailsContent":"<h1 class=\"preview__body--title\" id=\"vpc-network-ac-ls-example\">VPC Network ACLs Example</h1><div class=\"preview__body--border\"></div><p>This example creates an App VPC and a Mgmt VPC and shows how to use the\n<a href=\"/repos/v0.12.4/terraform-aws-vpc/modules/vpc-app-network-acls\" class=\"preview__body--description--blue\">vpc-app-network-acls</a> and <a href=\"/repos/v0.12.4/terraform-aws-vpc/modules/vpc-mgmt-network-acls\" class=\"preview__body--description--blue\">vpc-mgmt-network-acls</a>\nmodules to add Network ACLs that control what inbound and outbound network traffic is allowed in each subnet\nof those VPCs. We also launch a number of EC2 instances in each VPC to test the ACLs.</p>\n<h2 class=\"preview__body--subtitle\" id=\"quick-start\">Quick start</h2>\n<p>To try these templates out you must have Terraform installed (minimum version: <code>0.12</code>):</p>\n<ol>\n<li>Open <code>vars.tf</code>, set the environment variables specified at the top of the file, and fill in any other variables that\ndon't have a default.</li>\n<li>Run <code>terraform get</code>.</li>\n<li>Run <code>terraform plan</code>.</li>\n<li>If the plan looks good, run <code>terraform apply</code>.</li>\n</ol>\n<h2 class=\"preview__body--subtitle\" id=\"whats-a-network-acl\">What's a Network ACL?</h2>\n<p><a href=\"http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_ACLs.html\" class=\"preview__body--description--blue\" target=\"_blank\">Network ACLs</a> provide an extra layer of network\nsecurity, similar to a <a href=\"http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-network-security.html\" class=\"preview__body--description--blue\" target=\"_blank\">security group</a>.\nWhereas a security group controls what inbound and outbound traffic is allowed for a specific resource (e.g. a single\nEC2 instance), a network ACL controls what inbound and outbound traffic is allowed for an entire subnet.</p>\n<h2 class=\"preview__body--subtitle\" id=\"our-vpc-structure\">Our VPC Structure</h2>\n<p>To keep this example simple, we create just two VPCs. For a real-world use-case, we recommend following the<a href=\"https://www.whaletech.co/2014/10/02/reference-vpc-architecture.html\" class=\"preview__body--description--blue\" target=\"_blank\">Reference\nVPC Architecture</a> and creating three VPCs:</p>\n<ul>\n<li><strong>Prod VPC</strong>: For production workloads. You can create this type of VPC using the <a href=\"/repos/v0.12.4/terraform-aws-vpc/modules/vpc-app\" class=\"preview__body--description--blue\">vpc-app</a> module,\nas shown in the <a href=\"/repos/v0.12.4/terraform-aws-vpc/examples/vpc-app\" class=\"preview__body--description--blue\">vpc-app</a> example.</li>\n<li><strong>Stage VPC</strong>: For non-production workloads. You can create this type of VPC using the <a href=\"/repos/v0.12.4/terraform-aws-vpc/modules/vpc-app\" class=\"preview__body--description--blue\">vpc-app</a>\nmodule, as shown in the <a href=\"/repos/v0.12.4/terraform-aws-vpc/examples/vpc-app\" class=\"preview__body--description--blue\">vpc-app</a> example.</li>\n<li><strong>Mgmt VPC</strong>: Where operators run DevOps tooling and login. You can create this type of VPC using the\n<a href=\"/repos/v0.12.4/terraform-aws-vpc/modules/vpc-mgmt\" class=\"preview__body--description--blue\">vpc-mgmt</a> module, as shown in the templates in the <a href=\"/repos/v0.12.4/terraform-aws-vpc/examples/vpc-mgmt\" class=\"preview__body--description--blue\">vpc-mgmt</a> example.</li>\n</ul>\n<h2 class=\"preview__body--subtitle\" id=\"vpc-isolation\">VPC Isolation</h2>\n<p>Each VPC is completely isolated from the other, so if you connect to one VPC, there is no way to access another VPC.\nThis is part of the "defense-in-depth" philosophy: even if attackers breaches one level of our security, they still\nhave other problems to deal with at the next level. It's also useful to ensure that changes you make in one VPC don't\naccidentally cause problems in another. However, it can be useful to permit limited, controlled access between VPCs,\nsuch as allowing a DevOps tool in the Mgmt VPC to deploy code in the Stage and Prod VPCs. See the\n<a href=\"/repos/v0.12.4/terraform-aws-vpc/examples/vpc-peering\" class=\"preview__body--description--blue\">vpc-peering</a> example to learn how this can be done.</p>\n<p>Note that to make testing easier in this example, we create all three VPCs in the same Terraform template, but in\nreal-world usage you should create each VPC in a separate set of templates so that it gets a separate state file. That\nway, you get more isolation, and if you somehow corrupt the state file while testing a change in one VPC, it does\nnot affect the state file for another VPC.</p>\n<h2 class=\"preview__body--subtitle\" id=\"subnets-and-network-ac-ls\">Subnets and Network ACLs</h2>\n<p>Each VPC defines different "tiers" of subnets, or logical subdivisions of the VPC. The <a href=\"/repos/v0.12.4/terraform-aws-vpc/modules/vpc-app\" class=\"preview__body--description--blue\">vpc-app</a>\nmodule creates public, private app, and private persistence subnets. The <a href=\"/repos/v0.12.4/terraform-aws-vpc/modules/vpc-mgmt\" class=\"preview__body--description--blue\">vpc-mgmt</a> module\ncreates public and private subnets. By default, the only limitations on those subnets are that public subnets are\naccessible from the public Internet, while private subnets are not.</p>\n<p>The templates in this example show how we can improve security in these subnets by adding Network ACLs. In particular,\nthe ACLs ensure that each subnet can only receive and send traffic to "adjacent" subnets (e.g. the private persistence\nsubnet receive requests from the private app subnet, but not the public subnet) as well as the Mgmt VPC. See the\n<a href=\"/repos/v0.12.4/terraform-aws-vpc/modules/vpc-app-network-acls\" class=\"preview__body--description--blue\">vpc-app-network-acls</a> and <a href=\"/repos/v0.12.4/terraform-aws-vpc/modules/vpc-mgmt-network-acls\" class=\"preview__body--description--blue\">vpc-mgmt-network-acls</a>\nmodules for details.</p>\n<h2 class=\"preview__body--subtitle\" id=\"ec-2-instances-in-this-example\">EC2 instances in this example</h2>\n<p>This example launches the following resources for demonstration and testing purposes:</p>\n<ol>\n<li><strong>App VPC instances</strong>: Launch one EC2 Instance in a public subnet, one in a private app subnet, and one in a\nprivate persistence subnet.</li>\n<li><strong>Mgmt VPC instances</strong>: Launch one EC2 Instance in a public subnet and one in a private subnet.</li>\n</ol>\n<h2 class=\"preview__body--subtitle\" id=\"ssh-access\">SSH access</h2>\n<p>Any instance launched in a private subnet will not have a public IP address. Therefore, the only way to SSH to an\ninstance in a private subnet is to first SSH to an instance in a public subnet and use it as a "jump host". Note that\nthe Network ACLs in the templates in this example prevent any connections in the App VPCs between a public\nsubnet and a private persistence subnet, unless that public subnet is in the Mgmt VPC. Therefore, the only way to SSH\nto an instance in the private persistence subnet is to enable VPC peering as shown in the <a href=\"/repos/v0.12.4/terraform-aws-vpc/examples/vpc-peering\" class=\"preview__body--description--blue\">vpc-peering\nexample</a> and to connect via an instance in the public subnet of the Mgmt VPC. See the <a href=\"/repos/module-server/examples/bastion-host\" class=\"preview__body--description--blue\">Bastion Host\nexamples</a> for more info.</p>\n<h2 class=\"preview__body--subtitle\" id=\"known-errors\">Known Errors</h2>\n<p>This terraform template may intermittently trigger certain non-critical errors caused by eventual consistency bugs in\nTerraform. These are usually harmless and all you need to do to get around them is to re-run <code>terraform apply</code>.</p>\n","repoName":"terraform-aws-vpc","repoRef":"v0.12.0","serviceDescriptor":{"serviceName":"Virtual Private Cloud (VPC)","serviceRepoName":"terraform-aws-vpc","serviceRepoOrg":"gruntwork-io","cloudProviders":["aws"],"description":"Create a Virtual Private Cloud (VPC). Includes multiple subnet tiers, NACLs, NAT gateways, Internet Gateways, and VPC peering.","imageUrl":"vpc.png","licenseType":"subscriber","technologies":["Terraform"],"compliance":[],"tags":[""]},"serviceCategoryName":"Networking","fileName":"README.md","filePath":"/examples/vpc-network-acls","title":"Repo Browser: Virtual Private Cloud (VPC)","description":"Browse the repos in the Gruntwork Infrastructure as Code Library."}