This is a continuation of the previous article where I set up the Virtual Private Network required to host the application using CloudFormation. Feel free to read the need and how to set up the VPC at the below link,
Get rid of old habits- Use CloudFormation for infrastructure set up -01
Now that we have set up various subnets as Public and Private subnets we need to control incoming and outgoing traffic to ensure that our application is secured and able to cater to the user requests. For this purpose, we will have to enable a certain type of traffic through certain ports. E.g. TCP over port 5000 for the application, TCP over port 3306 for MySQL. AWS has provided this facility through security groups that act as a virtual firewall for our EC2 instances that will host our application. Given below is the CloudFormation YAML for security group configuration.
######################################### | |
# All Security Groups of ABC VPC # | |
######################################### | |
--- | |
Resources: | |
#Security Groups | |
WebDMZSG: | |
Type: AWS::EC2::SecurityGroup | |
Properties: | |
GroupDescription: Web Ec2 and ALB SG | |
GroupName: WebDMZSG | |
VpcId: !ImportValue AbVPC | |
SecurityGroupIngress: | |
- IpProtocol: tcp | |
FromPort: 80 | |
ToPort: 80 | |
CidrIp: 0.0.0.0/0 | |
- IpProtocol: tcp | |
FromPort: 443 | |
ToPort: 443 | |
CidrIp: 0.0.0.0/0 | |
- IpProtocol: tcp | |
FromPort: 22 | |
ToPort: 22 | |
CidrIp: 0.0.0.0/0 | |
- IpProtocol: tcp | |
FromPort: 5000 | |
ToPort: 5000 | |
CidrIp: 0.0.0.0/0 | |
- IpProtocol: icmp | |
FromPort: 8 | |
ToPort: -1 | |
CidrIp: 10.0.0.0/16 | |
DataBaseSG: | |
Type: AWS::EC2::SecurityGroup | |
Properties: | |
GroupDescription: Data Base SG | |
GroupName: DataBaseSG | |
VpcId: !ImportValue AbVPC | |
SecurityGroupIngress: | |
- IpProtocol: tcp | |
FromPort: 3306 | |
ToPort: 3306 | |
SourceSecurityGroupId: !GetAtt WebDMZSG.GroupId | |
ALBSecurityGroup: | |
Type: 'AWS::EC2::SecurityGroup' | |
Properties: | |
VpcId: !ImportValue AbVPC | |
GroupName: InternetAlbSG | |
GroupDescription: Enable HTTP/HTTPS access | |
SecurityGroupIngress: | |
- IpProtocol: 'tcp' | |
FromPort: '80' | |
ToPort: '80' | |
CidrIp: 0.0.0.0/0 | |
- IpProtocol: 'tcp' | |
FromPort: '443' | |
ToPort: '443' | |
CidrIp: 0.0.0.0/0 | |
VpcLinkSecurityGroup: | |
Type: 'AWS::EC2::SecurityGroup' | |
Properties: | |
VpcId: !ImportValue AbVPC | |
GroupName: VpcSG | |
GroupDescription: Enable HTTP/HTTPS access | |
SecurityGroupIngress: | |
- IpProtocol: 'tcp' | |
FromPort: '80' | |
ToPort: '80' | |
CidrIp: 0.0.0.0/0 | |
- IpProtocol: 'tcp' | |
FromPort: '443' | |
ToPort: '443' | |
CidrIp: 0.0.0.0/0 | |
ExConnALBSecurityGroup: | |
Type: 'AWS::EC2::SecurityGroup' | |
Properties: | |
VpcId: !ImportValue AbVPC | |
GroupName: InternalSG | |
GroupDescription: Enable HTTP/HTTPS access | |
SecurityGroupIngress: | |
- IpProtocol: 'tcp' | |
FromPort: '80' | |
ToPort: '80' | |
SourceSecurityGroupId: !GetAtt VpcLinkSecurityGroup.GroupId | |
- IpProtocol: 'tcp' | |
FromPort: '443' | |
ToPort: '443' | |
SourceSecurityGroupId: !GetAtt VpcLinkSecurityGroup.GroupId |
As you can see, I have created security groups enabling traffic for EC2 instances in the app subnets, database subnet, public load balancer, VPC link, and the private load balancer. This basically covers all the areas for which we need to enable traffic.
As the next step, we will have to export some of these configurations as output values to be used in the coming stacks. I'll be doing that in the below code.
Outputs: | |
#Security Groups | |
WebSG: | |
Description: Ec2 security group | |
Value: !Ref WebDMZSG | |
Export: | |
Name: Ec2SG | |
DB: | |
Description: DataBase security group | |
Value: !Ref DataBaseSG | |
Export: | |
Name: DBSG | |
InternetALB: | |
Description: Internet facing Load Balancer security group | |
Value: !Ref ALBSecurityGroup | |
Export: | |
Name: ALBSG | |
InternalALB: | |
Description: Internal Load Balancer security group | |
Value: !Ref ExConnALBSecurityGroup | |
Export: | |
Name: ExConnALBSG | |
VPCLink: | |
Description: API Gw Vpc Link security group | |
Value: !Ref VpcLinkSecurityGroup | |
Export: | |
Name: VpcLinkSG |
I am not going into details as most of these CloudFormation code snippets are self-explanatory. The description section has a brief on what each part does.
There are two ways to gain access to the EC2 instances in a private subnet. One of them is using the bastion host and the other is to use Systems Manager (SSM) provided by AWS. I prefer to use SSM and you can read more on this at "Toward a bastion less world". The reason I mentioned this is, in the upcoming section where I share the code to configure the IAM roles, you'll see me using policies that are related to SSM and I don't want you to be confused.
#################################################################### | |
# All IAM Configurations of ABC (Roles, Profiles, Policies) # | |
#################################################################### | |
--- | |
Resources: | |
Ec2Instanceprofile: | |
Type: AWS::IAM::InstanceProfile | |
Properties: | |
Path: / | |
Roles: | |
- !Ref Ec2Role | |
Ec2Role: | |
Type: AWS::IAM::Role | |
Properties: | |
AssumeRolePolicyDocument: | |
Version: 2012-10-17 | |
Statement: | |
- Effect: Allow | |
Principal: | |
Service: ec2.amazonaws.com | |
Action: sts:AssumeRole | |
Path: / | |
Ec2RolePolicies: | |
Type: AWS::IAM::Policy | |
Properties: | |
PolicyName: ec2policies | |
PolicyDocument: | |
Version: 2012-10-17 | |
Statement: | |
- Effect: Allow | |
Action: 's3:*' | |
Resource: '*' | |
- Effect: Allow | |
Action: | |
- 'ssm:DescribeAssociation' | |
- 'ssm:GetDeployablePatchSnapshotForInstance' | |
- 'ssm:GetDocument' | |
- 'ssm:DescribeDocument' | |
- 'ssm:GetManifest' | |
- 'ssm:GetParameter' | |
- 'ssm:GetParameters' | |
- 'ssm:ListAssociations' | |
- 'ssm:ListInstanceAssociations' | |
- 'ssm:PutInventory' | |
- 'ssm:PutComplianceItems' | |
- 'ssm:PutConfigurePackageResult' | |
- 'ssm:UpdateAssociationStatus' | |
- 'ssm:UpdateInstanceAssociationStatus' | |
- 'ssm:UpdateInstanceInformation' | |
Resource: '*' | |
- Effect: Allow | |
Action: | |
- 'ssmmessages:CreateControlChannel' | |
- 'ssmmessages:CreateDataChannel' | |
- 'ssmmessages:OpenControlChannel' | |
- 'ssmmessages:OpenDataChannel' | |
Resource: '*' | |
- Effect: Allow | |
Action: | |
- 'ec2messages:AcknowledgeMessage' | |
- 'ec2messages:DeleteMessage' | |
- 'ec2messages:FailMessage' | |
- 'ec2messages:GetEndpoint' | |
- 'ec2messages:GetMessages' | |
- 'ec2messages:SendReply' | |
Resource: '*' | |
Roles: | |
- !Ref Ec2Role | |
#Output resources | |
Outputs: | |
RoleOutput: | |
Description: Output of S3 full access Role and SSM using Instance Profile | |
Value: !Ref Ec2Instanceprofile | |
Export: | |
Name: Ec2InstanceProfile |
Now we have the VPC, subnets, the required security groups, and IAM roles configured using CloudFormation to host our applications. In the next article, I'll be adding some compute resources to each of these subnets so you can host your application. Also, in an article to follow, I'll share how to run these templates and get the infrastructure setup in AWS along with the complete code hosted in Github. Thanks for reading.
Top comments (0)