Help us shape the future of Go! Take the 2026 Go Developer Survey

homepki

command module
v0.8.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 26, 2026 License: MIT Imports: 2 Imported by: 0

README ΒΆ

homepki

A simple PKI management tool for local development. Create and manage three-tier certificate authorities, intermediate CAs, and TLS certificates with a single CLI.

πŸ“– Documentation Β· bcollard.github.io/homepki

Install

brew tap bcollard/homepki
brew install --cask homepki

Quick Start

# Create root CA
homepki root-ca --domain runlocal.dev

# Create intermediate CA
homepki intermediate-ca --domain runlocal.dev --name bu1

# Create server certificate
homepki server-cert --domain runlocal.dev --intermediate bu1 --server kong-gateway

# Create client certificate
homepki client-cert --domain runlocal.dev --intermediate bu1 --client my-client

# Trust the root CA in the system, Firefox and Java trust stores (macOS, Linux)
homepki trust install --domain runlocal.dev

Certificates and keys are stored in ~/.homepki by default. homepki is a single Go binary with no runtime dependency: keys, signing and chain verification use Go's crypto/x509, so openssl does not need to be installed.

Configuration

Override the default storage location using:

  • The --workdir flag:
    homepki root-ca --domain runlocal.dev --workdir /path/to/pki
    
  • The HOMEPKI_WORKDIR environment variable:
    export HOMEPKI_WORKDIR=/path/to/pki
    homepki root-ca --domain runlocal.dev
    

Agent Skill (AI coding tools)

homepki ships an Agent Skill that teaches AI coding tools how to drive homepki β€” issuing TLS and mTLS material for scripts, demos, and tests. Install it once and every future agent session knows how to use homepki without you explaining it each time:

homepki skill install          # β†’ ~/.claude/skills/homepki/SKILL.md
homepki skill install --force  # overwrite an existing copy (e.g. after upgrading homepki)
homepki skill path             # print the install path
homepki skill install --print  # emit the skill to stdout (pipe it anywhere)

The skill is embedded in the binary, so no download is needed. Start a new agent session after installing to pick it up.

Overview

homepki implements a three-tier PKI structure:

  • Root CA: The top-level certificate authority
  • Intermediate CA: Organization/tenant-specific intermediate certificate authorities
  • End-entity certificates: Server and client certificates for services

Build from Source

go build -o homepki

Project Structure

.
β”œβ”€β”€ main.go                         # Entry point
β”œβ”€β”€ skill.go                        # Embeds SKILL.md into the binary
β”œβ”€β”€ SKILL.md                        # Agent Skill definition (single source of truth)
β”œβ”€β”€ go.mod
β”œβ”€β”€ cmd/
β”‚   β”œβ”€β”€ root.go                     # CLI setup, --workdir flag
β”‚   β”œβ”€β”€ root_ca.go                  # root-ca command (generate + list)
β”‚   β”œβ”€β”€ intermediate_ca.go          # intermediate-ca command (generate + list)
β”‚   β”œβ”€β”€ server_cert.go              # server-cert command (generate + list)
β”‚   β”œβ”€β”€ client_cert.go              # client-cert command (generate + list)
β”‚   β”œβ”€β”€ sign.go                     # sign command (external CSRs)
β”‚   β”œβ”€β”€ trust.go                    # trust install/uninstall/status (system, NSS, Java)
β”‚   β”œβ”€β”€ revoke.go                   # revoke + crl commands
β”‚   β”œβ”€β”€ leaf.go                     # shared server/client leaf issuance
β”‚   β”œβ”€β”€ paths.go                    # shared flags, CA file locations, helpers
β”‚   └── skill.go                    # skill install + path
└── pkg/
    └── pki/
        β”œβ”€β”€ pki.go                  # file helpers, chain verification, SAN parsing
        β”œβ”€β”€ certs.go                # certificate issuance (crypto/x509)
        β”œβ”€β”€ keys.go                 # --key-type β†’ key generation, PEM key I/O
        β”œβ”€β”€ constraints.go          # --name-constraint parsing
        β”œβ”€β”€ csr.go                  # CSR loading and subject policy checks
        β”œβ”€β”€ crl.go                  # CRL signing, loading, revocation reasons
        β”œβ”€β”€ pkcs12.go               # PKCS#12 bundles
        └── trust.go                # trust store detection and commands

Usage Guide

1. Creating a Root CA
homepki root-ca --domain runlocal.dev

# List root CAs (table, default)
homepki root-ca list

# List as JSON
homepki root-ca list -o json

This creates:

  • Root CA directory structure
  • Root CA private key and self-signed certificate
2. Creating an Intermediate CA
homepki intermediate-ca --domain runlocal.dev --name bu1

# List intermediate CAs (table, default)
homepki intermediate-ca list --domain runlocal.dev

# List as JSON
homepki intermediate-ca list --domain runlocal.dev -o json

