Clear rules of AWS security group for a particular port - amazon-web-services

How to remove all rules for a given port using the "aws ec2"?
aws ec2 revoke-security-group-ingress --group-name MySecurityGroup --protocol tcp --port 22 **--ALL-IP**

As per the documentation, This commands works on either --cidr or --source-group. so If you have multiple IP addresses then I would say the only option is to run the same command multiple times for the individual IP address (which would take the form of 1.1.1.1/32).
Or,
You can list all the ipadress in cidr format (1.1.1.1/32) in a file (each ip address on a new line) and then run a for loop over it running above command for each iteration. e.g.
for i in `cat ip_address_cidr.txt`; do aws ec2 revoke-security-group-ingress --group-name MySecurityGroup --protocol tcp --port 22 $i; done
I have not tested above command syntax but that should do it so that you can revoke the rules in a single one-liner command.

I think that this is what you are looking for: How to Close All Open SSH Ports in AWS Security Groups
Here a solution for a specific security group-id:
#!/bin/bash
sg = {security group}
# get the cidrs for the ingress rule
rules=$(aws ec2 describe-security-groups --group-ids $sg --output text --query 'SecurityGroups[*].IpPermissions')
# rules will contain something like:
# 22 tcp 22
# IPRANGES 108.42.177.53/32
# IPRANGES 10.0.0.0/16
# 80 tcp 80
# IPRANGES 0.0.0.0/0
# luckily, aws returns all ipranges per port grouped together
# flag for if we are reading ipranges
reading=0
# loop returned lines
while read -r line; do
# split the line up
rulebits=($line)
# check if if we are reading ssh port ipranges
if [ $reading -eq 0 ] ; then
# we are not reading ipranges
# check if '22 tcp 22'
if [ ${rulebits[0]} == "22" ] && [ ${rulebits[1]} == "tcp" ] && [ ${rulebits[2]} == "22" ] ; then
# found it
reading=1
fi
else
# we are reading ipranges
# check if first word is 'IPRANGES'
if [ ${rulebits[0]} == "IPRANGES" ] ; then
# found a cidr for open ssh port
cidr=${rulebits[1]}
echo -n found port 22 open cidr $cidr closing...
# close it
result=$(aws ec2 revoke-security-group-ingress --group-id $sg --protocol tcp --port 22 --cidr $cidr --output text)
if [ "$result" == "true" ] ; then
echo " OK"
else
echo " ERROR"
fi
else
# new port
reading=0
fi
fi
done

revoke-security-group-ingress in version 2 gives us to specify multiple IP CIDRS. See below solution written in PHP which I am trying to clean in multiple region and multiple prots.
To specify multiple rules in a single command use the --ip-permissions option https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/revoke-security-group-ingress.html
$cleanports = [22,5984];
$sgids = [["sgid"=>"sg1","region"=>"us-east-1"],["sgid"=>"sg1","region"=>"us-east-1"]];
foreach($sgids as $sgidDetail){
$iprules = json_decode(shell_exec("/usr/bin/aws ec2 describe-security-groups --group-ids {$sgidDetail['sgid']} --region {$sgidDetail['region']} --query 'SecurityGroups[*].IpPermissions'"), true)[0];
foreach ($iprules as $key => $ips) {
if(!empty($ips['FromPort']) && !empty($ips['ToPort']) && in_array($ips['FromPort'], $cleanports) && in_array($ips['ToPort'], $cleanports)){
echo "\n\n";
echo shell_exec("/usr/bin/aws ec2 revoke-security-group-ingress --group-id {$sgidDetail['sgid']} --region {$sgidDetail['region']} --ip-permissions '".json_encode($ips)."'");
}
}
}

Related

Terraform throwing this error Getting Extra characters after interpolation expression;

I'm trying to associate the Elastic IP address with Auto scaling group, so whenever the autoscaling triggers it will automatically associate with the EIP.
For this I'm trying to add the script in user data.
My intention is to we have 2 servers so its associated with 2 EIP's, whenever the autoscaling triggers it has to check whether the EIP is free or not if its free it has to associate with that instance using the instance id.
Below is my script where I'm getting the error
In EIP_LIST im getting this error Extra characters after interpolation expression; Expected a closing brace to end the interpolation expression, but found extra characters.
INSTANCE_ID=$(ec2-metadata --instance-id | cut -d " " -f 2);
MAXWAIT=10
# Get list of EIPs
EIP_LIST=${"eipalloc-09e7274dd3c641ae6" "eipalloc-05e8e926926f9de55"}
# Iterate over EIP list
for EIP in ${EIP_LIST}; do
echo "Checking if EIP with ALLOC_ID[$EIP] is free...."
ISFREE=$(aws ec2 describe-addresses --allocation-ids $EIP --query Addresses[].InstanceId --output text --region ap-south-1)
STARTWAIT=$(date +%s)
while [ ! -z "$ISFREE" ]; do
if [ "$(($(date +%s) - $STARTWAIT))" -gt $MAXWAIT ]; then
echo "WARNING: We waited 30 seconds, we're forcing it now."
ISFREE=""
else
echo "Waiting for EIP with ALLOC_ID[$EIP] to become free...."
sleep 3
ISFREE=$(aws ec2 describe-addresses --allocation-ids $EIP --query Addresses[].InstanceId --output text --region ap-south-1)
fi
done
echo Running: aws ec2 associate-address --instance-id $INSTANCE_ID --allocation-id $EIP --allow-reassociation --region ap-south-1
aws ec2 associate-address --instance-id $INSTANCE_ID --allocation-id $EIP --allow-reassociation --region ap-south-1
$ is TF symbol used for interpolation of variables. It clashes with the same symbol used in bash. You have to escape it using $$ if you want to us $ in bash, not in TF, e.g.
$${EIP_LIST}
will result in ${EIP_LIST} in your script.

Can't Re-allocate Elastic IP to EC2 Scaling Group

I've tried several methods to re-allocate the elastic iP, but no luck:
amazon web services - AWS EC2 User Data script to allocate Elastic IP - Stack Overflow
Elastic IP in an Auto-Scaling Group | by lakshman sundaram | Medium
I configured the EC2 Scaling Group to work with Launch Template and Launch Configuration as follows:
min= 1, desired= 1, max= 2.
I have two subnets with same region, but have two different availability zones.
Whenever I terminate an instance, the new instance launches but it doesn't auto receive a Public IP. Even though the settings is set to auto-receive for public IP. Sometimes it has new public ip, but it's different from the one that I wanted.
I'm currently using one Elastic IP.
User data:
#!/bin/bash
INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)
MAXWAIT=3
ALLOC_ID=eipalloc-redacted
AWS_DEFAULT_REGION=us-east-1
# Make sure the EIP is free
echo "Checking if EIP with ALLOC_ID[$ALLOC_ID] is free...."
ISFREE=$(aws ec2 describe-addresses --allocation-ids $ALLOC_ID --query Addresses[].InstanceId --output text)
STARTWAIT=$(date +%s)
while [ ! -z "$ISFREE" ]; do
if [ "$(($(date +%s) - $STARTWAIT))" -gt $MAXWAIT ]; then
echo "WARNING: We waited 30 seconds, we're forcing it now."
ISFREE=""
else
echo "Waiting for EIP with ALLOC_ID[$ALLOC_ID] to become free...."
sleep 3
ISFREE=$(aws ec2 describe-addresses --allocation-ids $ALLOC_ID --query Addresses[].InstanceId --output text)
fi
done
# Now we can associate the address
echo Running: aws ec2 associate-address --instance-id $INSTANCE_ID --allocation-id $ALLOC_ID --allow-reassociation}
aws ec2 associate-address --instance-id $INSTANCE_ID --allocation-id $ALLOC_ID --allow-reassociation}
Role Policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:DescribeAddresses",
"ec2:AllocateAddress",
"ec2:DescribeInstances",
"ec2:AssociateAddress"
],
"Resource": "*"
}
]
}
error:
Cloud-init v. 20.4.1-0ubuntu1~20.04.1 running 'modules:config' at Fri, 12 Feb 2021 21:35:16 +0000. Up 21.57 seconds.
Checking if EIP with ALLOC_ID[eipalloc-redacted1234] is free....
/var/lib/cloud/instance/scripts/part-001: line 9: aws: command not found
Running:
/var/lib/cloud/instance/scripts/part-001: line 24: aws: command not found
/var/lib/cloud/instance/scripts/part-001: line 25: aws: command not found
Cloud-init v. 20.4.1-0ubuntu1~20.04.1 running 'modules:final' at Fri, 12 Feb 2021 21:35:28 +0000. Up 33.63 seconds.
2021-02-12 21:35:28,823 - cc_scripts_user.py[WARNING]: Failed to run module scripts-user (scripts in /var/lib/cloud/instance/scripts)
2021-02-12 21:35:28,824 - util.py[WARNING]: Running module scripts-user (<module 'cloudinit.config.cc_scripts_user' from '/usr/lib/python3/dist-packages/cloudinit/config/cc_scripts_user.py'>) failed
Cloud-init v. 20.4.1-0ubuntu1~20.04.1 finished at Fri, 12 Feb 2021 21:35:29 +0000. Datasource DataSourceEc2Local. Up 34.17 seconds
I figured out the issue.
The instance was missing the awscli tool.
Once I installed it, the script is working !
Thanks for the person whom wrote this script.

