Skip to content

Instantly share code, notes, and snippets.

@debakarr
Created June 25, 2025 13:20
Show Gist options
  • Select an option

  • Save debakarr/b4d1d2f1b45d3a41ed4a2c6e2c590442 to your computer and use it in GitHub Desktop.

Select an option

Save debakarr/b4d1d2f1b45d3a41ed4a2c6e2c590442 to your computer and use it in GitHub Desktop.
Code to create Certs using Python
import logging
from datetime import datetime, timedelta
import pytest
from cryptography import x509
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.x509.oid import NameOID
# Set up logger
logger = logging.getLogger(__name__)
def generate_key():
logger.info("Generating RSA private key")
return rsa.generate_private_key(public_exponent=65537, key_size=2048)
def generate_cert(subject, issuer, public_key, issuer_key, is_ca=False, alt_names=None):
logger.info(
"Generating certificate: subject=%s, issuer=%s, is_ca=%s, alt_names=%s",
subject.rfc4514_string(),
issuer.rfc4514_string(),
is_ca,
alt_names,
)
builder = (
x509.CertificateBuilder()
.subject_name(subject)
.issuer_name(issuer)
.public_key(public_key)
.serial_number(x509.random_serial_number())
.not_valid_before(datetime.utcnow())
.not_valid_after(datetime.utcnow() + timedelta(days=3650))
)
builder = builder.add_extension(
x509.BasicConstraints(ca=is_ca, path_length=None), critical=True
)
# Add Subject Alternative Names (SANs) if provided
if alt_names:
logger.info("Adding Subject Alternative Names: %s", alt_names)
san = x509.SubjectAlternativeName([x509.DNSName(name) for name in alt_names])
builder = builder.add_extension(san, critical=False)
cert = builder.sign(private_key=issuer_key, algorithm=hashes.SHA256())
logger.info("Certificate generated successfully")
return cert
def write_key(key, path):
logger.info("Writing key to %s", path)
path.write_bytes(
key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption(),
)
)
def write_cert(cert, path):
logger.info("Writing certificate to %s", path)
path.write_bytes(cert.public_bytes(serialization.Encoding.PEM))
def build_subject(name):
logger.info("Building X.509 subject for %s", name)
return x509.Name(
[
x509.NameAttribute(NameOID.COUNTRY_NAME, "US"),
x509.NameAttribute(NameOID.ORGANIZATION_NAME, "Test Org"),
x509.NameAttribute(NameOID.COMMON_NAME, name),
]
)
@pytest.fixture(scope="session")
def generated_cert_chain(tmp_path_factory):
logger.info("Creating temporary directory for certificate chain")
tmp = tmp_path_factory.mktemp("cert_chain")
# === Generate CA key and cert ===
logger.info("Generating CA key and certificate")
ca_key = generate_key()
ca_subject = build_subject("MyTestCA")
ca_cert = generate_cert(
ca_subject, ca_subject, ca_key.public_key(), ca_key, is_ca=True
)
write_key(ca_key, tmp / "ca-key.pem")
write_cert(ca_cert, tmp / "ca-cert.pem")
# === Generate Server key and cert ===
logger.info("Generating server key and certificate")
server_key = generate_key()
server_subject = build_subject("pytest-fixture-server")
alt_names = ["localhost", "127.0.0.1", "host.docker.internal"]
server_cert = generate_cert(
server_subject, ca_subject, server_key.public_key(), ca_key, alt_names=alt_names
)
write_key(server_key, tmp / "server-key.pem")
write_cert(server_cert, tmp / "server-cert.pem")
# === Generate Client key and cert ===
logger.info("Generating client key and certificate")
client_key = generate_key()
client_subject = build_subject("pytest-fixture-client")
client_cert = generate_cert(
client_subject, ca_subject, client_key.public_key(), ca_key
)
write_key(client_key, tmp / "client-key.pem")
write_cert(client_cert, tmp / "client-cert.pem")
logger.info("Certificate chain generation complete. Output directory: %s", tmp)
return {
"dir": tmp,
"ca_cert": tmp / "ca-cert.pem",
"ca_key": tmp / "ca-key.pem",
"server_cert": tmp / "server-cert.pem",
"server_key": tmp / "server-key.pem",
"client_cert": tmp / "client-cert.pem",
"client_key": tmp / "client-key.pem",
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment