Deploy Software Trust Manager support for customer-hosted Private CA
Uses a container-based deployment model and is distributed as a Docker image, enabling consistent and portable execution across environments. It supports deployment in standalone Docker setups as well as orchestration platforms such as Kubernetes and OpenShift, and can also be deployed using Docker Swarm for scalable container management.
Before configuring Software Trust Manager daemon, ensure that you have:
Kubernetes cluster access with kubectl configured (or OpenShift cluster with oc CLI)
Helm 3.x installed
Docker installed (to pull/load the daemon image)
Outbound HTTPS access to Software Trust Manager cloud
Internal network access from Software Trust Manager daemon to customer-hosted Private CA
Kubernetes TLS secret for daemon ingress/service TLS (or OpenShift Route with TLS)
DigiCert Software Trust Manager Cloud service user API key (account admin) and customer-hosted Private CA API key available as secure secrets
Note
config.jobs.enabled: true is required for asynchronous operations (signing jobs, revocation, and keypair discovery), so you shoul not disable it.
This procedure walks you through deploying Software Trust Manager to support customer-hosted Private CA.
Obtain the daemon image
Use one of the following options:
# Option A: Pull from Docker Hub docker pull digicertinc/stm-daemon:<version> # Option B: Load from an offline image archive docker load -i stm-daemon_<version>.tar
Create an external values file
Create a file named
stm-daemon-values.yamloutside the image with the required deployment settings:image: repository: digicertinc/stm-daemon tag: "<version>" pullPolicy: IfNotPresent service: type: LoadBalancer port: 8443 ingress: enabled: true className: "nginx" hosts: - host: daemon.stm.cluster.local paths: - path: / pathType: Prefix tls: - secretName: stm-daemon-tls hosts: - daemon.stm.cluster.local # Optional: Use hostAliases only if custom DNS resolution is needed # hostAliases: # - ip: "<customer-ca-ip>" # hostnames: # - "ca.one.digicert.com" config: stmCloud: host: "one.digicert.com" port: 443 scheme: "https" caManager: host: "ca.one.digicert.com" port: 443 scheme: "https" enablePartitionSupport: true server: port: 8443 tlsEnabled: true logLevel: "debug" hsmRouting: enabled: true hierarchySync: enabled: true accountId: "<account-id>" intervalMinutes: 60 partitionSync: enabled: true intervalMinutes: 60 jobs: enabled: true pollIntervalSeconds: 20 proxy: timeoutSeconds: 30 secrets: create: true tlsCertSecret: "stm-daemon-tls" # DigiCert Software Trust Manager Cloud service user API key (account admin) for authenticating with DigiCert Software Trust Manager Cloud stmApiKey: "<stm-cloud-service-user-api-key>" caManagerApiKey: "<ca-manager-key>"Note
Backend TLS verification is always enforced. Ensure the customer-hosted private CA presents a certificate trusted by the daemon.
Here are the values in
Values in stm-daemon-values.yamlfile:Value
Description
image.repositoryContainer image repository name
image.tagContainer image version tag to deploy
image.pullPolicyImage pull behavior (
IfNotPresent,Always, orNever)service.typeKubernetes service type (
LoadBalancer,ClusterIP, orNodePort)service.portService port exposed by Kubernetes for the daemon
ingress.enabledEnables/disables ingress creation
ingress.classNameIngress controller class (for example
nginx)ingress.hosts[].hostThe production hostname used by clients to reach Software Trust Manager daemon (for example stm-daemon.example.com).
ingress.hosts[].paths[]URL paths routed to the daemon service
ingress.tls[].secretNameTLS secret containing
tls.crtandtls.keyfor ingress hostingress.tls[].hosts[]Hosts covered by the ingress TLS certificate
hostAliases[].ipIP mapped inside pod
/etc/hostshostAliases[].hostnames[]Hostnames resolved to that IP from inside daemon pod
config.stmCloud.hostSoftware Trust Manager cloud hostname the daemon connects to (one.digicert.com).
config.stmCloud.portSoftware Trust Manager cloud port (usually
443)config.stmCloud.schemeProtocol for Software Trust Manager cloud (
httpsrecommended)config.caManager.hostCustomer-hosted Private CA hostname or IP (for example ca.one.digicert.com).
config.caManager.portCustomer-hosted Private CA port
config.caManager.schemeProtocol to customer-hosted Private CA (
httporhttps)config.caManager.enablePartitionSupportEnables partition sync support
config.server.portDaemon listener port inside container
config.server.tlsEnabledEnables HTTPS listener on daemon
config.server.logLevelRuntime logging level (
debug,info,warn,error)config.hsmRouting.enabledRoutes supported operations to customer-hosted Private CA CA/HSM path
config.hierarchySync.enabledEnables CA hierarchy sync background job
config.hierarchySync.accountIdAccount ID used for hierarchy sync scope
config.hierarchySync.intervalMinutesHierarchy sync interval
config.partitionSync.enabledEnables HSM partition sync background job
config.partitionSync.intervalMinutesPartition sync interval
config.jobs.enabledEnables daemon background job polling/execution
config.jobs.pollIntervalSecondsJob poll interval
config.proxy.timeoutSecondsBackend request timeout
secrets.createCreates Kubernetes secret from values in this file when
truesecrets.tlsCertSecretExisting TLS secret name mounted into daemon pod (
tls.crt/tls.key)secrets.stmApiKeyDigiCert Software Trust Manager Cloud service user API key (account admin) for authenticating with DigiCert Software Trust Manager Cloud (when
secrets.create=true)secrets.caManagerApiKeyCustomer-hosted Private CA API key value (when
secrets.create=true)Deploy with Helm chart folder
Deploy when the Helm chart folder is available
use the following command if you have Helm chart folder locally available:
helm upgrade --install stm-daemon ./helm/stm-daemon \ --namespace stm-daemon \ --create-namespace \ --values ./stm-daemon-values.yaml
Deploy when the Helm chart folder is not available
If the image is provided without the chart files, use a chart package supplied separately (for example
stm-daemon-<chart-version>.tgz):helm upgrade --install stm-daemon ./stm-daemon-<chart-version>.tgz \ --namespace stm-daemon \ --create-namespace \ --values ./stm-daemon-values.yaml
Note
Provide a TLS certificate issued by a trusted CA for the daemon hostname via the
stm-daemon-tlssecret referenced bysecrets.tlsCertSecret. The certificate is preserved across upgradesDeploy on OpenShift
OpenShift deployment uses the same Helm chart with OpenShift-specific configurations. Use
ocCLI instead ofkubectl.Prerequisites for OpenShift:
1. OpenShift cluster access with
ocCLI configured2. Helm 3.x installed
3. Appropriate permissions to create projects and deploy workloads
4. OpenShift route or ingress for external access
Create OpenShift project
oc new-project stm-daemon
Configure OpenShift-specific values
Create
stm-daemon-openshift-values.yamlwith OpenShift route configuration:image: repository: digicertinc/stm-daemon tag: "<version>" pullPolicy: IfNotPresent # Use ClusterIP service with OpenShift Route service: type: ClusterIP port: 8443 # OpenShift Route configuration (alternative to Ingress) route: enabled: true host: daemon.stm.apps.cluster.local tls: termination: passthrough insecureEdgeTerminationPolicy: Redirect # If using Ingress instead of Route ingress: enabled: false # Optional: hostAliases for custom DNS resolution # hostAliases: # - ip: "<customer-ca-ip>" # hostnames: # - "ca.one.digicert.com" config: stmCloud: host: "one.digicert.com" port: 443 scheme: "https" caManager: host: "ca.one.digicert.com" port: 443 scheme: "https" enablePartitionSupport: true server: port: 8443 tlsEnabled: true logLevel: "info" hsmRouting: enabled: true hierarchySync: enabled: true accountId: "<account-id>" intervalMinutes: 60 partitionSync: enabled: true intervalMinutes: 60 jobs: enabled: true pollIntervalSeconds: 20 proxy: timeoutSeconds: 30 skipBackendTlsVerify: false secrets: create: true tlsCertSecret: "stm-daemon-tls" # DigiCert Software Trust Manager Cloud service user API key (account admin) for authenticating with DigiCert Software Trust Manager Cloud stmApiKey: "<stm-cloud-service-user-api-key>" caManagerApiKey: "<ca-manager-key>" # OpenShift security context (if needed) securityContext: runAsNonRoot: true allowPrivilegeEscalation: false capabilities: drop: - ALLCreate
ConfigMapCreate
ConfigMapmounted at/run/machine-idfor registrattion.oc create configmap stm-daemon-machine-id \ --from-literal=machine-id=$(uuidgen | tr -d '-') \ -n stm-daemon
Deploy using Helm on OpenShift
helm upgrade --install stm-daemon ./helm/stm-daemon \ --namespace stm-daemon \ --values ./stm-daemon-openshift-values.yaml --set-json 'extraVolumes=[{"name":"machine-id","configMap":{"name":"stm-daemon-machine-id"}}]'Deploy using packaged chart
You must reuse the same UUID while performing upgrades.
helm upgrade --install stm-daemon ./stm-daemon-<chart-version>.tgz \ --namespace stm-daemon \ --values ./stm-daemon-openshift-values.yaml
Verify OpenShift deployment
# Check deployment status oc get pods,svc,route -n stm-daemon # View route URL oc get route stm-daemon -n stm-daemon -o jsonpath='{.spec.host}' # Check logs oc logs -n stm-daemon -l app.kubernetes.io/name=stm-daemon --tail=100OpenShift route vs ingress
OpenShift supports both routes (native) and ingress controllers:
- Route (recommended for OpenShift): Native OpenShift resource with integrated load balancing
- Ingress: Standard Kubernetes resource, requires ingress controller
For route configuration, set
route.enabled: trueandingress.enabled: falsein your values file.Security Context Constraints (SCC)
If your OpenShift cluster has strict SCC policies, you may need to adjust the security context or bind a custom SCC:
For clusters that requires restricted security context:
podSecurityContext: runAsNonRoot: true runAsUser: null # OpenShift assigns UID from the project range fsGroup: null # OpenShift assigns GID seccompProfile: type: RuntimeDefaultFor clusters that require an explicit binding:
oc adm policy add-scc-to-user <custom-scc> -z stm-daemon -n stm-daemon
Update client_tools to call Software Trust Manager daemon
After deployment, configure smctl to call Software Trust Manager daemon instead of Software Trust Manager cloud directly.
For Linux/macOS shell:
export SM_HOST="https://daemon.stm.cluster.local" export SM_API_KEY="<user-api-key>"
For Windows PowerShell:
$env:SM_HOST="https://daemon.stm.cluster.local" $env:SM_API_KEY="<user-api-key>"
Run a read-only command to validate keypair listing via daemon:
smctl kp ls
Run a healthcheck through
smctl:smctl healthcheck
If your customer-hosted HSM already contains a keypair created outside Software Trust Manager, you can discover it directly from the Software Trust Manager online portal and surface it on the Software Trust Manager cloud. Once discovered, the key is available for signing and certificate operations. The discovered key is imported with the CUSTOMER_HOSTED_PRIVATE_CA_DEFAULT_USAGE usage type.
Prerequsites:
The Software Trust Manager daemon is deployed and healthy (see Get started).
config.jobs.enabled: true and config.partitionSync.enabled: true in your values file.
The daemon can reach the Customer-hosted Private CA (CA Manager).
Your user has the GENERATE_SM_KEYPAIR or MANAGE_SM_KEYPAIR permission.
Initiate discovery
On the Keypair list page in the Software Trust Manager online portal, select Discover HSM keypair, then provide the requested details along with either the public key of the key on the HSM or its label.
Search on the customer-hosted HSM
Software Trust Manager cloud and the Software Trust Manager daemon search for the specified key on the Customer-hosted HSM using the customer-hosted Private CA. The daemon processes the request on the interval configured by
config.jobs.pollIntervalSeconds.Verify the discovered key
Once found, the key is surfaced on STM cloud and appears on the keypair list page. You can also confirm it through the daemon:
smctl kp ls
The discovered key appears with usage type
CUSTOMER_HOSTED_PRIVATE_CA_DEFAULT_USAGE.Note
Search by public key or label. Provide either the public key of the HSM key or its label to locate it.
Duplicates are skipped. A key that already exists in the account (matching public key or alias) is not re-imported.
Key not found. If no matching key exists on the HSM, discovery returns without importing anything; verify the public key/label and the target partition.
Verify workload health
Kubernetes:
kubectl get pods,svc,ingress -n stm-daemon
OpenShift:
oc get pods,svc,route -n stm-daemon
Verify daemon health endpoint
Kubernetes:
kubectl port-forward -n stm-daemon svc/stm-daemon 8443:8443 curl -k https://localhost:8443/health
OpenShift:
oc port-forward -n stm-daemon svc/stm-daemon 8443:8443 curl -k https://localhost:8443/health
Configure the client to use the daemon endpoint
Configure the client to use the daemon endpoint and run a read-only command.
Check runtime logs
Kubernetes:
# Recent logs kubectl logs -n stm-daemon -l app.kubernetes.io/name=stm-daemon --tail=200 # Stream logs continuously kubectl logs -n stm-daemon -l app.kubernetes.io/name=stm-daemon -f
OpenShift:
# Recent logs oc logs -n stm-daemon -l app.kubernetes.io/name=stm-daemon --tail=200 # Stream logs continuously oc logs -n stm-daemon -l app.kubernetes.io/name=stm-daemon -f
Note
Configure the daemon with a TLS certificate issued by a trusted CA (or one recognized by the client trust store) for the production daemon hostname. Ensure the daemon hostname is DNS-resolvable from the client.
Error | Solution |
|---|---|
Pod does not start | Verify |
Helm render fails when HSM routing is enabled | Provide customer-hosted Private CA host and customer-hosted Private CA key secret wiring. |
Health check fails | Validate ingress/service routing and certificate chain trust |
Sync does not run | Verify |
OpenShift: Pod security issues | Check Security Context Constraints (SCC). May need to adjust |
OpenShift: Route not accessible | Verify route host is DNS-resolvable and TLS termination is set to |
Discovery does not complete | Verify |
OpenShift: Pod stuck in CreateContainerConfigError | Security context constraints violation; keep |
Helm install fails: TLS secret cannot be imported | A manually created |
Discovery does not complete | Confirm |
Key not found | Verify the public key/label is correct and the key exists on the Customer-hosted HSM/partition. |
Key not visible after discovery | Verify the daemon can reach the Customer-hosted Private CA, and confirm the user permission and account. |
Kubernetes:
To uninstall the Software Trust Manager daemon, use the following command:
helm uninstall stm-daemon -n stm-daemon
Optional cleanup:
kubectl delete namespace stm-daemon
OpenShift:
To uninstall the Software Trust Manager daemon, use the following command:
helm uninstall stm-daemon -n stm-daemon
Optional cleanup:
oc delete project stm-daemon