Updating long list of IP descriptions with AWS CLI

I'm running into quoting issues with AWS CLI when trying to update description of security group rules.
Can anyone advise how I can rewrite this piece to accommodate a list of IPs?
while read -r line; do
aws ec2 update-security-group-rule-descriptions-ingress \
--group-id sg-123456 \
--region us-east-2 \
--ip-permissions "[{'IpProtocol': 'tcp', 'FromPort': 443, 'ToPort': 443, 'IpRanges': [{'CidrIp': ${line}, 'Description': 'Meaningful description'}]}]"
done < ip_list
Move the single quotes to encompass the whole JSON, then use double quotes for the JSON content, which typically expects double quotes.
--ip-permissions '[{"IpProtocol": "tcp", "FromPort": 443, "ToPort": 443, "IpRanges": [{"CidrIp": ${line}, "Description": "Meaningful description"}]}]'
I ended up having to use this format:
while IFS=, read -r IP CLIENT_DESC
do
aws ec2 authorize-security-group-ingress --region us-east-2 --group-id sg-123456 --ip-permissions IpProtocol=tcp,FromPort=443,ToPort=443,IpRanges="[{CidrIp=${IP},Description=${CLIENT_DESC}}]"
done < server_rules

Do not print the error when running the AWS commmand

I am trying to delete the security groups by running the command
for i in `aws ec2 describe-security-groups --filters Name=vpc-id,Values="${vpcid}" | grep sg- | sed -E 's/^.*(igw-[a-z0-9]+).*$/\1/'`; do aws ec2 delete-security-group --group-id $i; done
It will delete the custom security group successfully. However, return an error when trying to delete a default security group. I don't want the error to be returned on the terminal, and instead just return nothing.
I have tried to add || true at the end of delete-security-group command, which looks like
for i in `aws ec2 describe-security-groups --filters Name=vpc-id,Values="${vpcid}" | grep sg- | sed -E 's/^.*(igw-[a-z0-9]+).*$/\1/'`; do aws ec2 delete-security-group --group-id $i || true; done
while the error is still printed on the terminal. Any helps
using command 2>/dev/null to redirect the error

Revoke all AWS security group ingress rules

