aws.plugin.zsh 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. function agp() {
  2. echo $AWS_PROFILE
  3. }
  4. function agr() {
  5. echo $AWS_REGION
  6. }
  7. # Update state file if enabled
  8. function _aws_update_state() {
  9. if [[ "$AWS_PROFILE_STATE_ENABLED" == true ]]; then
  10. test -d $(dirname ${AWS_STATE_FILE}) || exit 1
  11. echo "${AWS_PROFILE} ${AWS_REGION}" > "${AWS_STATE_FILE}"
  12. fi
  13. }
  14. function _aws_clear_state() {
  15. if [[ "$AWS_PROFILE_STATE_ENABLED" == true ]]; then
  16. test -d $(dirname ${AWS_STATE_FILE}) || exit 1
  17. echo -n > "${AWS_STATE_FILE}"
  18. fi
  19. }
  20. # AWS profile selection
  21. function asp() {
  22. if [[ -z "$1" ]]; then
  23. unset AWS_DEFAULT_PROFILE AWS_PROFILE AWS_EB_PROFILE AWS_PROFILE_REGION
  24. _aws_clear_state
  25. echo AWS profile cleared.
  26. return
  27. fi
  28. local -a available_profiles
  29. available_profiles=($(aws_profiles))
  30. if [[ -z "${available_profiles[(r)$1]}" ]]; then
  31. echo "${fg[red]}Profile '$1' not found in '${AWS_CONFIG_FILE:-$HOME/.aws/config}'" >&2
  32. echo "Available profiles: ${(j:, :)available_profiles:-no profiles found}${reset_color}" >&2
  33. return 1
  34. fi
  35. export AWS_DEFAULT_PROFILE=$1
  36. export AWS_PROFILE=$1
  37. export AWS_EB_PROFILE=$1
  38. export AWS_PROFILE_REGION=$(aws configure get region)
  39. _aws_update_state
  40. if [[ "$2" == "login" ]]; then
  41. if [[ -n "$3" ]]; then
  42. aws sso login --sso-session $3
  43. else
  44. aws sso login
  45. fi
  46. elif [[ "$2" == "logout" ]]; then
  47. aws sso logout
  48. fi
  49. }
  50. # AWS region selection
  51. function asr() {
  52. if [[ -z "$1" ]]; then
  53. unset AWS_DEFAULT_REGION AWS_REGION
  54. _aws_update_state
  55. echo AWS region cleared.
  56. return
  57. fi
  58. local -a available_regions
  59. available_regions=($(aws_regions))
  60. if [[ -z "${available_regions[(r)$1]}" ]]; then
  61. echo "${fg[red]}Available regions: \n$(aws_regions)"
  62. return 1
  63. fi
  64. export AWS_REGION=$1
  65. export AWS_DEFAULT_REGION=$1
  66. _aws_update_state
  67. }
  68. # AWS profile switch
  69. function acp() {
  70. if [[ -z "$1" ]]; then
  71. unset AWS_DEFAULT_PROFILE AWS_PROFILE AWS_EB_PROFILE
  72. unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN
  73. echo AWS profile cleared.
  74. return
  75. fi
  76. local -a available_profiles
  77. available_profiles=($(aws_profiles))
  78. if [[ -z "${available_profiles[(r)$1]}" ]]; then
  79. echo "${fg[red]}Profile '$1' not found in '${AWS_CONFIG_FILE:-$HOME/.aws/config}'" >&2
  80. echo "Available profiles: ${(j:, :)available_profiles:-no profiles found}${reset_color}" >&2
  81. return 1
  82. fi
  83. local profile="$1"
  84. local mfa_token="$2"
  85. # Get fallback credentials for if the aws command fails or no command is run
  86. local aws_access_key_id="$(aws configure get aws_access_key_id --profile $profile)"
  87. local aws_secret_access_key="$(aws configure get aws_secret_access_key --profile $profile)"
  88. local aws_session_token="$(aws configure get aws_session_token --profile $profile)"
  89. # First, if the profile has MFA configured, lets get the token and session duration
  90. local mfa_serial="$(aws configure get mfa_serial --profile $profile)"
  91. local sess_duration="$(aws configure get duration_seconds --profile $profile)"
  92. if [[ -n "$mfa_serial" ]]; then
  93. local -a mfa_opt
  94. if [[ -z "$mfa_token" ]]; then
  95. echo -n "Please enter your MFA token for $mfa_serial: "
  96. read -r mfa_token
  97. fi
  98. if [[ -z "$sess_duration" ]]; then
  99. echo -n "Please enter the session duration in seconds (900-43200; default: 3600, which is the default maximum for a role): "
  100. read -r sess_duration
  101. fi
  102. mfa_opt=(--serial-number "$mfa_serial" --token-code "$mfa_token" --duration-seconds "${sess_duration:-3600}")
  103. fi
  104. # Now see whether we need to just MFA for the current role, or assume a different one
  105. local role_arn="$(aws configure get role_arn --profile $profile)"
  106. local sess_name="$(aws configure get role_session_name --profile $profile)"
  107. if [[ -n "$role_arn" ]]; then
  108. # Means we need to assume a specified role
  109. aws_command=(aws sts assume-role --role-arn "$role_arn" "${mfa_opt[@]}")
  110. # Check whether external_id is configured to use while assuming the role
  111. local external_id="$(aws configure get external_id --profile $profile)"
  112. if [[ -n "$external_id" ]]; then
  113. aws_command+=(--external-id "$external_id")
  114. fi
  115. # Get source profile to use to assume role
  116. local source_profile="$(aws configure get source_profile --profile $profile)"
  117. if [[ -z "$sess_name" ]]; then
  118. sess_name="${source_profile:-profile}"
  119. fi
  120. aws_command+=(--profile="${source_profile:-profile}" --role-session-name "${sess_name}")
  121. echo "Assuming role $role_arn using profile ${source_profile:-profile}"
  122. else
  123. # Means we only need to do MFA
  124. aws_command=(aws sts get-session-token --profile="$profile" "${mfa_opt[@]}")
  125. echo "Obtaining session token for profile $profile"
  126. fi
  127. # Format output of aws command for easier processing
  128. aws_command+=(--query '[Credentials.AccessKeyId,Credentials.SecretAccessKey,Credentials.SessionToken]' --output text)
  129. # Run the aws command to obtain credentials
  130. local -a credentials
  131. credentials=(${(ps:\t:)"$(${aws_command[@]})"})
  132. if [[ -n "$credentials" ]]; then
  133. aws_access_key_id="${credentials[1]}"
  134. aws_secret_access_key="${credentials[2]}"
  135. aws_session_token="${credentials[3]}"
  136. fi
  137. # Switch to AWS profile
  138. if [[ -n "${aws_access_key_id}" && -n "$aws_secret_access_key" ]]; then
  139. export AWS_DEFAULT_PROFILE="$profile"
  140. export AWS_PROFILE="$profile"
  141. export AWS_EB_PROFILE="$profile"
  142. export AWS_ACCESS_KEY_ID="$aws_access_key_id"
  143. export AWS_SECRET_ACCESS_KEY="$aws_secret_access_key"
  144. if [[ -n "$aws_session_token" ]]; then
  145. export AWS_SESSION_TOKEN="$aws_session_token"
  146. else
  147. unset AWS_SESSION_TOKEN
  148. fi
  149. echo "Switched to AWS Profile: $profile"
  150. fi
  151. }
  152. function aws_change_access_key() {
  153. if [[ -z "$1" ]]; then
  154. echo "usage: $0 <profile>"
  155. return 1
  156. fi
  157. local profile="$1"
  158. # Get current access key
  159. local original_aws_access_key_id="$(aws configure get aws_access_key_id --profile $profile)"
  160. asp "$profile" || return 1
  161. echo "Generating a new access key pair for you now."
  162. if aws --no-cli-pager iam create-access-key; then
  163. echo "Insert the newly generated credentials when asked."
  164. aws --no-cli-pager configure --profile $profile
  165. else
  166. echo "Current access keys:"
  167. aws --no-cli-pager iam list-access-keys
  168. echo "Profile \"${profile}\" is currently using the $original_aws_access_key_id key. You can delete an old access key by running \`aws --profile $profile iam delete-access-key --access-key-id AccessKeyId\`"
  169. return 1
  170. fi
  171. read -q "yn?Would you like to disable your previous access key (${original_aws_access_key_id}) now? "
  172. case $yn in
  173. [Yy]*)
  174. echo -n "\nDisabling access key ${original_aws_access_key_id}..."
  175. if aws --no-cli-pager iam update-access-key --access-key-id ${original_aws_access_key_id} --status Inactive; then
  176. echo "done."
  177. else
  178. echo "\nFailed to disable ${original_aws_access_key_id} key."
  179. fi
  180. ;;
  181. *)
  182. echo ""
  183. ;;
  184. esac
  185. echo "You can now safely delete the old access key by running \`aws --profile $profile iam delete-access-key --access-key-id ${original_aws_access_key_id}\`"
  186. echo "Your current keys are:"
  187. aws --no-cli-pager iam list-access-keys
  188. }
  189. function aws_regions() {
  190. local region
  191. if [[ $AWS_DEFAULT_REGION ]];then
  192. region="$AWS_DEFAULT_REGION"
  193. elif [[ $AWS_REGION ]];then
  194. region="$AWS_REGION"
  195. else
  196. region="us-west-1"
  197. fi
  198. if [[ $AWS_DEFAULT_PROFILE || $AWS_PROFILE ]];then
  199. aws ec2 describe-regions --region $region |grep RegionName | awk -F ':' '{gsub(/"/, "", $2);gsub(/,/, "", $2);gsub(/ /, "", $2); print $2}'
  200. else
  201. echo "You must specify a AWS profile."
  202. fi
  203. }
  204. function aws_profiles() {
  205. aws --no-cli-pager configure list-profiles 2> /dev/null && return
  206. [[ -r "${AWS_CONFIG_FILE:-$HOME/.aws/config}" ]] || return 1
  207. grep --color=never -Eo '\[.*\]' "${AWS_CONFIG_FILE:-$HOME/.aws/config}" | sed -E 's/^[[:space:]]*\[(profile)?[[:space:]]*([^[:space:]]+)\][[:space:]]*$/\2/g'
  208. }
  209. function _aws_regions() {
  210. reply=($(aws_regions))
  211. }
  212. compctl -K _aws_regions asr
  213. function _aws_profiles() {
  214. reply=($(aws_profiles))
  215. }
  216. compctl -K _aws_profiles asp acp aws_change_access_key
  217. # AWS prompt
  218. function aws_prompt_info() {
  219. local _aws_to_show
  220. local region="${AWS_REGION:-${AWS_DEFAULT_REGION:-$AWS_PROFILE_REGION}}"
  221. if [[ -n "$AWS_PROFILE" ]];then
  222. _aws_to_show+="${ZSH_THEME_AWS_PROFILE_PREFIX="<aws:"}${AWS_PROFILE}${ZSH_THEME_AWS_PROFILE_SUFFIX=">"}"
  223. fi
  224. if [[ -n "$region" ]]; then
  225. [[ -n "$_aws_to_show" ]] && _aws_to_show+="${ZSH_THEME_AWS_DIVIDER=" "}"
  226. _aws_to_show+="${ZSH_THEME_AWS_REGION_PREFIX="<region:"}${region}${ZSH_THEME_AWS_REGION_SUFFIX=">"}"
  227. fi
  228. echo "$_aws_to_show"
  229. }
  230. if [[ "$SHOW_AWS_PROMPT" != false && "$RPROMPT" != *'$(aws_prompt_info)'* ]]; then
  231. RPROMPT='$(aws_prompt_info)'"$RPROMPT"
  232. fi
  233. if [[ "$AWS_PROFILE_STATE_ENABLED" == true ]]; then
  234. AWS_STATE_FILE="${AWS_STATE_FILE:-/tmp/.aws_current_profile}"
  235. test -s "${AWS_STATE_FILE}" || return
  236. aws_state=($(cat $AWS_STATE_FILE))
  237. export AWS_DEFAULT_PROFILE="${aws_state[1]}"
  238. export AWS_PROFILE="$AWS_DEFAULT_PROFILE"
  239. export AWS_EB_PROFILE="$AWS_DEFAULT_PROFILE"
  240. test -z "${aws_state[2]}" && AWS_REGION=$(aws configure get region)
  241. export AWS_REGION=${AWS_REGION:-$aws_state[2]}
  242. export AWS_DEFAULT_REGION="$AWS_REGION"
  243. fi
  244. # Load awscli completions
  245. # AWS CLI v2 comes with its own autocompletion. Check if that is there, otherwise fall back
  246. if command -v aws_completer &> /dev/null; then
  247. autoload -Uz bashcompinit && bashcompinit
  248. complete -C aws_completer aws
  249. else
  250. function _awscli-homebrew-installed() {
  251. # check if Homebrew is installed
  252. (( $+commands[brew] )) || return 1
  253. # speculatively check default brew prefix
  254. if [ -h /usr/local/opt/awscli ]; then
  255. _brew_prefix=/usr/local/opt/awscli
  256. else
  257. # ok, it is not in the default prefix
  258. # this call to brew is expensive (about 400 ms), so at least let's make it only once
  259. _brew_prefix=$(brew --prefix awscli)
  260. fi
  261. }
  262. # get aws_zsh_completer.sh location from $PATH
  263. _aws_zsh_completer_path="$commands[aws_zsh_completer.sh]"
  264. # otherwise check common locations
  265. if [[ -z $_aws_zsh_completer_path ]]; then
  266. # Homebrew
  267. if _awscli-homebrew-installed; then
  268. _aws_zsh_completer_path=$_brew_prefix/libexec/bin/aws_zsh_completer.sh
  269. # Ubuntu
  270. elif [[ -e /usr/share/zsh/vendor-completions/_awscli ]]; then
  271. _aws_zsh_completer_path=/usr/share/zsh/vendor-completions/_awscli
  272. # NixOS
  273. elif [[ -e "${commands[aws]:P:h:h}/share/zsh/site-functions/aws_zsh_completer.sh" ]]; then
  274. _aws_zsh_completer_path="${commands[aws]:P:h:h}/share/zsh/site-functions/aws_zsh_completer.sh"
  275. # RPM
  276. else
  277. _aws_zsh_completer_path=/usr/share/zsh/site-functions/aws_zsh_completer.sh
  278. fi
  279. fi
  280. [[ -r $_aws_zsh_completer_path ]] && source $_aws_zsh_completer_path
  281. unset _aws_zsh_completer_path _brew_prefix
  282. fi