在 Amazon EC2 上运行 Java 应用程序时,如何解决“The security token included in the request is expired”错误?

上次更新时间: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)

我如何解决此问题?

简短描述

必须使用 AWS 颁发的凭证对发送到 Amazon Web Services (AWS) 的所有应用程序 API 请求进行加密签名。

如果您的应用程序在创建 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 使用此类来通过 AWS 凭证签署 API 请求,使用的是来自 Amazon EC2 实例元数据临时安全凭证

重要说明:如果您的应用程序使用 AWS 开发工具包 ProfileCredentialsProvider 类提供临时 AWS 凭证,则由您负​责检查凭证并在过期前进行刷新。不检查或不刷新凭证会增加 ExpiredToken 错误引发应用程序故障的可能性。

解决方法

使用 Amazon Time Sync Service 或 NTP 源

在 Amazon EC2 实例上配置 Amazon Time Sync Service 或其他网络时间协议 (NTP) 源。这可以确保您的 Linux 实例具有一致且准确的时间参考。有关更多信息,请参阅设置 Linux 实例的时间设置 Windows 实例的时间

使用自定义临时 AWS 凭证

请在凭证过期前 5 分钟刷新临时凭证。

使用分配给实例的 IAM 角色

实例配置文件附加到您的实例。有关更多信息,请参阅使用 IAM 角色向在 Amazon EC2 实例上运行的应用程序授予权限。验证未在您的代码或实例中指定其他凭证。实例配置文件凭证是默认凭证提供程序链搜索凭证的最后位置。如果您将凭证放置在搜索链中靠前的任何位置,则这些凭证将阻止使用 IAM。有关更多信息,请参阅使用 AWS 凭证

要查看附加到实例的 IAM 角色的 AWS 凭证,请在 Linux shell 或 Windows PowerShell(v3.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

使用上述命令检查实例的最新临时凭证。这些凭证在分配的临时凭证过期前约 5 分钟自动轮换或刷新。

相关信息

使用 AWS 凭证(适用于 Java 的 AWS 开发工具包)

使用凭证(适用于 Java 的 AWS 开发工具包 2.0)

适用于 Amazon EC2 的 IAM 角色

为 Amazon EC2 配置 IAM 角色(高级)


这篇文章对您有帮助吗?


您是否需要账单或技术支持?