Python:load_pem_private_key 无法识别生产中的我的私钥

问题描述 投票:0回答:1

在本地,我有一个 .env 文件,其中包含单行 RSA 密钥,如下所示:

PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\ncontentsofkey\n-----END RSA PRIVATE KEY-----\n" 

每 64 个字符包含一个

\n
以转义新行。 此密钥格式在本地工作并允许我的 Python 应用程序按预期运行,私钥能够加载。

问题始于生产。我将私钥一行格式复制并粘贴到 GitHub Secret 中,但是完全相同的密钥和格式会引发此错误:

ValueError: ('无法反序列化密钥数据。数据可能格式不正确,可能使用不支持的算法加密,或者可能是不支持的密钥类型(例如具有显式参数的 EC 曲线)。', [ ])

在处理上述异常的过程中,又发生了一个异常:

ValueError: ('无法反序列化密钥数据。数据可能格式不正确,可能使用不支持的算法加密,或者可能是不支持的密钥类型(例如具有显式参数的 EC 曲线)。', [ ])

正如reason_text中所述,似乎不支持密钥格式并且没有状态行?这让我非常困惑,因为这是在本地工作的,但在生产中却不起作用。在生产中,当我测试本地时,我使用完全相同的requirements.txt和python版本运行venv。

我在 load_pem_private_key() 函数之前添加了一条打印语句来查看密钥的格式,它的打印格式与我的 .env 文件完全相同......在本地工作得很好:

"-----BEGIN RSA PRIVATE KEY-----\ncontentsofkey\n-----END RSA PRIVATE KEY-----\n" 

我没有看到本地打印语句和生产中的打印语句之间有任何区别,以查看按键是否在某处被操作。

有人遇到过这种情况吗?我需要将私钥存储在一行中,否则 GitHub Actions 工作流程会返回 YAML 语法错误。

这是我正在使用的代码,它在本地运行得很好,但在生产中却不起作用:

        now = int(time.time())
        payload = {"iat": now, "exp": now + expiration, "iss": self.id}
        print(self.key)
        # This line below is throwing the error showed above
        encrypted = jwt.encode(payload, key=self.key, algorithm="RS256")

        if isinstance(encrypted, bytes):
            encrypted = encrypted.decode("utf-8")
        return encrypted

上面代码中的打印语句用于调试目的。

有什么想法吗?加密包抛出

_handle_key_loading_error
load_pem_public_key

这是 GitHub 工作流程:

      - name: Deploy secrets
    if: ${{ github.event_name == 'release' || github.event_name == 'workflow_dispatch' }}
    run:  |
      eval "echo \"$(cat .deployment/secret.yaml)\"" | kubectl apply -f -
    env: 
      GITHUBAPP_KEY: '${{ secrets.PRIVATE_KEY }}'

下面是k8的secret的部署文件

apiVersion: v1
kind: Secret
metadata:
  name: xxx
  namespace: xxx
type: Opaque
stringData:
  GITHUBAPP_KEY: '${GITHUBAPP_KEY}'

python flask cryptography github-actions rsa
1个回答
0
投票

我试图模仿你的场景。直接使用单行键创建变量效果很好。但是,当通过

yaml
模块从 YAML 文件读取时,它包含
\\n
而不是
\n
。我遇到了与
\\n
相同的反序列化失败错误。将它们替换为
\n
解决了问题,之后
jwt.encode()
开始正常工作。

在下面的示例中,

key
是直接赋值的变量,
key1
是从YAML文件中读取的(观察转义字符和大小差异):

>>> key
'-----BEGIN RSA PRIVATE KEY-----\nKEY\n-----END RSA PRIVATE KEY-----'
>>> key1
'-----BEGIN RSA PRIVATE KEY-----\\nKEY\\n-----END RSA PRIVATE KEY-----'
>>> len(key)
1650
>>> len(key1)
1652

这是测试流程(

TEST_PRIVATE_KEY
是单行私钥):

name: python_jwt

on: workflow_dispatch

jobs:
  ci:
    runs-on: ubuntu-latest

    steps:
    - name: Create secret.yaml
      env:
        GITHUBAPP_KEY: '${{ secrets.TEST_PRIVATE_KEY }}'
      shell: bash
      run: |
        cat > secret.yaml << EOF
        apiVersion: v1
        kind: Secret
        metadata:
          name: xxx
          namespace: xxx
        type: Opaque
        stringData:
          GITHUBAPP_KEY: '${GITHUBAPP_KEY}'
        EOF
        eval "echo \"$(cat secret.yaml)\"" > secret-new.yaml
        ls -l secret*

    - name: JWT
      shell: python
      run: |
        import yaml, time, jwt
        with open('secret.yaml') as f:
            secret = yaml.safe_load(f)
        key = secret['stringData']['GITHUBAPP_KEY'].encode().replace(b'\\n', b'\n')
        print(f'{len(key)} | {key}')
        now = int(time.time())
        payload = {"iat": now, "exp": now, "iss": "123456"}
        encrypted = jwt.encode(payload, key=key, algorithm="RS256")
        print(f'encrypted: {encrypted}')

输出:

您需要在您这边验证这一点,并找出传递给

jwt.encode()
的实际密钥。

© www.soinside.com 2019 - 2024. All rights reserved.