AWS – Get Security Group mapping/listing Service wise using Powershell

I needed to find out which all Security Groups are in use(active), and which all are not linked to any service (are unused), so that I could do a clean up. Unfortunately, the AWS command for Security Groups does not provide this info, and the only way is to check through each service that is using a Security Group. So, to gather all that info, I wrote a powershell script.

This script pulls the details of all SGs, then pulls details of all EC2, RDS, ELB and EFS instances. It then compares the data to see where a particular SG is being used. It also checks if an SG is being used within another SG, before marking it inactive. The results are saved in 2 CSV files; one containing the mapping of SG to various servcies, and the other containing the inbound and outbound rules.

There is AWS Config service as well, which may provide all this info. I have not used that service, hence don’t know what all info it provides. There is a cost when using this service.

The formatting is all screwed up by wordpress, and I don’t know how to set it right.

 


$AllEC2Instances = (Get-EC2Instance).Instances #Fetch all the EC2 instances in your environment. The region is set in the credentials of the shell.
$AllRDSInstances = Get-RDSDBInstance #Fetch all the RDS instances in the environment.
$AllSecurityGroups = Get-EC2SecurityGroup
$AllELBs_1 = Get-ELBLoadBalancer
$AllELBs_2 = Get-ELB2LoadBalancer
$AllEFSs = Get-EFSFileSystem
$AllEFSsDetails = @()
#To get the security group ID for EFS is not easy. You need to first get the file system ID, then the mount target ID, and then use it to get Security Group ID.
foreach ($i in $AllEFSs) {
$A = Get-EFSMountTarget -FileSystemId $i.FileSystemId
$B = Get-EFSMountTargetSecurityGroup -MountTargetId $A.MountTargetId
$details = @{
FileSystemId = $i.FileSystemId
Name = $i.Name
MountTargetId = $A.MountTargetId
SecurityGroupId = $B
FileSystemState = $i.LifeCycleState
}
$AllEFSsDetails += $details
}

$instanceDetails = @() #Array
$details = @{} #Hash Table
$SGList = New-Object 'System.Collections.Generic.List[System.String]'
$instanceSecurityGroupDetails = @() #Array

foreach ($sg in $AllSecurityGroups) {
#Fetch Inbound and Outbound rules of all Security Groups
$securityGroupDetailsInbound = $sg.IpPermissions
$securityGroupDetailsOutbound = $sg.IpPermissionsEgress
#Loop through all Inbound rules of SG.
foreach ($j in $securityGroupDetailsInbound) {
#Ipv4Ranges contains the IP v4 address being referenced in a rule.
foreach ($i in $j.Ipv4Ranges) {
$SecDetails = @{
VPCID = $sg.VpcId
SecurityGroupID = $sg.GroupId
SecurityGroupName = $sg.GroupName
SecurityGroupDescription = $sg.Description
SecurityGroupRuleFromPort = ($j.FromPort | out-string).Trim()
SecurityGroupRuleToPort = ($j.ToPort | out-string).Trim()
SecurityGroupRuleIPRange = ($i.CidrIP | out-string).Trim()
SecurityGroupRuleIPRangeDesciption = ($i.Description | out-string).Trim()
SecurityGroupProtocol = ($j.IpProtocol | Out-String).Trim()
SecurityGroupRuleDirection = “Inbound”
}
$instanceSecurityGroupDetails += New-Object PSObject -Property $SecDetails
}
#UserIdGroupPairs attribute stores the ID of the SG if it is being referenced in a rule.
foreach ($i in $j.UserIdGroupPairs) {
$SecDetails = @{
VPCID = $sg.VpcID
SecurityGroupID = $sg.GroupId
SecurityGroupName = $sg.GroupName
SecurityGroupDescription = $sg.Description
SecurityGroupRuleFromPort = ($j.FromPort | out-string).Trim()
SecurityGroupRuleToPort = ($j.ToPort | out-string).Trim()
SecurityGroupRuleIPRange = ($i.GroupId | out-string).Trim()
SecurityGroupRuleIPRangeDesciption = ($i.Description | out-string).Trim()
SecurityGroupProtocol = ($j.IpProtocol | Out-String).Trim()
SecurityGroupRuleDirection = “Inbound”
}
$instanceSecurityGroupDetails += New-Object PSObject -Property $SecDetails
}
#Ipv6Ranges contains the IP v6 address being referenced in a rule.
foreach ($i in $j.Ipv6Ranges) {
$SecDetails = @{
VPCID = $sg.VpcID
SecurityGroupID = $sg.GroupId
SecurityGroupName = $sg.GroupName
SecurityGroupDescription = $sg.Description
SecurityGroupRuleFromPort = ($j.FromPort | out-string).Trim()
SecurityGroupRuleToPort = ($j.ToPort | out-string).Trim()
SecurityGroupRuleIPRange = ($i.CidrIPv6 | out-string).Trim()
SecurityGroupRuleIPRangeDesciption = ($i.Description | out-string).Trim()
SecurityGroupProtocol = ($j.IpProtocol | Out-String).Trim()
SecurityGroupRuleDirection = “Inbound”
}
$instanceSecurityGroupDetails += New-Object PSObject -Property $SecDetails
}
}
#Loop through all Outbound rules of SG.
foreach ($j in $securityGroupDetailsOutbound) {
#Ipv4Ranges contains the IP v4 address being referenced in a rule.
foreach ($i in $j.Ipv4Ranges) {
$SecDetails = @{
VPCID = $sg.VpcID
SecurityGroupID = $sg.GroupId
SecurityGroupName = $sg.GroupName
SecurityGroupDescription = $sg.Description
SecurityGroupRuleFromPort = ($j.FromPort | out-string).Trim()
SecurityGroupRuleToPort = ($j.ToPort | out-string).Trim()
SecurityGroupRuleIPRange = ($i.CidrIP | out-string).Trim()
SecurityGroupRuleIPRangeDesciption = ($i.Description | out-string).Trim()
SecurityGroupProtocol = ($j.IpProtocol | Out-String).Trim()
SecurityGroupRuleDirection = “Outbound”
}
$instanceSecurityGroupDetails += New-Object PSObject -Property $SecDetails
}
#UserIdGroupPairs attribute stores the ID of the SG if it is being referenced in a rule.
foreach ($i in $j.UserIdGroupPairs) {
$SecDetails = @{
VPCID = $sg.VpcID
SecurityGroupID = $sg.GroupId
SecurityGroupName = $sg.GroupName
SecurityGroupDescription = $sg.Description
SecurityGroupRuleFromPort = ($j.FromPort | out-string).Trim()
SecurityGroupRuleToPort = ($j.ToPort | out-string).Trim()
SecurityGroupRuleIPRange = ($i.GroupId | out-string).Trim()
SecurityGroupRuleIPRangeDesciption = ($i.Description | out-string).Trim()
SecurityGroupProtocol = ($j.IpProtocol | Out-String).Trim()
SecurityGroupRuleDirection = “Outbound”
}
$instanceSecurityGroupDetails += New-Object PSObject -Property $SecDetails
}
#Ipv6Ranges contains the IP v6 address being referenced in a rule.
foreach ($i in $j.Ipv6Ranges) {
$SecDetails = @{
VPCID = $sg.VpcID
SecurityGroupID = $sg.GroupId
SecurityGroupName = $sg.GroupName
SecurityGroupDescription = $sg.Description
SecurityGroupRuleFromPort = ($j.FromPort | out-string).Trim()
SecurityGroupRuleToPort = ($j.ToPort | out-string).Trim()
SecurityGroupRuleIPRange = ($i.CidrIPv6 | out-string).Trim()
SecurityGroupRuleIPRangeDesciption = ($i.Description | out-string).Trim()
SecurityGroupProtocol = ($j.IpProtocol | Out-String).Trim()
SecurityGroupRuleDirection = “Outbound”
}
$instanceSecurityGroupDetails += New-Object PSObject -Property $SecDetails
}
}
#Below, first the SG ID is compared with the security group data returned by each instance of other services. If a match is found, that particular service(s) data is then stored.
$EC2Detail = $AllEC2Instances | Where {$_.securitygroups.GroupId | foreach { if ($_ -eq $sg.GroupId) { $_ }}}
$RDSDetail = $AllRDSInstances | Where {$_.VpcSecurityGroups.VpcSecurityGroupId | foreach { if ($_ -eq $sg.GroupId) { $_ }}}
$AllELB_1 = $AllELBs_1 | Where {$_.SecurityGroups | foreach { if ($_ -eq $sg.GroupId) { $_ }}}
$AllELB_2 = $AllELBs_2 | Where {$_.SecurityGroups | foreach { if ($_ -eq $sg.GroupId) { $_ }}}
$AllEFS = $AllEFSsDetails | Where {$_.SecurityGroupId | foreach { if ($_ -eq $sg.GroupId) { $_ }}}
if ($EC2Detail -OR $RDSDetail -OR $AllELB_1 -OR $AllELB_2 -OR $AllEFS) { $SGList.Add($sg.GroupId) }
if ($EC2Detail) {
foreach ($instance in $EC2Detail) {
$details = @{
InstanceID = $instance.InstanceId
InstanceName = ($instance.Tag | Where-Object { $_.key -ceq “Name” } | select -ExpandProperty Value);
InstanceState = $instance.State | select -ExpandProperty Name
Type = “EC2”
SecurityGroupID = $sg.GroupId
SecurityGroupName = $sg.GroupName
SecurityGroupDescription = ($sg.Description | out-string).Trim()
SecurityGroupActive = “Yes”
}
$instanceDetails += New-Object PSObject -Property $details # Add the data of the hash table to an object, which will be later exported in CSV format.
}
}
else {
$sgtemp = $sg.GroupId
if (!($SGList.Contains($sgtemp))) {
$ActiveStatus = “No”
$instanceSecurityGroupDetails | where {$_.SecurityGroupRuleIPRange | foreach { if ($_ -eq $sgtemp) { $ActiveStatus = “Yes” }}}
$details = @{
InstanceID = “”
InstanceName = “”
InstanceState = “”
Type = “”
SecurityGroupID = $sg.GroupId
SecurityGroupName = $sg.GroupName
SecurityGroupDescription = $sg.Description
SecurityGroupActive = $ActiveStatus
}
$instanceDetails += New-Object PSObject -Property $details # Add the data of the hash table to an object, which will be later exported in CSV format.
}
}
if ($RDSDetail) {
foreach ($instance in $RDSDetail) {
$details = @{
InstanceID = $instance.DbiResourceId
InstanceName = $instance.DBInstanceIdentifier
InstanceState = $instance.DBInstanceStatus
Type = “RDS”
SecurityGroupID = $sg.GroupId
SecurityGroupName = $sg.GroupName
SecurityGroupDescription = ($sg.Description | out-string).Trim()
SecurityGroupActive = “Yes”
}
$instanceDetails += New-Object PSObject -Property $details # Add the data of the hash table to an object, which will be later exported in CSV format.
}
}
if ($AllELB_1) {
foreach ($instance in $AllELB_1) {
$details = @{
InstanceID = “”
InstanceName = $instance.LoadBalancerName
InstanceState = “”
Type = “ELB”
SecurityGroupID = $sg.GroupId
SecurityGroupName = $sg.GroupName
SecurityGroupDescription = ($sg.Description | out-string).Trim()
SecurityGroupActive = “Yes”
}
$instanceDetails += New-Object PSObject -Property $details # Add the data of the hash table to an object, which will be later exported in CSV format.
}
}
if ($AllELB_2) {
foreach ($instance in $AllELB_2) {
$details = @{
InstanceID = “”
InstanceName = $instance.LoadBalancerName
InstanceState = $instance.State.Code
Type = ($instance.Type.Value | out-string).Trim() + ” ELB”
SecurityGroupID = $sg.GroupId
SecurityGroupName = $sg.GroupName
SecurityGroupDescription = ($sg.Description | out-string).Trim()
SecurityGroupActive = “Yes”
}
$instanceDetails += New-Object PSObject -Property $details # Add the data of the hash table to an object, which will be later exported in CSV format.
}
}
if ($AllEFS) {
foreach ($instance in $AllEFS) {
$details = @{
InstanceID = $instance.FileSystemId
InstanceName = $instance.Name
InstanceState = $instance.FileSystemState
Type = “EFS”
SecurityGroupID = $sg.GroupId
SecurityGroupName = $sg.GroupName
SecurityGroupDescription = ($sg.Description | out-string).Trim()
SecurityGroupActive = “Yes”
}
$instanceDetails += New-Object PSObject -Property $details # Add the data of the hash table to an object, which will be later exported in CSV format.
}
}
}

#The instance data and SG rules are exported to different files in CSV format.
$instanceDetails | export-csv -Path c:\AWSinstanceDetails_2.csv -NoTypeInformation -Encoding UTF8 #Export the data to a csv file.
$instanceSecurityGroupDetails | export-csv -Path c:\AWSSecurityRuleDetails_2.csv -NoTypeInformation -Encoding UTF8 #Export the data to a csv file.

When using the above script, if you have instances in multiple regions, please mention region ID explicitly, as by default the script will pick the region set in the shell.

If you find any way to make this code more efficient, elegant or smaller, please do let me know.

Posted in AWS.

Leave a comment