Skip to content

Instantly share code, notes, and snippets.

@naamancampbell
Last active November 16, 2022 03:15
Show Gist options
  • Save naamancampbell/f0f0fde6e9a9ecc7268e19b49e13ae57 to your computer and use it in GitHub Desktop.
Save naamancampbell/f0f0fde6e9a9ecc7268e19b49e13ae57 to your computer and use it in GitHub Desktop.
awscli-sso-config - generates AWS CLI config file for SSO accounts and roles
#!/bin/bash
#
# awscli-sso-config - generates AWS CLI config file for
# SSO accounts and roles
#
# Usage: ./awscli-sso-config.sh aws_profile sso_start_url [--resume]
#
# Requires: awscli, jq
#
# Author: Naaman Campbell
# 28 August 2021
#
# Version: 1.1.4 - 2022-11-16 - NC
#
aws_dir="$HOME/.aws"
sso_dir="$aws_dir/cli-sso"
client_type="public"
grant_type="urn:ietf:params:oauth:grant-type:device_code"
default_role_order="SystemAdministrator AdministratorAccess ReadOnly"
delimiters=":_"
resume=0
if [ $# -lt 2 ]; then
exit "Usage: ./awscli-sso-config.sh aws_profile sso_start_url [--resume]"
fi
profile=$1
start_url=$2
if [[ ! -f $aws_dir/config || $(grep -c "^\[profile $profile\]" $aws_dir/config) -lt 1 ]]; then
echo "$profile not found in $aws_dir/config"
echo "Add AWS SSO profile - aws configure sso"
exit 1
fi
if [[ $# -eq 3 && "$3" == "--resume" ]]; then
resume=1
fi
add_profile () {
# add_profile profile_name start_url region account_id role_name
# skip adding current profile
if [ "$1" != "$profile" ]; then
echo "[profile $1]" >> $aws_dir/config
echo "sso_start_url = $2" >> $aws_dir/config
echo "sso_region = $3" >> $aws_dir/config
echo "sso_account_id = $4" >> $aws_dir/config
echo "sso_role_name = $5" >> $aws_dir/config
echo "region = $3" >> $aws_dir/config
echo "output = json" >> $aws_dir/config
echo "" >> $aws_dir/config
fi
}
if [ $resume -eq 0 ]; then
now=$(date +%s)
mkdir -p $sso_dir
# sso-oidc register-client
generate_client=1
if [ -f $sso_dir/cli-sso-client.json ]; then
client_expiry=$(jq -r '.clientSecretExpiresAt' $sso_dir/cli-sso-client.json)
if [ $now -lt $client_expiry ]; then
generate_client=0
fi
fi
if [ $generate_client -eq 1 ]; then
aws sso-oidc register-client \
--client-name "cli-sso-config-$now" \
--client-type $client_type \
--profile $profile \
> $sso_dir/cli-sso-client.json
fi
client_id=$(jq -r '.clientId' $sso_dir/cli-sso-client.json)
client_secret=$(jq -r '.clientSecret' $sso_dir/cli-sso-client.json)
# sso-oidc start-device-authorization
aws sso-oidc start-device-authorization \
--client-id $client_id \
--client-secret $client_secret \
--start-url $start_url \
--profile $profile \
> $sso_dir/cli-sso-device.json
echo "Open the following URL to authorise this device and"
echo "re-run $0 with the --resume flag.."
echo ""
jq -r '.verificationUriComplete' $sso_dir/cli-sso-device.json
echo ""
exit 0
else
# cli-sso --resume after device authorisation
timestamp=$(date -Iseconds)
if [ -f $aws_dir/credentials ]; then
echo "Existing AWS credentials file found - incompatible with SSO CLI"
mv $aws_dir/credentials $aws_dir/credentials-$timestamp
echo "Moved to $aws_dir/credentials-$timestamp"
fi
if [ -f $aws_dir/config ]; then
echo "Existing AWS config file found"
mv $aws_dir/config $aws_dir/config-$timestamp
echo "Moved to $aws_dir/config-$timestamp"
echo ""
# copy profile to new config
sed -n "/^\[profile $profile\]/,/^$/p" $aws_dir/config-$timestamp > $aws_dir/config
fi
region=$(aws configure get region --profile $profile)
device_code=$(jq -r '.deviceCode' $sso_dir/cli-sso-device.json)
client_id=$(jq -r '.clientId' $sso_dir/cli-sso-client.json)
client_secret=$(jq -r '.clientSecret' $sso_dir/cli-sso-client.json)
# sso-oidc create-token
aws sso-oidc create-token \
--client-id $client_id \
--client-secret $client_secret \
--grant-type $grant_type \
--device-code $device_code \
--profile $profile \
> $sso_dir/cli-sso-token.json
if [ $? -gt 0 ]; then
exit "Failed: aws sso-oidc create-token"
fi
access_token=$(jq -r '.accessToken' $sso_dir/cli-sso-token.json)
# sso list-accounts
aws sso list-accounts \
--access-token $access_token \
--profile $profile \
> $sso_dir/cli-sso-accounts.json
# sso list-account-roles
jq -c '.accountList[]' $sso_dir/cli-sso-accounts.json | while read account
do
id=$(echo $account | jq -r '.accountId')
name=$(echo $account | jq -r '.accountName')
email=$(echo $account | jq -r '.emailAddress')
default_role=""
default_role_match=$(echo $default_role_order | awk '{print NF + 1}')
echo "${id}: ${name}"
roles=$(aws sso list-account-roles \
--access-token $access_token \
--account-id $id \
--profile $profile \
| jq -r '.roleList[].roleName')
if [ -z "$roles" ]; then
echo "No roles found for account: $name"
continue
fi
for role in $roles
do
add_profile "${id}_${role}" $start_url $region $id $role
role_match=$(awk "BEGIN{RS=FS}/$role/{print NR}" <<< $default_role_order)
if [[ ! -z $role_match && $role_match -lt $default_role_match ]]; then
default_role=$role
default_role_match=$role_match
fi
done
# profile aliases
if [ -z "$default_role" ]; then
default_role=$(echo $roles | awk '{print $1}')
fi
email_prefix=$(echo $email | awk -F'@' '{print $1}')
add_profile $email_prefix $start_url $region $id $default_role
account_prefix=$(echo $name | awk -F"[$delimiters]" '{print $1}')
if [ "$email_prefix" != "$account_prefix" ]; then
add_profile $account_prefix $start_url $region $id $default_role
fi
done
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment