Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

First Run

This guide takes you from a freshly installed kipuka binary to a running EST server responding to /cacerts requests. By the end you will have a working server with a self-signed CA suitable for development and testing.

Step 1: Create directories and service account

sudo mkdir -p /etc/kipuka/{tls,ca}
sudo mkdir -p /var/lib/kipuka
sudo mkdir -p /var/log/kipuka
sudo useradd -r -s /sbin/nologin -d /var/lib/kipuka kipuka
sudo chown kipuka:kipuka /var/lib/kipuka /var/log/kipuka
PathPurpose
/etc/kipuka/tls/Server TLS certificate and private key
/etc/kipuka/ca/CA certificate and signing key
/var/lib/kipuka/Database files, OTP state
/var/log/kipuka/Audit logs (when file-based logging is enabled)

Step 2: Generate test certificates

The repository includes a helper script that creates a complete test PKI:

./contrib/local-dev/setup-ca.sh

This generates a root CA, a server TLS certificate, and a client certificate under contrib/local-dev/pki/. Copy the relevant files:

sudo cp contrib/local-dev/pki/ca.pem /etc/kipuka/ca/ca.pem
sudo cp contrib/local-dev/pki/ca-key.pem /etc/kipuka/ca/ca-key.pem
sudo cp contrib/local-dev/pki/server.pem /etc/kipuka/tls/server.pem
sudo cp contrib/local-dev/pki/server-key.pem /etc/kipuka/tls/server-key.pem

Manual certificate generation

If you prefer to create certificates by hand:

# Root CA
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 \
  -keyout /etc/kipuka/ca/ca-key.pem \
  -out /etc/kipuka/ca/ca.pem \
  -days 3650 -nodes \
  -subj "/CN=kipuka Test CA"

# Server TLS certificate
openssl req -newkey ec -pkeyopt ec_paramgen_curve:P-256 \
  -keyout /etc/kipuka/tls/server-key.pem \
  -out /tmp/server.csr -nodes \
  -subj "/CN=localhost"

openssl x509 -req -in /tmp/server.csr \
  -CA /etc/kipuka/ca/ca.pem \
  -CAkey /etc/kipuka/ca/ca-key.pem \
  -CAcreateserial \
  -out /etc/kipuka/tls/server.pem \
  -days 365 \
  -extfile <(printf "subjectAltName=DNS:localhost,IP:127.0.0.1")

rm /tmp/server.csr

Set restrictive permissions on key material:

sudo chmod 600 /etc/kipuka/ca/ca-key.pem /etc/kipuka/tls/server-key.pem
sudo chown kipuka:kipuka /etc/kipuka/ca/* /etc/kipuka/tls/*

Step 3: Write a minimal configuration

Create /etc/kipuka/kipuka.toml:

[server]
listen = "0.0.0.0:9443"

[tls]
cert = "/etc/kipuka/tls/server.pem"
key = "/etc/kipuka/tls/server-key.pem"

[tls.client_auth]
# Trust anchor for EST client certificate authentication.
# Clients presenting a certificate signed by this CA are
# permitted to re-enroll without an OTP.
trust_anchors = ["/etc/kipuka/ca/ca.pem"]

[db]
# SQLite for development.  Use a PostgreSQL URL for production.
url = "sqlite:///var/lib/kipuka/kipuka.db?mode=rwc"

[[ca]]
id = "default"
cert = "/etc/kipuka/ca/ca.pem"
key = "/etc/kipuka/ca/ca-key.pem"

# Optional: restrict which subject names this CA will sign.
# allowed_subjects = ["CN=*"]

# Optional: set a default certificate validity period.
# validity_days = 365

Production note: For production deployments, replace the [db] URL with a PostgreSQL connection string and store CA keys in an HSM. See the Configuration Reference for the full set of options.

Step 4: Run database migrations

kipuka manages its own schema. Run the migration command before the first start:

sudo -u kipuka kipuka migrate --config /etc/kipuka/kipuka.toml

Expected output:

Applied 3 migrations to sqlite:///var/lib/kipuka/kipuka.db

Step 5: Start the server

Start kipuka in the foreground to verify everything works:

sudo -u kipuka kipuka --config /etc/kipuka/kipuka.toml

You should see log output similar to:

2026-06-24T12:00:00.000Z  INFO kipuka::server: kipuka v0.1.0 starting
2026-06-24T12:00:00.001Z  INFO kipuka::tls: TLS configured, client auth enabled
2026-06-24T12:00:00.002Z  INFO kipuka::ca: Loaded CA "default" (CN=kipuka Test CA)
2026-06-24T12:00:00.003Z  INFO kipuka::db: Database connected (sqlite)
2026-06-24T12:00:00.004Z  INFO kipuka::server: Listening on 0.0.0.0:9443

Press Ctrl+C to stop. For long-running deployments, use the systemd service instead.

Step 6: Verify the EST endpoint

The /cacerts endpoint returns the CA certificate(s) without requiring client authentication. Use it to confirm the server is responding:

curl -sk https://localhost:9443/.well-known/est/cacerts \
  | base64 -d \
  | openssl pkcs7 -inform DER -print_certs

You should see the PEM-encoded CA certificate:

subject=CN = kipuka Test CA
issuer=CN = kipuka Test CA
-----BEGIN CERTIFICATE-----
MIIBkTCB+...
-----END CERTIFICATE-----

If this works, your server is ready to issue certificates.

Logging

kipuka uses Rust’s tracing framework. Control verbosity with the RUST_LOG environment variable:

LevelWhat you see
RUST_LOG=errorOnly errors
RUST_LOG=warnErrors and warnings
RUST_LOG=infoStartup, shutdown, enrollment events (default)
RUST_LOG=debugRequest/response details, TLS handshake info
RUST_LOG=traceFull ASN.1 dumps, raw bytes, internal state

To set the log level when running directly:

RUST_LOG=debug kipuka --config /etc/kipuka/kipuka.toml

For the systemd service, add an environment override:

sudo systemctl edit kipuka
[Service]
Environment="RUST_LOG=debug"

Next: Your First Certificate walks through the complete enrollment flow — generating an OTP, submitting a CSR, and extracting the signed certificate.