4

When you login via SSO in the browser, if you open one of your accounts and then assume a role, a new tab is opened after you click on "Management console". The syntax of the url of that link is something like https:/ /my-sso-portal.awsapps.com/start/#/saml/custom/my-account-name/base-64-string

If you decode that base 64 string in the url, you can notice there are 3 numbers, with this structure: number1_ins-number2_p-number3 The first number is your AWS Organization number, the second one identifies the account, and the third one the assumed role.

Even though I figured out the structure of this string, I still have no idea whether is possible for an user to get the second and third number (without using the url, of course). I basically want to programmatically construct that url but it looks like those two numbers are IDs that AWS keeps for itself, I'm not sure though. Anyone else knows more about this?

2 Answers2

1

You can use AWS SSO APIs to get this information. I haven't found documentation for them, but the SSO user portal uses them.

The first one (the organization id) can be retrieved using GET https://portal.sso.<SSO_REGION>.amazonaws.com/token/whoAmI. Search for the 'accountId' property in the response.

The second one (the app instance id) can be retrieved using GET https://portal.sso.<SSO_REGION>.amazonaws.com/instance/appinstances. The response contains a list of instances and each contains an 'id' property.

The last one (the profile id) can be retrieved using GET https://portal.sso.<SSO_REGION>.amazonaws.com/instance/appinstance/<APP_INSTANCE_ID>/profiles. The response contains a list of profiles, each has the id property.

For each of these APIs you need the SSO token which can be retrieved by the CLI/SDK. The UI is inserting the token into two headers: 'x-amz-sso-bearer-token' and 'x-amz-sso_bearer_token'.

Gal Malka
  • 307
  • 3
  • 12
1

Taking Gal's answer and building on top of that:

A note that as far as I can tell the relevant values returned from these GET requests don't appear to change, so you can cache them locally for each user.

With command-line tools like base64, curl and jq and a quick assist with Perl for %-encoding it can look like this, assuming you have your SSO token stored in TOKEN, account number (not the alias) in account and role-name in role:

ORGID=$(curl -s -H "x-amz-sso_bearer_token: $TOKEN" -H "x-amz-sso-bearer-token: $TOKEN" $PORTALBASE/token/whoAmI | jq -r .accountId)
AID=$(curl -s -H "x-amz-sso_bearer_token: $TOKEN" -H "x-amz-sso-bearer-token: $TOKEN" $PORTALBASE/instance/appinstances | jq -r '.result[]|select(.searchMetadata.AccountId=="'$account'").id')
ANAME=$(curl -s -H "x-amz-sso_bearer_token: $TOKEN" -H "x-amz-sso-bearer-token: $TOKEN" $PORTALBASE/instance/appinstances | jq -r '.result[]|select(.searchMetadata.AccountId=="'$account'").name')
RID=$(curl -s -H "x-amz-sso_bearer_token: $TOKEN" -H "x-amz-sso-bearer-token: $TOKEN" $PORTALBASE/instance/appinstance/$AID/profiles | jq -r '.result[]|select(.name=="'$role'").id')

Combine those parts and base64-encode that:

LINK=$(echo -n "${ORGID}_${AID}_${RID}" | base64)

%-encode the account "name" and the link component:

ANAME=$(echo -n "$ANAME" | perl -lne 's/([^a-zA-Z0-9-])/sprintf("%%%02X", ord($1))/ge;print')
LINK=$(echo -n "$LINK" | perl -lne 's/([^a-zA-Z0-9-])/sprintf("%%%02X", ord($1))/ge;print')

And putting it all together, where AWS_SSO_START_URL is something along the lines of https://my-sso-portal.awsapps.com/start/#/:

URL="${AWS_SSO_START_URL}saml/custom/${ANAME}/${LINK}"
Erwin
  • 844
  • 4
  • 14