`aws login` sometimes writes a login cache that can't be read back (AWS_ERROR_CAL_UNSUPPORTED_KEY_FORMAT)

未关闭
#10,879 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 2 天内回复

还没有人认领这个 Issue。

评估

难度
4/5
预计耗时
3-5 天
新手友好度
44/100
Issue 类型
缺陷
描述清晰度
基本清楚
活跃度
活跃
技术栈
aws, python

调研方向

Start with awscli/botocore/credentials.py at _load_private_key and the key generation and export calls in awscli/customizations/login/utils.py. Reproduce the failure using the supplied loop on Linux with the pinned awscrt version, then inspect the linked aws-c-cal issue for the underlying fix. Done means cached keys load successfully and malformed cached keys produce the expected LoginTokenLoadError instead of a traceback.

由索引模型根据 Issue 内容生成。

描述

bug needs-triage
Describe the bug

About 1 in 256 aws login runs succeeds but leaves a cached token that every later command fails to load.

The login generates a P-256 DPoP key and stores it in the login cache as a SEC1 PEM. When the key's private scalar happens to start with a zero byte, awscrt on Linux exports it with a 31-byte privateKey instead of 32, and awscrt's own importer refuses a scalar that isn't exactly 32 bytes. The login itself works because it uses the key in memory, but everything after it reads the key from the cache and fails.

The root cause is in aws-c-cal, and I filed it there with a C repro and a patch: https://github.com/awslabs/aws-c-cal/issues/262. Filing here as well because this is where it shows up for users, and because the CLI turns it into a traceback.

Regression Issue
  • Select this option if this issue appears to be a regression.
Expected Behavior

A key written by aws login can be read back by the next command. If the cached key can't be loaded for any reason, I'd expect the "Unable to load private key from cached token" error instead of a traceback.

Current Behavior

After one login, every aws command using that profile failed like this until I ran aws login again:

File "awscli/botocore/credentials.py", line 2547, in refresh_credentials
File "awscli/botocore/credentials.py", line 2656, in _load_private_key
File "awscrt/crypto.py", line 279, in new_key_from_der_data
RuntimeError: 7178 (AWS_ERROR_CAL_UNSUPPORTED_KEY_FORMAT): Key format is not supported.

The dpopKey in the cache file decoded to this (values left out):

SEQUENCE len=118
  INTEGER len=1 value=1
  OCTET STRING len=31        <- privateKey, should be 32
  [0] OID prime256v1
  [1] BIT STRING len=66
Reproduction Steps

It takes a few hundred logins to hit by hand, so this does the same three calls as the CLI in a loop: generate the key (awscli/customizations/login/utils.py:70), export it as SEC1 (utils.py:202), and load it back (awscli/botocore/credentials.py:2656). Run it on Linux with the awscrt that the CLI pins (pip install awscrt==0.38.0 for 2.39.3):

from awscrt.crypto import EC, ECExportFormat, ECType

for i in range(1, 5001):
    der = EC.new_generate(ECType.P_256).export_key(ECExportFormat.SEC1)
    try:
        EC.new_key_from_der_data(der)
    except Exception as e:
        # der[6] is the length of the privateKey OCTET STRING
        print(f"key {i}: privateKey is {der[6]} bytes: {type(e).__name__}: {e}")
        break
else:
    print("no failure in 5000 keys")

Three runs:

key 99: privateKey is 31 bytes: RuntimeError: 7178 (AWS_ERROR_CAL_UNSUPPORTED_KEY_FORMAT): Key format is not supported.
key 142: privateKey is 31 bytes: RuntimeError: 7178 (AWS_ERROR_CAL_UNSUPPORTED_KEY_FORMAT): Key format is not supported.
key 737: privateKey is 31 bytes: RuntimeError: 7178 (AWS_ERROR_CAL_UNSUPPORTED_KEY_FORMAT): Key format is not supported.

On macOS the same loop doesn't fail (20,000 keys), because awscrt uses a different crypto backend there that always stores 32 bytes.

Possible Solution

The real fix is in aws-c-cal: pad the scalar on export, and accept a short one on import so caches already on disk become readable again. Details are in the issue linked above.

Two things I noticed on the CLI side (I haven't tried changing either):

Additional Information/Context

Workaround: run aws login again. The next key almost certainly has a non-zero first byte.

2.40.0 pins awscrt 0.38.1, which bundles the same aws-c-cal commit as 0.38.0, so I expect it to behave the same, but I haven't run 2.40.0.

CLI version used

aws-cli/2.39.3 (awscrt 0.38.0, aws-c-cal v1.0.0)

Environment details (OS name and version, etc.)

The failed login was on Linux. The repro above ran on Debian 13 (arm64), Python 3.13.5, awscrt 0.38.0 from PyPI.

Generated by AI tools, and reviewed by Danny Lin.

主要语言
Python
星标
17.4k
派生
4.8k
平均合并
4 天 3 小时
30 天内合并 PR
64

环境准备

  • 没有 Dockerfile 或 Docker Compose 文件
  • 没有 Pull Request 模板
  • 阅读贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

aws/aws-cli 的其他 Issue

查看 aws/aws-cli 的全部 Issue

相似的 Issue

更多 Python Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。