├── .gitattributes ├── CloudTrail └── Basics.ps1 ├── EC2 ├── BootstrapExample.ps1 ├── Get-EC2Images_GroupByOwnerCount.ps1 ├── Get-EC2VPCOrgs.ps1 ├── Get-SnapshotsByOwner.ps1 ├── ListAllEC2Instances.ps1 └── Register-IAMInstanceProfileToAllEC2.ps1 ├── IAM ├── Convert Policy to Json.ps1 ├── Get MFA Devices in all Orgs.ps1 ├── Get-IAMUsersMFAStatus.ps1 ├── GetAWSUsersInRoles_allOrgs.ps1 ├── GetAccessKeyList_AllOrgs.ps1 ├── GetCredentialReport.ps1 ├── Level6.ps1 ├── New-IAMAuditor - RAPID 7 deployment.ps1 ├── New-IAMAuditor.ps1 ├── New-MFADevice.ps1 ├── Remove-IAMAccessKeyAllOrgs.ps1 ├── Update-PasswordPolicyAllOrgs.ps1 └── security_assessment_access.template ├── LICENSE ├── Organizations ├── Get-AllOrgOus.ps1 └── Get-OrgPolicyInformation.ps1 ├── README.md ├── S3 ├── FlawsS3Buckets.ps1 ├── Get-AWSCanonicalUserID.ps1 ├── Get-AccessKeysInMetadata.ps1 ├── Get-AccessKeysInS3.ps1 ├── Get-S3AllObjectMetadata.ps1 ├── Get-S3BucketRegion.ps1 ├── List All Files In Buckets.ps1 └── Set-S3ACLEasy.ps1 ├── STS ├── Get-AWSTempCred.ps1 └── STS Switch Roles in Organization.ps1 └── SecurityHub └── AddUsertoHub.ps1 /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /CloudTrail/Basics.ps1: -------------------------------------------------------------------------------- 1 | $events = Find-CTEvent -StartTime (get-date).AddDays(-1) -EndTime (get-date) -MaxResult 50 2 | 3 | 4 | convertfrom-json($events[0].cloudtrailevent) 5 | (convertfrom-json($events[0].cloudtrailevent)).useridentity 6 | (convertfrom-json($events[0].cloudtrailevent)).useridentity.sessioncontext 7 | (convertfrom-json($events[0].cloudtrailevent)).useridentity.sessioncontext.attributes -------------------------------------------------------------------------------- /EC2/BootstrapExample.ps1: -------------------------------------------------------------------------------- 1 | 2 | 3 | $installdir = "C:\Bootstrap" 4 | $filename = "filename.zip" 5 | mkdir $installdir 6 | set-location $installdir 7 | 8 | #download file to the folder on local machine 9 | $WebClient = New-object System.net.webclient 10 | $FileURL = "Http://s3bucketlocation/Filurl/" + $filename 11 | $localfile = $installdir + "\" + $filename 12 | $WebClient.DownloadFile("$fileurl","$localfile") 13 | 14 | 15 | #unzip file onto local machine 16 | $NewShell = new-object -com shell.application 17 | $zipFilePath = $newshell.namespace($localfile); 18 | $dest = $NewShell.namespace((get-location).path) 19 | $destionation.copyhere($zipfilepath.items(),0x14) 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /EC2/Get-EC2Images_GroupByOwnerCount.ps1: -------------------------------------------------------------------------------- 1 | #get only machines with ownerid count is 1-5 2 | # 3 | 4 | Function Get-EC2Images_GroupByOwnerCount{ 5 | 6 | param ( 7 | [Parameter(Mandatory=$true)][int]$MaxImages 8 | 9 | ) 10 | 11 | $filter = @{ 12 | Name = 'Owner-id' 13 | Values = '137112412989' 14 | } 15 | $CommonOwners = @('099720109477','137112412989') 16 | get-date 17 | $amilist = @() 18 | Get-AWSRegion|%{ 19 | $amilist += Get-EC2Image -Region $_.Region| where {$filter} 20 | } 21 | get-date 22 | <#PS $amilist.count 23 | 105431 24 | $amilist2 = get-ec2image -Region eu-west-1 25 | $amilist2.count 26 | 85700 27 | #> 28 | 29 | 30 | $COmmonOwners|%{ 31 | $amilist = $amilist|Where-Object -Property ownerid -NE $_ 32 | } 33 | 34 | 35 | group-object 36 | 37 | 38 | 39 | } -------------------------------------------------------------------------------- /EC2/Get-EC2VPCOrgs.ps1: -------------------------------------------------------------------------------- 1 | Function Get-EC2VpcOrgs { 2 | [cmdletbinding()] 3 | param( 4 | [Parameter(Mandatory=$true)][string]$Role, #role used for cross account access 5 | [object]$OrganizationList, #Supply region list you want to test against 6 | [switch]$SkipDefault #if specified, do not list any default VPCs in output 7 | ) 8 | if (!$OrganizationList){$OrganizationList = Get-ORGAccountList }else{} 9 | $regions = Get-AWSRegion |Where-Object { 10 | $_.Region -ne 'me-south-1' -and 11 | $_.region -ne 'ap-east-1'} 12 | $orgProgress = 1 13 | $ocount = $organizationlist.count 14 | $originID = (Get-STSCallerIdentity).account 15 | $vpcArray = @() 16 | $OrganizationList |%{ 17 | 18 | $orgid = $_.ID 19 | $oname = $_.Name 20 | if ($orgid -ne $originID){$Credentials = Get-STSCreds -OrganizationID $orgid -role $role} 21 | Write-Progress -Activity "Searching Through Orgs: $oname" -id 1 -Status "$orgProgress complete of $ocount" -PercentComplete ($orgProgress/$ocount*100) 22 | 23 | $regionProgress = 1 24 | $rcount = $regions.count 25 | $Regions |%{ 26 | 27 | $region = $_ 28 | $rname = $_.name 29 | Write-Progress -Activity "Searching Through REGION: $rname on ORG: $oname" -id 2 -Status "$regionProgress complete of $Rcount" -PercentComplete ($regionProgress/$Rcount*100) -CurrentOperation "Looking for VPCs in all regions for All Orgs" 30 | if ($orgid -ne $originID){$VPCs = get-ec2vpc -Region $_.Region -Credential $Credentials}else{ 31 | $VPCs = get-ec2vpc -Region $_.Region 32 | } 33 | 34 | $VPCs |%{ 35 | if($SkipDefault -and $_.IsDefault -eq $true){}Else{ 36 | $obj = new-object psobject 37 | $obj |Add-member NoteProperty OrganizationID $orgid 38 | $obj |Add-member NoteProperty OrganizationName $oName 39 | $obj |Add-member NoteProperty Region $rname 40 | $obj |Add-member NoteProperty VPC $VPCs 41 | $obj |Add-member NoteProperty CidrBlock $_.CidrBlock 42 | $obj |Add-member NoteProperty IsDefault $_.IsDefault 43 | if($_.tags.key -contains 'Name'){ 44 | $n = ($_.tags|where-object {$_.key -eq 'Name'}).value 45 | }else{ 46 | $n = 'NoTagName' 47 | } 48 | $obj |Add-member NoteProperty Name $n 49 | $obj |Add-member NoteProperty OwnerID $_.OwnerId 50 | $obj |Add-member NoteProperty VPCID $_.VpcId 51 | $obj |Add-member NoteProperty State $_.State 52 | 53 | $VPCArray += $obj 54 | } 55 | } 56 | 57 | 58 | 59 | 60 | $regionProgress++ 61 | } 62 | 63 | $orgProgress++ 64 | } 65 | $VPCArray 66 | } 67 | 68 | #list all orgs, foreach org, get all regions, foreach region get ec2vpcs, -------------------------------------------------------------------------------- /EC2/Get-SnapshotsByOwner.ps1: -------------------------------------------------------------------------------- 1 | Function Get-SnapshotsByOwner{ 2 | 3 | param ( 4 | [Parameter(Mandatory=$true)][string]$OrganizationID, 5 | [Parameter(Mandatory=$true)][string]$Profile 6 | 7 | ) 8 | $snapshotlist = @() 9 | Get-AWSRegion|%{ 10 | $rn = $_.Region 11 | try{$snapshotlist += Get-EC2Snapshot -ProfileName $Profile -Region $_.region -OwnerId $OrganizationID} 12 | catch{write-host "Error on Region $rn"} 13 | 14 | } 15 | $snapshotlist 16 | } -------------------------------------------------------------------------------- /EC2/ListAllEC2Instances.ps1: -------------------------------------------------------------------------------- 1 | Function Get-EC2InstanceList { 2 | [CmdletBinding()] 3 | 4 | param 5 | ( 6 | [Parameter(Mandatory = $false, 7 | Position = 1, 8 | HelpMessage = 'Supply a stored AWS credential role authorized for cross accounts listing')] 9 | [System.String]$Role 10 | ) 11 | 12 | 13 | $regions = Get-AWSRegion 14 | $rcount = $Regions.count 15 | $ec2Array = @() 16 | if ($Role){ 17 | $orgs = Get-ORGAccountList 18 | $orgProgress = 1 19 | $ocount = $orgs.count 20 | 21 | $orgs|%{ 22 | $org = $_ 23 | $oname = $org.name 24 | Write-Progress -Activity "Searching Through Org: $oname" -id 1 -Status "$orgProgress complete of $ocount" -PercentComplete ($orgProgress/$ocount*100) 25 | 26 | $regionProgress = 1 27 | try{ 28 | try{$Credentials = Get-STSCreds -OrganizationID $_.Id -role $role 29 | $regions | % { 30 | $oname = $org.name 31 | $region = $_ 32 | $rname = $_.name 33 | Write-Progress -Activity "Searching Through REGION: $rname on ORG: $oname" -id 2 -Status "$regionProgress complete of $Rcount" -PercentComplete ($regionProgress/$Rcount*100) -CurrentOperation "Looking for EC2s in all regions for All Orgs" 34 | 35 | try{$ec2 = Get-EC2Instance -Credential $Credentials -Region $_.Region 36 | $EC2|%{ 37 | Clear-Variable -Name status 38 | $status = Get-ec2instancestatus -InstanceId $_.instances.instanceid -Region $region.Region -Credential $Credentials 39 | $Pemkey = $ec2 |select instances 40 | $obj = new-object psobject 41 | 42 | $obj |Add-member NoteProperty OrganizationID $org.id 43 | $obj |Add-member NoteProperty OrganizationName $org.Name 44 | $obj |Add-member NoteProperty InstanceID $_.instances.instanceid 45 | $obj |Add-member NoteProperty InstanceType $_.instances.InstanceType 46 | $obj |Add-member NoteProperty Region $region.Region 47 | if($status){ 48 | $obj |Add-member NoteProperty InstanceState $status.instancestate.name 49 | $obj |Add-member NoteProperty Reachability $status.status.status 50 | $obj |Add-member NoteProperty InstanceStatus $status 51 | 52 | } 53 | else{ 54 | $obj |Add-member NoteProperty InstanceState "NoStateFound" 55 | $obj |Add-member NoteProperty Reachability "NoStateFound" 56 | $obj |Add-member NoteProperty InstanceStatus "NoStateFound" 57 | } 58 | $obj |Add-member NoteProperty Instances $_.instances 59 | $ec2Array += $obj 60 | 61 | } 62 | 63 | } 64 | catch{} 65 | $regionProgress++ 66 | } 67 | } 68 | catch{} 69 | #Iterate over all regions and list instances 70 | 71 | } 72 | catch{$regions | % { 73 | $oname = $org.name 74 | $region = $_ 75 | $rname = $_.name 76 | Write-Progress -Activity "Searching Through REGION: $rname on ORG: $oname" -id 2 -Status "$regionProgress complete of $Rcount" -PercentComplete ($regionProgress/$Rcount*100) -CurrentOperation "Looking for EC2s in all regions for All Orgs" 77 | try{$ec2 = Get-EC2Instance -Region $_.Region 78 | $EC2|%{ 79 | Clear-Variable -Name status 80 | $status = Get-ec2instancestatus -InstanceId $_.instances.instanceid -Region $region.Region 81 | $Pemkey = $_ |select instances 82 | $obj = new-object psobject 83 | 84 | $obj |Add-member NoteProperty OrganizationID $org.id 85 | $obj |Add-member NoteProperty OrganizationName $org.Name 86 | $obj |Add-member NoteProperty InstanceID $_.instances.instanceid 87 | $obj |Add-member NoteProperty InstanceType $_.instances.InstanceType 88 | $obj |Add-member NoteProperty Region $region.Region 89 | if($status){ 90 | $obj |Add-member NoteProperty InstanceState $status.instancestate.name 91 | $obj |Add-member NoteProperty Reachability $status.status.status 92 | $obj |Add-member NoteProperty InstanceStatus $status 93 | 94 | } 95 | else{ 96 | $obj |Add-member NoteProperty InstanceState "NoStateFound" 97 | $obj |Add-member NoteProperty Reachability "NoStateFound" 98 | $obj |Add-member NoteProperty InstanceStatus "NoStateFound" 99 | } 100 | $obj |Add-member NoteProperty Instances $ec2.instances 101 | $ec2Array += $obj 102 | 103 | } 104 | 105 | } 106 | catch{} 107 | $regionProgress++ 108 | } 109 | } 110 | $orgProgress++ 111 | } 112 | }else{ #NO role Specified, only doing for 1 account 113 | 114 | $regions | % { 115 | $oname = Get-IAMAccountAlias 116 | $acctid = (Get-STSCallerIdentity).account 117 | if (!$oname){$oname = 'NoAccountAlias'} 118 | $region = $_ 119 | $rname = $_.name 120 | Write-Progress -Activity "Searching Through REGION: $rname on ORG: $oname" -id 2 -Status "$regionProgress complete of $Rcount" -PercentComplete ($regionProgress/$Rcount*100) -CurrentOperation "Looking for EC2s in all regions for All Orgs" 121 | try{$ec2 = Get-EC2Instance -Region $_.Region 122 | $EC2|%{ 123 | Clear-Variable -Name status 124 | $status = Get-ec2instancestatus -InstanceId $_.instances.instanceid -Region $region.Region 125 | $Pemkey = $_ |select instances 126 | $obj = new-object psobject 127 | 128 | $obj |Add-member NoteProperty OrganizationID $acctid 129 | $obj |Add-member NoteProperty OrganizationName $oname 130 | $obj |Add-member NoteProperty InstanceID $_.instances.instanceid 131 | $obj |Add-member NoteProperty InstanceType $_.instances.InstanceType 132 | $obj |Add-member NoteProperty Region $region.Region 133 | if($status){ 134 | $obj |Add-member NoteProperty InstanceState $status.instancestate.name 135 | $obj |Add-member NoteProperty Reachability $status.status.status 136 | $obj |Add-member NoteProperty InstanceStatus $status 137 | 138 | } 139 | else{ 140 | $obj |Add-member NoteProperty InstanceState "NoStateFound" 141 | $obj |Add-member NoteProperty Reachability "NoStateFound" 142 | $obj |Add-member NoteProperty InstanceStatus "NoStateFound" 143 | } 144 | $obj |Add-member NoteProperty Instances $ec2.instances 145 | $ec2Array += $obj 146 | 147 | } 148 | 149 | } 150 | catch{} 151 | $regionProgress++ 152 | } 153 | 154 | } 155 | 156 | 157 | 158 | 159 | $ec2Array 160 | 161 | } 162 | 163 | 164 | 165 | -------------------------------------------------------------------------------- /EC2/Register-IAMInstanceProfileToAllEC2.ps1: -------------------------------------------------------------------------------- 1 | Function Register-EC2IamInstanceProfileAll { 2 | [CmdletBinding()] 3 | 4 | param 5 | ( 6 | [Parameter(Mandatory = $true, 7 | Position = 1, 8 | HelpMessage = 'List of EC2s to attach IAM Role onto')] 9 | [object]$EC2List, 10 | [Parameter(Mandatory = $true, 11 | Position = 2, 12 | HelpMessage = 'The EC2 IAM Role to be attached to EC2 in list')] 13 | [System.String]$InstanceProfileName, 14 | [Parameter(Mandatory = $false, 15 | Position = 3, 16 | HelpMessage = 'Cross account role with access to set ec2 instance profiles')] 17 | [System.String]$Role 18 | ) 19 | $ec2array = @() 20 | if($Role){ 21 | 22 | }else{ 23 | $EC2Profile = Get-IAMInstanceProfile -InstanceProfileName $InstanceProfileName 24 | if (!$EC2Profile){Write-Warning "$InstanceProfileName Does not exist. Exiting Script"} 25 | $EC2List |%{ 26 | clear-variable -name attached 27 | $ec2id = $_.instanceid 28 | $ec2region = $_.region 29 | $attached = Get-EC2IamInstanceProfileAssociation -Filter @{name='instance-id'; values=$ec2id} -Region $ec2region 30 | if ($attached.IamInstanceProfile.id -contains $EC2Profile.InstanceProfileId){ 31 | #do nothing, already attached 32 | $profileinfo = Get-EC2IamInstanceProfileAssociation -Region $ec2region |where {($_.instanceid -eq $ec2id) -and ($_.iaminstanceprofile.id -eq $EC2Profile.instanceprofileid)} 33 | $obj = new-object psobject 34 | 35 | $obj |Add-member NoteProperty InstanceID $ec2id 36 | $obj |Add-member NoteProperty Region $ec2region 37 | $obj |Add-member NoteProperty ProfileName $InstanceProfileName 38 | $obj |Add-Member Noteproperty AttachedStatus $profileinfo 39 | $ec2array += $obj 40 | }else{ 41 | $iamec2arn = $ec2profile.arn 42 | Register-EC2IamInstanceProfile -InstanceId $ec2id -region $ec2region -IamInstanceProfile_Arn $iamec2arn 43 | $profileinfo = Get-EC2IamInstanceProfileAssociation -Region $ec2region |where {($_.instanceid -eq $ec2id) -and ($_.iaminstanceprofile.id -eq $EC2Profile.instanceprofileid)} 44 | 45 | $obj = new-object psobject 46 | 47 | $obj |Add-member NoteProperty InstanceID $ec2id 48 | $obj |Add-member NoteProperty Region $ec2region 49 | $obj |Add-member NoteProperty ProfileName $InstanceProfileName 50 | $obj |Add-Member Noteproperty AttachedStatus $profileinfo 51 | $ec2array += $obj 52 | } 53 | } 54 | } 55 | $ec2array 56 | } -------------------------------------------------------------------------------- /IAM/Convert Policy to Json.ps1: -------------------------------------------------------------------------------- 1 | Function Convert-PolicyToJson { 2 | 3 | param ( 4 | $Policy 5 | ) 6 | if (($Policy|gm).name -contains 'document'){ 7 | [System.Reflection.Assembly]::LoadWithPartialName("System.Web.HttpUtility") 8 | $policy = [System.Web.HttpUtility]::UrlDecode($Policy.Document) 9 | $policy 10 | } 11 | 12 | } -------------------------------------------------------------------------------- /IAM/Get MFA Devices in all Orgs.ps1: -------------------------------------------------------------------------------- 1 | Function Get-MFADevicesAllOrgs { 2 | param ( 3 | 4 | [Parameter(Mandatory=$true)][string]$Role 5 | 6 | ) 7 | $mfadevices = @() 8 | $orgs = Get-ORGAccountList|select id, name, email 9 | foreach ($org in $orgs){ 10 | $orgid = $null 11 | $credentials = $null 12 | $rolearn = $null 13 | 14 | $Orgid= $org.id 15 | $RoleArn = "arn:aws:iam::${Orgid}:role/$role" 16 | if ((Get-STSCallerIdentity).account -ne $Orgid){ 17 | write-verbose "On $orgID" 18 | try{$credentials = Switch-AWSRoles -OrganizationID $Orgid -Role $Role 19 | #Get-IAMVirtualMFADevice -Credential $Credentials 20 | $mfadevices += Get-IAMVirtualMFADevice -Credential $Credentials 21 | } 22 | Catch{write-verbose $error[0]} 23 | } 24 | 25 | else{ 26 | $mfadevices += Get-IAMVirtualMFADevice 27 | } 28 | 29 | } 30 | $MFAreadable = @() 31 | 32 | foreach ($device in $mfadevices){ 33 | $obj = new-object psobject 34 | $obj |Add-member NoteProperty SerialNumber $device.serialnumber 35 | $obj |Add-member NoteProperty DevOrganizationID $(($device.serialnumber -split ":")[4]) 36 | $obj | Add-member NoteProperty UserARN $device.user.Arn 37 | $obj | Add-member NoteProperty UserName $device.user.UserName 38 | $obj |Add-member NoteProperty UserOrganizationID $(($device.user.Arn -split ":")[4]) 39 | $MFAreadable += $obj 40 | } 41 | $mfareadable 42 | } -------------------------------------------------------------------------------- /IAM/Get-IAMUsersMFAStatus.ps1: -------------------------------------------------------------------------------- 1 |  2 | 3 | function Get-IAMUsersMFAStatus { 4 | #used in conjunction with list all admins output 5 | param ( 6 | [parameter(Mandatory=$true)][object]$UserList, 7 | [parameter(Mandatory=$true)][string]$Role 8 | 9 | ) 10 | 11 | $mfadevices = @() 12 | $MFAreadable = @() 13 | $MFAListAll = @() 14 | foreach ($org in $userlist){ 15 | $orgid = $null 16 | $polgroupmembers = $null 17 | $policyusers = $null 18 | $orgid = $org.organizationid 19 | $polgroupmembers = $org.polgroupmembers 20 | $policyusers = $org.policyusers 21 | 22 | 23 | $account = $orgid 24 | #$RoleArn = "arn:aws:iam::${Account}:role/$role" 25 | if ((Get-STSCallerIdentity).account -ne $orgid){ 26 | #$Response = (Use-STSRole -Region $Region -RoleArn $RoleArn -RoleSessionName 'CMDB').Credentials 27 | $Credentials = Switch-AWSRoles -OrganizationID $orgid -Role $role 28 | #New-AWSCredentials -AccessKey $Response.AccessKeyId -SecretKey $Response.SecretAccessKey -SessionToken $Response.SessionToken 29 | $mfadevices += Get-IAMVirtualMFADevice -Credential $Credentials 30 | } else { 31 | $mfadevices += Get-IAMVirtualMFADevice 32 | } 33 | 34 | # 35 | foreach ($device in $mfadevices){ 36 | $obj = new-object psobject 37 | $obj |Add-member NoteProperty SerialNumber $device.serialnumber 38 | $obj | Add-member NoteProperty UserARN $device.user.Arn 39 | $obj |Add-member NoteProperty OrganizationID $(($device.serialnumber -split ":")[4]) 40 | $obj | Add-member NoteProperty UserName $device.user.UserName 41 | $MFAreadable += $obj 42 | } 43 | 44 | 45 | 46 | #check for root in mfareadable 47 | $obj = new-object psobject 48 | $obj |Add-member NoteProperty OrganizationID $org.OrganizationID 49 | $obj |Add-member NoteProperty OrganizationName $org.OrganizationName 50 | $obj |Add-member Noteproperty Username "Root" 51 | $orgID = $org.OrganizationID 52 | $rootarn = "arn:aws:iam::${orgid}:root" 53 | $rootmfaexists = $null 54 | $rootmfaexists = ($mfadevices.user.arn -contains $rootarn) 55 | if ($rootmfaexists -eq $true){ 56 | #this if shows that an mfa device is created for the root account 57 | $obj |Add-member NoteProperty MFAEnabled "YES" 58 | }else { 59 | #this else shows there is no MFA device created for the root accoutn 60 | $obj |Add-member NoteProperty MFAEnabled "NO" 61 | } 62 | $mfalistall += $obj 63 | if($org.polgroupmembers.count -gt 0){ 64 | foreach ($u in $org.polgroupmembers){ 65 | $obj = new-object psobject 66 | $orgID = $org.OrganizationID 67 | $uname = $u.username 68 | 69 | $obj |Add-member NoteProperty OrganizationID $orgID 70 | $obj |Add-member NoteProperty OrganizationName $org.OrganizationName 71 | $obj |Add-member Noteproperty Username $uname 72 | 73 | $arn = "arn:aws:iam::${orgid}:user/${Uname}" 74 | 75 | $rootmfaexists = $null 76 | $rootmfaexists = ($MFAreadable.userarn -eq $arn) 77 | if ($rootmfaexists){ 78 | #this if shows that an mfa device is created for the root account 79 | $obj |Add-member NoteProperty MFAEnabled "YES" 80 | } 81 | else { 82 | #this else shows there is no MFA device created for the root accoutn 83 | $obj |Add-member NoteProperty MFAEnabled "NO" 84 | } 85 | $mfalistall += $obj 86 | } 87 | 88 | } 89 | if($org.policyusers.count -gt 0){ 90 | foreach ($u in $org.policyusers){ 91 | $obj = new-object psobject 92 | $orgID = $org.OrganizationID 93 | $uname = $u.username 94 | $obj |Add-member NoteProperty OrganizationID $org.OrganizationID 95 | $obj |Add-member NoteProperty OrganizationName $org.OrganizationName 96 | $obj |Add-member Noteproperty Username $uname 97 | 98 | $arn = "arn:aws:iam::${orgid}:user/${Uname}" 99 | $rootmfaexists = $null 100 | $rootmfaexists = ($MFAreadable.userarn -eq $arn) 101 | if ($rootmfaexists){ 102 | #this if shows that an mfa device is created for the root account 103 | $obj |Add-member NoteProperty MFAEnabled "YES" 104 | } 105 | else { 106 | #this else shows there is no MFA device created for the root accoutn 107 | $obj |Add-member NoteProperty MFAEnabled "NO" 108 | } 109 | $mfalistall += $obj 110 | } 111 | 112 | } 113 | } 114 | 115 | 116 | #now i have all the mfa devices in an entire org, split the $mfadevices into an object that is org id/ user 117 | 118 | $MFALISTALL |Sort-Object -Property organizationid,username -Unique 119 | 120 | } 121 | 122 | -------------------------------------------------------------------------------- /IAM/GetAWSUsersInRoles_allOrgs.ps1: -------------------------------------------------------------------------------- 1 | Function Get-IAMUsersInRoleAllOrgs { 2 | [alias("Get-AWSRoleUserList")] 3 | #This function currently lists all IAM user accounts specified in an instance under the policy titled: AdministratorAccess 4 | param( 5 | [Parameter(Mandatory=$true)]$Role, #where $role is the role you want to assume to authenticate to another organization. 6 | [string]$PolicyName = "AdministratorAccess", 7 | [switch]$AllUsers 8 | ) 9 | $orgs = Get-ORGAccountList|select id, name, email 10 | $adminlist = @() 11 | $userlist = @() 12 | foreach ($org in $orgs){ 13 | if($AllUsers){ 14 | $id =$org.Id 15 | $nm = $org.name 16 | #write-host "On account $id $nm" 17 | $obj = new-object psobject 18 | $obj |Add-member NoteProperty OrganizationID $id 19 | $obj |Add-member NoteProperty Arn $org.arn 20 | $obj | Add-Member NoteProperty OrganizationName $nm 21 | $account = $org.id 22 | $Credentials = Get-STSCreds -OrganizationID $id -Role $role 23 | $userinORglist = Get-IAMUserList -Credential $Credentials 24 | $obj |add-member NoteProperty IAMUsers $userinORglist 25 | $userlist += $obj 26 | }else{ 27 | $id =$org.Id 28 | $nm = $org.name 29 | #write-host "On account $id $nm" 30 | $obj = new-object psobject 31 | $obj |Add-member NoteProperty OrganizationID $id 32 | $obj |Add-member NoteProperty Arn $org.arn 33 | $obj | Add-Member NoteProperty OrganizationName $nm 34 | $account = $org.id 35 | 36 | #$RoleArn = "arn:aws:iam::${Account}:role/$role" 37 | 38 | #Request temporary credentials for each account and create a credential object 39 | try { 40 | #$Response = (Use-STSRole -Region $Region -RoleArn $RoleArn -RoleSessionName 'CMDB').Credentials 41 | $Credentials = Switch-AWSRoles -OrganizationID $id -Role $role 42 | #New-AWSCredentials -AccessKey $Response.AccessKeyId -SecretKey $Response.SecretAccessKey -SessionToken $Response.SessionToken 43 | 44 | #List all policies, get all entities on policy 45 | $admins = "" 46 | $admins = Get-IAMEntitiesForPolicy -PolicyArn "arn:aws:iam::aws:policy/$PolicyName" -Credential $Credentials 47 | $obj | add-member NoteProperty PolicyGroups $admins.policygroups 48 | if ($admins.policygroups.count -gt 0){ 49 | $i = 0 50 | foreach ($grp in $admins.policygroups){ 51 | $grpmembers = get-iamgroup -GroupName $admins.PolicyGroups[$i].groupname -Credential $Credentials 52 | $obj |add-member NoteProperty PolGroupMembers $grpmembers.users 53 | $i++ 54 | $grpmembers = $null 55 | } 56 | 57 | } 58 | else{ 59 | 60 | } 61 | } 62 | catch {$admins = Get-IAMEntitiesForPolicy -PolicyArn "arn:aws:iam::aws:policy/$PolicyName" 63 | $obj | add-member NoteProperty PolicyGroups $admins.policygroups 64 | if ($admins.policygroups.count -gt 0){ 65 | $i = 0 66 | foreach ($grp in $admins.policygroups){ 67 | $grpmembers = get-iamgroup -GroupName $admins.PolicyGroups[$i].groupname 68 | $obj |add-member NoteProperty PolGroupMembers $grpmembers.users 69 | $i++ 70 | } 71 | 72 | } 73 | else{ 74 | 75 | } 76 | } 77 | 78 | 79 | $obj | add-member NoteProperty PolicyRoles $admins.PolicyRoles 80 | $obj | add-member NoteProperty PolicyUsers $admins.PolicyUsers 81 | $adminlist += $obj 82 | 83 | 84 | }} 85 | 86 | if ($AllUsers){$userlist}else{ 87 | $adminlist } 88 | } 89 | -------------------------------------------------------------------------------- /IAM/GetAccessKeyList_AllOrgs.ps1: -------------------------------------------------------------------------------- 1 | Function Get-IAMAccessKeysAllOrgs{ 2 | 3 | param( 4 | [Parameter(Mandatory=$true)]$Role 5 | 6 | ) 7 | 8 | $orgs = Get-ORGAccountList|select id, name, email 9 | $AKDetails = @() 10 | 11 | $accesskeys = @() 12 | 13 | foreach ($org in $orgs){ 14 | $id =$org.Id 15 | $nm = $org.name 16 | $userlist = @() 17 | $accesskeys = @() 18 | if ((Get-STSCallerIdentity).account -ne $id){ 19 | 20 | $id = $null 21 | $credentials = $null 22 | $rolearn = $null 23 | 24 | $id= $org.id 25 | $RoleArn = "arn:aws:iam::${Orgid}:role/$role" 26 | $Credentials = Switch-AWSRoles -OrganizationID $id -Role $role 27 | $userlist = get-iamuserlist -Credential $Credentials 28 | $userlist |% { 29 | $uarn = $_.arn 30 | $uorg = ($uarn -split ":")[4] 31 | $accesskeys += Get-IAMAccessKey -UserName $_.UserName -Credential $credentials 32 | } 33 | $accesskeys |% { 34 | $lastused = Get-IAMAccessKeyLastUsed -AccessKeyId $_.AccessKeyId -Credential $credentials 35 | 36 | $obj = new-object psobject 37 | $obj |Add-member NoteProperty OrganizationID $uorg 38 | $obj |Add-member NoteProperty OrganizationName $nm 39 | $obj |Add-member NoteProperty UserName $lastused.UserName 40 | $obj |Add-member Noteproperty AccessKeyID $_.AccessKeyId 41 | $obj |Add-Member NoteProperty KeyCreateDate $_.CreateDate 42 | $obj |Add-Member NoteProperty KeyStatus $_.Status 43 | $obj |Add-member Noteproperty LastUsed $lastused.AccessKeyLastUsed.LastUsedDate 44 | $obj |Add-member Noteproperty Region $lastused.AccessKeyLastUsed.Region 45 | $obj |Add-member Noteproperty Service $lastused.AccessKeyLastUsed.ServiceName 46 | $akdetails += $obj 47 | } 48 | } 49 | 50 | else { 51 | 52 | 53 | $id = $null 54 | $credentials = $null 55 | $rolearn = $null 56 | 57 | $id= $org.id 58 | $userlist = get-iamuserlist 59 | $userlist |% { 60 | $uarn = $_.arn 61 | $uorg = ($uarn -split ":")[4] 62 | $accesskeys += Get-IAMAccessKey -UserName $_.UserName 63 | } 64 | $accesskeys |% { 65 | $lastused = Get-IAMAccessKeyLastUsed -AccessKeyId $_.AccessKeyId 66 | 67 | $obj = new-object psobject 68 | $obj |Add-member NoteProperty OrganizationID $uorg 69 | $obj |Add-member NoteProperty OrganizationName $nm 70 | $obj |Add-member NoteProperty UserName $lastused.UserName 71 | $obj |Add-member Noteproperty AccessKeyID $_.AccessKeyId 72 | $obj |Add-Member NoteProperty KeyCreateDate $_.CreateDate 73 | $obj |Add-Member NoteProperty KeyStatus $_.Status 74 | $obj |Add-member Noteproperty LastUsed $lastused.AccessKeyLastUsed.LastUsedDate 75 | $obj |Add-member Noteproperty Region $lastused.AccessKeyLastUsed.Region 76 | $obj |Add-member Noteproperty Service $lastused.AccessKeyLastUsed.ServiceName 77 | $akdetails += $obj 78 | } 79 | } 80 | 81 | } 82 | $akdetails |sort-object organizationid,LastUsed 83 | 84 | } 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /IAM/GetCredentialReport.ps1: -------------------------------------------------------------------------------- 1 | function Get-AWSCredentialReport { 2 | 3 | param( 4 | [string]$Role 5 | ) 6 | $originID = (Get-STSCallerIdentity).account 7 | $objects = @() 8 | if(!$Role){ 9 | Request-IAMCredentialReport |Out-Null 10 | $report = Get-iamCredentialReport -AsTextArray 11 | 12 | $columnnames = $report[0] -split ',' 13 | $i = 1 #start above first line 14 | 15 | do { 16 | $values = $report[$i] -split ',' 17 | 18 | $columnnum = 0 19 | $obj = new-object psobject 20 | foreach ($column in $columnnames){ 21 | $obj |Add-member NoteProperty $column $values[$columnnum] 22 | $columnnum++ 23 | } 24 | $objects += $obj 25 | 26 | $i++ 27 | } 28 | while ($i -lt $report.count) 29 | }else{ 30 | $OrgAccountList = Get-ORGAccountList 31 | $ocount = $OrgAccountList.count 32 | $orgProgress = 1 33 | 34 | foreach ($acct in $orgaccountlist){ 35 | $orgid = $acct.ID 36 | $oname = $acct.Name 37 | if ($orgid -ne $originID){$Credentials = Get-STSCreds -OrganizationID $orgid -role $role} 38 | Write-Progress -Activity "Searching Through Orgs: $oname" -id 1 -Status "$orgProgress complete of $ocount" -PercentComplete ($orgProgress/$ocount*100) 39 | ###Adding code here 40 | if ($orgid -ne $originID){Request-IAMCredentialReport -Credential $credentials|Out-Null 41 | $report = Get-iamCredentialReport -Credential $Credentials -AsTextArray 42 | }else{ 43 | Request-IAMCredentialReport|Out-Null 44 | $report = Get-iamCredentialReport -AsTextArray 45 | } 46 | 47 | 48 | $columnnames = $report[0] -split ',' 49 | $i = 1 #start above first line 50 | 51 | do { 52 | $values = $report[$i] -split ',' 53 | 54 | $columnnum = 0 55 | $obj = new-object psobject 56 | $obj |Add-member NoteProperty AccountID $acct.id 57 | $obj |Add-member NoteProperty AccountName $acct.Name 58 | foreach ($column in $columnnames){ 59 | $obj |Add-member NoteProperty $column $values[$columnnum] 60 | $columnnum++ 61 | } 62 | $objects += $obj 63 | 64 | $i++ 65 | } 66 | while ($i -lt $report.count) 67 | ### 68 | 69 | $orgProgress++ 70 | } 71 | } 72 | 73 | 74 | 75 | $objects 76 | } -------------------------------------------------------------------------------- /IAM/Level6.ps1: -------------------------------------------------------------------------------- 1 | #Show attached policies to user and other user info: 2 | $profile = "level6" 3 | $user = (Get-IAMAccountAuthorizationDetail -ProfileName $profile).UserDetailList|Where-Object -Property arn -eq ((Get-STSCallerIdentity -ProfileName $profile).Arn) 4 | 5 | $user.attachedmanagedpolicies 6 | 7 | Get-IAMPolicy -PolicyArn arn:aws:iam::975426262029:policy/list_apigateways 8 | 9 | Get-IAMPolicyversion -PolicyArn arn:aws:iam::975426262029:policy/list_apigateways -VersionId v4 10 | 11 | get-lmfunctionlist 12 | 13 | $pol = Get-LMPolicy -FunctionName Level6 14 | $temp = (ConvertFrom-Json $pol.Policy).statement 15 | $temp.condition 16 | <# 17 | ArnLike 18 | ------- 19 | @{AWS:SourceArn=arn:aws:execute-api:us-west-2:975426262029:s33ppypa75/*/GET/level6} 20 | #> 21 | get-agstagelist -RestApiId s33ppypa75 22 | 23 | build url = 24 | htt[s://$lambdaname.$executeapi.$region.amazonaws.com/$stagelist.Stagename/ -------------------------------------------------------------------------------- /IAM/New-IAMAuditor - RAPID 7 deployment.ps1: -------------------------------------------------------------------------------- 1 | get orgs 2 | sift through, foreach do assume role, and then new iamauditor 3 | 4 | $STSRole = 'Credential-role' 5 | #===================================== 6 | $policyjson = '{ 7 | "Version": "2012-10-17", 8 | "Statement": [ 9 | { 10 | "Effect": "Allow", 11 | "Action": [ 12 | "acm:ListTagsForCertificate", 13 | "cloudtrail:ListPublicKeys", 14 | "cloudtrail:ListTags", 15 | "cloudtrail:GetTrailStatus", 16 | "cloudtrail:GetEventSelectors", 17 | "ecr:DescribeRepositories", 18 | "ecr:GetLifecyclePolicy", 19 | "ecr:GetRepositoryPolicy", 20 | "ecr:ListImages", 21 | "iam:GenerateServiceLastAccessedDetails", 22 | "lambda:GetFunction", 23 | "lambda:GetLayerVersion", 24 | "lambda:GetLayerVersionPolicy", 25 | "lambda:GetPolicy", 26 | "lambda:ListFunctions", 27 | "lambda:ListLayerVersions", 28 | "sqs:ListQueues", 29 | "sqs:ListDeadLetterSourceQueues", 30 | "sqs:ListQueueTags", 31 | "sqs:GetQueueUrl", 32 | "sqs:GetQueueAttributes", 33 | "states:DescribeStateMachineForExecution", 34 | "states:DescribeActivity", 35 | "states:DescribeStateMachine", 36 | "states:DescribeExecution", 37 | "states:ListExecutions", 38 | "states:GetExecutionHistory" 39 | ], 40 | "Resource": "*" 41 | } 42 | ] 43 | }' 44 | #supplied by rapid7 45 | #===================================== 46 | $rolejson = '{ 47 | "Version": "2012-10-17", 48 | "Statement": [ 49 | { 50 | "Sid": "", 51 | "Effect": "Allow", 52 | "Principal": { 53 | "AWS": "arn:aws:iam::012345678910:root" 54 | }, 55 | "Action": "sts:AssumeRole", 56 | "Condition": { 57 | "StringEquals": { 58 | "sts:ExternalId": "51f6f3c1-bd77-aaaa-aaaa-88884f42cccc" 59 | } 60 | } 61 | } 62 | ] 63 | }' 64 | #====================================== 65 | 66 | $orgs = Get-ORGAccountList 67 | 68 | $orgs |%{ 69 | 70 | $creds = Switch-AWSRoles -OrganizationID $_.id -Role $STSRole 71 | New-IAMAuditor -PolicyDocument $policyjson -RoleDocument $rolejson -Credentials $creds 72 | 73 | } 74 | 75 | 76 | -------------------------------------------------------------------------------- /IAM/New-IAMAuditor.ps1: -------------------------------------------------------------------------------- 1 | Function New-IAMAuditor { 2 | [cmdletbinding()] 3 | param( 4 | [string]$PolicyName = 'Rapid7-Security-Audit', 5 | [parameter(Mandatory=$true)][string]$PolicyDocument, 6 | [string]$RoleName = $PolicyName, 7 | [parameter(Mandatory=$true)][string]$RoleDocument, 8 | [object]$Credentials 9 | 10 | 11 | ) 12 | #$PolicyName 13 | 14 | try{$NewiamPol = New-IAMPolicy -PolicyName $PolicyName -PolicyDocument $PolicyDocument -Credential $Credentials} 15 | catch{ 16 | if ($error[0].Exception -like "*Duplicate*"){ 17 | $OrganizationID = (Get-STSCallerIdentity -Credential $creds).account 18 | $policyarn = "arn:aws:iam::${OrganizationID}:policy/$PolicyName" 19 | $newiampol = Get-IAMPolicy -PolicyArn $policyarn -Credential $Credentials 20 | 21 | } 22 | 23 | } 24 | $NewIAMRole = New-IAMRole -RoleName $RoleName -AssumeRolePolicyDocument $RoleDocument -Credential $Credentials 25 | 26 | Register-IAMRolePolicy -PolicyArn $NewiamPol.Arn -RoleName $RoleName -Credential $Credentials 27 | 28 | Register-IAMRolePolicy -PolicyArn 'arn:aws:iam::aws:policy/SecurityAudit' -RoleName $RoleName -Credential $Credentials 29 | 30 | $NewIAMRole.Arn 31 | } -------------------------------------------------------------------------------- /IAM/New-MFADevice.ps1: -------------------------------------------------------------------------------- 1 | function New-MFADevice { 2 | param( 3 | 4 | [parameter(Mandatory=$true)][string]$DeviceName, 5 | $OpenInChrome, 6 | [Switch]$Credential, 7 | [string]$CSVImport, 8 | [Switch]$FindKeys 9 | 10 | ) 11 | 12 | $Device = New-IAMVirtualMFADevice -VirtualMFADeviceName $devicename -Credential $creds 13 | $BR = New-Object System.IO.BinaryReader($Device.QRCodePNG) 14 | $BR.ReadBytes($BR.BaseStream.Length) | Set-Content -Encoding Byte -Path "c:\reports\QRCode.png" 15 | 16 | 17 | } -------------------------------------------------------------------------------- /IAM/Remove-IAMAccessKeyAllOrgs.ps1: -------------------------------------------------------------------------------- 1 | $daysold = 45 2 | $lastusedDays = 90 3 | $role = 'cross-account-access-role' 4 | $iamkeys = Get-IAMAccessKeysAllOrgs -Role $role 5 | 6 | $oldiamkeys = $iamkeys|Where-Object -Property keycreatedate -lt ((get-date).AddDays(-$daysold))|Where-Object -Property lastused -lt ((get-date).AddDays(-$lastusedDays)) 7 | $oldiamkeys |%{ 8 | 9 | $creds = Get-STSCreds -OrganizationID $_.OrganizationID -Role $role 10 | $keyid = $_.accesskeyid 11 | Get-IAMUserList -Credential $creds|%{get-iamaccesskey -UserName $_.username -Credential $creds|where-object -Property accesskeyid -eq $keyid|Remove-IAMAccessKey -AccessKeyId $keyid -Credential $creds} 12 | 13 | } -------------------------------------------------------------------------------- /IAM/Update-PasswordPolicyAllOrgs.ps1: -------------------------------------------------------------------------------- 1 | Function Update-IAMAccountPasswordPolicyOrgs{ 2 | [CmdletBinding()] 3 | 4 | param 5 | ( 6 | [string]$Role, 7 | [object]$OrganizationList, 8 | [bool]$AllowUsersToChangePassword = $True, 9 | [bool]$ExpirePasswords = $True, 10 | [bool]$HardExpiry = $False, 11 | [int]$MaxPasswordAge = 90, 12 | [int]$MinimumPasswordLength = 15, 13 | [int]$PasswordReusePrevention = 5, 14 | [bool]$RequireLowercaseCharacters = $True, 15 | [bool]$RequireNumbers =$True, 16 | [bool]$RequireSymbols =$True, 17 | [bool]$RequireUppercaseCharacters = $True 18 | ) 19 | 20 | # set password policy from a list of orgs 21 | if (!$OrganizationList){try{$organizationlist = Get-ORGAccountList}catch{}} 22 | if (!$Role){ 23 | $a = (get-stscalleridentity).account 24 | Write-host "No Role Specified. Setting PWD Policy only on account $a" 25 | Update-IAMAccountPasswordPolicy -AllowUsersToChangePassword $AllowUsersToChangePassword -MaxPasswordAge $MaxPasswordAge -MinimumPasswordLength $MinimumPasswordLength -PasswordReusePrevention $PasswordReusePrevention -RequireLowercaseCharacter $RequireLowercaseCharacters -RequireNumber $RequireNumbers -RequireSymbol $RequireSymbols -RequireUppercaseCharacters $RequireUppercaseCharacters -hardexpiry $false 26 | Get-IAMAccountPasswordPolicy 27 | break 28 | } 29 | if (!$OrganizationList){ 30 | $a = (get-stscalleridentity).account 31 | Write-host "No Organization Account List Found. Setting PWD Policy only on account $a" 32 | Update-IAMAccountPasswordPolicy -AllowUsersToChangePassword $AllowUsersToChangePassword -MaxPasswordAge $MaxPasswordAge -MinimumPasswordLength $MinimumPasswordLength -PasswordReusePrevention $PasswordReusePrevention -RequireLowercaseCharacter $RequireLowercaseCharacters -RequireNumber $RequireNumbers -RequireSymbol $RequireSymbols -RequireUppercaseCharacters $RequireUppercaseCharacters -hardexpiry $false 33 | Get-IAMAccountPasswordPolicy 34 | break 35 | } 36 | 37 | foreach($org in $organizationlist){ 38 | $credential = get-stscreds -OrganizationID $org.id -Role $Role 39 | $name = $org.name 40 | write-host "On $name" 41 | Update-IAMAccountPasswordPolicy -Credential $credential -AllowUsersToChangePassword $AllowUsersToChangePassword -MaxPasswordAge $MaxPasswordAge -MinimumPasswordLength $MinimumPasswordLength -PasswordReusePrevention $PasswordReusePrevention -RequireLowercaseCharacter $RequireLowercaseCharacters -RequireNumber $RequireNumbers -RequireSymbol $RequireSymbols -RequireUppercaseCharacters $RequireUppercaseCharacters -hardexpiry $false 42 | 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /IAM/security_assessment_access.template: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: 'Provides Summit Route with the ability to perform a security assessment on this account. An IAM role is created to provide view-only access of the metadata in the account.' 3 | Resources: 4 | CFNSummitRouteRole: 5 | Type: AWS::IAM::Role 6 | Properties: 7 | AssumeRolePolicyDocument: 8 | Version: '2012-10-17' 9 | Statement: 10 | - Effect: Allow 11 | Principal: 12 | AWS: arn:aws:iam::393727464233:root 13 | Action: 'sts:AssumeRole' 14 | Condition: 15 | Bool: 16 | 'aws:MultiFactorAuthPresent': true 17 | ManagedPolicyArns: 18 | - 'arn:aws:iam::aws:policy/SecurityAudit' 19 | - 'arn:aws:iam::aws:policy/job-function/ViewOnlyAccess' 20 | RoleName: SummitRouteAudit 21 | Policies: 22 | - PolicyName: SummitRouteAdditionalViewPrivileges 23 | PolicyDocument: 24 | Version : '2012-10-17' 25 | Statement: 26 | - Effect: Allow 27 | Action: 28 | - 'acm:DescribeCertificate' 29 | - 'eks:DescribeCluster' 30 | - 'eks:ListClusters' 31 | - 'elasticfilesystem:DescribeMountTargetSecurityGroups' 32 | - 'elasticfilesystem:DescribeMountTargets' 33 | - 'elasticmapreduce:DescribeCluster' 34 | - 'elasticmapreduce:DescribeSecurityConfiguration' 35 | - 'events:DescribeRule' 36 | - 'fms:ListComplianceStatus' 37 | - 'fms:ListPolicies' 38 | - 'guardduty:ListDetectors' 39 | - 'guardduty:ListFindings' 40 | - 'guardduty:ListIPSets' 41 | - 'guardduty:ListInvitations' 42 | - 'guardduty:ListMembers' 43 | - 'guardduty:ListThreatIntelSets' 44 | - 'iam:GenerateServiceLastAccessedDetails' 45 | - 'inspector:DescribeAssessmentRuns' 46 | - 'inspector:DescribeAssessmentTargets' 47 | - 'inspector:DescribeAssessmentTemplates' 48 | - 'inspector:DescribeCrossAccountAccessRole' 49 | - 'inspector:DescribeFindings' 50 | - 'inspector:DescribeResourceGroups' 51 | - 'inspector:DescribeRulesPackages' 52 | - 'iot:DescribeAuthorizer' 53 | - 'iot:DescribeCACertificate' 54 | - 'iot:DescribeCertificate' 55 | - 'iot:DescribeDefaultAuthorizer' 56 | - 'iot:GetPolicy' 57 | - 'iot:GetPolicyVersion' 58 | - 'lambda:GetFunctionConfiguration' 59 | - 'lightsail:GetInstances' 60 | - 'lightsail:GetLoadBalancers' 61 | - 'opsworks:DescribeStacks' 62 | - 'organizations:Describe*' 63 | - 'organizations:List*' 64 | - 'shield:DescribeAttack' 65 | - 'shield:DescribeProtection' 66 | - 'shield:DescribeSubscription' 67 | - 'sso:DescribePermissionsPolicies' 68 | - 'sso:ListApplicationInstanceCertificates' 69 | - 'sso:ListApplicationInstances' 70 | - 'sso:ListApplicationTemplates' 71 | - 'sso:ListApplications' 72 | - 'sso:ListDirectoryAssociations' 73 | - 'sso:ListPermissionSets' 74 | - 'sso:ListProfileAssociations' 75 | - 'sso:ListProfiles' 76 | Resource: '*' -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Organizations/Get-AllOrgOus.ps1: -------------------------------------------------------------------------------- 1 | Function Get-OrgOUList{ 2 | [Alias("Get-IAMOrgOUList")] 3 | <# 4 | .SYNOPSIS 5 | Displays a formatted table of AWS Organization OUs on the console 6 | 7 | .DESCRIPTION 8 | Starting at the root OU, this function displays a formatted list of OUs in an AWS Organization. The user MUST be a user with admin access to the Organization's root account and this function MUST be run in that root account 9 | 10 | .PARAMETER AWSStoredProfile 11 | A stored profile containing the AWS credentials providing admin access to the AWS Organization's master account 12 | 13 | .PARAMETER CSV 14 | This parameter allows you to send the output of the function in CSV format to a file in your home directory. Specify $true; defaults to $false 15 | 16 | .EXAMPLE 17 | PS C:\> ./AddNewOrgAccounToMFSMaster.ps1 -AWSStoredProfile # Displays OUs as table on console 18 | PS C:\> ./AddNewOrgAccounToMFSMaster.ps1 -AWSStoredProfile | Out-File # Writes text to file 19 | PS C:\> ./AddNewOrgAccounToMFSMaster.ps1 -AWSStoredProfile -CSV $true 20 | 21 | 22 | .NOTES 23 | Updates 9/12/2019 - DRowe - Updated output to remove format-table. Allows script to be exported into variable with ease 24 | 9/19/2019 - Added root ou to output 25 | 26 | 27 | Alex Neihaus 2019-07-15 28 | (c) 2019 Air11 Technology LLC -- licensed under the Apache OpenSource 2.0 license, https://opensource.org/licenses/Apache-2.0 29 | Licensed under the Apache License, Version 2.0 (the "License"); 30 | you may not use this file except in compliance with the License. 31 | You may obtain a copy of the License at 32 | http://www.apache.org/licenses/LICENSE-2.0 33 | 34 | Unless required by applicable law or agreed to in writing, software 35 | distributed under the License is distributed on an "AS IS" BASIS, 36 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 37 | See the License for the specific language governing permissions and 38 | limitations under the License. 39 | 40 | Author's blog: https://www.yobyot.com 41 | 42 | 43 | #> 44 | [CmdletBinding()] 45 | 46 | param 47 | ( 48 | [Parameter(Mandatory = $false, 49 | Position = 1, 50 | HelpMessage = 'Supply a stored AWS credential profile authorized in the master account to create new accounts')] 51 | [Alias('creds')] 52 | [System.String]$AWSStoredProfile, 53 | [Parameter(Position = 2, 54 | HelpMessage = 'Enter TRUE to pipe output to a file in .csv format')] 55 | [ValidateSet($true, $false, IgnoreCase = $true)] 56 | [boolean]$CSV = $false, 57 | [Parameter(Mandatory = $false, 58 | Position = 2, 59 | HelpMessage = 'Use if you want to list accounts instead of OUs')] 60 | [switch]$ListAccounts 61 | ) 62 | <# This function recursively lists all OUs starting from the root and places the ARN, ID and name 63 | of the OU into an array to be presented to the user as a formatted table 64 | #> 65 | function Get-OrgChildOUs { 66 | param( 67 | [Parameter(Mandatory = $false, 68 | Position = 1)] 69 | [System.String]$ParentOUId, 70 | [Parameter(Mandatory = $false, 71 | Position = 2)] 72 | [System.String]$ParentName, 73 | [System.String]$ChildType = 'ORGANIZATIONAL_UNIT' 74 | ) 75 | 76 | 77 | $childouids = Get-ORGChild -ParentId $ParentOUId -ChildType $ChildType 78 | foreach ($childouid in $childouids.Id) { 79 | $obj = New-Object -TypeName PSObject -Property @{ 80 | "Arn" = ""; 81 | "Id" = ""; 82 | "Name" = ""; 83 | "Parent" = ""; 84 | } 85 | $t = Get-ORGOrganizationalUnit -OrganizationalUnitId $childouid 86 | # If we assign output of Get-ORGOrganizationUnit to a variable, it becomes type Amazon.Organizations.Model.OrganizationalUnit which we cannot modify 87 | # So, we manually copy the properties into our object, which is then added to the array of all OUs 88 | $obj.Arn = $t.Arn 89 | $obj.Id = $t.Id 90 | $obj.Name = $t.Name 91 | $obj.Parent = $ParentName 92 | $Script:AllOUs += $obj 93 | Start-Sleep -Seconds .6 # For some reason, AWS cmdlet Get-OrgOrganizationalUnit fails if lots of IDs are passed via pipeline, so this foreach loop slows it down 94 | # Using the current OU id, see if there are any child OUs and recursively call this function. 95 | do { 96 | if(!$PSBoundParameters.ContainsKey('ListAccounts')){Get-OrgChildOUs -ParentOUId $obj.Id -ParentName $obj.Name} 97 | else{Get-OrgChildOUs -ParentOUId $obj.Id -ParentName $obj.Name -ChildType ACCOUNT} 98 | 99 | } 100 | until ($null -eq $($AWSHistory.LastServiceResponse.Children)) # $AWSHistory contains $null when there are no more child OUs 101 | 102 | } 103 | } 104 | function Get-AllOrgOus { 105 | Begin { 106 | switch ($PSVersionTable.PSEdition) { 107 | # Find out which version of pwsh is running and load the proper AWS cmdlet module 108 | "Core" { 109 | Import-Module AWSPowerShell.NetCore 110 | } 111 | "Desktop" { 112 | Import-Module AWSPowerShell 113 | } 114 | default { 115 | "There's a big problem; this version of PowerShell is unknown" 116 | "Returned edition of PowerShell is: $PSVersionTable.PSEdition" 117 | exit 118 | } 119 | } 120 | $error.clear() # Reset the error variable 121 | # On macOS using the VSCode debugger as of 2019-07-19, a simple Set-AWSCredential causes an error 122 | # If so, Initialize-AWSDefaultConfiguration works. See https://github.com/PowerShell/vscode-powershell/issues/2050 123 | switch (Test-Path Variable:PSDebugContext -IsValid) { 124 | $true { 125 | if ($PSBoundParameters.ContainsKey('AWSStoredProfile')){Initialize-AWSDefaultConfiguration -ProfileName $AWSStoredProfile} 126 | else{} 127 | } 128 | $false { 129 | if ($PSBoundParameters.ContainsKey('AWSStoredProfile')){ 130 | Set-AWSCredential -ProfileName $AWSStoredProfile -ErrorAction SilentlyContinue # Set the profile to be used 131 | if ($null -ne $error[0]) { 132 | # Profile was NOT set correctly; Set-AWSCredentals does NOT store errors in $AWSHistory variable, so check $error array varaiable 133 | "Your AWS stored profile was incorrect in some way" 134 | "Set-AWSCredential returned: $error[0].Exception" 135 | exit 136 | } 137 | } 138 | 139 | } 140 | } 141 | } 142 | Process { 143 | # Start by getting the OUs off the root. 144 | $Script:AllOUs = @() 145 | $objarray = @() 146 | $r = get-orgroot 147 | $RootOUId = $r.Id # Get the four-character root OU ID 148 | $obj = new-object psobject 149 | 150 | $obj |Add-member NoteProperty Parent "TOP" 151 | $obj |Add-member NoteProperty OUName $r.name 152 | $obj |Add-member NoteProperty Id $RootOUId 153 | $obj |Add-member NoteProperty Arn $r.Arn 154 | $objarray += $obj 155 | Get-OrgChildOUs -ParentOUId $RootOUId -ParentName "Root" # Get the OU IDs at level one below the root 156 | } 157 | End { 158 | 159 | foreach ($id in $Script:AllOUs.id) { 160 | $obj = new-object psobject 161 | 162 | $obj |Add-member NoteProperty Parent $($Script:AllOUs.Parent[($Script:AllOUs.id).IndexOf($id)]) 163 | $obj |Add-member NoteProperty OUName $($Script:AllOUs.Name[($Script:AllOUs.id).IndexOf($id)]) 164 | $obj |Add-member NoteProperty Id $($Script:AllOUs.Id[($Script:AllOUs.id).IndexOf($id)]) 165 | $obj |Add-member NoteProperty Arn $($Script:AllOUs.Arn[($Script:AllOUs.id).IndexOf($id)]) 166 | <#"OUName" = "$($Script:AllOUs.Name[($Script:AllOUs.id).IndexOf($id)])"; 167 | "OUId" = "$($Script:AllOUs.Id[($Script:AllOUs.id).IndexOf($id)])"; 168 | "Parent" = "$($Script:AllOUs.Parent[($Script:AllOUs.id).IndexOf($id)])"; 169 | "Arn" = "$($Script:AllOUs.Arn[($Script:AllOUs.id).IndexOf($id)])";#> 170 | 171 | $objarray += $obj 172 | } 173 | switch ($CSV) { 174 | $false { 175 | # Write-Host -ForegroundColor Yellow "Displaying all OUs in this AWS Organization" 176 | $objarray | Sort-Object -Property "OUName" #| Format-Table Parent, OUName, OUId, Arn -AutoSize 177 | } 178 | $true { 179 | $csvfile = "$HOME/AWSOUs-$(Get-Date -Format "yyyy-mm-dd-THH-MM-ss").csv" 180 | Write-Host -ForegroundColor Yellow "Writing a CSV file to $csvfile with all OUs in this AWS Organization" 181 | $objarray | Sort-Object -Property "OUName" | Export-Csv -Path $csvfile 182 | } 183 | } 184 | 185 | } 186 | } 187 | Get-AllOrgOus 188 | } 189 | 190 | Function Get-OrgAccountLocation{ 191 | 192 | <# 193 | .SYNOPSIS 194 | Displays a formatted table of AWS Organization SCPs applied to OUs 195 | 196 | .DESCRIPTION 197 | Pulls SCP information from the Ous provided and generates output of all attached scps to OUs. The user MUST be a user with admin access to the Organization's root account and this function MUST be run in that root account 198 | 199 | .PARAMETER OrgList 200 | A parameter containing the AWS OUs. Currently only set to work from the output of get-allorgous.ps1 201 | 202 | .EXAMPLE 203 | Get-OrgPolicyInformation -OrgList $OUs #WHere OUs is $ous = Get-OrgOUList 204 | Get-OrgPolicyInformation -OrgList (Get-OrgOUList) 205 | 206 | .NOTES 207 | v1 - Created script and output data - Generates SCP attached to OUs. Made to work with the input from Get-AllOrgOus.ps1 208 | 209 | 210 | David Rowe 2019-09-19 211 | (c) 2019 SecFrame - licensed under the Apache OpenSource 2.0 license, https://opensource.org/licenses/Apache-2.0 212 | Licensed under the Apache License, Version 2.0 (the "License"); 213 | you may not use this file except in compliance with the License. 214 | You may obtain a copy of the License at 215 | http://www.apache.org/licenses/LICENSE-2.0 216 | 217 | Unless required by applicable law or agreed to in writing, software 218 | distributed under the License is distributed on an "AS IS" BASIS, 219 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 220 | See the License for the specific language governing permissions and 221 | limitations under the License. 222 | 223 | Author's blog: https://www.secframe.com 224 | 225 | 226 | #> 227 | [CmdletBinding()] 228 | 229 | param 230 | ( 231 | [Parameter(Mandatory = $false, 232 | Position = 1, 233 | HelpMessage = 'A parameter containing the AWS OUs. Currently only set to work from the output of get-allorgous.ps1')] 234 | [object]$OrgList 235 | ) 236 | $Accts = @() 237 | $orglist |%{ 238 | $o = $_ 239 | $ChildAccounts = Get-ORGChild -ParentId $_.OUID -ChildType Account 240 | $childaccounts |%{ 241 | $acct = get-orgaccount -accountid $_.id 242 | 243 | $obj = new-object psobject 244 | #$obj |Add-member NoteProperty OUParent $o.Parent 245 | $obj |Add-member NoteProperty OUName $o.OUName 246 | $obj |Add-member NoteProperty OUID $o.OUID 247 | $obj |Add-member Noteproperty OUArn $o.arn 248 | $obj |Add-member NoteProperty AccountID $acct.Id 249 | $obj |Add-member NoteProperty AccountName $acct.name 250 | $obj |Add-member NoteProperty AccountArn $acct.arn 251 | $obj |Add-member NoteProperty AccountStatus $acct.status 252 | $accts += $obj 253 | Start-Sleep -Seconds .6 254 | } 255 | } 256 | $Accts 257 | 258 | } -------------------------------------------------------------------------------- /Organizations/Get-OrgPolicyInformation.ps1: -------------------------------------------------------------------------------- 1 | Function Get-OrgPolicyInformation{ 2 | 3 | <# 4 | .SYNOPSIS 5 | Displays a formatted table of AWS Organization SCPs applied to OUs 6 | 7 | .DESCRIPTION 8 | Pulls SCP information from the Ous provided and generates output of all attached scps to OUs. The user MUST be a user with admin access to the Organization's root account and this function MUST be run in that root account 9 | 10 | .PARAMETER OrgList 11 | A parameter containing the AWS OUs. Currently only set to work from the output of get-allorgous.ps1 12 | 13 | .EXAMPLE 14 | Get-OrgPolicyInformation -OrgList $OUs #WHere OUs is $ous = Get-OrgOUList 15 | Get-OrgPolicyInformation -OrgList (Get-OrgOUList) 16 | 17 | .NOTES 18 | v1 - Created script and output data - Generates SCP attached to OUs. Made to work with the input from Get-AllOrgOus.ps1 19 | 20 | 21 | David Rowe 2019-09-19 22 | (c) 2019 SecFrame - licensed under the Apache OpenSource 2.0 license, https://opensource.org/licenses/Apache-2.0 23 | Licensed under the Apache License, Version 2.0 (the "License"); 24 | you may not use this file except in compliance with the License. 25 | You may obtain a copy of the License at 26 | http://www.apache.org/licenses/LICENSE-2.0 27 | 28 | Unless required by applicable law or agreed to in writing, software 29 | distributed under the License is distributed on an "AS IS" BASIS, 30 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 31 | See the License for the specific language governing permissions and 32 | limitations under the License. 33 | 34 | Author's blog: https://www.secframe.com 35 | 36 | 37 | #> 38 | [CmdletBinding()] 39 | 40 | param 41 | ( 42 | [Parameter(Mandatory = $false, 43 | Position = 1, 44 | HelpMessage = 'A parameter containing the AWS OUs. Currently only set to work from the output of get-allorgous.ps1')] 45 | [object]$OrgList, 46 | [validateset('OUId','AccountID')][string]$TargetID 47 | ) 48 | $objarray = @() 49 | $OrgList | %{ 50 | $ou = $_ 51 | if (!$targetid){$targetid = 'OUId'} 52 | $targetid 53 | $policyfortarget = Get-ORGPolicyForTarget -TargetId $ou.$TargetID -Filter SERVICE_CONTROL_POLICY 54 | $policyfortarget |%{ 55 | $pol = Get-ORGPolicy -PolicyId $_.Id 56 | $obj = new-object psobject 57 | $json = ($pol.content |ConvertFrom-Json).statement 58 | 59 | $obj |Add-member NoteProperty PolicyName $pol.PolicySummary.name 60 | $obj |Add-member NoteProperty PolicyID $pol.PolicySummary.id 61 | $obj |Add-member NoteProperty PolicyDesc $pol.PolicySummary.Description 62 | $obj |Add-member NoteProperty Parent $ou.Parent 63 | if ($targetid -eq 'OUID'){ 64 | $obj |Add-member NoteProperty AttachedToName $ou.OUName 65 | $obj |Add-member NoteProperty AttachedToId $ou.ouId 66 | $obj |Add-member NoteProperty AttachedToArn $ou.Arn 67 | $obj |Add-member Noteproperty AttachedToType 'OU' 68 | 69 | } 70 | if ($targetid -eq 'AccountID'){ 71 | $obj |Add-member NoteProperty AttachedToName $ou.AccountName 72 | $obj |Add-member NoteProperty AttachedToId $ou.AccountID 73 | $obj |Add-member NoteProperty AttachedToArn $ou.AccountArn 74 | $obj |Add-member Noteproperty AttachedToType 'Account' 75 | 76 | } 77 | $obj |Add-member NoteProperty Content $json 78 | $obj |Add-member NoteProperty PolicySummary $pol.PolicySummary 79 | 80 | $objarray += $obj 81 | Start-Sleep .6 82 | } 83 | 84 | 85 | } 86 | 87 | $objarray 88 | } 89 | 90 | Function Convert-RoleToJson { 91 | [CmdletBinding()] 92 | 93 | param 94 | ( 95 | [Parameter(Mandatory = $false, 96 | Position = 1, 97 | HelpMessage = 'A parameter containing the PolList. Currently only set to work from the output of Get-OrgPolicyInformation')] 98 | [object]$PolList, 99 | [string]$DestFolder 100 | ) 101 | $uniquePols = $PolList|select policyname, content -unique 102 | $poljson = @() 103 | $uniquePols |%{ 104 | $obj = new-object psobject 105 | $obj |add-member NoteProperty Name $_.policyname 106 | $obj |Add-member NoteProperty Content ($_.content|convertto-json) 107 | $poljson += $obj 108 | } 109 | $poljson 110 | if($DestFolder){ 111 | $poljson |%{ 112 | 113 | $n = $_.name 114 | $filename = ($DestFolder +'\' + $_.name + ".json") 115 | $_.content |Out-File $filename 116 | write-host "File saved for $n at $filename" 117 | } 118 | 119 | } 120 | } 121 | 122 | 123 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AWS_PowerTools 2 | AWS Powershell scripts to make management of AWS accounts easier 3 | -------------------------------------------------------------------------------- /S3/FlawsS3Buckets.ps1: -------------------------------------------------------------------------------- 1 | 2017-02-18 14:41:52 2f4e53154c0a7fd086a04a12a452c2a4caed8da0.flaws.cloud 2 | 2017-05-29 12:34:53 config-bucket-975426262029 3 | 2018-07-07 12:09:49 flaws-logs 4 | 2017-02-18 14:40:54 flaws.cloud 5 | 2017-02-24 00:15:42 level2-c8b217a33fcf1f839f6f1f73a00a9ae7.flaws.cloud 6 | 2017-02-26 13:29:03 level3-9afd3927f195e10225021a578e6f78df.flaws.cloud 7 | 2017-02-26 13:49:31 level4-1156739cfb264ced6de514971a4bef68.flaws.cloud 8 | 2017-02-26 14:49:03 level5-d2891f604d2061b6977c2481b0c8333e.flaws.cloud 9 | 2017-02-26 14:48:40 level6-cc4c404a8a8b876167f5e70a7d8c9880.flaws.cloud 10 | 2017-02-26 15:07:13 theend-797237e8ada164bf9f12cebf93b282cf.flaws.cloud -------------------------------------------------------------------------------- /S3/Get-AWSCanonicalUserID.ps1: -------------------------------------------------------------------------------- 1 | function Get-AWSCanonicalUserID { 2 | [CmdletBinding()] 3 | 4 | $buckets = get-s3bucket 5 | $region = 'us-east-1' 6 | $objects = $buckets| %{Get-S3Object -BucketName $_.bucketName -region $region -MaxKey 10} 7 | ($objects |select-object -property owner -unique).owner.id 8 | } 9 | 10 | Function Get-AWSCanonicalUserIDOrgs { 11 | [CmdletBinding()] 12 | param ( 13 | #[Parameter(Mandatory=$true)][object]$OrgList, 14 | [Parameter(Mandatory=$true)][string]$Role 15 | 16 | ) 17 | $CanIDList = @() 18 | get-orgaccountlist -ProfileName default |%{ 19 | Set-AWSCredential -ProfileName Default 20 | try {$creds = Get-STSCreds -OrganizationID $_.id -role $Role 21 | Set-AWSCredential -Credential $creds -storeas TempProfile 22 | set-awscredential -ProfileName tempprofile 23 | } 24 | catch{} 25 | $CanID = Get-AWSCanonicalUserID 26 | $obj = new-object psobject 27 | $obj |add-member NoteProperty OrgID $_.id 28 | $Obj | Add-member NoteProperty OrgName $_.name 29 | $Obj | Add-member NoteProperty CanonicalID $CanID 30 | $canidlist += $obj 31 | } 32 | $CanIDList 33 | } 34 | 35 | -------------------------------------------------------------------------------- /S3/Get-AccessKeysInMetadata.ps1: -------------------------------------------------------------------------------- 1 | Function Get-AccessKeysInMetadata{ 2 | param( 3 | [parameter(Mandatory=$true)][string]$BucketName 4 | 5 | ) 6 | #$bucketname = "4d0cf09b9b2d761a7d87be99d17507bce8b86f3b.flaws.cloud" 7 | $magic = "/proxy/169.254.169.254/latest/meta-data/" 8 | $AccessKeyRegEx = "(^|[^A-Z0-9])[A-Z0-9]{20}(?![A-Z0-9])" 9 | $SecretKeyRegEx = "(^|[^A-Za-z0-9/+=])[A-Za-z0-9/+=]{40}(?![A-Za-z0-9/+=])" 10 | $url = "HTTP://" + $BucketName + $magic 11 | 12 | $webpage = Invoke-WebRequest $url -UseBasicParsing 13 | 14 | if($webpage){ 15 | $content = $webpage.Content.Split([environment]::NewLine) 16 | $content |% { 17 | $url2 = ($url + $_) 18 | $url2 19 | $webpage2 = Invoke-WebRequest $url2 -UseBasicParsing 20 | $content2 = $webpage2.Content.Split([environment]::NewLine) 21 | 22 | $content2 |% { 23 | $url3 = ($url2 + $_) 24 | $url3 25 | try{$webpage3 = Invoke-WebRequest $url3 -UseBasicParsing 26 | $content3 = $webpage2.Content.Split([environment]::NewLine) 27 | 28 | } 29 | catch { 30 | $content2 31 | } 32 | } 33 | } 34 | 35 | } 36 | 37 | 38 | 39 | 40 | } -------------------------------------------------------------------------------- /S3/Get-AccessKeysInS3.ps1: -------------------------------------------------------------------------------- 1 | Function Get-AccessKeysInS3 { 2 | param( 3 | 4 | #[parameter(Mandatory=$true)][string]$BucketName, 5 | [parameter(Mandatory=$true)][string]$GitFolder 6 | 7 | ) 8 | 9 | 10 | 11 | if (-not (test-path -literalpath $GitFolder) ){ 12 | 13 | write-warning -Message "$GitFolder Does not exist. Exiting Script" 14 | break 15 | } 16 | 17 | Import-Module posh-git 18 | cd $GitFolder 19 | #get to git master branch to list all commits 20 | if ((git branch) -ne '* master') { 21 | 22 | git checkout master 23 | } 24 | 25 | $gitHist = (git log --format="%ai`t%H`t%an`t%ae`t%s" -n 100) | ConvertFrom-Csv -Delimiter "`t" -Header ("Date","CommitId","Author","Email","Subject") 26 | $showall = @() 27 | 28 | $gitHist|% { 29 | $showall += git show $_.commitid 30 | } 31 | 32 | $AccessKeyRegEx = "(^|[^A-Z0-9])[A-Z0-9]{20}(?![A-Z0-9])" 33 | $SecretKeyRegEx = "(^|[^A-Za-z0-9/+=])[A-Za-z0-9/+=]{40}(?![A-Za-z0-9/+=])" 34 | 35 | $accesskeys = $showall|Select-String -Pattern $AccessKeyRegEx 36 | $secretkeys = $showall|Select-String -Pattern $SecretKeyRegEx|where-object {($_ -notlike "commit*")}|where-object {($_ -notlike "+git checkout*")} 37 | 38 | 39 | $secretslist = @() 40 | $i=0 41 | $accesskeys |% { 42 | $Key = $_ # -split ""|Select-String -Pattern $AccessKeyRegEx 43 | 44 | $obj = new-object psobject 45 | $obj |Add-member NoteProperty AccessKeyMatch $_ 46 | $obj |Add-member NoteProperty SecretKeyMatch "" 47 | $githist | %{ if(git show $_.commitid|Select-String -simplematch -Pattern $key){ 48 | $obj |Add-member Noteproperty CommitID $_.commitid} 49 | else{} 50 | } 51 | 52 | $secretslist += $obj 53 | $i++ 54 | } 55 | 56 | $secretkeys |% { 57 | $key = $_ 58 | $obj = new-object psobject 59 | $obj |Add-member NoteProperty AccessKeyMatch "" 60 | $obj |Add-member NoteProperty SecretKeyMatch $_ 61 | $githist | %{ if(git show $_.commitid|Select-String -simplematch -Pattern $key){ 62 | $obj |Add-member Noteproperty CommitID $_.commitid} 63 | else{} } 64 | 65 | $secretslist += $obj 66 | } 67 | #$secretslist 68 | 69 | $formattedSecrets = @() 70 | $accesskeys | %{ 71 | $ak = [regex]::match($_,$AccessKeyRegEx).value 72 | $ak = $Ak -replace '[\W]','' 73 | $secretkeys |%{ 74 | $sk = [regex]::match($_,$SecretKeyRegEx).value 75 | $sk = $sk -replace ' ','' 76 | $sk = $sk -replace '`','' 77 | $obj = new-object psobject 78 | $obj |Add-Member NoteProperty AccessKey $ak 79 | $obj |Add-member NoteProperty Secret $sk 80 | $formattedSecrets += $obj 81 | } 82 | 83 | } 84 | remove-Module posh-git 85 | $secretsunique = $formattedSecrets |sort-object accesskey,secret |Get-Unique -AsString 86 | $secretsunique | % { 87 | Switch-AccessWithAWSKey -AccessKey $_.accesskey -SecretKey $_.secret -Profile GITTest 88 | $temp = $_ 89 | try {Get-STSCallerIdentity -ProfileName GITTest|Out-Null 90 | } 91 | catch {$secretsunique = $secretsunique -ne $temp 92 | } 93 | 94 | 95 | } 96 | 97 | 98 | 99 | $secretsunique 100 | } -------------------------------------------------------------------------------- /S3/Get-S3AllObjectMetadata.ps1: -------------------------------------------------------------------------------- 1 | $buckets = get-s3bucket 2 | $region = 'us-east-1' 3 | $objects = $buckets| %{Get-S3Object -BucketName $_.bucketName -region $region|%{get-s3objectmetadata -bucketName $_.bucketName -key $_.key -Region $region }} -------------------------------------------------------------------------------- /S3/Get-S3BucketRegion.ps1: -------------------------------------------------------------------------------- 1 | 2 | Function Get-S3BucketRegion { 3 | [cmdletbinding()] 4 | param( 5 | [string]$BucketName, 6 | [object]$Regions, #Supply region list you want to test against 7 | [object]$Credential # use for organization testing for all buckets and regions 8 | ) 9 | #standardize bucketname string to an object 10 | if (!$BucketName -and !$Credential){ 11 | $S3 = get-s3bucket 12 | } 13 | if (!$BucketName -and $Credential){ 14 | $s3 = get-s3bucket -credential $credential 15 | } 16 | if ($bucketname -and !$Credential){$S3 = Get-S3Bucket |where-object {$_.bucketname -eq $bucketname}} 17 | if ($bucketname -and $Credential){$S3 = Get-S3Bucket -Credential $credential|where-object {$_.bucketname -eq $bucketname}} 18 | if (!$S3){ 19 | write-warning "No Bucket found with name $bucketname. Aborting script" 20 | break 21 | } 22 | 23 | 24 | if(!$Regions){$Regions = Get-AWSRegion|Sort-Object name -Descending} 25 | $objarray = @() 26 | 27 | 28 | 29 | $S3|%{ 30 | 31 | $bname = $_ 32 | 33 | $Regions | %{ 34 | if (!$region) { 35 | $r = $_ 36 | try { 37 | 38 | if (!$credential) {$region = Get-s3bucketversioning -BucketName $bname.BucketName -Region $r.region}else{ 39 | $region = Get-s3bucketversioning -BucketName $bname.BucketName -Region $r.region -Credential $credential 40 | #if ($region.status -ne 'Enabled'){write-error -message 'wrong region'} 41 | } 42 | 43 | try{ 44 | if ($credential){get-s3publicaccessblock -BucketName $_.bucketname -credential $creds -Region $_.Region}else{ 45 | $publicaccess = get-s3publicaccessblock -BucketName $_.bucketname -Region $_.Region 46 | } 47 | }catch{} 48 | 49 | $region = $r 50 | $obj = new-object psobject 51 | 52 | $obj |Add-member NoteProperty BucketName $bname.BucketName 53 | $obj |Add-member NoteProperty Region $r 54 | if($publicaccess){ 55 | $obj |Add-member NoteProperty BlockPublicAcls $publicaccess.BlockPublicAcls 56 | $obj |Add-member NoteProperty IgnorePublicAcls $publicaccess.IgnorePublicAcls 57 | $obj |Add-member NoteProperty BlockPublicPolicy $publicaccess.BlockPublicPolicy 58 | $obj |Add-member NoteProperty RestrictPublicBuckets $publicaccess.RestrictPublicBuckets 59 | }else{ 60 | $obj |Add-member NoteProperty BlockPublicAcls "No Configuration Found" 61 | $obj |Add-member NoteProperty IgnorePublicAcls "No Configuration Found" 62 | $obj |Add-member NoteProperty BlockPublicPolicy "No Configuration Found" 63 | $obj |Add-member NoteProperty RestrictPublicBuckets "No Configuration Found" 64 | } 65 | $objarray += $obj 66 | }Catch{ 67 | 68 | } 69 | } 70 | 71 | } 72 | } # 73 | $objarray 74 | 75 | } 76 | 77 | 78 | Function Get-S3BucketRegionOrgs { 79 | [cmdletbinding()] 80 | param( 81 | [Parameter(Mandatory = $true, 82 | Position = 1, 83 | HelpMessage = 'Role used to authenticate and read into sub accounts')] 84 | [string]$Role 85 | ) 86 | try {$orgs = Get-ORGAccountList }catch {break} 87 | $s3array = @() 88 | $callerID = (Get-STSCallerIdentity).account 89 | $orgcount = $orgs.count 90 | $orgprogress = 1 91 | $orgs |%{ 92 | $org = $_ 93 | Write-Progress -Activity "Searching Through Accounts in Organization" -id 1 -Status "$orgProgress complete of $orgcount" -PercentComplete ($orgProgress/$orgcount*100) 94 | if ($_.id -ne $callerID){ 95 | $creds = get-stscreds -organizationid $_.id -role $role 96 | $s3 = get-s3bucketregion -Credential $creds}else{ 97 | $s3 = get-s3bucketregion 98 | } 99 | $s3count = $s3.count 100 | $s3progress = 1 101 | $s3 |%{ 102 | if($s3count -gt 0){Write-Progress -Activity "Searching Through S3 Buckets in Account" -id 2 -Status "$s3progress complete of $s3count" -PercentComplete ($s3progress/$s3count*100)} 103 | Clear-Variable -Name publicaccess 104 | if ($org.id -ne $callerid){ 105 | 106 | try{$publicaccess = get-s3publicaccessblock -BucketName $_.bucketname -credential $creds -Region $_.Region}catch{}}Else{ 107 | try{$publicaccess = get-s3publicaccessblock -BucketName $_.bucketname -Region $_.Region}catch{} 108 | } 109 | 110 | $obj = new-object psobject 111 | $obj |Add-member NoteProperty AccountID $org.Id 112 | $obj |Add-member Noteproperty AccountName $org.Name 113 | $obj |Add-member NoteProperty BucketName $_.BucketName 114 | $obj |Add-member NoteProperty Region $_.Region 115 | if($publicaccess){ 116 | $obj |Add-member NoteProperty BlockPublicAcls $publicaccess.BlockPublicAcls 117 | $obj |Add-member NoteProperty IgnorePublicAcls $publicaccess.IgnorePublicAcls 118 | $obj |Add-member NoteProperty BlockPublicPolicy $publicaccess.BlockPublicPolicy 119 | $obj |Add-member NoteProperty RestrictPublicBuckets $publicaccess.RestrictPublicBuckets 120 | }else{ 121 | $obj |Add-member NoteProperty BlockPublicAcls "No Configuration Found" 122 | $obj |Add-member NoteProperty IgnorePublicAcls "No Configuration Found" 123 | $obj |Add-member NoteProperty BlockPublicPolicy "No Configuration Found" 124 | $obj |Add-member NoteProperty RestrictPublicBuckets "No Configuration Found" 125 | } 126 | 127 | $s3array += $obj 128 | $s3progress++ 129 | } 130 | $orgProgress++ 131 | } 132 | $s3array 133 | } -------------------------------------------------------------------------------- /S3/List All Files In Buckets.ps1: -------------------------------------------------------------------------------- 1 | Function Get-AllFilesInS3Bucket { 2 | param( 3 | 4 | [parameter(Mandatory=$true)][string]$BucketName, 5 | [switch]$OpenInChrome, 6 | [Switch]$Sync, 7 | [Switch]$FindKeys 8 | 9 | ) 10 | 11 | #Bucket 12 | #$s3 = "level3-9afd3927f195e10225021a578e6f78df.flaws.cloud" 13 | $s3 = $BucketName 14 | 15 | #region 16 | $region = (resolve-dnsname ((resolve-dnsname $s3).ipaddress)).namehost 17 | $regionsplit = ($region.Split("-.")[2]+"-"+$region.Split("-.")[3]+"-"+$region.Split("-.")[4]) 18 | 19 | 20 | #All Files 21 | #$files = aws s3 ls s3://$s3 --no-sign-request --region ($region.Split("-.")[2]+"-"+$region.Split("-.")[3]+"-"+$region.Split("-.")[4]) 22 | $files = Get-S3Object -BucketName $s3 -Region $regionsplit 23 | 24 | #HTTP URL For all files 25 | $output = @() 26 | $files|%{ 27 | $output += "http://" + $s3 +"."+ $region +'/'+$_.key 28 | } 29 | $output 30 | 31 | if($PSBoundParameters.ContainsKey('OpenInChrome')){ 32 | $output | % { 33 | & 'C:\Program Files (x86)\Google\Chrome\Application\chrome.exe' $_ 34 | } 35 | 36 | } 37 | 38 | if($PSBoundParameters.ContainsKey('Sync')){ 39 | #if (-not (test-path -literalpath (((Get-location).path) + "\ListAllFilesInBucket"))) {New-Item -Path $path -ItemType Directory -ErrorAction Stop | Out-Null } 40 | $syncvar = "aws s3 sync s3://$s3/ . --no-sign-request --region $regionsplit" 41 | aws s3 sync s3://$s3/ . --no-sign-request --region $regionsplit 42 | 43 | } 44 | $cd = (get-location) 45 | if ($PSBoundParameters.ContainsKey('FindKeys')){ 46 | if ($output -like "*/.git/*"){ 47 | Get-AccessKeysInS3 -GitFolder $cd} 48 | else{write-host "Couldnt find a /.git/ folder"} 49 | } 50 | 51 | 52 | } -------------------------------------------------------------------------------- /S3/Set-S3ACLEasy.ps1: -------------------------------------------------------------------------------- 1 | Function Set-S3ACLEasy{ 2 | [CmdletBinding()] 3 | param ( 4 | [Parameter(Mandatory=$true)][string]$BucketName, 5 | [Parameter(Mandatory=$true)][string]$Region, 6 | [Parameter(Mandatory=$true)][object]$Credential, 7 | [Parameter(Mandatory=$true)] 8 | [ValidateSet("READ","FULL_CONTROL","WRITE","READ_ACP","WRITE_ACP","RESTORE_OBJECT")] 9 | [string]$Permission, 10 | [Object]$CanonicalID 11 | ) 12 | 13 | <# 14 | 15 | When applied to a bucket, grants permission to list the bucket. 16 | When applied to an object, this grants permission to read the 17 | object data and/or metadata. 18 | 19 | 20 | 21 | 22 | When applied to a bucket, grants permission to create, overwrite, 23 | and delete any object in the bucket. This permission is not 24 | supported for objects. 25 | 26 | 27 | 28 | 29 | Grants permission to read the ACL for the applicable bucket or object. 30 | The owner of a bucket or object always has this permission implicitly. 31 | 32 | 33 | 34 | 35 | Gives permission to overwrite the ACP for the applicable bucket or object. 36 | The owner of a bucket or object always has this permission implicitly. 37 | Granting this permission is equivalent to granting FULL_CONTROL because 38 | the grant recipient can make any changes to the ACP. 39 | 40 | 41 | 42 | 43 | Provides READ, WRITE, READ_ACP, and WRITE_ACP permissions. 44 | It does not convey additional rights and is provided only for convenience. 45 | 46 | 47 | 48 | 49 | Gives permission to restore an object that is currently stored in Amazon Glacier 50 | for archival storage. 51 | 52 | 53 | #> 54 | #$grants = Get-S3acl -BucketName $bucketname -Region $Region -Credential $Credential 55 | $ACL = Get-S3ACL -BucketName $BucketName -Region $Region -Credential $Credential 56 | $grants = @() 57 | $acl.grants |%{ 58 | $grants += $_ 59 | } 60 | $CanonicalID|%{ 61 | $grantee = New-Object -TypeName Amazon.S3.Model.S3Grantee 62 | $grantee.DisplayName = get-iamaccountalias -Credential $Credential 63 | $grantee.CanonicalUser = $_.CanonicalID 64 | 65 | 66 | $grant = New-Object -TypeName Amazon.S3.Model.S3Grant 67 | $grant.Grantee = $grantee 68 | $grant.Permission = [Amazon.S3.S3Permission]::$Permission 69 | $grants += $grant 70 | } 71 | Set-S3ACL -BucketName $BucketName -Region $region -Credential $Credential -Grant $grants -OwnerId $acl.owner.id 72 | 73 | } -------------------------------------------------------------------------------- /STS/Get-AWSTempCred.ps1: -------------------------------------------------------------------------------- 1 | #original source https://gist.github.com/jgard/17262e0fc073c82bc7930db2f5603446 2 | #Thanks to the work of jgard. Some stuff didnt work, but a bit of debugging got it going! 3 | 4 | Function Get-Choice { 5 | [cmdletbinding()] 6 | param( 7 | [parameter( 8 | Mandatory = $true, 9 | ValueFromPipeline = $true)] 10 | [string[]]$Options, 11 | [string]$Property, 12 | [string]$Message="Make a selection" 13 | ) 14 | Begin { 15 | $i=0 16 | $array = @() 17 | } 18 | Process { 19 | $i++ 20 | $array += $_ 21 | write-host " $i. " -NoNewline -ForegroundColor 'Green' 22 | if ($Property) { 23 | write-host $_.$Property 24 | } else { 25 | write-host $_ 26 | } 27 | } 28 | End { 29 | Do { 30 | $answer=Read-Host -Prompt $message 31 | try{ 32 | $Chosen = $array[[int]$answer-1] 33 | } catch { 34 | } 35 | if (!$Chosen) { 36 | Write-Host "Invalid choice '$answer'. Please try again or press Ctrl+C to quit." -ForegroundColor Yellow 37 | } else { 38 | $Chosen 39 | } 40 | } While (!$Chosen) 41 | } 42 | } 43 | 44 | Function Get-STSSAMLCred { 45 | [CmdletBinding()] 46 | [alias("Get-AWSTempCred")] 47 | param ( 48 | [string]$ADFSHost='adfs.domain.com', ##Change for environment-appropriate default if desired 49 | [string]$RelyingParty = 'urn:amazon:webservices', 50 | [switch]$SetHost, 51 | [switch]$ChangeUser, 52 | [pscredential]$Credential 53 | ) 54 | $WebRequestParams=@{ #Initialize parameters object 55 | Uri = "https://$ADFSHost/adfs/ls/IdpInitiatedSignon.aspx?LoginToRP=$RelyingParty" 56 | Method = 'POST' 57 | ContentType = 'application/x-www-form-urlencoded' 58 | SessionVariable = 'WebSession' 59 | UseBasicParsing = $true 60 | } 61 | if ($Credential) { 62 | $WebRequestParams.Add('Body',@{UserName=$Credential.UserName;Password=$Credential.GetNetworkCredential().Password}) 63 | } else { 64 | if ($changeuser){$Credential = Get-Credential -Message "Enter the domain credentials" } 65 | else {$Credential = Get-Credential -Message "Enter the domain credentials" -UserName "$env:USERDOMAIN\$env:USERNAME"} 66 | $WebRequestParams.Add('Body',@{UserName=$Credential.UserName;Password=$Credential.GetNetworkCredential().Password}) 67 | } 68 | 69 | #Initial post to ADFS 70 | $InitialResponse=Invoke-WebRequest @WebRequestParams 71 | $SAMLResponseEncoded=$InitialResponse.InputFields.FindByName('SAMLResponse').value 72 | if (!$SAMLResponseEncoded) { #Initial result from ADFS didn't have assertion 73 | if ($InitialResponse.InputFields.FindByName('AuthMethod').value -eq 'SecurIDv2Authentication') { #Handle RSA SecurID 74 | $SAMLResponseEncoded = Read-SecurIDv2Authentication -WebRequestParams $WebRequestParams -InitialResponse $InitialResponse 75 | } 76 | } 77 | if (!$SAMLResponseEncoded) { 78 | Throw "No valid ADFS assertion received. Suggestion: Supply alternate credentials, use different ADFSHost, or a new MFA method is not yet supported by this module." 79 | } 80 | 81 | #Evaluate SAML Response 82 | $SAMLResponseDecoded=[xml]([System.Text.Encoding]::utf8.GetString([System.Convert]::FromBase64String($SAMLResponseEncoded))) | select -ExpandProperty response 83 | #removing this portion temporarily because the configabbrev doesnt look to be a standard response. This portion should pull the account name into the get-choice function 84 | #once i figure out what the standard is, i can add it to the parameter list and set a standard. 85 | <# $AvailableAWSAccts = $SAMLResponseDecoded.Assertion.AttributeStatement.Attribute |?{$_.name -eq 'https://ConfigAbbrev.bch'} | %{ 86 | $_.AttributeValue |%{ 87 | [PSCustomObject]@{"Accts" = (($_ -replace "\|", "`t ") -split "`t")[0,2] -join ""} 88 | } 89 | }#> 90 | 91 | $AvailableRoles = $SAMLResponseDecoded.Assertion.AttributeStatement.Attribute |?{$_.name -eq 'https://aws.amazon.com/SAML/Attributes/Role'} | %{ 92 | <#$AvailableRoles = $SAMLResponseDecoded.Assertion.AttributeStatement.Attribute |?{$_.name -eq 'https://ConfigAbbrev.bch'} | %{ 93 | $_.AttributeValue |%{ 94 | [PSCustomObject]@{"Role" = ($_ -split "|",0,"SimpleMatch")[0,2] -join "";"SAMLProvider" = ($_ -split ",")[1]} 95 | } 96 | #> 97 | $_.AttributeValue |%{ 98 | [PSCustomObject]@{"Role" = ($_ -split ",")[0];"SAMLProvider" = ($_ -split ",")[1]} 99 | } 100 | } 101 | $AvailableRoles = @($AvailableRoles) #Force to be an array to simplfy role count assessment 102 | if ($AvailableRoles.count -eq 0) { 103 | Throw "No available AWS roles found in ADFS response." 104 | } 105 | 106 | If ($AvailableRoles.count -gt 1) { 107 | 108 | <# $AccountsandRoles = @() 109 | $I = 0 110 | do { 111 | $obj = new-object psobject 112 | $obj | Add-member NoteProperty AccountName $AvailableAWSAccts[$i].accts 113 | $obj | Add-Member NoteProperty Role $AvailableRoles[$i].role 114 | $obj | Add-member Noteproperty SAMLProvider $AvailableRoles[$i].SAMLProvider 115 | $AccountsandRoles += $obj 116 | $i++ 117 | } 118 | while ($I -lt $AvailableRoles.count)#Choose role logic 119 | #> 120 | $ChosenRole= $AvailableRoles | Get-Choice -Message "Choose which role to assume" -Property 'Role' 121 | } else { 122 | $ChosenRole=$AvailableRoles[0] 123 | } 124 | 125 | #Send token to AWS STS 126 | try { 127 | Write-Host "Using role $($ChosenRole.Role)" 128 | $AssumedRole=Use-STSRoleWithSAML -SAMLAssertion $SAMLResponseEncoded -PrincipalArn $ChosenRole.SAMLProvider -RoleArn $ChosenRole.Role -ErrorAction Stop 129 | 130 | 131 | } catch{ 132 | Write-Warning "STS error: $($_.Exception.Message)" 133 | Throw "Failure calling AWS STS service. Likely issues: a) Outgoing internet connectivity or proxy issue, or b) Problem with ADFS trust, claims, or role." 134 | } 135 | write-host "" 136 | #Write-Host "New access key: $($AssumedRole.Credentials.AccessKeyId), expires $($AssumedRole.Credentials.Expiration)" 137 | #Write-Host "Setting as default AWSCredential for future AWSPowershell usage, by exporting to `$Global:StoredAWSCredentials" 138 | #write-host "" 139 | 140 | 141 | if ($SetHost){ 142 | Write-Host "Setting as default AWSCredential for future AWSPowershell usage, by exporting to `$Global:StoredAWSCredentials" 143 | Set-AWSCredential -AccessKey $AssumedRole.Credentials.AccessKeyId -SecretKey $AssumedRole.Credentials.SecretAccessKey -SessionToken $AssumedRole.Credentials.SessionToken -StoreAs SAML 144 | Set-AWSCredential -ProfileName SAML 145 | #todo, make the $assumedrole export to the .aws credentials file and overwrite the default 146 | $Global:StoredAWSCredentials = $StoredAWSCredentials 147 | } 148 | else{ 149 | #Updating to pscustomobjectoutput. This hides the end of the session token. So to see the output of the script, you will have to store the get-stssamlcred as a variable 150 | [PSCustomObject]@{'AccessKey' = $($AssumedRole.Credentials.AccessKeyId); 'SecretKey' = $($AssumedRole.Credentials.SecretAccessKey); 'SessionToken' = $($AssumedRole.Credentials.SessionToken)} 151 | 152 | } 153 | #Set-AWSCredential -AccessKey $AssumedRole.Credentials.AccessKeyId -SecretKey $AssumedRole.Credentials.SecretAccessKey -SessionToken $AssumedRole.Credentials.SessionToken 154 | #$Global:StoredAWSCredentials = $StoredAWSCredentials 155 | } 156 | 157 | function Read-SecurIDv2Authentication { 158 | [CmdletBinding()] 159 | param ( 160 | [hashtable]$WebRequestParams, 161 | $InitialResponse 162 | ) 163 | 164 | $WebRequestParams.Remove('SessionVariable') 165 | $WebRequestParams.Add('WebSession',$WebSession) 166 | $WebRequestParams['Body'] = @{AuthMethod=$InitialResponse.InputFields.FindByName('AuthMethod').value;Context=$InitialResponse.InputFields.FindByName('Context').value;InitStatus='true'} 167 | if ($InitialResponse.BaseResponse.ResponseUri.AbsoluteUri) { 168 | $WebRequestParams['Uri'] = $InitialResponse.BaseResponse.ResponseUri.AbsoluteUri 169 | } else { 170 | $WebRequestParams['Uri'] = $InitialResponse.BaseResponse.RequestMessage.RequestUri.AbsoluteUri 171 | } 172 | $RSAInitResponse=Invoke-WebRequest @WebRequestParams 173 | 174 | if ($RSAInitResponse.InputFields.FindById('passcodeInput')) { 175 | $passcode = Read-Host 'Enter RSA SecurID passcode' -AsSecureString 176 | $WebRequestParams['Body'] = @{AuthMethod=$RSAInitResponse.InputFields.FindByName('AuthMethod').value;Context=$RSAInitResponse.InputFields.FindByName('Context').value;Passcode=(New-Object PSCredential "user",$passcode).GetNetworkCredential().Password} 177 | if ($RSAInitResponse.BaseResponse.ResponseUri.AbsoluteUri) { 178 | $WebRequestParams['Uri'] = $RSAInitResponse.BaseResponse.ResponseUri.AbsoluteUri 179 | } else { 180 | $WebRequestParams['Uri'] = $RSAInitResponse.BaseResponse.RequestMessage.RequestUri.AbsoluteUri 181 | } 182 | $RSAResponse = Invoke-WebRequest @WebRequestParams 183 | $RSAResponse.InputFields.FindByName('SAMLResponse').value 184 | } 185 | } 186 | 187 | -------------------------------------------------------------------------------- /STS/STS Switch Roles in Organization.ps1: -------------------------------------------------------------------------------- 1 | Function Get-STSCreds { 2 | [alias("Switch-AWSRoles")] 3 | param( 4 | [Parameter(Mandatory=$true)][string]$OrganizationID, 5 | [Parameter(Mandatory=$true)][string]$Role 6 | 7 | ) 8 | 9 | $region = (Get-AWSRegion|where-object -Property isshelldefault -eq $true) 10 | 11 | $RoleArn = "arn:aws:iam::${OrganizationID}:role/$role" 12 | 13 | #Request temporary credentials for each account and create a credential object 14 | 15 | $Response = (Use-STSRole -Region $Region -RoleArn $RoleArn -RoleSessionName 'CMDB').Credentials 16 | $Credentials = New-AWSCredentials -AccessKey $Response.AccessKeyId -SecretKey $Response.SecretAccessKey -SessionToken $Response.SessionToken 17 | Set-AWSCredential -AccessKey $Response.AccessKeyId -SecretKey $Response.SecretAccessKey -SessionToken $Response.SessionToken -StoreAs 'STSCreds' 18 | $Credentials 19 | 20 | } 21 | 22 | Function Get-STSRoleToken { 23 | 24 | param( 25 | [Parameter(Mandatory=$true)][string]$OrganizationID, 26 | [Parameter(Mandatory=$true)][string]$Role, 27 | [int]$DurationInSeconds = 3600 28 | 29 | ) 30 | 31 | $region = (Get-AWSRegion|where-object -Property isshelldefault -eq $true) 32 | 33 | $RoleArn = "arn:aws:iam::${OrganizationID}:role/$role" 34 | 35 | #Request temporary credentials for each account and create a credential object 36 | 37 | $Response = (Use-STSRole -Region $Region -RoleArn $RoleArn -RoleSessionName 'CMDB' -DurationInSeconds $DurationInSeconds).Credentials 38 | $Response 39 | 40 | } 41 | 42 | Function Switch-AccessWithAWSKey { 43 | param ( 44 | [Parameter(Mandatory=$true)][string]$AccessKey, 45 | [Parameter(Mandatory=$true)][string]$SecretKey, 46 | [string]$SessionToken, 47 | [string]$Profile = 'tempprofile' 48 | ) 49 | if ($PSBoundParameters.ContainsKey('SessionToken')){ 50 | Set-AWSCredential -AccessKey $AccessKey -SecretKey $SecretKey -StoreAs $Profile -SessionToken $SessionToken 51 | } 52 | else{Set-AWSCredential -AccessKey $AccessKey -SecretKey $SecretKey -StoreAs $Profile} 53 | Set-AWSCredential -ProfileName $Profile 54 | } 55 | 56 | -------------------------------------------------------------------------------- /SecurityHub/AddUsertoHub.ps1: -------------------------------------------------------------------------------- 1 | $orgs = Get-ORGAccountList|select id, name, email|ft --------------------------------------------------------------------------------