Skip to content

Instantly share code, notes, and snippets.

@gregory-seidman
Created November 2, 2021 20:30
Show Gist options
  • Save gregory-seidman/b67a244bf9df8227416279af229f7837 to your computer and use it in GitHub Desktop.
Save gregory-seidman/b67a244bf9df8227416279af229f7837 to your computer and use it in GitHub Desktop.
Script to log into AWS via SSO and get credentials that can be used programmatically
#!/usr/bin/env pwsh
param (
[Parameter(Position=0)]
[string]$ProfileFilter = $null,
[switch]$NoLogin
)
if ((Get-Command -ErrorAction SilentlyContinue aws) -eq $null) {
Write-Error "The AWS CLI must be installed, try: winget install Amazon.AWSCLI"
exit 1
}
$awsArgs = @("--no-cli-pager", "--no-cli-auto-prompt")
$awsDir = Join-Path $HOME ".aws"
$ssoDir = Join-Path (Join-Path $awsDir "sso") "cache"
$configFile = Join-Path $awsDir "config"
$credsFile = Join-Path $awsDir "credentials"
if (-Not (Test-Path -PathType Leaf $configFile)) {
Write-Error "No AWS CLI config found: $configFile"
exit 1
}
Try {
[System.IO.File]::OpenRead($configFile).Close()
}
catch {
Write-Error "AWS CLI config '$configFile' can't be read"
exit 1
}
if (Test-Path $credsFile) {
if (-Not (Test-Path -PathType Leaf $credsFile)) {
Write-Error "AWS CLI credentials '$credsFile' can't be written"
exit 1
}
Try {
[System.IO.File]::OpenWrite($credsFile).Close()
}
catch {
Write-Error "AWS CLI credentials '$credsFile' can't be written"
exit 1
}
}
if ((Get-Module PsIni) -eq $null) {
if ((Get-Module -ListAvailable PsIni) -eq $null) {
Write-Debug "Installing PsIni module"
Install-Module -Scope CurrentUser PsIni
}
Import-Module PsIni
}
function SelectProfile {
param (
[Parameter(Mandatory,Position=0)]
[string[]]$options
)
[System.Management.Automation.Host.ChoiceDescription[]]$choices = `
$options | % {$index=0}{
$index++
"&$index $_"
}
$choice = $Host.UI.PromptForChoice("Select Profile:", $null, $choices, -1)
$options[$choice]
}
function StripBOM {
param (
[Parameter(Mandatory,Position=0)]
[string]$filePath
)
$cleaned = Get-Content $filePath |`
% { $_ -replace "\xEF\xBB\xBF", "" }
$cleaned | Set-Content $filePath
}
$cfg = Get-IniContent $configFile
$profiles = $cfg.Keys |`
where { $_.StartsWith("profile ") } |`
% { $_.Substring(8) }
if ($profiles.Length -eq 0) {
Write-Error "No profiles found"
exit 1
}
$hasFilter = (-Not [string]::IsNullOrWhitespace($ProfileFilter))
if ($hasFilter) {
$profiles = $profiles | where { $_.ToString().Contains($ProfileFilter) }
}
if ($profiles -is [string]) {
$profiles = @($profiles)
}
switch ($profiles.Length) {
0 {
Write-Error "Profile not found: '$ProfileFilter'"
exit 1
}
1 {
$selectedProfile = $profiles[0]
break
}
default {
$GridArguments = @{
OutputMode = "Single"
Title = "Select Profile"
}
$selectedProfile = SelectProfile($profiles)
}
}
$selectedConfig = $cfg["profile $selectedProfile"]
@("sso_start_url", "sso_account_id", "sso_role_name", "sso_region") | % {
if (-Not $selectedConfig.Contains($_)) {
Write-Error "Profile $selectedProfile is missing $_"
exit 1
}
}
if (-Not $NoLogin) {
aws @awsArgs sso login --profile $selectedProfile
if (-Not $?) {
Write-Error "Login failed"
exit 1
}
}
$roleCredentialsArgs = @(
"--region", $selectedConfig["sso_region"]
"--account-id", $selectedConfig["sso_account_id"]
"--role-name", $selectedConfig["sso_role_name"]
)
[System.Text.RegularExpressions.Regex]$tokenFileRegex = "^[0-9a-f]+\.json$"
$tokenFile = Get-ChildItem $ssoDir -Filter "*.json" |`
% { $_.Name } |`
where { $tokenFileRegex.IsMatch($_) }
if ($tokenFile -is [Array]) {
if ($tokenFile.Length -ne 1) {
Write-Error "Unexpected difficulty finding access token JSON"
exit 1
}
$tokenFile = $tokenFile[0]
}
if (-Not $tokenFile -is [string]) {
Write-Error "Unexpected difficulty finding access token JSON"
exit 1
}
if ([string]::IsNullOrWhitespace($tokenFile)) {
Write-Error "Unexpected difficulty finding access token JSON"
exit 1
}
$token = `
(Get-Content (Join-Path $ssoDir $tokenFile) |`
ConvertFrom-Json).accessToken
$credentialsData = aws @awsArgs sso get-role-credentials `
@roleCredentialsArgs --access-token $token
if (-Not $?) {
Write-Error "Could not retrieve role credentials"
exit 1
}
$roleCredentials = ($credentialsData | ConvertFrom-Json).roleCredentials
if (Test-Path $credsFile) {
$credentials = Get-IniContent $credsFile
if (-Not $credentials.Contains("default")) {
$credentials.default = `
[System.Collections.Specialized.OrderedDictionary]::new()
}
} else {
$credentials = @{
default = `
[System.Collections.Specialized.OrderedDictionary]::new()
}
}
$defaultSection = $credentials.default
$defaultSection.aws_access_key_id = $roleCredentials.accessKeyId
$defaultSection.aws_session_token = $roleCredentials.sessionToken
$defaultSection.aws_secret_access_key = $roleCredentials.secretAccessKey
Out-IniFile $credsFile -Force -InputObject $credentials
StripBOM($credsFile)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment