Skip to content

Commit

Permalink
Merge pull request #21 from fireflycons/dev
Browse files Browse the repository at this point in the history
CLoses #20
  • Loading branch information
fireflycons authored Jul 11, 2019
2 parents 8726b82 + 523d4b0 commit 1c83749
Show file tree
Hide file tree
Showing 11 changed files with 438 additions and 45 deletions.
5 changes: 5 additions & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Release Notes

## 0.15.0

* New Command `Get-ATEC2SecurityGroupDependencies`. Given a security group ID or IDs, find all network interfaces and other security groups that refer to the input IDs.
Useful before trying to delete a group, as it will not delete if it has any dependecies.

## 0.14.1

* Fix a bug that arose today. Seems AWS have changed S3 URL format for urls with region in. Was s3-eu-west-1, now s3.eu-west-1. Either way, support both.
Expand Down
52 changes: 52 additions & 0 deletions aws-toolbox/Private/EC2/Get-SecurityGroupWithStack.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
function Get-SecurityGroupWithStack
{
<#
.SYNOPSIS
Return security group ID with the name of the stack that created the group
Helps us to spot default SGs created by EB
#>
[CmdletBinding()]
param
(
[Parameter(ValueFromPipelineByPropertyName)]
[string[]]$GroupId
)

begin
{}

process
{
$GroupId |
ForEach-Object {
$sg = Get-EC2SecurityGroup -GroupId $_

if ($null -ne $sg)
{
# Determine how it was created from tags
$stackName = $sg.Tags |
Where-Object {
$_.Key -ieq 'aws:cloudformation:stack-name'
} |
Select-Object -ExpandProperty Value

if (-not $stackName)
{
$stackName = '*NONE*'
}

New-Object PSObject -Property @{
SecurityGroupId = $_
OwningStack = $stackName
} |
Add-Member -PassThru -MemberType ScriptMethod -Name ToString -Force -Value {
"$($this.SecurityGroupId) ($($this.OwningStack))"
}
}
}
}

end
{}
}

38 changes: 0 additions & 38 deletions aws-toolbox/Public/EB/Get-ATEBEnvironmentResourceList.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -60,44 +60,6 @@ function Get-ATEBEnvironmentResourceList
[switch]$AsText
)

function Get-SecurityGroupWithStack
{
<#
.SYNOPSIS
Return security group ID with the name of the stack that created the group
Helps us to spot default SGs created by EB
#>
param
(
[string[]]$GroupId
)

$GroupId |
ForEach-Object {
$sg = Get-EC2SecurityGroup -GroupId $_

# Determine how it was created from tags
$stackName = $sg.Tags |
Where-Object {
$_.Key -ieq 'aws:cloudformation:stack-name'
} |
Select-Object -ExpandProperty Value

if (-not $stackName)
{
$stackName = '*NONE*'
}

New-Object PSObject -Property @{
SecurityGroupId = $_
OwningStack = $stackName
} |
Add-Member -PassThru -MemberType ScriptMethod -Name ToString -Force -Value {
"$($this.SecurityGroupId) ($($this.OwningStack))"
}
}
}

# Pass relevant arguments from function call to Get-EBEnvironment
$envArgs = @{}

