|
| 1 | +#!/usr/bin/env bash |
| 2 | + |
| 3 | +set -eo pipefail |
| 4 | + |
| 5 | +[[ ! -z "${AWSECURE_CLI_AWS_BIN_FILEPATH}" ]] && declare -x AWSECURE_CLI_AWS_BIN_FILEPATH_TMP="${AWSECURE_CLI_AWS_BIN_FILEPATH}" |
| 6 | +[[ ! -z "${AWSECURE_CLI_MUTED}" ]] && declare -lx AWSECURE_CLI_MUTED_TMP="${AWSECURE_CLI_MUTED}" |
| 7 | +[[ ! -z "${AWSECURE_CLI_AUTOROTATE_AWS_ACCESS_KEYS}" ]] && declare -lx AWSECURE_CLI_AUTOROTATE_AWS_ACCESS_KEYS_TMP="${AWSECURE_CLI_AUTOROTATE_AWS_ACCESS_KEYS}" |
| 8 | +[[ ! -z "${AWSECURE_CLI_AUTOROTATE_PERIOD}" ]] && declare -lx AWSECURE_CLI_AUTOROTATE_PERIOD_TMP="${AWSECURE_CLI_AUTOROTATE_PERIOD}" |
| 9 | +[[ ! -z "${AWSECURE_CLI_AUTOROTATE_CHECK}" ]] && declare -lx AWSECURE_CLI_AUTOROTATE_CHECK_TMP="${AWSECURE_CLI_AUTOROTATE_CHECK}" |
| 10 | + |
| 11 | +. ~/.awsecure-cli |
| 12 | + |
| 13 | +[[ ! -z "${AWSECURE_CLI_AWS_BIN_FILEPATH_TMP}" ]] && declare -gx AWSECURE_CLI_AWS_BIN_FILEPATH="${AWSECURE_CLI_AWS_BIN_FILEPATH_TMP:-$AWSECURE_CLI_AWS_BIN_FILEPATH}" |
| 14 | +[[ ! -z "${AWSECURE_CLI_MUTED_TMP}" ]] && declare -glx AWSECURE_CLI_MUTED="${AWSECURE_CLI_MUTED_TMP:-$AWSECURE_CLI_MUTED}" |
| 15 | +[[ ! -z "${AWSECURE_CLI_AUTOROTATE_AWS_ACCESS_KEYS_TMP}" ]] && declare -glx AWSECURE_CLI_AUTOROTATE_AWS_ACCESS_KEYS="${AWSECURE_CLI_AUTOROTATE_AWS_ACCESS_KEYS_TMP:-$AWSECURE_CLI_AUTOROTATE_AWS_ACCESS_KEYS}" |
| 16 | +[[ ! -z "${AWSECURE_CLI_AUTOROTATE_PERIOD_TMP}" ]] && declare -glx AWSECURE_CLI_AUTOROTATE_PERIOD="${AWSECURE_CLI_AUTOROTATE_PERIOD_TMP:-$AWSECURE_CLI_AUTOROTATE_PERIOD}" |
| 17 | +[[ ! -z "${AWSECURE_CLI_AUTOROTATE_CHECK_TMP}" ]] && declare -glx AWSECURE_CLI_AUTOROTATE_CHECK="${AWSECURE_CLI_AUTOROTATE_CHECK_TMP:-$AWSECURE_CLI_AUTOROTATE_CHECK}" |
| 18 | + |
| 19 | +if [[ $(type awsecure_cli_log_info 2> /dev/null) == "" || -z "${AWSECURE_CLI_SRC_DIRECTORY// /}" ]]; then |
| 20 | + [[ -L ${0} ]] && declare -gr AWSECURE_CLI_SRC_DIRECTORY="$(realpath $(readlink ${0}) | xargs dirname)/../../src" || declare -gr AWSECURE_CLI_SRC_DIRECTORY="$(realpath ${0} | xargs dirname)/../../src" |
| 21 | + . ${AWSECURE_CLI_SRC_DIRECTORY}/common/logging.shinc |
| 22 | +fi |
| 23 | + |
| 24 | +if [[ ! -z "${ZSH_NAME}" ]]; then |
| 25 | + declare -lr AWSECURE_CLI_SH_INTERPRETER="zsh" |
| 26 | +elif [[ ! -z "${BASH}" ]]; then |
| 27 | + declare -lr AWSECURE_CLI_SH_INTERPRETER="bash" |
| 28 | +else |
| 29 | + awsecure_cli_log_error "SH Interpreter not supported or not defined" |
| 30 | +fi |
| 31 | + |
| 32 | +declare -lrx AWSECURE_CLI_OS_NAME="$(uname -s)" |
| 33 | + |
| 34 | +function awsecure_cli_date_format() { |
| 35 | + date -u "${@}" +"%s" |
| 36 | +} |
| 37 | + |
| 38 | +function awsecure_cli_aws_access_keys_not_older_than() { |
| 39 | + case "${AWSECURE_CLI_OS_NAME// /}" in |
| 40 | + darwin) |
| 41 | + awsecure_cli_date_format -v "-${AWSECURE_CLI_AUTOROTATE_PERIOD// /}H" |
| 42 | + ;; |
| 43 | + linux) |
| 44 | + awsecure_cli_date_format -d "now - ${AWSECURE_CLI_AUTOROTATE_PERIOD// /} hours" |
| 45 | + ;; |
| 46 | + *) |
| 47 | + echo "Unknown OS" |
| 48 | + ;; |
| 49 | + esac |
| 50 | +} |
| 51 | + |
| 52 | +function awsecure_cli_get_aws_access_keys() { |
| 53 | + ${AWSECURE_CLI_AWS_BIN_FILEPATH} --output json iam list-access-keys |
| 54 | +} |
| 55 | + |
| 56 | +function awsecure_cli_get_aws_access_key_age() { |
| 57 | + jq -r '.AccessKeyMetadata[0].CreateDate' <<< ${AWSECURE_CLI_GET_AWS_ACCESS_KEYS} | sed 's/+.*//' |
| 58 | +} |
| 59 | + |
| 60 | +function awsecure_cli_get_aws_access_first_key_id() { |
| 61 | + jq -r '.AccessKeyMetadata[0].AccessKeyId' <<< ${AWSECURE_CLI_GET_AWS_ACCESS_KEYS} |
| 62 | +} |
| 63 | + |
| 64 | +function awsecure_cli_validate_aws_access_key() { |
| 65 | + : "${AWSECURE_CLI_CREATED_AWS_ACCESS_KEY:?"Variable not set or empty"}" |
| 66 | + |
| 67 | + jq -r '.AccessKey.Status' <<< "${AWSECURE_CLI_CREATED_AWS_ACCESS_KEY}" | grep "^Active$" &> /dev/null |
| 68 | + |
| 69 | + awsecure_cli_get_aws_access_keys | jq -r ".AccessKeyMetadata[] | select(.AccessKeyId == \"${AWSECURE_CLI_NEW_AWS_ACCESS_KEY_ID}\").Status" | grep "^Active$" &> /dev/null |
| 70 | +} |
| 71 | + |
| 72 | +function awsecure_cli_disable_old_access_key() { |
| 73 | + awsecure_cli_log_info "Disabling the old AWS key from AWS" |
| 74 | + sleep 10 |
| 75 | + ${AWSECURE_CLI_AWS_BIN_FILEPATH} iam update-access-key --access-key-id "${AWSECURE_CLI_GET_CURRENT_AWS_ACCESS_KEY_ID// /}" --status Inactive |
| 76 | +} |
| 77 | + |
| 78 | +function awsecure_cli_remove_old_access_key() { |
| 79 | + awsecure_cli_log_info "Deleting the old AWS key from AWS" |
| 80 | + sleep 10 |
| 81 | + ${AWSECURE_CLI_AWS_BIN_FILEPATH} iam delete-access-key --access-key-id "${AWSECURE_CLI_GET_CURRENT_AWS_ACCESS_KEY_ID// /}" |
| 82 | +} |
| 83 | + |
| 84 | +function awsecure_cli_change_aws_config_file() { |
| 85 | + awsecure_cli_log_info "Getting the AWS_ACCESS_KEY_ID in use" |
| 86 | + local -r AWSECURE_CLI_GET_CURRENT_AWS_ACCESS_KEY_ID="$(${AWSECURE_CLI_AWS_BIN_FILEPATH} configure get aws_access_key_id)" |
| 87 | + : "${AWSECURE_CLI_GET_CURRENT_AWS_ACCESS_KEY_ID:?"Variable not set or empty"}" |
| 88 | + |
| 89 | + awsecure_cli_log_info "Getting the AWS_SECRET_ACCESS_KEY in use" |
| 90 | + local -r AWSECURE_CLI_GET_CURRENT_AWS_SECRET_ACCESS_KEY="$(${AWSECURE_CLI_AWS_BIN_FILEPATH} configure get aws_secret_access_key | sed 's,\+,\\+,g')" |
| 91 | + : "${AWSECURE_CLI_GET_CURRENT_AWS_SECRET_ACCESS_KEY:?"Variable not set or empty"}" |
| 92 | + |
| 93 | + [[ ${AWSECURE_CLI_OS_NAME} == "darwin" ]] && local -r AWSECURE_CLI_SED_CMD=" " |
| 94 | + |
| 95 | + awsecure_cli_log_info "Setting the new AWS_ACCESS_KEY_ID and disabling the old AWS_ACCESS_KEY_ID in the AWS config file ${AWS_CONFIG_FILE}" |
| 96 | + sed -i${AWSECURE_CLI_SED_CMD}'' -E "s,(${AWSECURE_CLI_GET_CURRENT_AWS_ACCESS_KEY_ID}),${AWSECURE_CLI_NEW_AWS_ACCESS_KEY_ID}\n# AWS_ACCESS_KEY_ID = \\1," ${AWS_CONFIG_FILE} |
| 97 | + |
| 98 | + awsecure_cli_log_info "Setting the new AWS_SECRET_ACCESS_KEY and disabling the old AWS_SECRET_ACCESS_KEY in the AWS config file ${AWS_CONFIG_FILE}" |
| 99 | + sed -i${AWSECURE_CLI_SED_CMD}'' -E "s,(${AWSECURE_CLI_GET_CURRENT_AWS_SECRET_ACCESS_KEY}),${NEW_AWS_SECRET_ACCESS_KEY}\n# AWS_SECRET_ACCESS_KEY = \\1," ${AWS_CONFIG_FILE} |
| 100 | + |
| 101 | + awsecure_cli_disable_old_access_key |
| 102 | + awsecure_cli_remove_old_access_key |
| 103 | +} |
| 104 | + |
| 105 | +function awsecure_cli_rotate_aws_access_key() { |
| 106 | + awsecure_cli_log_info "Creating a new AWS keys" |
| 107 | + local -r AWSECURE_CLI_CREATED_AWS_ACCESS_KEY="$(${AWSECURE_CLI_AWS_BIN_FILEPATH} --output json iam create-access-key)" |
| 108 | + : "${AWSECURE_CLI_CREATED_AWS_ACCESS_KEY:?"Variable not set or empty"}" |
| 109 | + |
| 110 | + awsecure_cli_log_info "Getting the new AWS_ACCESS_KEY_ID" |
| 111 | + local -r AWSECURE_CLI_NEW_AWS_ACCESS_KEY_ID="$(jq -r '.AccessKey.AccessKeyId' <<< ${AWSECURE_CLI_CREATED_AWS_ACCESS_KEY})" |
| 112 | + : "${AWSECURE_CLI_NEW_AWS_ACCESS_KEY_ID:?"Variable not set or empty"}" |
| 113 | + |
| 114 | + awsecure_cli_log_info "Getting the new AWS_SECRET_ACCESS_KEY" |
| 115 | + local -r NEW_AWS_SECRET_ACCESS_KEY="$(jq -r '.AccessKey.SecretAccessKey' <<< ${AWSECURE_CLI_CREATED_AWS_ACCESS_KEY})" |
| 116 | + : "${NEW_AWS_SECRET_ACCESS_KEY:?"Variable not set or empty"}" |
| 117 | + |
| 118 | + awsecure_cli_log_info "Validating the new AWS_SECRET_ACCESS_KEY" |
| 119 | + awsecure_cli_validate_aws_access_key |
| 120 | + |
| 121 | + awsecure_cli_log_info "Changing your AWS_CONFIG_FILE" |
| 122 | + awsecure_cli_change_aws_config_file |
| 123 | +} |
| 124 | + |
| 125 | +function awsecure_cli_create_autorotate_state_file() { |
| 126 | + set -eo pipefail |
| 127 | + ${AWSECURE_CLI_STATE_FILE_OPTION} ${AWSECURE_CLI_AUTOROTATE_STATE_FILE// /} &> /dev/null |
| 128 | +} |
| 129 | + |
| 130 | +function awsecure_cli_autorotate_aws_access_keys() { |
| 131 | + . ${AWSECURE_CLI_SRC_DIRECTORY}/${AWSECURE_CLI_SH_INTERPRETER}/validate-prereqs.sh |
| 132 | + [[ "${SKIP_AWSECURE_CLI_AUTOROTATE_AWS_ACCESS_KEYS}" = "true" ]] && return 0 |
| 133 | + |
| 134 | + local -r AWS_CONFIG_FILE=${AWS_CONFIG_FILE:-~/.aws/credentials} |
| 135 | + |
| 136 | + local -r AWSECURE_CLI_AUTOROTATE_PERIOD="${AWSECURE_CLI_AUTOROTATE_PERIOD:-"168"}" |
| 137 | + local -r AWSECURE_CLI_AWS_ACCESS_KEYS_NOT_OLDER_THAN=$(awsecure_cli_aws_access_keys_not_older_than) |
| 138 | + : "${AWSECURE_CLI_AWS_ACCESS_KEYS_NOT_OLDER_THAN:?"Variable not set or empty"}" |
| 139 | + |
| 140 | + local -r AWSECURE_CLI_GET_AWS_ACCESS_KEYS="$(awsecure_cli_get_aws_access_keys)" |
| 141 | + : "${AWSECURE_CLI_GET_AWS_ACCESS_KEYS:?"Variable not set or empty"}" |
| 142 | + |
| 143 | + case "${AWSECURE_CLI_OS_NAME// /}" in |
| 144 | + darwin) |
| 145 | + local -r AWSECURE_CLI_FIRST_AWS_ACCESS_KEY_AGE="$(awsecure_cli_get_aws_access_key_age | xargs -I{} ${AWSECURE_CLI_SH_INTERPRETER} -c "$(declare -f awsecure_cli_date_format) ; awsecure_cli_date_format -jf%Y-%m-%dT%H:%M:%S {}")" |
| 146 | + : "${AWSECURE_CLI_FIRST_AWS_ACCESS_KEY_AGE:?"Variable not set or empty"}" |
| 147 | + ;; |
| 148 | + linux) |
| 149 | + local -r AWSECURE_CLI_FIRST_AWS_ACCESS_KEY_AGE="$(awsecure_cli_get_aws_access_key_age | xargs -I{} ${AWSECURE_CLI_SH_INTERPRETER} -c "$(declare -f awsecure_cli_date_format) ; awsecure_cli_date_format -d {}")" |
| 150 | + : "${AWSECURE_CLI_FIRST_AWS_ACCESS_KEY_AGE:?"Variable not set or empty"}" |
| 151 | + ;; |
| 152 | + *) |
| 153 | + echo "Unknown OS" |
| 154 | + ;; |
| 155 | + esac |
| 156 | + |
| 157 | + local -r AWSECURE_CLI_FIRST_ACCESS_KEY_ID="$(awsecure_cli_get_aws_access_first_key_id)" |
| 158 | + |
| 159 | + if [[ ${AWSECURE_CLI_AWS_ACCESS_KEYS_NOT_OLDER_THAN} -gt ${AWSECURE_CLI_FIRST_AWS_ACCESS_KEY_AGE} ]]; then |
| 160 | + awsecure_cli_log_info "Your key ${AWSECURE_CLI_FIRST_ACCESS_KEY_ID} is older than ${AWSECURE_CLI_AUTOROTATE_PERIOD// /} hours" |
| 161 | + awsecure_cli_log_info "Starting renewing your access key ${AWSECURE_CLI_FIRST_ACCESS_KEY_ID}" |
| 162 | + awsecure_cli_rotate_aws_access_key |
| 163 | + else |
| 164 | + awsecure_cli_log_info "No need to renew the access keys ${AWSECURE_CLI_FIRST_ACCESS_KEY_ID}, it's newer than ${AWSECURE_CLI_AUTOROTATE_PERIOD// /} hours" |
| 165 | + fi |
| 166 | + |
| 167 | + set +eo pipefail |
| 168 | + [[ ! -z "${AWSECURE_CLI_STATE_FILE_OPTION// /}" ]] && awsecure_cli_create_autorotate_state_file |
| 169 | + set -eo pipefail |
| 170 | +} |
| 171 | + |
| 172 | +function awsecure_cli_autorotate_check() { |
| 173 | + local -rl AWSECURE_CLI_AUTOROTATE_STATE_FILE=~/.awsecure-cli-state-file-${AWS_PROFILE// /} |
| 174 | + local -rl AWSECURE_CLI_AUTOROTATE_CHECK="${AWSECURE_CLI_AUTOROTATE_CHECK:-"daily"}" |
| 175 | + |
| 176 | + case "${AWSECURE_CLI_AUTOROTATE_CHECK// /}" in |
| 177 | + daily) |
| 178 | + local -r AWSECURE_CLI_STATE_FILE_OPTION="touch" |
| 179 | + set +eo pipefail |
| 180 | + local -r FIND_AWSECURE_CLI_AUTOROTATE_STATE_FILE_CMD="$(find ${AWSECURE_CLI_AUTOROTATE_STATE_FILE} -type f -ctime +24h 2> /dev/null | grep . > /dev/null 2>&1 ; echo $?)" |
| 181 | + set -eo pipefail |
| 182 | + if [[ ! -f ${AWSECURE_CLI_AUTOROTATE_STATE_FILE} ]]; then |
| 183 | + awsecure_cli_autorotate_aws_access_keys |
| 184 | + elif [[ ${FIND_AWSECURE_CLI_AUTOROTATE_STATE_FILE_CMD} -eq 0 ]]; then |
| 185 | + set -eo pipefail |
| 186 | + awsecure_cli_autorotate_aws_access_keys |
| 187 | + else |
| 188 | + awsecure_cli_log_info "AWS Access Keys autorotate was already checked in the last 24h" |
| 189 | + fi |
| 190 | + set -eo pipefail |
| 191 | + ;; |
| 192 | + on-reboot) |
| 193 | + local -r AWSECURE_CLI_STATE_FILE_OPTION="mktemp" |
| 194 | + [[ ! -f ${AWSECURE_CLI_AUTOROTATE_STATE_FILE} ]] && awsecure_cli_autorotate_aws_access_keys || awsecure_cli_log_info "AWS Access Keys autorotate was already checked since the last time you reboot the machine" |
| 195 | + ;; |
| 196 | + always) |
| 197 | + local -r AWSECURE_CLI_STATE_FILE_OPTION="" |
| 198 | + awsecure_cli_autorotate_aws_access_keys |
| 199 | + ;; |
| 200 | + *) |
| 201 | + awsecure_cli_log_info "The option ${AWSECURE_CLI_AUTOROTATE_CHECK} is unknown" |
| 202 | + ;; |
| 203 | + esac |
| 204 | +} |
| 205 | +awsecure_cli_autorotate_check |
0 commit comments