This creates:

  • Intermediate CA private key and certificate signed by the root CA
  • Certificate chain file ({name}-intermediate-ca-chain.crt)
3. Creating Server Certificates
homepki server-cert --domain runlocal.dev --intermediate bu1 --server kong-gateway

# List server certificates (table, default)
homepki server-cert list --domain runlocal.dev --intermediate bu1

# List as JSON
homepki server-cert list --domain runlocal.dev --intermediate bu1 -o json
4. Creating Client Certificates
homepki client-cert --domain runlocal.dev --intermediate bu1 --client my-service

# List client certificates (table, default)
homepki client-cert list --domain runlocal.dev --intermediate bu1

# List as JSON
homepki client-cert list --domain runlocal.dev --intermediate bu1 -o json
5. Signing an External CSR

Sign a request generated elsewhere β€” the private key never reaches homepki:

openssl req -new -nodes -newkey rsa:2048 -keyout my-service.key -out my-service.csr \
  -subj "/O=runlocal-dev/OU=bu1/CN=my-service.bu1.runlocal.dev" \
  -addext "subjectAltName=DNS:my-service.bu1.runlocal.dev,DNS:my-service.local"

homepki sign --domain runlocal.dev --intermediate bu1 --csr my-service.csr

# As a client certificate, under a chosen name
homepki sign --domain runlocal.dev --intermediate bu1 --csr my-client.csr \
  --type client --name my-client

# Write the certificate outside the PKI tree
homepki sign --domain runlocal.dev --intermediate bu1 --csr my-service.csr \
  --out ./my-service.crt

The request's subject must carry the root CA's organization (O=, dots replaced by dashes) and the intermediate's organizational unit (OU=). Mismatches are rejected with the exact -subj to use printed in the error. Subject Alternative Names are copied from the request; every other requested extension is ignored, so a request cannot ask to be a CA.

Trusting the Root CA

Add the root CA to this machine's trust stores so browsers, curl and JVMs accept certificates issued under it:

homepki trust install --domain runlocal.dev                   # every store available on this host
homepki trust install --domain runlocal.dev --store nss,java  # skip the system store (no sudo)
homepki trust status                                          # every root CA in the workdir
homepki trust status --domain runlocal.dev -o json
homepki trust uninstall --domain runlocal.dev
--store Covers Needs
system macOS System keychain; Linux anchors on Debian/Ubuntu/Alpine, Fedora/RHEL, Arch, openSUSE sudo
nss Firefox profiles, and Chrome/Chromium's ~/.pki/nssdb on Linux certutil (brew install nss, apt install libnss3-tools)
java $JAVA_HOME cacerts keytool; sudo only if cacerts is not writable

Without --store, homepki uses the system store plus every NSS database and JDK it finds. status needs no privileges. Servers must still present the intermediate chain file, or clients cannot build the path from the leaf to the trusted root.

Key Types

Every generate command takes --key-type: rsa (2048-bit, the default), ecdsa / ecdsa-p256, ecdsa-p384, ecdsa-p521, or ed25519. Tiers are independent, so an ECDSA leaf under an RSA intermediate is fine.

homepki intermediate-ca --domain runlocal.dev --name bu1 --key-type ecdsa
homepki server-cert --domain runlocal.dev --intermediate bu1 --server gw --key-type ecdsa-p384

The signature digest follows the issuing CA's key: SHA-256 for RSA and P-256, SHA-384 for P-384, SHA-512 for P-521. Browsers reject Ed25519 certificates; use ed25519 for service-to-service TLS only.

Validity

Every command that signs takes --validity, in days (90d) or as a Go duration (24h). Defaults are 2190 days for CAs and 365 days for leaves. A certificate is never valid past its issuer: a longer request is capped, with a note.

homepki server-cert --domain runlocal.dev --intermediate bu1 --server gw --validity 24h
PKCS#12

--pkcs12 on server-cert and client-cert also writes <name>.p12 with the key, certificate and CA chain. The password is changeit unless --pkcs12-password sets another. The encoding is readable by Java, macOS Keychain, Windows and OpenSSL 3.

homepki client-cert --domain runlocal.dev --intermediate bu1 --client my-client --pkcs12
Revocation

revoke adds a leaf to its intermediate's CRL; crl writes or refreshes the CRLs without revoking anything.

homepki crl --domain runlocal.dev --intermediate bu1
homepki revoke --domain runlocal.dev --intermediate bu1 --client my-client --reason keyCompromise

This writes bu1-intermediate-ca.crl, ca/<root>-root-ca.crl, and bu1-crl-chain.crl (both CRLs, for servers such as nginx that check every tier). CRLs are valid for 365 days by default (--validity). client-cert list and server-cert list report revoked leaves as invalid.

Name Constraints

root-ca and intermediate-ca take a repeatable --name-constraint that limits the names the CA may issue for. Values use openssl syntax β€” permitted; or excluded;, then DNS, IP, email or URI. permitted; may be omitted and IP ranges accept CIDR.

