Skip to content

Trust an internal certificate

Connect the Dreadnode TUI, CLI, and SDK to a deployment secured by a private CA or self-signed certificate.

Obtain the root CA and any intermediate CA certificates from your platform operator through a trusted channel. Ask for these PEM files:

  • organization-root.crt — the public root certificate to install in the OS trust store
  • organization-ca-bundle.pem — the root plus any intermediate CA certificates, used to verify the ingress chain

For a temporary self-signed evaluation certificate, the leaf certificate is also its own root. Install that certificate as the trust anchor.

The server and client hold different parts of the TLS setup:

MaterialLocationPurpose
Ingress certificate chainKubernetes Secret as tls.crtIdentifies the Dreadnode host to clients
Ingress private keyKubernetes Secret as tls.keyProves the server owns the certificate; never leaves the cluster
Root and intermediate CA certificatesWorkstation and runtime trust storesLet clients verify the ingress certificate chain

The browser used for device login must trust the same Dreadnode origin as the CLI. A browser can use a different store from the OS, so verify both browser login and a Dreadnode client connection.

Inspect the root certificate and compare its SHA-256 fingerprint with the value the operator sent through a second trusted channel:

Terminal window
export ORGANIZATION_ROOT=/absolute/path/to/organization-root.crt
export ORGANIZATION_CA=/absolute/path/to/organization-ca-bundle.pem
openssl x509 -in "$ORGANIZATION_ROOT" \
-noout -subject -issuer -fingerprint -sha256
# sha256 Fingerprint=8A:...

Confirm that the bundle validates the certificate served by Dreadnode. SNI makes the ingress controller select the certificate for the configured hostname:

Terminal window
export DOMAIN=dreadnode.acme.internal
openssl s_client \
-connect "${DOMAIN}:443" \
-servername "$DOMAIN" \
-showcerts </dev/null 2>/dev/null |
openssl x509 -out /tmp/dreadnode-endpoint-leaf.pem
openssl verify \
-CAfile "$ORGANIZATION_CA" \
-verify_hostname "$DOMAIN" \
/tmp/dreadnode-endpoint-leaf.pem
# /tmp/dreadnode-endpoint-leaf.pem: OK

If verification fails, ask the operator for the missing root or intermediate certificate or have them correct the chain served by the ingress. Do not download a certificate from the endpoint and trust it automatically.

Extract a temporary self-signed certificate

Section titled “Extract a temporary self-signed certificate”

Endpoint extraction is a fallback for a temporary self-signed evaluation certificate, where the leaf is its own trust anchor. It is not a way to discover a private CA root because servers normally omit the root from the chain they send.

Terminal window
export DOMAIN=dreadnode.acme.internal
openssl s_client \
-connect "${DOMAIN}:443" \
-servername "$DOMAIN" </dev/null 2>/dev/null |
openssl x509 -out /absolute/path/to/dreadnode-self-signed.crt
openssl x509 \
-in /absolute/path/to/dreadnode-self-signed.crt \
-noout -subject -issuer -fingerprint -sha256

Before using the extracted certificate, compare its SHA-256 fingerprint with the operator through a trusted channel. Matching the live endpoint alone does not establish trust.

