AWS EC2子进程随机报Unable to locate credentials问题求助
我已找到临时解决方法,详见我的回答。
但仍有两点疑问:
- 下述脚本在哪个环节被限流——调用IMDS时?还是IMDS调用STS时?
- 为何将凭证从父进程传递给子进程无效?似乎限流并非发生在凭证请求阶段,而是后续环节,比如「验证通过环境变量传递的凭证」等。
回答任意一个问题即可获得赏金,若能提供文档/源码参考更佳。
请勿建议改用Python或其他语言重写,此不在本问题讨论范围内
我有一台配备96 vCPU的AWS EC2主机,执行以下脚本:该脚本会异步启动子进程(数量上限由脚本参数指定),每个子进程调用AWS CLI后退出。
#!/bin/bash function f() { p=$1 echo "$(date) entering f($p)" aws sts get-caller-identity echo "$(date) leaving f($p)" } a="" for i in {1..400}; do a="$a $i" done jobs_limit=$1 while read line; do jobs=$(jobs -r | wc -l) while [ $jobs -ge $jobs_limit ]; do sleep 0.1 jobs=$(jobs -r | wc -l) done echo "$(f $line)" & done < <(echo "$a") wait
**问题:**当子进程数量超过40时,部分进程会随机出现Unable to locate credentials. You can configure credentials by running "aws configure".错误。
以下是脚本在不同数量限制下的执行输出:
sh-4.2$ /tmp/b.sh 40 2>&1 | egrep 'Unable to locate credentials' | wc -l 0 sh-4.2$ /tmp/b.sh 40 2>&1 | egrep 'Unable to locate credentials' | wc -l 0 sh-4.2$ /tmp/b.sh 44 2>&1 | egrep 'Unable to locate credentials' | wc -l 22 sh-4.2$ /tmp/b.sh 44 2>&1 | egrep 'Unable to locate credentials' | wc -l 7 sh-4.2$ /tmp/b.sh 48 2>&1 | egrep 'Unable to locate credentials' | wc -l 18 sh-4.2$ /tmp/b.sh 48 2>&1 | egrep 'Unable to locate credentials' | wc -l 14
如上述结果所示,当限制为40时无错误,超过40则会出现随机数量的错误。
有人能解释这是怎么回事吗?
我曾猜测是调用/metadata端点获取凭证时遇到了速率限制,因此修改脚本在父进程中获取凭证并传递给子进程,但问题依然存在:
function f() { p=$1 cc=$2 echo "$(date) entering f($p)" k=$(echo $cc | jq .AccessKeyId -r) s=$(echo $cc | jq .SecretAccessKey -r) t=$(echo $cc | jq .Token -r) AWS_ACCESS_KEY_ID=$k AWS_SECRET_ACCESS_KEY=$s AWS_SESSION_TOKEN=$t aws sts get-caller-identity echo "$(date) leaving f($p)" } ... creds=$(curl http://169.254.169.254/latest/meta-data/iam/security-credentials/EMRJobFlowRole) ... echo "$(f $line $creds)" & ...
问题解答
1. 限流发生在IMDS调用STS的环节
IMDS本身的请求速率限制(比如IMDSv2令牌获取默认是每秒1000次/实例)远高于当前并发量,不会触发。真正的瓶颈是STS服务:sts:GetCallerIdentity接口默认的账户级速率限制是每秒100次,当子进程并发数超过40后,大量并行请求会快速触达这个阈值,导致STS返回限流错误。此时IMDS无法从STS获取到有效临时凭证,AWS CLI就会抛出Unable to locate credentials的错误。
2. 传递凭证后仍无效的原因
即使在父进程获取凭证并传递给子进程,AWS CLI在使用临时凭证时,依然会自动尝试刷新凭证(哪怕当前凭证未过期)。大量子进程同时触发凭证刷新请求,同样会触达STS的速率限制,导致部分进程刷新失败,进而抛出凭证不存在的错误。此外,bash传递大变量(如完整的JSON凭证)时,偶尔会出现变量截断或传递异常,但从测试结果来看,核心原因还是后续STS调用的限流。
如果要验证,可以给aws sts get-caller-identity添加--debug参数,日志中会明确显示STS请求被限流的报错信息。
内容的提问来源于stack exchange,提问作者Alexander Pavlov

