如何解決在 Amazon EC2 上執行 Java 應用程式時發生的「請求中包含的安全字符已過期」錯誤?

上次更新日期︰2021 年 3 月 4 日

我在 Amazon Elastic Compute Cloud (Amazon EC2) 執行個體上使用適用於 Java 的 AWS 開發套件的 Java 應用程式收到類似於以下內容的異常:

com.amazonaws.AmazonServiceException: The security token included in the request is expired (Service: AmazonSQS; Status Code: 403; Error Code: ExpiredToken; Request ID: 12a345b6-78cd-901e-fg23-45hi67890jkl)

如何解決此錯誤?

簡短描述

對 Amazon Web Services (AWS) 的所有應用程式 API 請求,必須使用 AWS 發出的憑證以加密方式簽署。

如果您的應用程式在建立 AWS 用戶端時使用臨時憑證,則憑證會在建立期間指定的時間間隔到期。您必須在憑證到期之前重新整理。

到期的另一個原因是使用不正確的時間。一致且準確的時間參考對於許多伺服器任務和流程至關重要。如果您的執行個體的日期和時間設定不正確,AWS 憑證將遭到拒絕。

如果您的應用程式在 Amazon EC2 執行個體上執行,則最佳實務是使用分配給該執行個體的 AWS Identity and Access Management (IAM) 角色。使用 IAM 角色允許使用預設建構函數。預設建構函數用戶端會以下列順序,使用預設憑證供應商鏈結來搜尋憑證:

  1. 在下列系統環境變數中︰AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY
  2. 在 Java 系統屬性中:aws.accessKeyIdaws.secretKey
  3. 在預設憑證檔案中 (該檔案的位置因平台而異)。
  4. 在與 EC2 執行個體的 IAM 角色關聯的執行個體中繼資料所包含的執行個體描述檔憑證中。將 執行個體描述檔連接至您的執行個體,會將執行個體描述檔憑證新增至預設憑證供應商鏈結。如需詳細資訊,請參閱使用 IAM 角色將許可授予在 Amazon EC2 執行個體上執行的應用程式

如果執行個體描述檔憑證可供使用,則預設用戶端建構函數會建立 AWS 開發套件 InstanceProfileCredentialsProvider 類別的執行個體。AWS 使用該類別,以透過使用 Amazon EC2 執行個體中繼資料臨時安全憑證的 AWS 憑證來簽署 API 請求。

重要事項:如果您的應用程式使用 AWS 開發套件 ProfileCredentialsProvider 類別來提供臨時的 AWS 登入資料,則您必須負責在到期前檢查並重新整理憑證。不檢查或重新整理您的憑據會增加由 ExpiredToken 錯誤引起的應用程式故障的可能性。

解決方案

使用 Amazon Time Sync Service 或 NTP 來源

在您的 Amazon EC2 執行個體上設定 Amazon Time Sync Service 或其他網路時間協定 (NTP) 來源。這樣一來,可確保您的 Linux 執行個體具有一致且準確的時間參考。如需詳細資訊,請參閱設定 Linux 執行個體的時間,或者設定 Windows 執行個體理的時間

使用自訂臨時 AWS 憑證

在過期前五分鐘重新整理臨時憑證。

使用指派給執行個體的 IAM 角色

執行個體描述檔連接至您的執行個體。如需詳細資訊,請參閱使用 IAM 角色將許可授予在 Amazon EC2 執行個體上執行的應用程式。.驗證您的程式碼或執行個體中未指定其他憑證。執行個體描述檔憑證是預設憑證提供程序鏈搜尋憑證據的最後位置。如果您的憑證位於搜尋鏈中較早的任何位置,則這些憑證會阻止使用 IAM。如需詳細資訊,請參閱使用 AWS 憑證

若要查看連接至執行個體的 IAM 角色的 AWS 憑證,請從 Linux Shell 或 Windows PowerShell (3.0 版或更新版本) 執行下列命令。請務必將 examplerole 取代為 IAM 角色的名稱。

Linux

使用 curl 命令以查看 AWS 憑證:

$ curl http://169.254.169.254/latest/meta-data/iam/security-credentials/examplerole

此命令會傳回類似於以下內容的輸出:

{
    "Code" : "Success",
    "LastUpdated" : "2016-04-26T16:39:16Z",
    "Type" : "AWS-HMAC",
    "AccessKeyId" : "AKIAIOSFODNN7EXAMPLE",
    "SecretAccessKey" : "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
    "Token" : "token",
    "Expiration" : "2016-04-27T22:39:16Z"
}

注意:如果執行前面的 curl 命令傳回 404 錯誤,請檢查以下內容:

1.    使用下列 命令來確認中繼資料 IP 地址的 HTTP 代理已停用

$ export NO_PROXY=169.254.169.254

2.    驗證執行個體沒有發出多個並發請求且並行執行了多個會話。多個並行請求和多個並行執行的工作階段可能會導致執行主體中繼資料服務 (IMDS) 進行限制。為了緩解這種情況,請使用快取和指數退避重試。與任何服務一樣,呼叫有時可能會失敗。發生這種情況時,預期用戶端會重試。如需詳細資訊,請參閱查詢調節

若要實作重試,請修改 AWS_METADATA_SERVICE_NUM_ATTEMPTS。您可以在 ~/.aws/config 檔案中,或在使用者 botocore 工作階段,使用環境變數選項。如需詳細資訊,請參閱 Boto3 DOCS 1.17.6 文件中的組態

範例:

AWS_METADATA_SERVICE_TIMEOUT = 10
AWS_METADATA_SERVICE_NUM_ATTEMPTS = 5

3.    如果您在 docker 容器中執行 curl 測試,請調整 instance-metadata-options http-put-response-hop-limit

$ aws ec2 modify-instance-metadata-options --instance-id $(curl 169.254.169.254/latest/meta-data/instance-id) --http-put-response-hop-limit 2 --http-endpoint enabled
PS C:\> Invoke-RestMethod http://169.254.169.254/latest/meta-data/iam/security-credentials/examplerole

此命令會傳回類似於以下內容的輸出:

Code            : Success
LastUpdated     : 2016-07-18T18:09:47Z
Type            : AWS-HMAC
AccessKeyId     : AKIAIOSFODNN7EXAMPLE
SecretAccessKey : wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Token           : token
Expiration      : 2016-04-27T22:39:16Z

使用這些命令檢查執行個體的最新臨時憑證。這些憑證會在分配的臨時憑證到期前大約五分鐘自動輪換或重新整理。

相關資訊

使用 AWS 憑證 (適用於 Java 的 AWS 開發套件)

使用憑證 (適用於 Java 2.0 的 AWS 開發套件)

適用於 Amazon EC2 的 IAM 角色

設定適用於 Amazon EC2 的 IAM 角色 (進階)


此文章是否有幫助?


您是否需要帳單或技術支援?