homepki root-ca --domain klimax.internal --name-constraint "permitted;DNS:.klimax.internal"
homepki intermediate-ca --domain klimax.internal --name bu1 \
  --name-constraint "permitted;DNS:.bu1.klimax.internal" --name-constraint "IP:10.0.0.0/8"

server-cert, client-cert and sign verify every new certificate against its chain before writing it, so a name outside the constraints is refused and nothing is written. Constrain a root before trusting it system-wide: it then cannot vouch for any other site, even if its key leaks.

Re-issuing

Generate commands refuse to overwrite existing material: a re-run exits 1, prints what is in the way, and changes nothing. --force replaces it.

homepki server-cert --domain runlocal.dev --intermediate bu1 --server kong-gateway --force

There is no CA database, so the same subject can be issued any number of times. For a CA tier, --force orphans every certificate beneath it β€” check the tier below the one you replaced, since it is the only one whose chain flips to invalid.

Listing and Chain Verification

All list subcommands verify the certificate's chain of trust and support two output formats via -o/--output:

Format Description
table Human-readable table with coloured chain status (default)
json Machine-readable JSON array, no extra output

Chain validity is checked at list time:

  • root-ca list β€” verifies each root cert is validly self-signed
  • intermediate-ca list β€” verifies the intermediate was signed by the root CA
  • server-cert list / client-cert list β€” verifies the leaf cert chains through the intermediate to the root CA

Example JSON output:

[
  {
    "name": "kong-gateway.crt",
    "expires": "2027-04-01",
    "days_left": 360,
    "chain_valid": true
  },
  {
    "name": "old.crt",
    "expires": "2025-01-01",
    "days_left": -270,
    "chain_valid": false,
    "chain_error": "x509: certificate has expired or is not yet valid"
  }
]

Security Features

  • 2048-bit RSA keys by default, or ECDSA P-256/P-384/P-521 or Ed25519 via --key-type
  • Private keys written as PKCS#8 PEM, mode 600, in 700 private/ directories
  • Random 128-bit serial numbers
  • Name constraints on either CA tier, enforced before a leaf is written
  • Chain verification on every issue and every list command, including revocation for leaves

File Organization

Root CA Structure
{domain-name}/
β”œβ”€β”€ ca/
β”‚   β”œβ”€β”€ {domain-name}-root-ca.crt     # Root certificate
β”‚   β”œβ”€β”€ {domain-name}-root-ca.crl     # Root CRL (after revoke / crl)
β”‚   └── private/                      # Protected private keys
β”‚       └── {domain-name}-root-ca.key # Root private key
Intermediate CA Structure
{domain-name}/
└── {organization}/
    β”œβ”€β”€ {org}-intermediate-ca.crt     # Intermediate certificate
    β”œβ”€β”€ {org}-intermediate-ca-chain.crt # Certificate chain
    β”œβ”€β”€ {org}-intermediate-ca.crl     # Intermediate CRL (after revoke / crl)
    β”œβ”€β”€ {org}-crl-chain.crl           # Intermediate + root CRLs
    β”œβ”€β”€ server-tls/                   # Server certificates
    β”œβ”€β”€ client-tls/                   # Client certificates
    └── private/                      # Protected private keys
        └── {org}-intermediate-ca.key # Intermediate private key

Defaults

  • Key: 2048-bit RSA (--key-type ecdsa for P-256, ecdsa-p384, ecdsa-p521, ed25519)
  • Digest: follows the issuer's key β€” SHA-256 (RSA, P-256), SHA-384 (P-384), SHA-512 (P-521)
  • Serial numbers: random 128-bit
  • Validity: 365 days for leaf certs, 2190 days (~6 years) for CAs, 365 days for CRLs (--validity overrides)
  • Extensions: Proper X.509 extensions for CA and end-entity certificates

Best Practices

  1. Secure storage: Keep private keys in secure, encrypted storage
  2. Access control: Limit access to CA private keys
  3. Backup: Regularly backup CA certificates and keys
  4. Rotation: Plan for certificate renewal and CA rotation
  5. Monitoring: Track certificate expiration dates

Troubleshooting

Common Issues
  1. Permission denied: Ensure proper file permissions on private directories
  2. Certificate validation: Check certificate chains and trust relationships
  3. Expired certificates: Monitor and renew certificates before expiration
Verification Commands

These use openssl, which homepki itself does not need.

# Inspect a certificate
openssl x509 -in certificate.crt -text -noout

# Manually verify a certificate chain
openssl verify -CAfile root-ca.crt -untrusted intermediate-ca.crt end-entity.crt

# Check a private key
openssl rsa -in private-key.key -check

License

MIT β€” see LICENSE.

Contributing

  1. Test changes thoroughly in isolated environments
  2. Follow existing naming conventions
  3. Ensure security best practices are maintained

Documentation ΒΆ

The Go Gopher

There is no documentation for this package.

Directories ΒΆ

Path Synopsis
pkg
pki

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL