Skip to content

CA-Signed Mode

CA-signed mode uses a Certificate Authority to issue and validate client certificates for Tarsus agents.

ScenarioWhy CA-Signed Mode
Enterprise environmentsCentralized certificate management
Large deploymentsScalable agent onboarding
Compliance requirementsPKI audit trail
Existing PKIReuse existing infrastructure
Automated provisioningCertificate lifecycle management
AspectThumbprintCA-Signed
Certificate issuanceSelf-signed per agentCentral CA
Trust modelIndividual trustHierarchical trust
OnboardingManual per agentAutomated possible
RevocationPer-thumbprintCA CRL/OCSP
ComplexityLowerHigher
ScalabilityLimitedExcellent
OptionDescriptionComplexity
Self-managed CACreate your own CAMedium
HashiCorp VaultVault PKI secrets engineMedium
AWS Private CAAWS Certificate Manager PCALow
Step CAOpen source ACME CAMedium
Enterprise CAActive Directory CSHigh

Create a private CA for Mantis:

Terminal window
# Create CA directory structure
mkdir -p /etc/mantis/ca/{certs,crl,newcerts,private}
chmod 700 /etc/mantis/ca/private
touch /etc/mantis/ca/index.txt
echo 1000 > /etc/mantis/ca/serial
# Generate CA private key
openssl genrsa -aes256 \
-out /etc/mantis/ca/private/ca.key 4096
chmod 400 /etc/mantis/ca/private/ca.key
# Generate CA certificate
openssl req -new -x509 \
-key /etc/mantis/ca/private/ca.key \
-out /etc/mantis/ca/certs/ca.crt \
-days 3650 \
-subj "/CN=Mantis Internal CA/O=Your Organization/C=US"

Create /etc/mantis/ca/openssl.cnf:

