Find manually created resources (AWS)
How many times have you come across AWS environments that grew organically, with resources created manually. Usually such projects later identify the need for Infrastructure as Code (IaC) but how do you find out what was created via Script (CloudFormation) vs by hand?
# To assist in identifying resources which have been provisioned manually and not through cloudformation.
# This approach was used as opposed to pulling all resources with specific tags, as not all resource types support tagging at this stage.
#Initially load your AWS creds - replace values with your keys.
Import-Module AWSPowerShell
$AWSKEY = "Somekey"
$AWSSECRET = "SomeSecret"
Set-AWSCredential -AccessKey $AWSKEY -SecretKey $AWSSECRET -StoreAs Default
#Define output location
$outputlocation = $ENV:TEMP
#Get all the stacks
$stacksNames = Get-CFNStack | ForEach-Object -MemberName StackName
#iterate through stacks getting all resources
$totalstackresources = foreach ($stacksname in $stacksNames){
Get-CFNStackResourceList -StackName $stacksname
}
#Useful for working through the various different resource types.
$ResourceTypes = $totalstackresources | select -Property ResourceType -Unique | Sort-Object Resourcetype
#unmanaged AutoScaleGroups
$CFASG = $totalstackresources | Where {$_.ResourceType -like "AWS::AutoScaling::AutoScalingGroup"} | select -Property PhysicalResourceId | Add-Member -MemberType AliasProperty -Name InstanceId -Value PhysicalResourceId -PassThru | select InstanceId
$ASGS = Get-ASAutoScalingGroup | Select-Object AutoScalingGroupName
$UnmanagedASG = Compare-Object $ASGS $CFASG | ForEach-Object { $_.InputObject}
$UnmanagedASG | Export-Csv $outputlocation/UnmanagedASG.csv
#unmanaged AutoScaleGroupLaunch Configuration
$CFASGLC = $totalstackresources | Where {$_.ResourceType -like "AWS::AutoScaling::LaunchConfiguration"} | select -Property PhysicalResourceId | Add-Member -MemberType AliasProperty -Name InstanceId -Value PhysicalResourceId -PassThru | select InstanceId
$ASGLC = Get-ASLaunchConfiguration | Select-Object LaunchConfigurationName
$UnmanagedASGLC = Compare-Object $ASGLC $CFASGLC | ForEach-Object { $_.InputObject}
$UnmanagedASGLC | Export-Csv $outputlocation/UnmanagedASGLC.csv
#Unmanaged EIPs
$CFEIP = $totalstackresources | Where {$_.ResourceType -like "AWS::EC2::EIP"} | select -Property PhysicalResourceId | Add-Member -MemberType AliasProperty -Name InstanceId -Value PhysicalResourceId -PassThru | select InstanceId
$EIPIds = Get-EC2Address | Select-Object NetworkInterfaceId, PublicIp, PrivateIpAddress
$UnmanagedEIPS = Compare-Object $EIPIds $CFEIP| ForEach-Object { $_.InputObject}
$UnmanagedEIPS | Export-Csv $outputlocation/UnmanagedEips.csv
#Unmanaged EC2 Instances
$CFInstance = $totalstackresources | Where {$_.ResourceType -like "AWS::EC2::Instance"} | select -Property PhysicalResourceId | Add-Member -MemberType AliasProperty -Name InstanceId -Value PhysicalResourceId -PassThru | select InstanceId
$InstanceIds = Get-EC2Instance | % { $_.RunningInstance } | Select-Object InstanceId,PublicDnsName,@{Name='TagValues'; Expression={($_.Tag | %{$_.Key + '=' + $_.Value}) -join ', '}}
$UnmanagedEC2Instances = Compare-Object $InstanceIds $CFInstance | ForEach-Object { $_.InputObject}
$UnmanagedEC2Instances| Export-Csv $outputlocation/UnmanagedEC2Instances.csv
#unmanaged SecurityGroups
$CFSG = $totalstackresources | Where {$_.ResourceType -like "AWS::EC2::SecurityGroup"} | select -Property PhysicalResourceId | Add-Member -MemberType AliasProperty -Name InstanceId -Value PhysicalResourceId -PassThru | select InstanceId
$SGIds = Get-EC2SecurityGroup | Select-Object GroupName,Description
$UnmanagedSG = Compare-Object $SGIds $CFSG| ForEach-Object { $_.InputObject}
$UnmanagedSG | Export-Csv $outputlocation/UnmanagedSG.csv
#Unmanaged ELB
$CFELB = $totalstackresources | Where {$_.ResourceType -like "AWS::ElasticLoadBalancing::LoadBalancer"} | select -Property PhysicalResourceId | Add-Member -MemberType AliasProperty -Name InstanceId -Value PhysicalResourceId -PassThru | select InstanceId
$ELBIds = Get-ELBLoadBalancer | Select-Object DNSName,LoadBalancerName,Instances
$UnmanagedELBs = Compare-Object $ELBIDs $CFELB | ForEach-Object { $_.InputObject}
$UnmanagedELBs | Export-Csv $outputlocation/UnmanagedELBs.csv
#Unmanaged ALB (ELB v2)
$CFALB = $totalstackresources | Where {$_.ResourceType -like "AWS::ElasticLoadBalancingV2::LoadBalancer"} | select -Property PhysicalResourceId | Add-Member -MemberType AliasProperty -Name InstanceId -Value PhysicalResourceId -PassThru | select InstanceId
$ALBIds = Get-ELB2LoadBalancer | Select-Object LoadBalancerArn,DNSName,LoadBalancerName
$UnmanagedALBs = Compare-Object $ALBIDs $CFALB | ForEach-Object { $_.InputObject}
$UnmanagedALBs | Export-Csv $outputlocation/UnmanagedALBs.csv
#Unmanaged Instance Profiles
$CFProfile = $totalstackresources | Where {$_.ResourceType -like "AWS::IAM::InstanceProfile"} | select -Property PhysicalResourceId
$ProfileIds = Get-IAMInstanceProfileList | Select-Object Arn,InstanceProfileName,InstanceProfileId
$UnmanagedProfiles = Compare-Object $ProfileIds $CFProfile | ForEach-Object { $_.InputObject}
$UnmanagedProfiles | Export-Csv $outputlocation/UnmanagedProfiles.csv
#Unmanaged IAM Policies - Please note that there a bunch of AWS defined policies which have been excluded based on the filter provided below.
$CFPolicy = $totalstackresources | Where {$_.ResourceType -like "AWS::IAM::Policy"} | select -Property PhysicalResourceId
$PolicyIds = Get-IAMPolicyList | Where-Object {$_.Arn -like "arn:aws:iam::862017364710:policy/*"}| Select-Object Arn,PolicyName,PolicyId
$UnmanagedPolicies = Compare-Object $PolicyIds $CFPolicy | ForEach-Object { $_.InputObject}
$UnmanagedPolicies | Export-Csv $outputlocation/UnmanagedPolicies.csv
#Unmanaged IAM Role
$CFIAMROLE = $totalstackresources | Where {$_.ResourceType -like "AWS::IAM::Role"} | select -Property PhysicalResourceId
$IAMROLEIds = Get-IAMRoleList | Select-Object RoleId,RoleName
$UnmanagedIAMRoles = Compare-Object $IAMROLEIds $CFIAMROLE | ForEach-Object { $_.InputObject}
$UnmanagedIAMRoles | Export-Csv $outputlocation/UnmanagedIAMRoles.csv
#Unmanaged Lambda Functions
$CFLambdaFN = $totalstackresources | Where {$_.ResourceType -like "AWS::Lambda::Function"} | select -Property PhysicalResourceId
$LambdaIDs = Get-LMFunctionList | Select-Object FunctionName,Runtime,RoleName
$UnmanagedLambdaIDs = Compare-Object $LambdaIDs $CFLambdaFN | ForEach-Object { $_.InputObject}
$UnmanagedLambdaIDs | Export-Csv $outputlocation/UnmanagedLambdas.csv
#Unmanaged Route53 Resources need to convert R53 string into array for comparison
$CFR53 = $totalstackresources | Where {$_.ResourceType -like "AWS::Route53::RecordSet"} | select -Property PhysicalResourceId
$R53list = Get-R53ResourceRecordSet -HostedZoneId Z1JVZK10L1ND7P | Select-Object ResourceRecordSets
$R53s = $R53s.ResourceRecordSets | Select-Object Name
$UnmanagedR53s = Compare-Object $R53s $CFR53 | ForEach-Object { $_.InputObject}
$UnmanagedR53s | Export-Csv $outputlocation/UnmanagedR53s.csv
#Unmanaged RDS instances
$CFRDS = $totalstackresources | Where {$_.ResourceType -like "AWS::RDS::DBInstance"} | select -Property PhysicalResourceId | Add-Member -MemberType AliasProperty -Name InstanceId -Value PhysicalResourceId -PassThru | select InstanceId
$DBARNS = Get-RDSDBInstance | ForEach-Object -MemberName DBInstanceArn
$dbtotal = @()
$DBARNS | foreach {
$DBARN = new-object PSObject -Property @{
InstanceId= ($_.Split(":")[6])}
$dbtotal +=$DBARN}
$UnmanagedDBInstances = Compare-Object $dbtotal $CFRDS | ForEach-Object { $_.InputObject}
$UnmanagedDBInstances| Export-Csv $outputlocation/UnmanagedDBInstances.csv
#Unmanaged RDS Subnet Groups
$CFRDSSG = $totalstackresources | Where {$_.ResourceType -like "AWS::RDS::DBSubnetGroup"} | select -Property PhysicalResourceId | Add-Member -MemberType AliasProperty -Name InstanceId -Value PhysicalResourceId -PassThru | select InstanceId
$DBSGS = Get-RDSDBSubnetGroup | Select-Object DBSubnetGroupArn, DBSubnetGroupName, DBSubnetGroupDescription
$UnmanagedRDSSG = Compare-Object $DBSGS $CFRDSSG | ForEach-Object { $_.InputObject}
$UnmanagedRDSSG | Export-Csv $outputlocation/UnmanagedRDSSG.csv
#Unmanaged RDS Option Groups
$CFRDSOG = $totalstackresources | Where {$_.ResourceType -like "AWS::RDS::OptionGroup"} | select -Property PhysicalResourceId | Add-Member -MemberType AliasProperty -Name InstanceId -Value PhysicalResourceId -PassThru | select InstanceId
$DBOGS = Get-RDSOptionGroup | Select-Object OptionGroupArn
$UnmanagedRDSOG = Compare-Object $DBOGS $CFRDSOG | ForEach-Object { $_.InputObject}
$UnmanagedRDSOG | Export-Csv $outputlocation/UnmanagedRDSOG.csv
#Unmanaged SQS resources
$CFSQS = $totalstackresources | Where {$_.ResourceType -like "AWS::SQS::Queue"} | select -Property PhysicalResourceId
$SQSIds = Get-IAMRoleList | Select-Object RoleId,RoleName
$UnmanagedSQS = Compare-Object $SQSIds $CFSQS | ForEach-Object { $_.InputObject}
$UnmanagedSQS | Export-Csv $outputlocation/UnmanagedSQS.csv
#Unmanaged Volumes - Please note that there are a bunch of volumes not in use which are NOT included.
$CFVolume = $totalstackresources | Where {$_.ResourceType -like "AWS::EC2::Volume"} | select -Property PhysicalResourceId | Add-Member -MemberType AliasProperty -Name InstanceId -Value PhysicalResourceId -PassThru | select InstanceId
$VolumeIds = Get-ec2volume | Where {$_.State -eq "in-use"} | Select-Object VolumeId, Attachments,Size
$UnmanagedVolumes = Compare-Object $VolumeIds $CFVolume | ForEach-Object { $_.InputObject}
$UnmanagedVolumes | Export-Csv $outputlocation/Unmanagedvolumes.csv