AWS CLI に aws login が入って、マネジメントコンソールにログインするのと同じ認証情報で
一時クレデンシャルを取れるように去年末くらいからなりました。
とある案件でこのログイン方式を利用し始めたら、
タイトルどおりの事象が起き、めんどくさいなとなっていました。
症状
ログイン直後はちゃんと動くのですが、
10分ほど経つと、そこから先は何を打っても以下のエラーで落ちてしまいます。
An error occurred (ValidationException) when calling the CreateOAuth2Token operation:
The provided authorization grant is invalid, expired, revoked, or malformed
aws login をやり直せば復活しますが、また10分で同じエラーが発生してしまいます。
AWS CDKでのデプロイ作業など少し長い作業の途中でこれが来るので、
そのたびに再ログインを挟むことになり、なんでだろうとなりました。
とりあえずドキュメント調査
さすがに10分でセッション切れてたらみんな使いにくすぎるだろと思い、
公式ドキュメントを調べてみるとこう書いてありました。
The short-term credentials expire in 15 minutes, but the CLI and SDKs will automatically refresh them as needed up to 12 hours.
15分で失効するけれど12時間までは自動更新されるとのこと。
15分とあるけど、その前の10分くらいで使えなくなるんだけど!?と思い、
もう少し深く調べてみました。
気になったところ
通常、AWS利用時には東京リージョンを利用していますが、
リージョンを間違えないために、毎回、AWS_REGION=ap-northeast-1 と入力するようにしていました。
そのため、別に設定しなくていいでしょと思い、
aws login時のリージョン指定をしないままにしていました。
そこから調査を進めていくと、このリージョン違いが認証が10分で切れてしまっていた原因でした。
そのため、直し方はシンプルで、 ~/.aws/config のプロファイルのリージョンを実作業のリージョンへ揃えて、ログインし直すことで解決できました。
[profile my-profile]
login_session = arn:aws:iam::123456789012:user/alice
region = ap-northeast-1
なぜリージョンが違うと10分で切れてしまうのか(With AI調査)
signin はリージョナルサービスで、
エンドポイントは https://signin.{Region}.{dnsSuffix} の形をしており、リージョンごとに別物です。
そのうえで、AWS CLI の中ではログインとリフレッシュでリージョンの決まり方が違います。
ログイン側は、ログイン時の指定されたリージョンを明示して signin のクライアントを作ります。
aws login はリージョンが決まらないとプロンプトで聞いてきて、その既定値は us-east-1 です。
一方リフレッシュ側は、セッションの実効リージョンそのままを渡してクライアントを作ります。
セッションの実効リージョンは --region や AWS_REGION で上書きされます。
結果として、region = us-east-1 のプロファイルに対して AWS_REGION=ap-northeast-1 で作業していると、
ログインは us-east-1 に対して行われ、リフレッシュだけが ap-northeast-1 へ飛びます。
東京リージョンでは身に覚えのないリフレッシュトークンなので、ValidationException を返してくるということでした。
なぜ「10分」なのか(With AI調査)
ドキュメントでは15分とあったので、10分の時点で、手元の accessToken はまだ5分ぶん有効なはずです。
リフレッシュに失敗しても、残っているトークンで続行してくれそうです。
botocoreの実装から以下のような処理フローになっています。
実際に signin へリフレッシュを投げるのは、残り TTL が5分を切ってからです。
TTL が15分なので、ログインから10分経ってようやく1回目が飛びます。
「10分」はトークンの寿命ではなく、リフレッシュの初回発火時刻でした。
そして botocore には、失効の10分前から始まる mandatory 窓というものがあります。
この窓の中でリフレッシュに失敗すると、
例外がそのまま呼び出し元まで飛んでコマンドごと落ちます。
初回発火の時点、つまり失効の5分前はすでに mandatory 窓の内側です。
1回目のリフレッシュがそのまま致命傷になる位置でしか試していない、ということでした。
まだ5分ぶん有効なトークンが手元にあるのに、
それを使わないまま落ちていた、というのが答えでした。
おわりに
以前は発行済のアクセスキー/シークレットアクセスキーだったので、デフォルトリージョン設定と利用リージョンがずれていてもなんの問題もなかったのですが、
aws login では裏で定期的に再認証が走る形式に変わったので、リージョンの設定をちゃんと確認する必要があるねという話でした。
aws login 自体は、アクセスキーを発行せずに済むという一点でメリットが大きいので、リージョンを揃えて利用しましょう!