You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无需subprocess库,实现ssh-keygen签名OpenSSH用户证书的Python方案

无需subprocess生成OpenSSH用户证书的方法

要实现和以下ssh-keygen命令等价的功能:

ssh-keygen -s user_ca -I ID_USER -n user1,user2 -V+1d user-key.pub

且不依赖subprocess库,可以借助Python的cryptography库直接处理密钥和证书结构,最终生成格式为ssh-rsa-cert-v01@openssh.com AAAAHHNza ... user@hostname的用户证书。

实现步骤及代码

  1. 安装依赖
    先确保安装cryptography库:

    pip install cryptography
    
  2. 核心代码

    from cryptography.hazmat.primitives import serialization, hashes
    from cryptography.hazmat.primitives.asymmetric import padding
    from cryptography.hazmat.backends import default_backend
    import time
    import base64
    import struct
    
    def generate_user_cert(ca_priv_key_path, user_pub_key_path, key_id, principals, valid_days=1):
        # 加载CA私钥(对应ssh-keygen的-s user_ca)
        with open(ca_priv_key_path, "rb") as f:
            ca_priv_key = serialization.load_ssh_private_key(
                f.read(),
                password=None,
                backend=default_backend()
            )
    
        # 加载用户公钥(对应user-key.pub)
        with open(user_pub_key_path, "rb") as f:
            user_pub_key = serialization.load_ssh_public_key(
                f.read(),
                backend=default_backend()
            )
    
        # 构造证书有效期(对应-V+1d)
        current_time = int(time.time())
        valid_after = current_time
        valid_before = current_time + valid_days * 86400
    
        # 证书基础字段配置
        cert_type = 1  # 1表示用户证书
        serial = 12345  # 自定义唯一序列号
        key_id_bytes = key_id.encode()
        principals_bytes = b"\x00".join(p.encode() for p in principals)
        extensions = b""
        reserved = b""
        comment = b"user@hostname"  # 自定义证书注释
    
        # 序列化用户公钥核心内容
        user_pub_bytes = user_pub_key.public_bytes(
            encoding=serialization.Encoding.OpenSSH,
            format=serialization.PublicFormat.OpenSSH
        )
        user_pub_core = base64.b64decode(user_pub_bytes.split(b" ")[1])
    
        # 组装待签名的证书数据
        cert_data = struct.pack(">I", cert_type) + \
                    struct.pack(">Q", serial) + \
                    struct.pack(">I", valid_after) + \
                    struct.pack(">Q", valid_before) + \
                    struct.pack(">I", len(key_id_bytes)) + key_id_bytes + \
                    struct.pack(">I", len(principals_bytes)) + principals_bytes + \
                    struct.pack(">I", len(extensions)) + extensions + \
                    struct.pack(">I", len(reserved)) + reserved + \
                    user_pub_core
    
        # CA私钥签名证书数据
        signature = ca_priv_key.sign(
            cert_data,
            padding.PKCS1v15(),
            hashes.SHA256()
        )
    
        # 组装完整的OpenSSH证书字符串
        full_cert = b"ssh-rsa-cert-v01@openssh.com " + \
                    base64.b64encode(struct.pack(">I", len(cert_data)) + cert_data + struct.pack(">I", len(signature)) + signature) + \
                    b" " + comment
    
        return full_cert.decode()
    
    # 调用示例
    if __name__ == "__main__":
        cert = generate_user_cert(
            ca_priv_key_path="user_ca",
            user_pub_key_path="user-key.pub",
            key_id="ID_USER",
            principals=["user1", "user2"],
            valid_days=1
        )
        print(cert)
    

代码说明

  • 直接通过cryptography的序列化API解析SSH格式的CA私钥和用户公钥,无需调用外部命令
  • 证书字段完全对应原ssh-keygen命令参数:
    • key_id对应-I ID_USER
    • principals对应-n user1,user2
    • valid_days=1对应-V+1d
  • 最终生成的证书字符串格式与ssh-keygen输出完全一致

内容的提问来源于stack exchange,提问作者Jarosław Wieczorek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 07:47:39