Here is my practice.
If you want to follow my advice, you will create two stacks,
Preproduction. The production stack runs the machines for the production site, whereas the preproduction stack is the exact copy of the production stack in order to check that deployment works before deploying to production.
Before creating the stacks, in order to enforce separation, create two VPC with for example the following network addresses :
Usually I leave DNS resolution and hostname to yes, because it’s quite difficult to work without them.
Under each VPC, I create two private subnets and two public subnets, in two different availability zones, but in the same region (
eu-west-1 in my case).
The two public subnets (
10.0.2.0/24 - with an even number for the third byte) will be used for the loadbalancers and the NAT instance that will be directly on the Internet.
Loadbalancers require two public subnets in order to assure redundancy, in case one zone is not available due to failure.
All other instances will be launched in the two private subnets (
10.0.3.0/24 - with an odd number for the third byte), not accessible directly from the web, and with no direct access to the web either. This security will protect them from unintended network activities.
I create two private subnets because services, such as RDS instances, require two subnets in order to assure redundancy, in case one zone is not available due to failure.
Instances will be directly on Internet,
able to query any Internet service directly,
being query-able from anywhere on the Internet.
having an IP address and the standard internet gateway in their route table. For this to work :
Set Auto-assign Public IP to true
Set the route table to
Destination Target 10.0.0.0/16 local 0.0.0.0/0 igw-*, the internet gateway
Security will be stronger : instances will have no IP, so it will not be possible to access them directly from the Internet and also for them to access the Internet directly.
Set Auto-assign Public IP to false
Launch a NAT instance in the public subnet with
a security group I name
NATSG, that will enable to filter communications between private instances and the Internet.
an elastic IP address, that will be the IP address of all outbound connections to the Internet from the private subnet, and that you will probably communicate to your different partners (if they filter accesses on IP) or use in other services’ security groups.
Set the route table to
Destination Target 10.0.0.0/16 local 0.0.0.0/0 nat instance
Open ports for some TCP connections on the security group
NATSGof the NAT instance that will filter the access of the private instance to web.
Type Port Source MYSQL 3306 10.0.0.0/16 GITHUB 9418 10.0.0.0/16 SMTP 2525 0.0.0.0/0 SMTPS 465 10.0.0.0/16 SSH 22 0.0.0.0/0 HTTP 80 10.0.0.0/16 HTTPS 443 10.0.0.0/16 SMTP 25 0.0.0.0/0
Open these ports for the private instance to access services outside the private networks, such as Github, SMTP servers, download mirrors, etc.
For the connection to come back.
Type Port Destination HTTP 80 0.0.0.0/0 HTTPS 443 0.0.0.0/0
Here is the final diagram (thanks to @AWS)
Now you’re ready to create your stacks, with their respective loadbalancers, and launch your instances.