Certificate Signing

Paramiko-Cloud signs OpenSSH certificates with the same high-level pattern for every provider:

  1. Create a cloud-backed ECDSA certificate authority key.

  2. Provide the public key that should receive a certificate.

  3. Choose principals, validity, certificate type, and options.

  4. Write the returned certificate line to the matching *-cert.pub file.

The result is an OpenSSH certificate public key line, not an X.509 certificate. OpenSSH certificates are compact SSH public-key records that bind a subject key to identity, validity, and policy fields signed by a trusted CA key.

Signing a User Certificate

This example uses AWS KMS for the certificate authority key, but the sign_certificate call is the same for AWS, Google Cloud, Azure, and any other Paramiko key that includes CertificateSigningKeyMixin.

from datetime import timedelta

from paramiko import RSAKey

from paramiko_cloud.aws.keys import ECDSAKey
from paramiko_cloud.pki import CertificateExtensions

ca_key = ECDSAKey(
    "arn:aws:kms:us-east-1:012345678901:key/example-key-id",
    region_name="us-east-1",
)
subject_key = RSAKey.generate(3072)

cert = ca_key.sign_certificate(
    subject_key,
    principals=["alice"],
    key_id="alice@example.com",
    serial=1001,
    valid_for=timedelta(hours=8),
    extensions={
        CertificateExtensions.PERMIT_PTY: "",
        CertificateExtensions.PERMIT_AGENT_FORWARDING: "",
    },
)

cert_line = cert.cert_string("alice@example.com")

cert_line is an OpenSSH certificate public key line. Save it next to the subject private key using OpenSSH’s certificate naming convention, such as id_rsa-cert.pub for id_rsa.

Certificate Parameters

sign_certificate accepts principals directly and forwards the remaining certificate configuration to CertificateParameters.

Common parameters are:

Parameter

Purpose

Default

principals

User names or host names valid for the certificate.

Required by sign_certificate.

type

CertificateType.USER or CertificateType.HOST.

CertificateType.USER

key_id

Audit label stored in the certificate.

Empty string

serial

CA-defined certificate serial number.

0

valid_after

Unix timestamp when the certificate becomes valid.

Current time

valid_before

Unix timestamp when the certificate expires.

valid_after + valid_for

valid_for

Duration used when valid_before is not provided.

One hour

critical_options

OpenSSH critical options.

No critical options

extensions

OpenSSH extensions.

All supported extensions enabled by sign_certificate

The certificate also includes a nonce, the subject public key, the CA public key, and a CA signature over the preceding certificate fields. Paramiko-Cloud handles those wire-format details when it builds the certificate.

OpenSSH treats critical options as mandatory restrictions. If a client or server does not understand a critical option in a certificate, it must reject that certificate. Extensions are non-critical grants such as PTY or agent forwarding. Pass extensions={} when you want a certificate with no extensions.

The standard extension values are empty strings:

extensions = {
    CertificateExtensions.PERMIT_PTY: "",
    CertificateExtensions.PERMIT_AGENT_FORWARDING: "",
}

Critical option values carry option-specific data:

from paramiko_cloud.pki import CertificateCriticalOptions

critical_options = {
    CertificateCriticalOptions.SOURCE_ADDRESS: "10.0.0.0/8,192.0.2.0/24",
}

OpenSSH treats an empty principals list as valid for any principal of the certificate type. Prefer explicit principals for normal user and host certificates.

Signing a Host Certificate

Host certificates use the same API with CertificateType.HOST. Principals are the hostnames or address names that should validate against the host key.

from datetime import timedelta

from paramiko import ECDSAKey as ParamikoECDSAKey

from paramiko_cloud.gcp.keys import ECDSAKey as GCPECDSAKey
from paramiko_cloud.pki import CertificateType

ca_key = GCPECDSAKey(kms_client, key_version_name)
host_key = ParamikoECDSAKey.generate()

host_cert = ca_key.sign_certificate(
    host_key,
    principals=["web-01.example.com", "10.0.0.15"],
    type=CertificateType.HOST,
    key_id="web-01",
    valid_for=timedelta(days=7),
    extensions={},
)

host_cert_line = host_cert.cert_string("web-01.example.com")

Public CA Key

Cloud-backed keys can expose their public key in OpenSSH format:

ca_public_key = ca_key.pubkey_string("production-user-ca")

Private key export and local key generation are intentionally disabled for cloud-backed keys. Create and rotate the CA key in the provider’s key management service, then point Paramiko-Cloud at the existing key.

OpenSSH validates the certificate only when the CA public key is trusted by the server for user certificates or by the client for host certificates.

Serializing Signing Requests

CertificateSigningRequest can serialize a request to protobuf and reconstruct it later. This is the format used by the gRPC API.

from paramiko import RSAKey

from paramiko_cloud.pki import (
    CertificateParameters,
    CertificateSigningRequest,
)

request = CertificateSigningRequest(
    RSAKey.generate(3072),
    CertificateParameters(principals=["alice"], key_id="alice@example.com"),
)

proto = request.to_proto()
payload = proto.SerializeToString()
restored_proto = type(proto).FromString(payload)
restored = CertificateSigningRequest.from_proto(restored_proto)
cert = restored.sign(ca_key)