AwsSSORoleHelper.psm1
function Get-AWSSSORoleCredential { #Requires -Modules AWSPowerShell <# .SYNOPSIS This is a simple utility script that allows you to retrieve credentials for AWS accounts that are secured using AWS SSO. Access tokens are cached locally to prevent the need to be pushed to a web browser each time you invoke the script (this is similar behaviour to aws cli v2). .DESCRIPTION This is a simple utility script that allows you to retrieve credentials for AWS accounts that are secured using AWS SSO. Access tokens are cached locally to prevent the need to be pushed to a web browser each time you invoke the script (this is similar behaviour to aws cli v2). Main usability enhancement compared to aws cli 2 is the abillity to retrieve all credentials for all accounts that you have access to. You can optionally specify a rolename with the -RoleName parameter and retrieve all credentials for that rolename across all of your accounts. Alternatively you can specify an AccountID by using the -AccountID parameter and retrieve all credentials for that AccountID. Region is set to US-East-1 by default as this is the only region that currently supports AWS SSO. .PARAMETER StartUrl The AWS SSO URL that you use to login. Example: https://mycompany.awsapps.com/start .PARAMETER AccountId Specify an AccountID to filter results to a specific account. .PARAMETER RoleName Specify a RoleName to filter results to a specific set of roles. .PARAMETER PassThru Returns AccountName, AccountId, RoleName, AccessKey, SecretKey, SessionToken, Expiration for all credentials based on filter. Pair with -AccountId and -RoleName to select a single set of credentials. .PARAMETER RefreshAccessToken Use this switch to manually refresh access token. Usually not needed, but included due to some inconsistencies with AWS SSO. .PARAMETER UseSharedCredentialsFile Use this switch to save profiles to the AWS Credentials file configured in the global environment variable 'AWS_SHARED_CREDENTIALS_FILE' .EXAMPLE #Generate credential profile for all accounts and role names, auto save to credential file. Get-AWSSSORoleCredential -StartUrl "https://mycompany.awsapps.com/start" .EXAMPLE #Generate credential profile for all accounts where role name is 'My_Role_Name', auto save to credential file. Get-AWSSSORoleCredential -StartUrl "https://mycompany.awsapps.com/start" -RoleName 'My_Role_Name' .EXAMPLE #Get credentials for specific account and rolename, then use those to retrieve S3 bucket. $RoleCredentials = Get-AWSSSORoleCredential -StartUrl "https://mycompany.awsapps.com/start" -AccountID 0123456789 -RoleName S3_Reader -Passthru Get-S3Bucket -AccessKey $RoleCredentials.AccessKey -SecretKey $RoleCredentials.SecretKey -SessionToken $RoleCredentials.SessionToken .EXAMPLE #Generate credential profile for all accounts and role names, save to shared credentials file. Get-AWSSSORoleCredential -StartUrl "https://mycompany.awsapps.com/start" -UseSharedCredentialFile .INPUTS StartUrl (Mandatory) .OUTPUTS Default Outputs: ProfileName, StoreTypeName, ProfileLocation PassThru Outputs: AccountName, AccountId, RoleName, AccessKey, SecretKey, SessionToken, Expiration #> [CmdletBinding()] param( [Parameter(Mandatory=$true)][string]$StartUrl, [string]$AccountId, [string]$RoleName, [switch]$PassThru, [switch]$RefreshAccessToken, [switch]$UseSharedCredentialsFile ) Function convertfrom-EpochTime ($epochdate) { if (("$epochdate").length -gt 10 ){ (Get-Date -Date "01/01/1970").AddMilliseconds($epochdate) } else { (Get-Date -Date "01/01/1970").AddSeconds($epochdate) } } if(!($UseSharedCredentialsFile)){ $CredentialPath = Join-Path $(Join-path $Home -ChildPath ".aws") "credentials" }else{ $CredentialPath = [Environment]::GetEnvironmentVariable('AWS_SHARED_CREDENTIALS_FILE') } # Required Defaults for OIDC Connection $ClientName = "default" $ClientType = "public" # Set a location to save AccessTokens $Path = (Join-Path $Home ".awsssohelper") # Hardcoding region as only us-east-1 currently supports SSO OIDC connection. $Region = 'us-east-1' $urlSubDomain = ([system.uri]$starturl).host.split('.')[0] $CachePath = Join-Path $Path $urlSubDomain if (!(Test-Path $Path)) { New-Item -Path $Path -ItemType Directory | Out-Null } if (Test-Path $CachePath) { $AccessToken = Get-Content $CachePath | ConvertFrom-Json } if (!$AccessToken) { $RefreshAccessToken = $true }else{ if($accesstoken.loggedat.gettype().name -eq 'DateTime'){ if($(New-timespan $accesstoken.loggedat (get-date).ToUniversalTime()).totalseconds -gt $AccessToken.ExpiresIn) { $RefreshAccessToken = $true } }else{ if($(New-TimeSpan (ConvertFrom-EpochTime $accesstoken.loggedat.split("(").split(")")[1]) (Get-Date).touniversaltime()).TotalSeconds -gt $AccessToken.ExpiresIn) { $RefreshAccessToken = $true } } } if(!($RefreshAccessToken)){ try{ $AWSAccounts = Get-SSOAccountList -AccessToken $AccessToken.AccessToken -Credential ([Amazon.Runtime.AnonymousAWSCredentials]::new()) -Region $region }catch{ $RefreshAccessToken = $true } } if ($RefreshAccessToken) { $Client = Register-SSOOIDCClient -ClientName $ClientName -ClientType $ClientType -Region $Region -Credential ([Amazon.Runtime.AnonymousAWSCredentials]::new()) $DeviceAuth = Start-SSOOIDCDeviceAuthorization -ClientId $Client.ClientId -ClientSecret $Client.ClientSecret -StartUrl $StartUrl -Region $Region -Credential ([Amazon.Runtime.AnonymousAWSCredentials]::new()) $SSOStart = (Get-Date).ToUniversalTime() $TimeoutInSeconds = $DeviceAuth.ExpiresIn try { $Process = Start-Process $DeviceAuth.VerificationUriComplete -PassThru } catch { continue } if (!$Process.Id) { Write-Host "`r`nVisit the following URL to authorise this session:`r`n" Write-Host -ForegroundColor White "$($DeviceAuth.VerificationUriComplete)`r`n" } Clear-Variable AccessToken -Force -ErrorAction SilentlyContinue Write-Host "Waiting for SSO login via browser..." while (!$AccessToken -and ((New-TimeSpan $SSOStart (Get-Date).ToUniversalTime()).TotalSeconds -lt $TimeoutInSeconds)) { try { $AccessToken = New-SSOOIDCToken -ClientId $Client.ClientId -ClientSecret $Client.ClientSecret -Code $DeviceAuth.Code -DeviceCode $DeviceAuth.DeviceCode -Region $Region -GrantType "urn:ietf:params:oauth:grant-type:device_code" -Credential ([Amazon.Runtime.AnonymousAWSCredentials]::new()) } catch { Start-Sleep -Seconds 5 } } if (!$AccessToken) { if(($(New-TimeSpan $SSOStart (Get-Date).ToUniversalTime()).TotalSeconds) -ge $timeoutinseconds){ throw 'Access Token Request Timed out. Please attempt to run the script again.' } throw 'No Access Token obtained.' } Write-Host "Login Successful. Access Token obtained." $AccessToken | ConvertTo-Json | Set-Content $CachePath $AWSAccounts = Get-SSOAccountList -AccessToken $AccessToken.AccessToken -Credential ([Amazon.Runtime.AnonymousAWSCredentials]::new()) -Region $region } if (!$AccountId) { $AccountId = $AWSAccounts | Select-Object -ExpandProperty AccountId } $Credentials = @() foreach ($Id in ($AccountId -split ' ')) { if (!$RoleName) { $SSORoles = Get-SSOAccountRoleList -AccessToken $AccessToken.AccessToken -AccountId $Id -Credential ([Amazon.Runtime.AnonymousAWSCredentials]::new()) -Region $region | Select-Object -ExpandProperty RoleName } else{ $SSORoles = $RoleName } $SSORoles | ForEach-Object { $SSORoleCredential = Get-SSORoleCredential -AccessToken $AccessToken.AccessToken -AccountId $Id -RoleName $_ -Credential ([Amazon.Runtime.AnonymousAWSCredentials]::new()) -Region $region $Credentials += [pscustomobject][ordered]@{ AccountName = $AWSAccounts | Where-Object {$_.AccountId -like $Id} | Select-Object -Expandproperty AccountName AccountId = $Id; RoleName = $_; AccessKey = $SSORoleCredential.AccessKeyId; Expiration = $SSORoleCredential.Expiration; SecretKey = $SSORoleCredential.SecretAccessKey; SessionToken = $SSORoleCredential.SessionToken } } } if ($PassThru) { $output = $Credentials | Select-Object AccountName,AccountId,RoleName,AccessKey,SecretKey,SessionToken,Expiration | Sort-Object }else{ $Credentials | ForEach-Object { Set-AWSCredential -AccessKey $_.AccessKey -SecretKey $_.SecretKey -SessionToken $_.SessionToken -StoreAs $($_.AccountName + '_' + $_.RoleName) -ProfileLocation $CredentialPath } Write-host $Credentials.Count "AWS Credentials have been added to your credential store." $output = Get-AWSCredential -ListProfileDetail | Sort-Object -Property ProfileLocation,ProfileName } $output } Export-ModuleMember -Function Get-AWSSSORoleCredential |