Is it possible to revoke all the ingress rules in an AWS security group? Is it possible to revoke all the SSH ingress rules? I'm trying with the cli command below, but it's not working:
aws ec2 revoke-security-group-ingress --group-id GroupID --protocol tcp --port 22
Based on the suggestion of #kuboon, here is a simpler, working version of that script, tested in zsh. The key differences are:
Forcing the first command to return json (which is not always the default) by explicitly using --output json option
Passing that result to parameter --ip-permissions of revoke-security-group-ingress rather than as a fully-formatted command in json (which it is not) that --cli-input-json would require.
groupId="your group-id"
aws ec2 revoke-security-group-ingress --group-id $groupId \
--ip-permissions \
"`aws ec2 describe-security-groups --output json --group-ids $groupId --query "SecurityGroups[0].IpPermissions"`"
I ended up writing a Powershell script that uses the AWS CLI to do that.
The script goes through all the regions, looks for the default security group, and deletes all rules in it.
Here it is:
# get all regions
write-host "Getting all regions.."
$regions = ([string](aws ec2 describe-regions --region eu-west-2) | ConvertFrom-Json).Regions.RegionName
write-host "Got them:"
$regions
write-host "-------------------"
write-host ""
# for all regions
foreach ($region in $regions)
{
write-host "Getting default security groups for $region.."
# get all subnets
$groupIds = ([string](aws ec2 describe-security-groups --filters Name=group-name,Values=default --region $region) | ConvertFrom-Json).SecurityGroups.GroupId
foreach ($groupId in $groupIds)
{
write-host "Got it: $groupId"
write-host "Getting all rules.."
$rules = [string](aws ec2 describe-security-groups --group-id $groupId --query "SecurityGroups[0].IpPermissions" --region $region) | ConvertFrom-Json
foreach ($rule in $rules)
{
$protocol = $rule.IpProtocol
$cidr = $rule.IpRanges.CidrIp
$fromPort = $rule.FromPort
$toPort = $rule.ToPort
$cidrIpv6 = $rule.Ipv6Ranges.CidrIpv6
$sourceGroup = $rule.UserIdGroupPairs.GroupId
$sourceGroupUserId = $rule.UserIdGroupPairs.UserId
if ($protocol -eq "icmpv6") {
$protocol = "icmp"
}
if (($protocol -eq "tcp") -Or ($protocol -eq "udp") -Or ($protocol -eq "icmp"))
{
if ($cidr){
if ($fromPort -eq -1){
write-host "Removing rule from security group using this command:"
write-host "aws ec2 revoke-security-group-ingress --group-id $groupId --protocol $protocol --port "$fromPort" --cidr $cidr --region $region"
aws ec2 revoke-security-group-ingress --group-id $groupId --protocol $protocol --port "$fromPort" --cidr $cidr --region $region
write-host "Done!"
query
}
else {
write-host "Removing rule from security group using this command:"
write-host "aws ec2 revoke-security-group-ingress --group-id $groupId --protocol $protocol --port "$fromPort-$toPort" --cidr $cidr --region $region"
aws ec2 revoke-security-group-ingress --group-id $groupId --protocol $protocol --port "$fromPort-$toPort" --cidr $cidr --region $region
write-host "Done!"
}
}
if ($cidrIpv6){
$json = ('{"IpProtocol": "'+$protocol+'", "FromPort": '+$fromPort+', "ToPort": '+$toPort+', "Ipv6Ranges": [{"CidrIpv6": "'+$cidrIpv6+'"}]}') | ConvertTo-Json
write-host "Removing Ipv6 version of rule from security group using this command:"
write-host "aws ec2 revoke-security-group-ingress --group-id $groupId --ip-permissions $json --region $region"
aws ec2 revoke-security-group-ingress --group-id $groupId --ip-permissions $json --region $region
write-host "Done!"
}
if ($sourceGroup -and $sourceGroupUserId)
{
write-host "Removing SourceGroup rule from security group using this command:"
write-host "aws ec2 revoke-security-group-ingress --group-id $groupId --protocol $protocol --port "$fromPort-$toPort" --cidr $cidr --region $region"
aws ec2 revoke-security-group-ingress --group-id $groupId --protocol $protocol --port "$fromPort-$toPort" --source-group $sourceGroup --group-owner $sourceGroupUserId --region $region
write-host "Done!"
}
}
else
{
if ($cidr){
write-host "Removing rule from security group using this command:"
write-host "aws ec2 revoke-security-group-ingress --group-id $groupId --protocol $protocol --cidr $cidr --region $region"
aws ec2 revoke-security-group-ingress --group-id $groupId --protocol $protocol --cidr $cidr --region $region
write-host "Done!"
}
if ($cidrIpv6){
$json = '{"IpProtocol": "-1", "Ipv6Ranges": [{"CidrIpv6": "'+$cidrIpv6+'"}]}' | ConvertTo-Json
write-host "Removing Ipv6 version of rule from security group using this command:"
write-host "aws ec2 revoke-security-group-ingress --group-id $groupId --ip-permissions $json --region $region"
aws ec2 revoke-security-group-ingress --group-id $groupId --ip-permissions $json --region $region
write-host "Done!"
}
if ($sourceGroup)
{
$json = '{ "IpProtocol": "-1", "UserIdGroupPairs":[{"GroupId":"'+$sourceGroup+'","UserId":"'+$sourceGroupUserId+'"}] }' | ConvertTo-Json
write-host "Removing SourceGroup rule from security group using this command:"
write-host "aws ec2 revoke-security-group-ingress --group-id $groupId --ip-permissions $json --region $region"
aws ec2 revoke-security-group-ingress --group-id $groupId --ip-permissions $json --region $region
write-host "Done!"
}
}
}
}
write-host "-------------------"
write-host ""
}
N.B.
This script cannot delete some rules (custom protocols, Custom ICMP Rule - IPv6), but it works for most rules.
I tested the script on the following set of rules:
This is what is left after running the script:
Hope this helps somebody out there!
It looks like you have to specify each source individually, for example --cidr 0.0.0.0/0 or --source-group sg-12345678.
Get list of rules and revoke all.
groupId="your group-id"
json=`aws ec2 describe-security-groups --group-id $groupId --query "SecurityGroups[0].IpPermissions"`
aws ec2 revoke-security-group-ingress --cli-input-json "{\"GroupId\": \"$groupId\", \"IpPermissions\": $json}"
Just a minor improvement to demonicdaron's script, more than 1 cidr can be returned to the same rule, in this case you just do a foreach() on the $cidr to loop over everyone.
But it works like a charm