How to use AWS cli to get access keys in an MFA context?
I'm developing a simple app that will run on an existing EC2 instance. The AWS account is secured with MFA. We use a main account and assume a role into our target account for personal access.
The app only deals with the MFA when I'm developing locally. I would like to avoid creating a user in the target account just for development, and wrap my local development in --profile like functionality.
My thought was to use aws sts
to generate the access key and secrete key, but performing an assume role using the same setup I have in my credentials file gives me an Access Denied error.
My credentials file follows this pattern:
[main-profile]
aws_access_key_id={access-key}
aws_secret_access_key={secret-key}
[target-profile]
mfa_serial=arn:blah
role_arn=arn:blah2
source_profile=main-profile
I tried to use aws sts --role-name arn:blah2 --role-session-name test --profile main-profile
. Похоже, мне также нужно было бы сослаться на устройство MFA, но я не вижу в этом возможности.
Могу ли я сделать то, что хочу?
Хорошо, поэтому я смог успешно получить и кэшировать учетные данные, но возвращенный ключ доступа кажется недействительным для установки в переменную среды. Мысли?
#!/bin/bash
#set -x
###
# Note: This uses jq (sudo apt-get install jq -y)
targetProfile="target-profile"
sessionFile="/tmp/session-$targetProfile.txt"
sessionFile=$(echo $sessionFile)
echo "Looking for $sessionFile"
if [[ -f "$sessionFile" ]]; then
echo "Found $sessionFile"
sessionInfo="$(cat $sessionFile)"
else
echo "Building $sessionFile"
roleArn="$(aws configure get role_arn --profile $targetProfile)"
mfaArn="$(aws configure get mfa_serial --profile $targetProfile)"
mainProfile="$(aws configure get source_profile --profile $targetProfile)"
echo MFA Token:
read mfaToken
echo "aws sts get-session-token --serial-number $mfaArn --token-code $mfaToken --profile $mainProfile"
sessionInfo="$(aws sts get-session-token --serial-number $mfaArn --token-code $mfaToken --profile $mainProfile)"
fi
echo "Current session info: $sessionInfo"
expirationDateValue="$(echo $sessionInfo | jq '.Credentials.Expiration' | tr -d '"')"
echo "Expiration value: $expirationDateValue"
expirationDate=$(date -d $expirationDateValue +%s)
echo "Expiration date: $expirationDate"
currentDate=$(date +%s)
echo "Current date: $currentDate"
if [[ $currentDate -ge $expirationDate ]]; then
rm $sessionFile
/bin/bash $0
exit
fi
echo "$sessionInfo" > $sessionFile
export AWS_ACCESS_KEY_ID=$(echo $sessionInfo | jq '.Credentials.AccessKeyId')
export AWS_SECRET_ACCESS_KEY=$(echo $sessionInfo | jq '.Credentials.SecretAccessKey')
export AWS_SESSION_TOKEN=$(echo $sessionInfo | jq '.Credentials.SessionToken')
#dotnet run
aws s3 ls
Когда я запускаю это, я получаю следующее сообщение об ошибке:
An error occurred (InvalidAccessKeyId) when calling the ListBuckets operation: The AWS Access Key Id you provided does not exist in our records.
Оказывается, я не мог повторно использовать кавычки в значениях, возвращаемых из сессионного JSON. Мне пришлось удалить кавычки и добавить новые, что действительно имеет смысл. Смотрите мой ответ ниже для моего решения.
2 ответа
Понял! Наконец-то я нашел правильное заклинание Bash: o)
#!/bin/bash
#set -x
###
# Note: This uses jq (sudo apt-get install jq -y)
targetProfile="target-profile"
sessionFile="/tmp/session-$targetProfile.txt"
sessionFile=$(echo $sessionFile)
echo "Looking for $sessionFile"
if [[ -f "$sessionFile" ]]; then
echo "Found $sessionFile"
sessionInfo="$(cat $sessionFile)"
else
echo "Building $sessionFile"
roleArn="$(aws configure get role_arn --profile $targetProfile)"
mfaArn="$(aws configure get mfa_serial --profile $targetProfile)"
mainProfile="$(aws configure get source_profile --profile $targetProfile)"
echo MFA Token:
read mfaToken
sessionInfo="$(aws sts get-session-token --serial-number $mfaArn --token-code $mfaToken --profile $mainProfile)"
fi
expirationDateValue="$(echo $sessionInfo | jq '.Credentials.Expiration' | tr -d '"')"
expirationDate=$(date -d $expirationDateValue +%s)
currentDate=$(date +%s)
if [[ $currentDate -ge $expirationDate ]]; then
echo "Session expired"
rm $sessionFile
/bin/bash $0
exit
fi
echo "$sessionInfo" > $sessionFile
export AWS_ACCESS_KEY_ID="$(echo $sessionInfo | jq '.Credentials.AccessKeyId' | tr -d '"')"
export AWS_SECRET_ACCESS_KEY="$(echo $sessionInfo | jq '.Credentials.SecretAccessKey' | tr -d '"')"
export AWS_SESSION_TOKEN="$(echo $sessionInfo | jq '.Credentials.SessionToken' | tr -d '"')"
#dotnet run
aws s3 ls
AWS CLI может использовать два разных файла для обработки config
а также credentials
.
- Файл конфигурации интерфейса командной строки AWS (
~/.aws/config
) - Файл общих учетных данных AWS (
~/.aws/credentials
)
По поводу файла общих учетных данных позвольте мне процитировать документацию:
В каждом разделе можно указать три приведенные выше переменные конфигурации:
aws_access_key_id
,aws_secret_access_key
,aws_session_token
. Это единственные поддерживаемые значения в файле общих учетных данных.
Ссылка: https://docs.aws.amazon.com/cli/latest/topic/config-vars.html
Таким образом, вы можете разместить свой основной профиль на credentials
файл, но вам нужно поместить ваш целевой профиль в config
файл.
См. Пример ниже:
# In ~/.aws/credentials:
[development]
aws_access_key_id=foo
aws_secret_access_key=bar
# In ~/.aws/config
[profile crossaccount]
role_arn=arn:aws:iam:...
source_profile=development
Также обратите внимание, что названия разделов отличаются от конфигурационного файла AWS CLI (~/.aws/config
). В файле конфигурации AWS CLI вы создаете новый профиль, создавая раздел[profile profile-name]
. В файле общих учетных данных профили не имеют префиксаprofile
.