0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

RunCommandでのInvalidAccessKeyIdエラーは、IMDSを呼び出すと解決できる

Last updated at Posted at 2025-09-01

はじめに :cloud:

RunCommandでインスタンスからS3にファイルをアップロードするスクリプトを使用していたところ、あるインスタンスのみ以下のようなエラーが発生し、S3へのファイルアップロードができませんでした。

upload failed: <filePATH> to s3://<bucketPATH> An error occurred (InvalidAccessKeyId) when calling the PutObject operation:
The AWS Access Key Id you provided does not exist in our records.

正常にアップロードが完了するインスタンスもあり、スクリプト自体の問題ではありませんでした。

結論 :page_facing_up: :pen_fountain:

原因は認証の呼び出し場所

どうやら、RunCommand実行時の認証の呼び出し場所が違うようです。

:o: エラーが発生しないインスタンス
Run Command 実行時に、EC2にアタッチされた IAM ロールの認証情報(IMDS)を使用して AWS CLI を実行する。

:heavy_multiplication_x: エラーが発生するインスタンス
Run Command 実行時に、インスタンス上のユーザー(root)の ~/.aws/credentials に保存された認証情報を使用してAWS CLIを実行する。

スクリプトでは、--profileなどの指定はなく、プレーンにaws s3 cpを呼び出していました。

aws s3 cp hogehoge.txt s3://hogehoge/hogehoge.txt

~/.aws/credentialsの認証情報にはS3へのPUT権限は付与されていないので、権限がなく実行が失敗していたようです。

OSに起因するものかと思っていたのですが、CentOSと一部のAmazon Linux2でエラーが発生していました。
どこかの設定が原因だとは思うのですが詳しい理由はわからず…
下記の解決策でどちらのOSも解決できました。

解決策 :sunrise_over_mountains:

エラーが発生するインスタンスにも 「認証はインスタンスのIAMロールを呼び出して使ってね!」 と明示してあげれば解決できました。

IAMロールの認証を呼び出す流れ

  1. curlでインスタンスに紐づいたIAMロールを取得
  2. IAMロールに紐づいた認証情報を取得(JSON形式)
  3. JSONから必要情報を抜き出して各変数に格納する
    :fast_forward: jqが便利だが使わなくても可能

:bulb: jq使用

ROLE_NAME=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/)
CREDS=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/$ROLE_NAME)

export AWS_ACCESS_KEY_ID=$(echo "$CREDS" | jq -r .AccessKeyId)
export AWS_SECRET_ACCESS_KEY=$(echo "$CREDS" | jq -r .SecretAccessKey)
export AWS_SESSION_TOKEN=$(echo "$CREDS" | jq -r .Token)
1行ずつ分解したもの
  • メタデータサービスからインスタンスに付与されたIAMロール名を取得してROLE_NAMEに格納
    169.254.169.254 は EC2 インスタンス内からのみアクセス可能なIP
ROLE_NAME=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/)
  • ROLE_NAMEに紐づくJSON形式の認証情報を取得しCREDSに格納
CREDS=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/$ROLE_NAME)
  • jqを使ってCREDSからAccessKeyIdを抽出してAWS_ACCESS_KEY_IDに格納
export AWS_ACCESS_KEY_ID=$(echo "$CREDS" | jq -r .AccessKeyId)
  • jqを使ってCREDSからSecretAccessKeyを抽出してAWS_SECRET_ACCESS_KEYに格納
export AWS_SECRET_ACCESS_KEY=$(echo "$CREDS" | jq -r .SecretAccessKey)
  • jqを使ってCREDSからToken(セッショントークン)を抽出してAWS_SESSION_TOKENに格納
export AWS_SESSION_TOKEN=$(echo "$CREDS" | jq -r .Token)

AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN を環境変数として指定すると、その後しばらくはAWS CLIやSDKがこの認証情報を使って通信をしてくれるので、コマンド自体を書き直す必要はありません。

:bulb: jq不使用

JQはインスタンスへのインストールが必要です。
「インストールするのはちょっと…」という場合はgrepcutで成形できます。

jq不要
ROLE_NAME=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/)
CREDS=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/$ROLE_NAME)
export AWS_ACCESS_KEY_ID=$(echo "$CREDS" | grep AccessKeyId | cut -d'"' -f4)
export AWS_SECRET_ACCESS_KEY=$(echo "$CREDS" | grep SecretAccessKey | cut -d'"' -f4)
export AWS_SESSION_TOKEN=$(echo "$CREDS" | grep Token | cut -d'"' -f4)
1行ずつ分解したもの
  • メタデータサービスからインスタンスに付与されたIAMロール名を取得してROLE_NAMEに格納
    169.254.169.254 は EC2 インスタンス内からのみアクセス可能なIP
ROLE_NAME=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/)
  • ROLE_NAMEに紐づくJSON形式の認証情報を取得しCREDSに格納
CREDS=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/$ROLE_NAME)
  • CREDSからAccessKeyIdを抽出してAWS_ACCESS_KEY_IDに格納
export AWS_ACCESS_KEY_ID=$(echo "$CREDS" | grep AccessKeyId | cut -d'"' -f4)
  • CREDSからSecretAccessKeyを抽出してAWS_SECRET_ACCESS_KEYに格納