[ ca ]
default_ca = CA_default
[ CA_default ]
dir = /etc/mantis/ca
certs = $dir/certs
crl_dir = $dir/crl
new_certs_dir = $dir/newcerts
database = $dir/index.txt
serial = $dir/serial
private_key = $dir/private/ca.key
certificate = $dir/certs/ca.crt
default_days = 365
default_md = sha256
policy = policy_loose
[ policy_loose ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
[ client_cert ]
basicConstraints = CA:FALSE
keyUsage = digitalSignature
extendedKeyUsage = clientAuth
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
[tls]
auth_mode = "ca_signed"
# Server certificate
cert_path = "/etc/mantis/certs/thorax.crt"
key_path = "/etc/mantis/certs/thorax.key"
# CA certificate for validating clients
ca_cert_path = "/etc/mantis/ca/certs/ca.crt"
Terminal window
export MANTIS_TLS_AUTH_MODE=ca_signed
export MANTIS_TLS_CERT_PATH=/etc/mantis/certs/thorax.crt
export MANTIS_TLS_KEY_PATH=/etc/mantis/certs/thorax.key
export MANTIS_TLS_CA_CERT_PATH=/etc/mantis/ca/certs/ca.crt

CA-signed mode controls only how the client certificate is trusted at the TLS layer — it does not auto-approve registrations. New agents still register through Mandible and follow the normal approval path; the SHA-256 thumbprint is recorded for audit and revocation regardless of mode.

To approve agents automatically during onboarding, issue each agent a single-use registration token (configured via TARSUS__REGISTRATION__TOKEN), which approves the agent on registration. Otherwise, agents land in the pending queue for manual approval.

On the CA server:

Terminal window
# 1. Generate CSR on agent
# (Run this on the Tarsus server)
openssl req -new -nodes \
-keyout /etc/tarsus/key.pem \
-out /tmp/agent.csr \
-subj "/CN=web-prod-01/O=Production Team"
# 2. Copy CSR to CA server
scp /tmp/agent.csr ca-server:/tmp/
# 3. Sign certificate (on CA server)
openssl ca -config /etc/mantis/ca/openssl.cnf \
-extensions client_cert \
-in /tmp/agent.csr \
-out /tmp/agent.crt
# 4. Copy certificate back to agent
scp /tmp/agent.crt agent-server:/etc/tarsus/cert.pem
# 5. Copy CA certificate to agent
scp /etc/mantis/ca/certs/ca.crt agent-server:/etc/tarsus/ca.crt

Using HashiCorp Vault:

Terminal window
# Enable PKI secrets engine
vault secrets enable pki
vault secrets tune -max-lease-ttl=87600h pki
# Generate root CA
vault write pki/root/generate/internal \
common_name="Mantis CA" \
ttl=87600h
# Create role for agent certificates
vault write pki/roles/mantis-agent \
allowed_domains="mantis.local" \
allow_subdomains=true \
max_ttl=8760h \
key_type=rsa \
key_bits=2048
# Issue certificate for agent
vault write pki/issue/mantis-agent \
common_name="web-prod-01.mantis.local" \
ttl=8760h

Standard client certificate template:

FieldValue
CNAgent hostname or identifier
OTeam or tenant name
Key UsageDigital Signature
Extended Key UsageClient Authentication
Validity365 days
[tls]
cert_path = "/etc/tarsus/cert.pem"
key_path = "/etc/tarsus/key.pem"
# CA certificate for verifying Thorax
ca_cert_path = "/etc/tarsus/ca.crt"
Terminal window
# Install certificate files
cp agent.crt /etc/tarsus/cert.pem
cp agent.key /etc/tarsus/key.pem
cp ca.crt /etc/tarsus/ca.crt
# Set permissions
chmod 644 /etc/tarsus/cert.pem /etc/tarsus/ca.crt
chmod 600 /etc/tarsus/key.pem
chown root:root /etc/tarsus/*.pem /etc/tarsus/ca.crt

Using cert-manager (Kubernetes):

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: tarsus-client
spec:
secretName: tarsus-client-tls
duration: 8760h # 1 year
renewBefore: 720h # 30 days before
issuerRef:
name: mantis-ca
kind: ClusterIssuer
commonName: web-prod-01
usages:
- client auth
- digital signature

Certificate revocation options:

MethodDescriptionLatency
CRLCertificate Revocation ListMinutes-hours
OCSPOnline Certificate Status ProtocolReal-time
Mantis revocationThumbprint revocationImmediate

Revoke in Mantis (always works):

Terminal window
mantisctl cert revoke "<REGISTRATION_UUID>" \
--reason "Certificate compromised"
AspectRecommendation
CA key storageHSM or encrypted storage
CA accessLimited, audited access
CA backupSecure offline backup
CA validity10+ years

CA-signed mode provides layered security:

┌─────────────────────────────────────────────────────────────┐
│ Security Layers │
├─────────────────────────────────────────────────────────────┤
│ │
│ Layer 1: TLS encryption │
│ All communication encrypted │
│ │
│ Layer 2: CA validation │
│ Only CA-signed certificates accepted │
│ │
│ Layer 3: Thumbprint verification │
│ Certificate must be registered in Mantis │
│ │
│ Layer 4: Registration status │
│ Agent must be approved (not pending/revoked) │
│ │
└─────────────────────────────────────────────────────────────┘

In CA-signed mode, trust is established by the CA signature: any certificate signed by the configured CA is accepted at the TLS layer, and the SHA-256 thumbprint is checked at the application layer. There are no required_org / required_ou subject-field filters — restrict which certificates are issued by controlling your CA’s issuance policy.

For large deployments, use intermediate CAs:

Root CA (offline)
└── Intermediate CA (online)
├── Agent certificates
└── Server certificates

Trust multiple CAs for different environments:

[tls]
# Concatenate multiple CA certificates into a single file
ca_cert_path = "/etc/mantis/certs/combined-ca.crt"

Or concatenate CA certificates:

Terminal window
cat production-ca.crt staging-ca.crt > combined-ca.crt

Problem: certificate verify failed: unable to get local issuer certificate

Diagnosis:

Terminal window
# Verify certificate chain
openssl verify -CAfile /etc/mantis/ca/certs/ca.crt \
/etc/tarsus/cert.pem
# Check CA file on Thorax
cat /etc/mantis/certs/ca.crt

Solution:

Terminal window
# Ensure CA certificate matches
diff /etc/mantis/ca/certs/ca.crt /path/used/by/thorax/ca.crt
# If intermediate CA, include full chain
cat intermediate.crt root.crt > ca-chain.crt

Problem: Agent rejected after certificate renewal

Solution:

Terminal window
# In CA-signed mode trust derives from the CA signature, so a renewed cert from the same
# CA is accepted without re-registration. If a registration tracks a specific thumbprint,
# re-register the new thumbprint (revoke old, pre-register new):
mantisctl cert revoke "$OLD_REGISTRATION_ID" --reason "certificate renewal"
mantisctl cert pre-register --name "web-prod-01" --thumbprint "$(tarsus show-thumbprint)"

Problem: CA-signed clients register but stay pending approval

Check:

Terminal window
# Confirm the agent was given a registration token (token-based auto-approval)
journalctl -u mantis-tarsus | grep -i "registration"
# Otherwise approve it manually
mantisctl cert approve "$REGISTRATION_ID"

CA-signed mode does not auto-approve agents — use a single-use registration token (TARSUS__REGISTRATION__TOKEN) for automatic approval, or approve from the pending queue.

ErrorCauseSolution
certificate signed by unknown authorityCA not trustedAdd CA to ca_cert_path
certificate has expiredCert expiredRenew certificate
certificate is not valid for any namesWrong CNCheck certificate CN
registration pendingAwaiting approvalUse a token or manually approve
  1. Deploy CA infrastructure
  2. Configure Thorax for CA-signed mode
  3. Issue CA-signed certificates to agents
  4. Update agent configurations
  5. Agents re-connect with new certificates

auth_mode accepts only thumbprint or ca_signed — there is no combined “both” mode. Migration is a cutover: keep Thorax in thumbprint mode until every agent holds a CA-signed certificate, then switch Thorax to ca_signed and restart.

[tls]
# After all agents have CA-signed certs, switch to ca_signed and restart Thorax
auth_mode = "ca_signed"
ca_cert_path = "/etc/mantis/ca/certs/ca.crt"

If issues occur during migration:

# Revert to thumbprint mode
[tls]
auth_mode = "thumbprint"

Existing thumbprint registrations remain valid.

  • Store CA private key in HSM or encrypted storage
  • Limit CA access to authorized personnel
  • Maintain offline backups
  • Audit all certificate issuance
Certificate TypeRecommended Validity
Root CA10-20 years
Intermediate CA5-10 years
Agent certificates1 year

Use tools like:

  • cert-manager (Kubernetes)
  • HashiCorp Vault
  • Step CA
  • ACME protocol
Terminal window
# List client certificates expiring within the threshold (default 30 days)
curl -H "Authorization: Bearer $TOKEN" \
"https://api.mantis.example.com/api/v1/certificates/expiring?days=30"
  • Document CA renewal procedure
  • Test CA renewal in staging
  • Plan for certificate re-issuance
  • Communicate timeline to teams