EC2のProxy環境で aws ecr get-login-password や aws sts get-caller-identity がタイムアウトする場合、まず NO_PROXY に 169.254.169.254 が入っているか確認するとほぼ解決します。
見えているエラーはSTSですが、実際に詰まっているのはその手前のIMDS到達です。
前提条件
- 実行環境: EC2(インスタンスプロファイル/IAMロールを使用)
- AWS CLI: v2 系
- ネットワーク: 外向き通信はProxy経由、IMDSは
NO_PROXYで除外する構成
エラー内容
CIでECRログインを実行したら、次のエラーで止まりました。
Connect timeout on endpoint URL: "https://sts.ap-northeast-1.amazonaws.com/"
同じインスタンスでSSHして手動実行すると通るので、最初は「ネットワークが不安定?」と思ったんですが、犯人はProxy設定でした。
実ログはこんな形でした(実行コマンド直後のstderr)。
$ aws sts get-caller-identity Connect timeout on endpoint URL: "https://sts.ap-northeast-1.amazonaws.com/"
再現コマンド(失敗時):
aws sts get-caller-identity
失敗時の出力例:
Connect timeout on endpoint URL: "https://sts.ap-northeast-1.amazonaws.com/"
原因
EC2のIAMロール資格情報は、AWS CLIが内部的にIMDS(169.254.169.254)から取得します。
NO_PROXY 未設定だとこのIMDSアクセスまでProxyに流れて、link-localに到達できずタイムアウトします。
処理の流れはこうです。
aws sts get-caller-identity -> 認証情報が必要 -> IMDS (http://169.254.169.254/...) へアクセス -> NO_PROXYなし: Proxy経由になって失敗 -> 結果としてSTS呼び出し前に詰まり、STSタイムアウトに見える
要するに「STSが悪い」のではなく、「IMDSをProxy除外していない」のが原因です。
解決方法
最小構成はこれです。EC2ランナーなら 169.254.169.254 が最重要です。
export HTTP_PROXY=http://proxy.example.com:8080 export HTTPS_PROXY=http://proxy.example.com:8080 export NO_PROXY=169.254.169.254,localhost
ワークフローに固定する場合:
env: HTTP_PROXY: ${{ secrets.HTTP_PROXY }} HTTPS_PROXY: ${{ secrets.HTTPS_PROXY }} NO_PROXY: 169.254.169.254,localhost
確認コマンド:
aws sts get-caller-identity
成功時の出力例:
{ "UserId": "AROAXXXXXXXXXXXXX:botocore-session-1234567890", "Account": "123456789012", "Arn": "arn:aws:sts::123456789012:assumed-role/your-role/i-0abc123def456" }
IMDS疎通も合わせて確認しておくと安全です。IMDSv2必須環境でも判定できるように、トークン取得付きで確認します。
TOKEN=$(curl -sS --max-time 2 -X PUT "http://169.254.169.254/latest/api/token" \
-H "X-aws-ec2-metadata-token-ttl-seconds: 60") \
&& curl -sS --max-time 2 -H "X-aws-ec2-metadata-token: $TOKEN" \
http://169.254.169.254/latest/meta-data/iam/info > /dev/null \
&& echo "IMDS reachable" || echo "IMDS unreachable"
なぜ気づきにくいか
このトラブル、実運用だと見抜きにくいです。
- SSHログイン時は
.bashrcなどでProxy変数が読み込まれて動く - CIプロセスはシェルプロファイルを読まず、設定差分が出る
- エラー文面がSTSなので、IMDS起因に見えない
「手動では通るのにCIだけ失敗」が出た時点で、NO_PROXY を最初に疑うのが早いです。
CI/CDでの防御策
テンプレート化して、毎回同じ3点セットで入れるのが一番事故りません。
env: HTTP_PROXY: ${{ secrets.HTTP_PROXY }} HTTPS_PROXY: ${{ secrets.HTTPS_PROXY }} NO_PROXY: "169.254.169.254,169.254.170.2,localhost"
補足:
- ECSタスクロールまで使うなら
169.254.170.2も入れます - 可能なら
aws sts get-caller-identityを最初のヘルスチェックに入れます - Proxy URLに認証情報を含める場合は、平文の
varsではなくsecretsで管理します
まとめ
Connect timeout on endpoint URL: https://sts.ap-northeast-1.amazonaws.com がEC2 Proxy環境で出たら、まず NO_PROXY=169.254.169.254 を確認することをお勧めします。
STSタイムアウトに見えても、実際はIMDS到達の問題であることが多いです。
参考
- Using an HTTP proxy for the AWS CLI - EC2でIAMロール利用時は
NO_PROXY=169.254.169.254が必要 - Use the Instance Metadata Service to access instance metadata - IMDSv2の仕組みと
169.254.169.254へのアクセス方法 - Troubleshoot instance metadata issues on my EC2 instance - Proxy環境でIMDSを除外しない場合の典型症状
- Using an HTTP proxy for Amazon ECS Linux container instances -
169.254.169.254と169.254.170.2を除外する実運用例