Adding Ingress Rules to an AWS Security Group
In this post we will look at how to modify the ingress rules for a security group using the AWS CLI to add and remove http and ssh access. In order to test and verify we'll create an EC2 instance running a basic webpage and attach our security group to it.
To keep things simple we will deploy into a Public subnet in our default VPC and will not use any Network Access Control Lists, NACLs.
Once this is done we will look at how to modify the security group to add and remove both ssh and http access to the EC2 instance.
Create a Key-Pair
The first thing we will do is create a key-pair to allow ssh access to the newly created instance. To do this we must first create the key-pair and also save the relevant private key to a suitable file on our client machine.
Once this is done the permissions must be changed on the private key.
This will allow us to connect to our instance when we create it.
Create a Security Group
The next thing to be done is to create the security group that will be attached to our instance. For this we will need to ensure that we define the correct VPC that we are using.
This has created a security group which currently has no ingress rules and the command also returns the GroupId which is needed for the creation of our EC2 instance.
We will add some ingress rules to the group but for the time-being this will be enough.
Creating an EC2 Instance
We will now create an EC2 instance that will run our web-server and be used for testing. We'll add some user-data to update the instance, install apache web-server and start it up.
We'll also need to make sure that we make use of our key-pair that we generated earlier.
To install the web-server we'll use the following user-data to bootstrap it:
This file will be passed to the instance when it's created using the ec2 run-instances command with the relevant options.
--image-id is the AMI image which in our case is the latest AWS Linux image
--count is the number of instances, in our case just a single one
--instance-type is t2-micro which is more then sufficient for our tests
--key-name is the Key Pair that we have previously created
--security-group-ids is the security group we have created (with no ingress at the moment
--user-data is the user-data we are using to bootstrap the instance
aws ec2 run-instances --image-id ami-0c2b8ca1dad447f8a --count 1 --instance-type t2.micro --key-name MyKeyPair --security-group-ids sg-0750df8c5753405fc --user-data file://user-data.txt
{
"Groups": [],
"Instances": [
{
"AmiLaunchIndex": 0,
"ImageId": "ami-0c2b8ca1dad447f8a",
"InstanceId": "i-027b63499df0102f5",
"InstanceType": "t2.micro",
"KeyName": "MyKeyPair",
"LaunchTime": "2021-08-23T17:58:07+00:00",
"Monitoring": {
"State": "disabled"
},
"Placement": {
"AvailabilityZone": "us-east-1c",
"GroupName": "",
"Tenancy": "default"
},
"PrivateDnsName": "ip-172-31-83-248.ec2.internal",
"PrivateIpAddress": "172.31.83.248",
"ProductCodes": [],
"PublicDnsName": "",
"State": {
"Code": 0,
"Name": "pending"
},
"StateTransitionReason": "",
"SubnetId": "subnet-0f9d0a27d9f06064f",
"VpcId": "vpc-0308ac31e67cd27a6",
"Architecture": "x86_64",
"BlockDeviceMappings": [],
"ClientToken": "7f557f8b-037f-430f-91d3-b720d24a7df1",
"EbsOptimized": false,
"EnaSupport": true,
"Hypervisor": "xen",
"NetworkInterfaces": [
{
"Attachment": {
"AttachTime": "2021-08-23T17:58:07+00:00",
"AttachmentId": "eni-attach-0ae9de90c635014d3",
"DeleteOnTermination": true,
"DeviceIndex": 0,
"Status": "attaching",
"NetworkCardIndex": 0
},
"Description": "",
"Groups": [
{
"GroupName": "my-sg",
:...skipping...
{
"Groups": [],
"Instances": [
{
"AmiLaunchIndex": 0,
"ImageId": "ami-0c2b8ca1dad447f8a",
"InstanceId": "i-027b63499df0102f5",
"InstanceType": "t2.micro",
"KeyName": "MyKeyPair",
"LaunchTime": "2021-08-23T17:58:07+00:00",
"Monitoring": {
"State": "disabled"
},
"Placement": {
"AvailabilityZone": "us-east-1c",
"GroupName": "",
"Tenancy": "default"
},
"PrivateDnsName": "ip-172-31-83-248.ec2.internal",
"PrivateIpAddress": "172.31.83.248",
"ProductCodes": [],
"PublicDnsName": "",
"State": {
"Code": 0,
"Name": "pending"
},
"StateTransitionReason": "",Group
"SubnetId": "subnet-0f9d0a27d9f06064f",
"VpcId": "vpc-0308ac31e67cd27a6",
"Architecture": "x86_64",
"BlockDeviceMappings": [],
"ClientToken": "7f557f8b-037f-430f-91d3-b720d24a7df1",
"EbsOptimized": false,
"EnaSupport": true,
"Hypervisor": "xen",
"NetworkInterfaces": [
{
"Attachment": {
"AttachTime": "2021-08-23T17:58:07+00:00",
"AttachmentId": "eni-attach-0ae9de90c635014d3",
"DeleteOnTermination": true,
"DeviceIndex": 0,
"Status": "attaching",
"NetworkCardIndex": 0
},
"Description": "",
"Groups": [
{
"GroupName": "my-sg",
"GroupId": "sg-0750df8c5753405fc"
}
],
:
Adding Ingress Rules to Security Group
We now have a running instance and will now add an ingress rule for ssh and http traffic using ec2 authorize-security-group-ingress command.
--group-name is the name of the security group we will add the rule to
--protocol is tcp for both http and ssh
--port is the port (22 for ssh, 80 for http)
--cidr is the source IP range, which in our case is from anywhere
We have now added two rules to the security group and can verify by describing the group that our ingress rules for port 22 (ssh) and port 80 (http) have been added.
aws ec2 describe-security-groups --group-ids sg-0750df8c5753405fc
{
"SecurityGroups": [
{
"Description": "My security group",
"GroupName": "my-sg",
"IpPermissions": [
{
"FromPort": 80,
"IpProtocol": "tcp",
"IpRanges": [
{
"CidrIp": "0.0.0.0/0"
}
],
"Ipv6Ranges": [],
"PrefixListIds": [],
"ToPort": 80,
"UserIdGroupPairs": []
},
{
"FromPort": 22,
"IpProtocol": "tcp",
"IpRanges": [
{
"CidrIp": "0.0.0.0/0"
}
],
"Ipv6Ranges": [],
"PrefixListIds": [],
"ToPort": 22,
"UserIdGroupPairs": []
}
],
"OwnerId": "082684335586",
"GroupId": "sg-0750df8c5753405fc",
"IpPermissionsEgress": [
{
"IpProtocol": "-1",
"IpRanges": [
{
"CidrIp": "0.0.0.0/0"
}
],
"Ipv6Ranges": [],
"PrefixListIds": [],
"UserIdGroupPairs": []
}
],
"VpcId": "vpc-0308ac31e67cd27a6"
}
]
}
Confirming Functionality
We can connect to the instance using ssh and our private key, confirming that apache is running (proving that our boot-strapping user-data has worked)
We can then confirm that http is working by a simple curl command to the public address of the instance.
Removing HTTP Ingress
It is a simple case of revoking the http access on the security group
A simple curl command proves we can no longer access the website
We can also prove by looking at the security group rules again.
aws ec2 describe-security-groups --group-ids sg-0750df8c5753405fc
{
"SecurityGroups": [
{
"Description": "My security group",
"GroupName": "my-sg",
"IpPermissions": [
{
"FromPort": 22,
"IpProtocol": "tcp",
"IpRanges": [
{
"CidrIp": "0.0.0.0/0"
}
],
"Ipv6Ranges": [],
"PrefixListIds": [],
"ToPort": 22,
"UserIdGroupPairs": []
}
],
"OwnerId": "082684335586",
"GroupId": "sg-0750df8c5753405fc",
"IpPermissionsEgress": [
{
"IpProtocol": "-1",
"IpRanges": [
{
"CidrIp": "0.0.0.0/0"
}
],
"Ipv6Ranges": [],
"PrefixListIds": [],
"UserIdGroupPairs": []
}
],
"VpcId": "vpc-0308ac31e67cd27a6"
}
]
}
This shows port 80 is no longer present.
Authorize HTTP Again
It is a simple case of authorizing the http ingress again.
Conclusions
It is relatively simple to modify ingress rules within a security group using the AWS CLI and this has been proven with this lab. We have also used a local user-data file to bootstrap our instance to install apache web-server and start the service up when it is created.
In the case of this lab we added two ingress rules to allow ssh and http to reach our test instance that had our security group attached to it.
In a real situation we could remove the ssh rule and if we had a need to access the instance again just add the rule back in (probably locked down to just the IP address of the connecting client).