Add aws app and config for mfa.

Signed-off-by: jmug <u.g.a.mariano@gmail.com>
This commit is contained in:
Mariano Uvalle 2025-07-14 18:16:56 -07:00
parent d72369c20b
commit c4b62ddeee
5 changed files with 169 additions and 3 deletions

View file

@ -0,0 +1,146 @@
{ pkgs }:
pkgs.writeShellApplication {
name = "aws-cli-mfa";
runtimeInputs = with pkgs; [
awscli2
yubikey-manager
yq-go
jq
];
text = ''
set -euo pipefail
CONFIG_DIR="$HOME/.config/aws-cli-mfa"
CONFIG_FILE="$CONFIG_DIR/config.yaml"
usage() {
echo "Usage: $0 [--unset] [--help]"
echo ""
echo "Options:"
echo " --unset Unset AWS environment variables"
echo " --help Show this help message"
echo ""
echo "This tool assumes temporary credentials with MFA using a YubiKey."
echo "Configuration file: $CONFIG_FILE"
}
unset_vars() {
if [[ -t 1 ]]; then
# Running directly - can't unset in parent shell, show instructions
echo "To unset AWS environment variables, run:"
echo " eval \$(aws-cli-mfa --unset)"
else
# Running from eval - output unset commands
echo "AWS environment variables unset." >&2
cat << EOF
unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN AWS_SECURITY_TOKEN
EOF
fi
}
# Parse command line arguments
if [[ $# -gt 0 ]]; then
case "$1" in
--unset)
unset_vars
exit 0
;;
--help)
usage
exit 1
;;
*)
echo "Unknown option: $1"
usage
exit 1
;;
esac
fi
# Check if config file exists
if [[ ! -f "$CONFIG_FILE" ]]; then
echo "Error: Configuration file not found: $CONFIG_FILE"
echo ""
echo "Please create a configuration file with the following format:"
echo ""
echo "mfa_serial: arn:aws:iam::123456789012:mfa/username"
echo "role_arn: arn:aws:iam::123456789012:role/RoleName"
echo "session_duration: 43200 # optional, defaults to 43200 seconds (12 hours)"
echo ""
exit 1
fi
# Read configuration
MFA_SERIAL=$(yq eval '.mfa_serial' "$CONFIG_FILE")
ROLE_ARN=$(yq eval '.role_arn' "$CONFIG_FILE")
SESSION_DURATION=$(yq eval '.session_duration // 43200' "$CONFIG_FILE")
if [[ "$MFA_SERIAL" == "null" || "$ROLE_ARN" == "null" ]]; then
echo "Error: mfa_serial and role_arn must be specified in $CONFIG_FILE"
exit 1
fi
echo "Getting TOTP code from YubiKey for device: $MFA_SERIAL" >&2
# Get TOTP code from YubiKey
if ! TOTP_CODE=$(ykman oath accounts code "$MFA_SERIAL" -s); then
echo "Error: Failed to get TOTP code from YubiKey for device '$MFA_SERIAL'"
echo "Available OATH accounts:"
ykman oath accounts list || echo "No OATH accounts found on YubiKey"
exit 1
fi
echo "Assuming role with MFA..." >&2
# Call AWS STS assume-role
if ! STS_RESPONSE=$(aws sts assume-role \
--role-arn "$ROLE_ARN" \
--role-session-name "aws-cli-mfa-$(date +%s)" \
--serial-number "$MFA_SERIAL" \
--token-code "$TOTP_CODE" \
--duration-seconds "$SESSION_DURATION" \
--output json); then
echo "Error: Failed to assume role. Check your AWS credentials and configuration."
exit 1
fi
# Extract credentials from response
AWS_ACCESS_KEY_ID=$(echo "$STS_RESPONSE" | jq -r '.Credentials.AccessKeyId')
AWS_SECRET_ACCESS_KEY=$(echo "$STS_RESPONSE" | jq -r '.Credentials.SecretAccessKey')
AWS_SESSION_TOKEN=$(echo "$STS_RESPONSE" | jq -r '.Credentials.SessionToken')
EXPIRATION=$(echo "$STS_RESPONSE" | jq -r '.Credentials.Expiration')
if [[ "$AWS_ACCESS_KEY_ID" == "null" || "$AWS_SECRET_ACCESS_KEY" == "null" || "$AWS_SESSION_TOKEN" == "null" ]]; then
echo "Error: Failed to extract credentials from AWS response"
exit 1
fi
# Check if running from eval (stdout is a pipe) or directly
if [[ -t 1 ]]; then
# Running directly - can't export to parent shell, show instructions
echo "Success! AWS temporary credentials retrieved."
echo "Credentials expire at: $EXPIRATION"
echo ""
echo "To use these credentials in your current shell, run:"
echo " eval \$(aws-cli-mfa)"
echo ""
echo "To unset the credentials later, run:"
echo " eval \$(aws-cli-mfa --unset)"
else
# Running from eval - only output export commands
echo "Success! AWS temporary credentials have been set." >&2
echo "Credentials expire at: $EXPIRATION" >&2
echo "" >&2
echo "To unset the credentials later, run:" >&2
echo " eval \$(aws-cli-mfa --unset)" >&2
# Output export commands for eval
cat << EOF
export AWS_ACCESS_KEY_ID='$AWS_ACCESS_KEY_ID'
export AWS_SECRET_ACCESS_KEY='$AWS_SECRET_ACCESS_KEY'
export AWS_SESSION_TOKEN='$AWS_SESSION_TOKEN'
export AWS_SECURITY_TOKEN='$AWS_SESSION_TOKEN'
EOF
fi
'';
}