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 | 