Expand Down
231 changes: 231 additions & 0 deletions aws-toolbox/Public/EC2/Get-ATEC2SecurityGroupDependencies.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
function Get-ATEC2SecurityGroupDependencies
{
<#
.SYNOPSIS
Find all dependencies of a given security group or groups.
.DESCRIPTION
You cannot delete a security group if it is in use anywhere.
Usages come down to whether it is bound to any network interface (e.g. instance or laod balancer),
or whether it is referenced as the target of a rule in another security group.
This cmdlet enables you to determine what may be linked to the given security group so you can
break those links prior to deleting it.
.PARAMETER GroupId
One or more security groups to obtain dependency information for
.PARAMETER AsText
If set, print a report to the console, else returns an object that can be used by a calling script.
Where possible, if a dependency belongs to a cloudformation stack, then the owning stack name is shown in parentheses.
.EXAMPLE
Get-ATEC2SecurityGroupDependencies -GroupId sg-00000000 -AsText
List dependencies of given group to console
.EXAMPLE
Get-ATEC2SecurityGroupDependencies -GroupId sg-00000000
Return dependencies of given group as object
.EXAMPLE
(Get-ATEBEnvironmentResourceList my-eb-environment).Instances.SecurityGroups.SecurityGroupId | sort -Unique | Get-ATEC2SecurityGroupDependencies -AsText
List dependencies of security groups attached to instances of an Elastic Beanstalk environment to console.
.EXAMPLE
(Get-ATEBEnvironmentResourceList my-eb-environment).LoadBalancers.SecurityGroups.SecurityGroupId | Get-ATEC2SecurityGroupDependencies -AsText
List dependencies of security groups attached to load balancers of an Elastic Beanstalk environment to console.
.NOTES
IAM permissions required to run this command
- ec2:DescribeSecurityGroups
- ec2:DescribeTags
- elasticloadbalancing:DescribeLoadBalancers
- elasticloadbalancing:DescribeTags
.INPUTS
[string]
Security Group ID(s)
.OUTPUTS
[object]
Or nothing if -AsText
#>
param
(
[Parameter(ValueFromPipeline, Position = 0)]
[string[]]$GroupId,

[switch]$AsText
)

begin
{
function Write-RuleReferences
{
param
(
[string]$ReferenceType,
[object]$References
)

if ($null -eq $References)
{
Write-Host "- No $($ReferenceType.ToLower()) rule references"
}
else
{
Write-Host "- $($ReferenceType) rule references from:"

$References |
ForEach-Object {
Write-Host " - $_"
}
}
}

function Get-ELBStack
{
param
(
[string]$ElbDescription
)

if ($ElbDescription -match '(ELB\s+)?\w+/(?<name>.*)?/')
{
$elbName = $matches.name

try
{
$elb = Get-ELB2LoadBalancer -Name $elbName
}
catch
{
$elb = null
}
}
elseif ($ElbDescription -match '(ELB\s+)?(?<name>.*)')
{
$elbName = $matches.name

try
{
$elb = Get-ELBLoadBalancer -LoadBalancerName $elbName
}
catch
{
$elb = $null
}
}

if ($null -eq $elb)
{
return 'Not a load balancer'
}

if ($elb -is [Amazon.ElasticLoadBalancing.Model.LoadBalancerDescription])
{
$tags = Get-ELBResourceTag -LoadBalancerName $elbName | Select-Object -ExpandProperty Tags

}
else
{
$tags = Get-ELB2Tag -ResourceArn $elb.LoadBalancerArn | Select-Object -ExpandProperty Tags
}

if ($null -eq $tags)
{
return '*NONE*'
}

$stack = $tags |
Where-Object {
$_.Key -eq 'aws:cloudformation:stack-name'
} |
Select-Object -ExpandProperty Value

if ($stack)
{
return $stack
}
else
{
return '*NONE*'
}
}
}

process
{
$GroupId |
Foreach-Object {

$sgs = Get-SecurityGroupWithStack -GroupId $_

if ($null -ne $sgs)
{
$sg = $sgs.SecurityGroupId

$detail = New-Object PSObject -Property @{
SecurityGroup = $sgs
NetworkInterfaces = Get-EC2NetworkInterface -Filter @{ Name = 'group-id'; Values = $sg }
IngressReferences = Get-EC2SecurityGroup -Filter @{ Name = 'ip-permission.group-id'; Values = $sg } |
Get-SecurityGroupWithStack |
Where-Object {
$_.SecurityGroupId -ne $sgs.SecurityGroupId
}
EgressReferences = Get-EC2SecurityGroup -Filter @{ Name = 'egress.ip-permission.group-id'; Values = $sg } |
Get-SecurityGroupWithStack |
Where-Object {
$_.SecurityGroupId -ne $sgs.SecurityGroupId
}
}

if ($AsText)
{
Write-Host "Dependencies for $sgs"
Write-Host "Attached to:"

if ($null -eq $detail.NetworkInterfaces)
{
Write-Host "- No network attachments"
}
else
{
$detail.NetworkInterfaces |
ForEach-Object {

if (-not [string]::IsNullOrEmpty($_.Attachment.InstanceId))
{
Write-Host "- Instance $($_.Attachment.InstanceId)"
}
elseif (-not [string]::IsNullOrEmpty($_.Description))
{
$elbStack = Get-ELBStack -ElbDescription $_.Description
Write-Host "- $($_.Description):$($_.AvailabilityZone) ($elbStack)"
}
else
{
Write-Host "- Unknown attachment"
}
}
}

Write-Host "Other security groups that reference this one:"
Write-RuleReferences -ReferenceType "Ingress" -References $detail.IngressReferences
Write-RuleReferences -ReferenceType "Egress" -References $detail.EgressReferences
Write-Host
}
else
{
$detail
}
}
}
}

end
{

}
}
9 changes: 9 additions & 0 deletions aws-toolbox/Public/SSM/Invoke-ATSSMPowerShellScript.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,15 @@ function Invoke-ATSSMPowerShellScript
.EXAMPLE
Invoke-ATSSMPowerShellScript -InstanceIds i-00000000 -AsText { dir c:\ }
Returns directory listing from remote instance to the console.
.NOTES
IAM permissions required to run this command
- ssm:GetConnectionStatus
- ssm:ListCommandInvocations
- ssm:ListCommands
- ssm:SendCommand
- ec2:DescribeInstances
#>
[CmdletBinding(DefaultParameterSetName = 'AsText')]
param
Expand Down
11 changes: 10 additions & 1 deletion aws-toolbox/Public/SSM/Invoke-ATSSMShellScript.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,17 @@ function Invoke-ATSSMShellScript
Format of bucket name is aws-toolbox-workspace-REGIONNAME-AWSACCOUNTID
.EXAMPLE
Invoke-ATSSMShellScript -InstanceIds i-00000000 -AsText { ls -la / }
Invoke-ATSSMShellScript -InstanceIds i-00000000 -AsText "ls -la /"
Returns directory listing from remote instance to the console.
.NOTES
IAM permissions required to run this command
- ssm:GetConnectionStatus
- ssm:ListCommandInvocations
- ssm:ListCommands
- ssm:SendCommand
- ec2:DescribeInstances
#>
[CmdletBinding(DefaultParameterSetName = 'AsText')]
param
Expand Down
3 changes: 2 additions & 1 deletion aws-toolbox/aws-toolbox.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
RootModule = 'aws-toolbox.psm1'

# Version number of this module.
ModuleVersion = '0.14.1'
ModuleVersion = '0.15.0'

# ID used to uniquely identify this module
GUID = 'e3c04d58-4e7d-4572-9e81-3b3a93f1a518'
Expand Down Expand Up @@ -52,6 +52,7 @@
'Compress-ATLMLambdaPackage'
'Set-ATConfigurationItem'
'Invoke-ATDiffTool'
'Get-ATEC2SecurityGroupDependencies'
)

# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
Expand Down
Loading

0 comments on commit 1c83749

Please sign in to comment.