vNugglets.AWSSSO_functions.psm1
|
function New-VNAWSSSOOIDCTokenViaDeviceCode { <# .Description Generate SSO OIDC Token using a device code via AWS SSO and SSOOIDC. To then subsequently use to get SSO role temporary credentials .Example New-VNAWSSSOOIDCTokenViaDeviceCode -StartUrl https://mycoolstart.awsapps.com/start/ Go through the process of getting a new SSO OIDC token, using browser for credential verification, and specified "Start" URL .Notes That this uses a browser for credential verification, you should have already authenticated in your browser with at least the credential to use for subsequent AWS role interaction. That is, if using Microsoft Online for account management, have authenticated with the desired account at http://myaccount.microsoft.com before using this script to generate a new AWS OIDC token Handy: so as to be able to use this cmdlet with some default StartUrl, you can leverage the PowerShell feature PSDefaultParameterValues: $PSDefaultParameterValues['New-VNAWSSSOOIDCTokenViaDeviceCode:StartUrl'] = "https://mycoolstart.awsapps.com/start/" Adding this to somewhere like, say, your PowerShell profile will then use that default value for the -StartUrl parameter to this cmdlet (easy!) #> #Requires -Module AWS.Tools.SSO, AWS.Tools.SSOOIDC [CmdletBinding()] param ( ## AWSApps "Start" url [parameter(Mandatory = $true)][System.Uri]$StartUrl, ## AWS Region to use $Region = "us-east-2" ) begin { ## set the AWS region to use for this script Set-DefaultAWSRegion -Scope Script -Region $Region ## set the AWS anonymous credentials to use for this script (actual user-specific creds are used in the browser) Set-AWSCredential -Scope Script -Credential ([Amazon.Runtime.AnonymousAWSCredentials]::new()) ## register the SSO OIDC client for use in device authorization and token creation $oSSOOIDCClient = Register-SSOOIDCClient -ClientName powershell-sso-client -ClientType public } process { ## API doc at https://docs.aws.amazon.com/singlesignon/latest/OIDCAPIReference/API_StartDeviceAuthorization.html $oDeviceAuthorization = $oSSOOIDCClient | Start-SSOOIDCDeviceAuthorization -StartUrl $StartUrl ## currently, launch web browser to authenticate $oTmp = Start-Process -PassThru $oDeviceAuthorization.VerificationUriComplete ## try to generate a new SSO OIDC token try { while (-not $oSSOOIDCToken) { try { $oSSOOIDCToken = $oSSOOIDCClient | New-SSOOIDCToken -DeviceCode $oDeviceAuthorization.DeviceCode -GrantType "urn:ietf:params:oauth:grant-type:device_code" } ## if still pending authorization, continue to wait and retry catch [Amazon.SSOOIDC.Model.AuthorizationPendingException] { Write-Verbose -Message "Standing by for authorization in browser (yes, by _you_!)"; Start-Sleep -Seconds 1 } } ## set as global variable, for subsequent use later in this session $oSSOOIDCToken | Add-Member -MemberType NoteProperty -Name ExpiresAt -Value (Get-Date).AddSeconds($oSSOOIDCToken.ExpiresIn) Set-Variable -Scope Global -Name AWSSSOOIDCToken -Value $oSSOOIDCToken Write-Verbose -Message "Generated new SSO OIDC token valid for a timespan of '$(New-TimeSpan -Seconds $oSSOOIDCToken.ExpiresIn)' (expires at '$($oSSOOIDCToken.ExpiresAt)'). Save as global variable '`$global:AWSSSOOIDCToken'" Write-Verbose -Message "You can use the SSO OIDC token for getting SSO accounts and their associated roles (via Get-SSOAccountList/Get-SSOAccountRoleList), and for generating new temporary credentials from an SSO role (say, via Get-SSORoleCredential or some helper script)" return $oSSOOIDCToken } ## else, return the error catch { $_ } } } function Get-VNAWSSSOAccountAndRoleInfo { <# .Description Get the AWS SSO account(s) and role(s) to which an identity has access (the identity associated with the given AccessToken), for subsequent use for generating temporary credentials for any such account/role .Example New-VNAWSSSOOIDCTokenViaDeviceCode -StartUrl https://mycoolstart.awsapps.com/start/ | Get-VNAWSSSOAccountAndRoleInfo Get a new SSO OIDC access token for some identity, then get the SSO accounts and roles to which the access token provides permission .Example Get-VNAWSSSOAccountAndRoleInfo -Name mysandbox*, mydev* Get the SSO accounts and roles to which the previously retrieved access token (via New-VNAWSSSOOIDCTokenViaDeviceCode) provides permission. Uses the wildcarded names to filter _which_ AWS accounts for which to get the account- and role info #> #Requires -Module AWS.Tools.SSO [CmdletBinding()] param ( ## AWS SSO OIDC access token to use for SSO getting role/credential items. Generated from something like New-VNAWSSSOOIDCTokenViaDeviceCode [parameter(ValueFromPipelineByPropertyName = $true)][String]$AccessToken = ${global:AWSSSOOIDCToken}.AccessToken, ## Name(s) of AWS account(s) of interest, for which to get account/role information. Defaults to getting role information for all AWS accounts to which the given access token has permissions. Supports using wildcards. [SupportsWildcards()][String[]]$Name = "*", ## AWS Region to use $Region = "us-east-2" ) begin { ## set the AWS region to use for this script Set-DefaultAWSRegion -Scope Script -Region $Region ## set the AWS anonymous credentials to use for this script (actual user-specific creds are used in the browser) Set-AWSCredential -Scope Script -Credential ([Amazon.Runtime.AnonymousAWSCredentials]::new()) } process { ## for this script, let's set the AccessToken for the SSO cmdlets to use; make sure that we have a defaultParams hashtable for starters $private:PSDefaultParameterValues = if ($private:PSDefaultParameterValues) { $private:PSDefaultParameterValues } else { @{} } $private:PSDefaultParameterValues['Get-SSO*:AccessToken'] = $AccessToken ## get the SSO Account(s) and corresponding Roles that this SSO OIDC access token has permissions to use (can later be used to generate role temporary credential via something like Get-SSORoleCredential) Get-SSOAccountList -PipelineVariable oThisSSOAccountItem | Where-Object {$Name.Where({$oThisSSOAccountItem.AccountName -like $_})} | Get-SSOAccountRoleList | Select-Object @{n="AccountName"; e={$oThisSSOAccountItem.AccountName }}, *, @{n="Region"; e={$Region}} } } function New-VNAWSSSORoleTempCredential { <# .Description Generate temporary credentials for some account(s) and role(s) via AWS SSO and SSOOIDC .Example New-VNAWSSSOOIDCTokenViaDeviceCode -StartUrl https://mycoolstart.awsapps.com/start/; Get-VNAWSSSOAccountAndRoleInfo -Name my-cool-account-* | Where-Object RoleName -match _mycoolrole_ | New-VNAWSSSORoleTempCredential | Set-AWSCredential -ProfileLocation (Resolve-Path ~\.aws\credentials) -Verbose For the SSO accounts/roles to which the given user is entitled and whose attributes match the filters (account name, role name), generate temporary credentials for the role and save in default AWS local creds store as specified "StoreAs" profile name in the object piped to Set-AWSCredential .Example New-VNAWSSSOOIDCTokenViaDeviceCode -StartUrl https://mycoolstart.awsapps.com/start/; Get-VNAWSSSOAccountAndRoleInfo | New-VNAWSSSORoleTempCredential | Set-AWSCredential -Verbose For all of the SSO accounts/roles to which the given user is entitled, generate temporary credentials for the role and save the credentials (from help for Set-AWSCredential, not specifying -ProfileLocation will try to use "the encrypted credential file used by the AWS SDK for .NET and AWS Toolkit for Visual Studio first. If the profile is not found then the cmdlet will search in the ini-format credential file at the default location: (user's home directory)\.aws\credentials") #> #Requires -Module AWS.Tools.SSO [CmdletBinding(SupportsShouldProcess)] param ( ## AWS Account ID (account number) for which to get temporary credential for SSO role [parameter(Mandatory, ValueFromPipelineByPropertyName = $true)][String]$AccountId, ## Name of AWS Role for which to getting temporary credentials [parameter(Mandatory, ValueFromPipelineByPropertyName = $true)][String]$RoleName, ## Diplay Name of AWS account involved. Only used for saving the credentials as a profile name. If none, AccountId is used for the persisted profile name [parameter(ValueFromPipelineByPropertyName = $true)][String]$AccountName, ## AWS SSO OIDC access token to use for SSO getting role/credential items. Generated from something like New-VNAWSSSOOIDCTokenViaDeviceCode, and possibly already defined as a global variable by such script, so may not need to explicitly pass here [parameter(ValueFromPipelineByPropertyName = $true)][String]$AccessToken = ${global:AWSSSOOIDCToken}.AccessToken, ## AWS Region to use [parameter(ValueFromPipelineByPropertyName = $true)]$Region = "us-east-2" ) begin { ## set the AWS region to use for this script Set-DefaultAWSRegion -Scope Script -Region $Region ## set the AWS anonymous credentials to use for this script (actual user-specific creds are used in the browser) Set-AWSCredential -Scope Script -Credential ([Amazon.Runtime.AnonymousAWSCredentials]::new()) } process { ## params for getting role credential $hshParamsForGetSSORoleCredential = @{ AccountId = $AccountId RoleName = $RoleName AccessToken = $AccessToken PipelineVariable = "oThisRoleCredential" } ## ShouldProcess args $strShouldProcessMsg = "Get temporary credential for role '$RoleName'" $strShouldProcessTarget = "AWS account '{0}'" -f $(if ($PSBoundParameters.ContainsKey("AccountName")) { "$AccountName ($AccountId)" } else { $AccountId }) if ($PSCmdlet.ShouldProcess($strShouldProcessTarget, $strShouldProcessMsg)) { ## get the role credential for the given acct/role, then write to local AWS temp creds store Get-SSORoleCredential @hshParamsForGetSSORoleCredential | ForEach-Object { ## make an object with the properties that Set-AWSCredential takes from pipeline (and an extra, informational property, "Note") New-Object -Type PSObject -Property @{ AccessKey = $_.AccessKeyId SecretKey = $_.SecretAccessKey SessionToken = $_.SessionToken StoreAs = if ($PSBoundParameters.ContainsKey("AccountName")) { $AccountName } else { $AccountId } Note = "credential for $strShouldProcessTarget, role '$RoleName'; expires at '{0} {1}' (in timespan of '{2}')" -f ($dteCredExpiry = Get-Date -UnixTimeSeconds ($oThisRoleCredential.Expiration / 1000)), ([System.DateTimeOffset]::Now).Offset.ToString(), $(New-TimeSpan -End $dteCredExpiry) } -OutVariable oCredsInfoItem Write-Verbose -Message "Got $($oCredsInfoItem.Note)" } } } } |