IMDSv2 支持

我写信是为了咨询 Discourse 是否支持通过实例配置文件使用 IMDSv2。我们正在将我们的服务迁移到使用 IMDSv2,因为 IMDSv1 不是一个安全选项。

我们想了解 Discourse 目前是否支持通过实例配置文件使用 IMDSv2,如果不支持,近期是否有计划支持。此外,是否有任何变通方法或补丁可以让我们在 Discourse 中使用 IMDSv2?

确保满足我们的安全要求对我们来说很重要,我们相信通过 IMDSv2 使用临时凭证是其中的关键部分。

通过实例配置文件访问安全凭证的期望行为是:

  • 实例上的应用程序从实例元数据项 iam/security-credentials/ role-name 中检索角色提供的安全凭证。
  • 应用程序通过与角色关联的安全凭证获得我们为角色定义的动作和资源的权限。这些安全凭证是临时的,会自动轮换。我们在旧凭证过期前至少五分钟提供新凭证。

我们注意到 IMDSv1 和 IMDSv2 调用之间存在差异。

IMDSv1 调用:

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

而 IMDSv2 调用需要使用 元数据令牌,并且可以使用以下命令进行:

TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"` \\\\\\\\\\\\\\\\\
&& curl -H "X-aws-ec2-metadata-token: $TOKEN" -v http://169.254.169.254/latest/meta-data/iam/security-credentials/s3access

如果您能提供有关如何在 Discourse 中使用 IMDSv2 的信息,或者是否有任何变通方法或补丁可用,我们将不胜感激。

参考:

我不知道 Discourse 本身有任何使用 IMDS 的方法。您是否以某种方式在 AWS 上安装了 Discourse?您是否已经在以某种方式将 IMDSv1 与 Discourse 一起使用?

您的用例是什么?

我找到了一个相关的代码。

这是在测试规范中。

Discourse 使用的 AWS SDK 版本 (3.130.2) 高于支持 IMDSv2 的最低要求,并且从我查看我们 AWS 部署中的 MetadataNoToken 指标来看,我们没有任何对 IMDSv1 的调用。

据我所知,我们已经在所有地方使用了 IMDSv2。

3 个赞

我们在一年前开始在 AWS EC2 实例上使用 Discourse。本周,我们将实例更新为仅使用 IMDSv2,这导致我们的 AWS S3 上传出现错误消息“unable to sign request without credentials set”。我们也使用了“s3 use iam profile”设置。

Discourse 使用本地 IMDS 服务来获取凭证,以便执行其他与 AWS 相关的服务 API 调用。这是使用 Ruby aws-sdk-s3 完成的

我们也在禁用 IMDSv1 以确保安全后遇到了此备份问题。

我们可以通过 MetadataNoToken 指标看到 IMDSv1 的使用(在 3.3.0.beta1-dev 中),因此我们想知道哪个版本的 Discourse 切换到了处处使用 v2?

我们今天也遇到了这个问题,因为我们将我们的 AWS 实例更改为仅使用 IMDSv2:我们的用户无法再将图像上传到 S3。

这可能与我们正在使用的 s3 use iam profile 选项有关。

目前我们已将其切换为“Optional”,这意味着 IMDSv1 仍然启用,这在安全方面不是最佳选择,但这使得上传再次生效。

1 个赞

有人有让 Discourse 与 IMDSv2 协同工作的解决方案/变通方法吗?

我们正在进行更改,以允许/期望通过 .aws/config 文件进行更多配置,这可能会与之重叠并使其成为可能。

@supermathie 最奇怪的是我无法弄清楚,我亲自设置了两个 discourse 实例(开发/生产),它们的配置完全相同(使用 IAM 配置文件进行 S3 上传和备份),并且更新到了相同的版本(9436f5e3d4),并且当我禁用 IMDSv1 时……在开发环境中一切都按预期工作,而在生产环境中却不行,并且一直抛出类似“无法在未设置凭证的情况下签名请求”的错误……非常令人费解。

如果您有任何关于我可以进行的测试/检查的想法,请告诉我。

@ducks 确定了用于获取 IMDS 凭证的 SDK 中的超时设置非常激进(1 秒,无重试),因此有可能它正在命中该超时。

但这只是猜测。

如果您通过控制台登录到生产环境,能否进行交互式操作,例如:

discourse(prod)> c = Aws::S3::Client.new(region: ENV['DISCOURSE_S3_REGION'])
=> #<Aws::S3::Client>

discourse(prod)> c.list_objects_v2(bucket: ENV['DISCOURSE_S3_BUCKET']).contents.count
=> 1000
1 个赞

我弄明白了问题所在,只能怪自己,但问题非常微妙。
问题在于“HttpPutResponseHopLimit”设置为 1,这不允许从容器内部调用 IMDSv2

执行此命令后,我得到了这个答案:

> aws ec2 describe-instances --instance-ids i-00000000000000000 --query “Reservations[0].Instances[0].MetadataOptions”`
{
“State”: “applied”,
“HttpTokens”: “optional”,
“HttpPutResponseHopLimit”: 1,
“HttpEndpoint”: “enabled”,
“HttpProtocolIpv6”: “disabled”,
“InstanceMetadataTags”: “disabled”
}

调整设置后,正确的输出是

> aws ec2 describe-instances --instance-ids i-00000000000000000 --query “Reservations[0].Instances[0].MetadataOptions”`
{
“State”: “applied”,
“HttpTokens”: “required”,
“HttpPutResponseHopLimit”: 2,
“HttpEndpoint”: “enabled”,
“HttpProtocolIpv6”: “disabled”,
“InstanceMetadataTags”: “disabled”
}

……最终谜团解开了 :sweat_smile:

感谢大家的帮助

1 个赞

很高兴知道这一点!

希望这对其他人也适用。

但我很想知道为什么这对我们来说不是问题。我们将其设置为 1,但它仍然有效?

discourse(prod)⟩ ENV['AWS_EC2_METADATA_V1_DISABLED'] = 'true'
=> "true"
discourse(prod)⟩ c = Aws::S3::Client.new(region: ENV['DISCOURSE_S3_REGION'])
=> #<Aws::S3::Client:0x00007f9c8a4f2b80>
discourse(prod)⟩ c.config.credentials.disable_imds_v1
=> true
discourse(prod)⟩ c.list_objects_v2(bucket: ENV['DISCOURSE_S3_BUCKET']).contents.count
=> 1000

并且该实例根据相同的查询命令具有以下元数据:

{
    "State": "applied",
    "HttpTokens": "optional",
    "HttpPutResponseHopLimit": 1,
    "HttpEndpoint": "enabled",
    "HttpProtocolIpv6": "disabled",
    "InstanceMetadataTags": "disabled"
}

我们像其他人一样在 EC2 上的 Docker 容器中运行 Discourse,所以……有什么区别?

此主题已在 21 小时后自动关闭。不再允许回复。