export AWS_SECRET_ACCESS_KEY=$(echo "$CREDS" | grep SecretAccessKey | cut -d'"' -f4)
  • CREDSからToken(セッショントークン)を抽出してAWS_SESSION_TOKENに格納
export AWS_SESSION_TOKEN=$(echo "$CREDS" | grep Token | cut -d'"' -f4)

最終的なスクリプトはこんな感じ

:ng: エラーが発生したスクリプト

schemaVersion: '2.2'
description: "cred test document"
mainSteps:
  - action: aws:runShellScript
    name: testdocuments
    inputs:
      runCommand:
        - |
          # Upload to S3
          aws s3 cp hogehoge.txt s3://hogehoge/hogehoge.txt
          aws s3 cp mochimochi.txt s3://hogehoge/mochimochi.txt

:white_check_mark: エラーが解消されたスクリプト

schemaVersion: '2.2'
description: "cred test document"
mainSteps:
  - action: aws:runShellScript
    name: testdocuments
    inputs:
      runCommand:
        - |
          # IAM role credentials (no jq)
          ROLE_NAME=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/)
          CREDS=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/$ROLE_NAME)
          export AWS_ACCESS_KEY_ID=$(echo "$CREDS" | grep AccessKeyId | cut -d'"' -f4)
          export AWS_SECRET_ACCESS_KEY=$(echo "$CREDS" | grep SecretAccessKey | cut -d'"' -f4)
          export AWS_SESSION_TOKEN=$(echo "$CREDS" | grep Token | cut -d'"' -f4)
          
          # Upload to S3
          aws s3 cp hogehoge.txt s3://hogehoge/hogehoge.txt
          aws s3 cp mochimochi.txt s3://hogehoge/mochimochi.txt

権限が必要な実行部分の前に、インスタンスメタデータ(IMDS)を呼び出して格納しておくことで、認証でエラーが出ることがなくなりました :ok_woman:

以下、解決への時系列 :clock9:

なにが原因だかわからず遠回りしたので、どうやってトラブルシューティングをしたかの備忘録です。

1. 最初に確認したこと

エラーが発生するインスタンスで、以下のことを確認しました。

  1. アップロードができないインスタンスも、正常にアップロードできるインスタンスと同じポリシーを付与している
  2. SSM Agentのバージョンは3.xx以上であり、フリートマネージャー上は通信が確認できる
  3. SessionManagerで接続し、aws configure listを確認しても、iam-roleのaccess_keyとsecret_keyを使用している

最初に気になったのは3つ目です。

SessionMangerでaws configure listした結果
sh-4.2$ aws configure list
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                <not set>             None    None
access_key     ****************LWOK         iam-role
secret_key     ****************n1C3         iam-role
    region           ap-northeast-1             imds

たしかにIMDSの認証を使っているし、IAM-ROLEのアクセスキーとシークレットアクセスキーです。

同じように、RunCommand実行時にもIAMロールの認証情報が使用されているなら、The AWS Access Key Id you provided does not exist in our records. は起きないはず。

2. RunCommandで使用されている認証情報を特定する

SessionManagerで接続した場合とRunCommandで実行した場合の認証が違いそうだったので、実際にRunCommand実行時に呼び出される認証情報を確認しました。

テスト用のRunCommandドキュメント

以下のRunCommandドキュメントを新規で作成し、エラーが発生しないインスタンスと、エラーが発生するインスタンスに走らせました。

認証確認テスト用ドキュメントYAML
schemaVersion: '2.2'
description: Run `aws configure list` to check AWS CLI configuration
mainSteps:
  - action: aws:runShellScript
    name: RunAwsConfigureList
    inputs:
      runCommand:
        - aws configure list

出力結果 : :o: エラーが発生しないインスタンス

      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                <not set>             None    None
access_key     ****************WUWI         iam-role    
secret_key     ****************OWU1         iam-role    
    region           ap-northeast-1             imds    

出力結果 : :heavy_multiplication_x: エラーが発生するインスタンス

      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                <not set>             None    None
access_key     ****************U3QW shared-credentials-file    
secret_key     ****************Ifje shared-credentials-file    
    region           ap-northeast-1      config-file    ~/.aws/config

SessionManagerで接続して確認したときと違って、shared-credentials-fileを使っている!

3. 対処法を生成AIと相談

ここまでで、「SessionManagerで接続するときはIAMロールの認証情報を使うのに、RunCommandではインスタンス上のユーザーの認証情報を使ってしまう」という事情があることがわかりました。

生成AIには、わかっている状況はこまかに伝えたうえで「あなたならなにが原因だと思いますか?」と相談しました :robot:
IMDSを呼び出す解決策を提案してくれましたが、なにが原因だったのかまではわからず…。きちんと調べて原因を究明できるようになりたいです。

おわりに

認証コンテキストってなに?

今回のように、同じスクリプトでも実行方法によって使われる認証情報が変わることがままあるようです。
この「どの認証情報が、どの実行環境で、どう使われるか」という背景を指すのが、認証コンテキスト というらしいです。
AWSは認証関係が難しいなと感じることが多いので、このあたりは今後も壁にぶつかりそうな気がします。

感想

エラー文章 The AWS Access Key Id you provided does not exist in our records. で調べても、RunCommandに関するものは見つからずに困っていましたが、解決できてよかった。
最終的にはAIに頼ってしまったけれど、どこに原因があるかの切り分けは楽しくできました。(解決できたいまだから思うことではある。)

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?