diff options
author | Tuowen Zhao <ztuowen@gmail.com> | 2020-11-21 14:57:26 -0700 |
---|---|---|
committer | Tuowen Zhao <ztuowen@gmail.com> | 2020-11-21 14:57:26 -0700 |
commit | 3aaa0bc62ece494dd2b6e47a191de79e562156f9 (patch) | |
tree | 53b623b60358bd9b8a5f9d267166f717e2f3947c /plugins/aws | |
parent | 058885f5263f29f046c96ea2ecf55e6dca3ed321 (diff) | |
parent | 88b3f028f4a2ffa4f3853a11e4b8e0d78008ca34 (diff) | |
download | zsh-3aaa0bc62ece494dd2b6e47a191de79e562156f9.tar.gz zsh-3aaa0bc62ece494dd2b6e47a191de79e562156f9.tar.bz2 zsh-3aaa0bc62ece494dd2b6e47a191de79e562156f9.zip |
Merge remote-tracking branch 'origin/master'
Diffstat (limited to 'plugins/aws')
-rw-r--r-- | plugins/aws/README.md | 41 | ||||
-rw-r--r-- | plugins/aws/aws.plugin.zsh | 112 |
2 files changed, 145 insertions, 8 deletions
diff --git a/plugins/aws/README.md b/plugins/aws/README.md index 57c3b54ac..011bbd8b4 100644 --- a/plugins/aws/README.md +++ b/plugins/aws/README.md @@ -15,6 +15,13 @@ plugins=(... aws) It also sets `$AWS_EB_PROFILE` to `<profile>` for the Elastic Beanstalk CLI. Run `asp` without arguments to clear the profile. +* `acp [<profile>]`: in addition to `asp` functionality, it actually changes the profile by + assuming the role specified in the `<profile>` configuration. It supports MFA and sets + `$AWS_ACCESS_KEY_ID`, `$AWS_SECRET_ACCESS_KEY` and `$AWS_SESSION_TOKEN`, if obtained. It + requires the roles to be configured as per the + [official guide](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-role.html). + Run `acp` without arguments to clear the profile. + * `agp`: gets the current value of `$AWS_PROFILE`. * `aws_change_access_key`: changes the AWS access key of a profile. @@ -33,6 +40,36 @@ plugins=(... aws) The plugin creates an `aws_prompt_info` function that you can use in your theme, which displays the current `$AWS_PROFILE`. It uses two variables to control how that is shown: -- ZSH_THEME_AWS_PREFIX: sets the prefix of the AWS_PROFILE. Defaults to `<aws:`. +* ZSH_THEME_AWS_PREFIX: sets the prefix of the AWS_PROFILE. Defaults to `<aws:`. + +* ZSH_THEME_AWS_SUFFIX: sets the suffix of the AWS_PROFILE. Defaults to `>`. + +## Configuration + +[Configuration and credential file settings](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html) by AWS -- ZSH_THEME_AWS_SUFFIX: sets the suffix of the AWS_PROFILE. Defaults to `>`. +### Scenario: IAM roles with a source profile and MFA authentication + +Source profile credentials in `~/.aws/credentials`: + +``` +[source-profile-name] +aws_access_key_id = ... +aws_secret_access_key = ... +``` + +Role configuration in `~/.aws/config`: + +``` +[profile source-profile-name] +mfa_serial = arn:aws:iam::111111111111:mfa/myuser +region = us-east-1 +output = json + +[profile profile-with-role] +role_arn = arn:aws:iam::9999999999999:role/myrole +mfa_serial = arn:aws:iam::111111111111:mfa/myuser +source_profile = source-profile-name +region = us-east-1 +output = json +``` diff --git a/plugins/aws/aws.plugin.zsh b/plugins/aws/aws.plugin.zsh index 7994963c3..e1566b113 100644 --- a/plugins/aws/aws.plugin.zsh +++ b/plugins/aws/aws.plugin.zsh @@ -23,31 +23,131 @@ function asp() { export AWS_EB_PROFILE=$1 } +# AWS profile switch +function acp() { + if [[ -z "$1" ]]; then + unset AWS_DEFAULT_PROFILE AWS_PROFILE AWS_EB_PROFILE + unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN + echo AWS profile cleared. + return + fi + + local -a available_profiles + available_profiles=($(aws_profiles)) + if [[ -z "${available_profiles[(r)$1]}" ]]; then + echo "${fg[red]}Profile '$1' not found in '${AWS_CONFIG_FILE:-$HOME/.aws/config}'" >&2 + echo "Available profiles: ${(j:, :)available_profiles:-no profiles found}${reset_color}" >&2 + return 1 + fi + + local profile="$1" + + # Get fallback credentials for if the aws command fails or no command is run + local aws_access_key_id="$(aws configure get aws_access_key_id --profile $profile)" + local aws_secret_access_key="$(aws configure get aws_secret_access_key --profile $profile)" + local aws_session_token="$(aws configure get aws_session_token --profile $profile)" + + + # First, if the profile has MFA configured, lets get the token and session duration + local mfa_serial="$(aws configure get mfa_serial --profile $profile)" + local sess_duration="$(aws configure get duration_seconds --profile $profile)" + + if [[ -n "$mfa_serial" ]]; then + local -a mfa_opt + local mfa_token + echo -n "Please enter your MFA token for $mfa_serial: " + read -r mfa_token + if [[ -z "$sess_duration" ]]; then + echo -n "Please enter the session duration in seconds (900-43200; default: 3600, which is the default maximum for a role): " + read -r sess_duration + fi + mfa_opt=(--serial-number "$mfa_serial" --token-code "$mfa_token" --duration-seconds "${sess_duration:-3600}") + + # Now see whether we need to just MFA for the current role, or assume a different one + local role_arn="$(aws configure get role_arn --profile $profile)" + local sess_name="$(aws configure get role_session_name --profile $profile)" + + if [[ -n "$role_arn" ]]; then + # Means we need to assume a specified role + aws_command=(aws sts assume-role --role-arn "$role_arn" "${mfa_opt[@]}") + + # Check whether external_id is configured to use while assuming the role + local external_id="$(aws configure get external_id --profile $profile)" + if [[ -n "$external_id" ]]; then + aws_command+=(--external-id "$external_id") + fi + + # Get source profile to use to assume role + local source_profile="$(aws configure get source_profile --profile $profile)" + if [[ -z "$sess_name" ]]; then + sess_name="${source_profile:-profile}" + fi + aws_command+=(--profile="${source_profile:-profile}" --role-session-name "${sess_name}") + + echo "Assuming role $role_arn using profile ${source_profile:-profile}" + else + # Means we only need to do MFA + aws_command=(aws sts get-session-token --profile="$profile" "${mfa_opt[@]}") + echo "Obtaining session token for profile $profile" + fi + + # Format output of aws command for easier processing + aws_command+=(--query '[Credentials.AccessKeyId,Credentials.SecretAccessKey,Credentials.SessionToken]' --output text) + + # Run the aws command to obtain credentials + local -a credentials + credentials=(${(ps:\t:)"$(${aws_command[@]})"}) + + if [[ -n "$credentials" ]]; then + aws_access_key_id="${credentials[1]}" + aws_secret_access_key="${credentials[2]}" + aws_session_token="${credentials[3]}" + fi + fi + + # Switch to AWS profile + if [[ -n "${aws_access_key_id}" && -n "$aws_secret_access_key" ]]; then + export AWS_DEFAULT_PROFILE="$profile" + export AWS_PROFILE="$profile" + export AWS_EB_PROFILE="$profile" + export AWS_ACCESS_KEY_ID="$aws_access_key_id" + export AWS_SECRET_ACCESS_KEY="$aws_secret_access_key" + + if [[ -n "$aws_session_token" ]]; then + export AWS_SESSION_TOKEN="$aws_session_token" + else + unset AWS_SESSION_TOKEN + fi + + echo "Switched to AWS Profile: $profile" + fi +} + function aws_change_access_key() { if [[ -z "$1" ]]; then echo "usage: $0 <profile>" return 1 fi - echo Insert the credentials when asked. + echo "Insert the credentials when asked." asp "$1" || return 1 AWS_PAGER="" aws iam create-access-key AWS_PAGER="" aws configure --profile "$1" - echo You can now safely delete the old access key running \`aws iam delete-access-key --access-key-id ID\` - echo Your current keys are: + echo "You can now safely delete the old access key running \`aws iam delete-access-key --access-key-id ID\`" + echo "Your current keys are:" AWS_PAGER="" aws iam list-access-keys } function aws_profiles() { [[ -r "${AWS_CONFIG_FILE:-$HOME/.aws/config}" ]] || return 1 - grep '\[profile' "${AWS_CONFIG_FILE:-$HOME/.aws/config}"|sed -e 's/.*profile \([a-zA-Z0-9@_\.-]*\).*/\1/' + grep --color=never -Eo '\[.*\]' "${AWS_CONFIG_FILE:-$HOME/.aws/config}" | sed -E 's/^[[:space:]]*\[(profile)?[[:space:]]*([-_[:alnum:]\.@]+)\][[:space:]]*$/\2/g' } function _aws_profiles() { reply=($(aws_profiles)) } -compctl -K _aws_profiles asp aws_change_access_key +compctl -K _aws_profiles asp acp aws_change_access_key # AWS prompt function aws_prompt_info() { @@ -55,7 +155,7 @@ function aws_prompt_info() { echo "${ZSH_THEME_AWS_PREFIX:=<aws:}${AWS_PROFILE}${ZSH_THEME_AWS_SUFFIX:=>}" } -if [ "$SHOW_AWS_PROMPT" != false ]; then +if [[ "$SHOW_AWS_PROMPT" != false && "$RPROMPT" != *'$(aws_prompt_info)'* ]]; then RPROMPT='$(aws_prompt_info)'"$RPROMPT" fi |