146 lines
No EOL
4.8 KiB
Nix
146 lines
No EOL
4.8 KiB
Nix
{ 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
|
|
'';
|
|
} |