Install organization-root.crt into the workstation’s OS store. The Dreadnode TUI, CLI, SDK platform client, dn/* model gateway, trace exporter, and spawned local runtime all use this native trust store. If your operator supplied more than one trust anchor, repeat the install command for each root certificate.

This behavior covers Dreadnode-owned platform API, model, and trace connections. OCI registry and S3/MinIO transfers are separate transports and are not covered by this release.

Copy the root into the local CA directory, then rebuild the system bundle:

Terminal window
sudo install -m 0644 \
"$ORGANIZATION_ROOT" \
/usr/local/share/ca-certificates/dreadnode-organization-root.crt
sudo update-ca-certificates

update-ca-certificates adds the root to /etc/ssl/certs/ca-certificates.crt while preserving the distribution’s public roots. Remove it by deleting the exact local anchor and rebuilding:

Terminal window
sudo rm /usr/local/share/ca-certificates/dreadnode-organization-root.crt
sudo update-ca-certificates --fresh

Copy the root into the system anchor directory, then rebuild the extracted trust bundles:

Terminal window
sudo install -m 0644 \
"$ORGANIZATION_ROOT" \
/etc/pki/ca-trust/source/anchors/dreadnode-organization-root.crt
sudo update-ca-trust extract

Remove it by deleting the exact anchor and rebuilding:

Terminal window
sudo rm /etc/pki/ca-trust/source/anchors/dreadnode-organization-root.crt
sudo update-ca-trust extract

Add the root to the System keychain so every user can trust it:

Terminal window
sudo security add-trusted-cert \
-d -r trustRoot \
-k /Library/Keychains/System.keychain \
"$ORGANIZATION_ROOT"

Remove the certificate and its trust settings by SHA-256 fingerprint:

Terminal window
CA_SHA256=$(
openssl x509 -in "$ORGANIZATION_ROOT" -noout -fingerprint -sha256 |
cut -d= -f2 |
tr -d :
)
sudo security delete-certificate \
-t -Z "$CA_SHA256" \
/Library/Keychains/System.keychain

Open PowerShell as the user who runs Dreadnode, then import the root into that user’s trusted root store:

Terminal window
$OrganizationRoot = 'C:\absolute\path\to\organization-root.cer'
$Certificate = Import-Certificate `
-FilePath $OrganizationRoot `
-CertStoreLocation 'Cert:\CurrentUser\Root'
$Certificate.Thumbprint
# 4D1B...

Use Cert:\LocalMachine\Root from an administrator PowerShell session for machine-wide trust. Remove the current-user certificate by its thumbprint:

Terminal window
$Thumbprint = (Get-PfxCertificate -FilePath $OrganizationRoot).Thumbprint
Remove-Item -Path "Cert:\CurrentUser\Root\$Thumbprint"

After any OS-store change, open https://dreadnode.acme.internal in the browser used for device login. Managed browsers can maintain a separate trust store; import the same root through the browser’s enterprise policy if it still reports an unknown issuer.

Restart Dreadnode after changing the OS trust store, then verify the API, log in, and launch the TUI. New client processes and TLS contexts pick up CA additions and removals.

Terminal window
export DREADNODE_SERVER=https://dreadnode.acme.internal
curl "$DREADNODE_SERVER/api/v1/health"
# {"status":"ok"}
dn login --server "$DREADNODE_SERVER" --profile acme-prod
dn whoami --profile acme-prod
dn --profile acme-prod

The device-login browser must also trust https://dreadnode.acme.internal. A successful API health check proves the OS store validates the platform endpoint; completing a model turn and confirming its trace reached the platform verifies the model and OTLP paths.

The TUI starts a local runtime with the same native trust behavior. Restart dn after CA changes so the TUI and runtime create fresh TLS contexts. Remote OpenSandbox runtimes use their image’s OS store and must be rebuilt and recreated after CA rotation.

SymptomNext action
CERTIFICATE_VERIFY_FAILED or unable to get local issuer certificateInstall the missing root in the OS store, repair the intermediate chain served by the ingress, and restart Dreadnode
Hostname mismatchReplace the ingress certificate with one whose SAN covers the configured hostname; see TLS certificates
Certificate expired or not yet validCheck openssl x509 -in certificate.pem -noout -dates and the client clock, then renew the certificate or correct the clock
Browser succeeds but CLI failsConfirm the CA is in the OS store used by the Dreadnode process, then restart dn
API succeeds but model or trace traffic failsRestart dn to recreate every TLS context; configure remote OpenSandbox trust separately

Keep verification enabled while diagnosing these failures. Dreadnode does not provide --ca-bundle, --trusted, or --insecure flags.