Quick Start¶
1. Bootstrap a Root CA¶
from tiny_ca.managers.sync_lifecycle_manager import CertLifecycleManager
from tiny_ca.storage.local_storage import LocalStorage
from tiny_ca.db.sync_db_manager import SyncDBHandler
from tiny_ca.models.certificate import CAConfig
storage = LocalStorage(base_folder="./pki")
db = SyncDBHandler(db_url="sqlite:///pki.db")
mgr = CertLifecycleManager(storage=storage, db_handler=db)
cert_path, key_path = mgr.create_self_signed_ca(
CAConfig(
common_name="My Root CA",
organization="ACME Corp",
country="UA",
key_size=4096,
days_valid=3650,
)
)
Note
This step creates a self-signed Root CA. Store the private key securely — compromise of this key breaks trust for all issued certificates.
Attach the factory:
from tiny_ca.ca_factory.utils.file_loader import CAFileLoader
from tiny_ca.ca_factory.factory import CertificateFactory
loader = CAFileLoader(ca_cert_path=cert_path, ca_key_path=key_path)
mgr.factory = CertificateFactory(loader)
Warning
Without attaching a CertificateFactory, the manager cannot issue certificates.
2. Issue a Leaf Certificate¶
from tiny_ca.models.certificate import ClientConfig
from tiny_ca.const import CertType
cert, key, csr = mgr.issue_certificate(
ClientConfig(
common_name="nginx.internal",
serial_type=CertType.SERVICE,
key_size=2048,
days_valid=365,
is_server_cert=True,
san_dns=["nginx.internal", "www.nginx.internal"],
san_ip=["192.168.1.10"],
),
cert_path="services",
)
Note
Subject Alternative Names (SAN) are required by modern TLS clients. The Common Name (CN) alone is not sufficient for hostname validation.
3. Renew a Certificate (same key)¶
renewed_cert = mgr.renew_certificate(
serial=cert.serial_number,
days_valid=365
)
Note
Renewal keeps the same key pair. Use this only if the private key is still secure.
4. Rotate a Certificate (new key)¶
new_cert, new_key, new_csr = mgr.rotate_certificate(
serial=cert.serial_number,
config=ClientConfig(
common_name="nginx.internal",
serial_type=CertType.SERVICE,
days_valid=365,
is_server_cert=True,
),
)
Warning
Rotation revokes the old certificate automatically. Ensure all clients switch to the new certificate before enforcing revocation.
5. Revoke a Certificate¶
from cryptography import x509
ok = mgr.revoke_certificate(
serial=cert.serial_number,
reason=x509.ReasonFlags.key_compromise,
)
Warning
Revocation is irreversible. Once revoked, a certificate should never be trusted again.
6. Generate and Verify a CRL¶
crl = mgr.generate_crl(days_valid=7)
mgr.verify_crl(crl)
Note
CRLs must be periodically regenerated and distributed to relying parties.
7. Export PKCS#12¶
p12_bytes = mgr.export_pkcs12(
cert=cert,
private_key=key,
password=b"strong-passphrase",
name="nginx.internal",
)
Warning
Always protect PKCS#12 bundles with a strong password. They contain the private key in exportable form.
8. Inspect a Certificate¶
details = mgr.inspect_certificate(cert)
print(details.common_name)
print(details.san_dns)
print(details.san_ip)
print(details.fingerprint_sha256)
print(details.public_key_size)
print(details.is_ca)
Note
This method returns a safe, serialisable snapshot — no raw cryptography objects.
9. List and Monitor Certificates¶
records = mgr.list_certificates(
status="valid",
key_type="service",
limit=50,
offset=0,
)
expiring = mgr.get_expiring_soon(within_days=30)
for r in expiring:
print(r.common_name, r.not_valid_after)
updated = mgr.refresh_expired_statuses()
deleted = mgr.delete_certificate(serial=cert.serial_number)
Note
Regular monitoring helps prevent unexpected certificate expiration outages.
Warning
Hard deletion removes both the database record and stored files. This action cannot be undone.