Trust store and certificate management in the Graph Studio Operator
1. What is a trust store?
A trust store is the pool of Certificate Authority (CA) certificates that a process/JVM uses to decide whether a certificate presented by a peer (e.g. a TLS server it connects to) should be trusted. It is the counterpart of a keystore, which holds a process's own private key and certificate (used to present an identity), whereas the trust store holds other parties' CA certificates (used to verify an identity).
In the Graph Studio Operator, the trust store concept shows up as two related but distinct CR fields on the Anzo resource:
| Field | Purpose |
|---|---|
spec.tlsCerts / spec.certificate | The server's own TLS identity: private key + certificate (+ optional PKCS12 keystore) presented by the Graph Studio pod. |
spec.trustBundle | Name of a ConfigMap in the CR's namespace containing a pool of CA certificates that Graph Studio/AnzoGraph and its watcher sidecar should trust when acting as a client (e.g. talking to LDAP, Keycloak, other Graph Studio components, or any TLS endpoint signed by a private/internal CA). |
2. Why trust store management is used in Graph Studio
Graph Studio frequently runs in environments where it must both:
- Present a certificate to clients connecting to it (browsers, other Graph Studio/AnzoGraph nodes, REST/JDBC clients) — handled via
spec.certificate(cert-manager issued) orspec.tlsCerts(a pre-existing secret). - Trust CAs of other services it connects to — internal CAs, Keycloak, LDAP, corporate proxy/MITM CAs, etc. — handled via
spec.trustBundle.
3. How to use certificate and trust management in the operator
3.1 Server certificate (via cert-manager) — spec.certificate
Set spec.certificate on the Anzo CR using the upstream cert-manager Certificate spec fields (the operator embeds certv1.CertificateSpec directly). The operator:
- Creates a cert-manager
Certificateobject named after theAnzoCR (namespace/name are always taken from the owningAnzo, not fromspec.certificate.metadata). - If
spec.certificate.spec.keystoresis not set, the operator auto-adds a PKCS12 keystore section and creates aSecretholding the keystore password (CreateKeystorePass), so a JKS/PKCS12 keystore is always available for Anzo's Java runtime. - Mounts the resulting TLS secret (
spec.certificate.spec.secretName) into the pod once cert-manager reports the certificate asReady.
3.2 Pre-existing certificate secret — spec.tlsCerts
If you already manage certificates outside cert-manager, set spec.tlsCerts to the name of an existing Secret (in the CR's namespace) containing the TLS key/cert. This is mutually exclusive in practice with spec.certificate — prefer one or the other. spec.tlsCerts takes precedence when both are set.
3.3 Trust bundle (client-side trust store) — spec.trustBundle
- Create/maintain a
ConfigMapin the CR's namespace whose data values are PEM-encoded CA certificates. - Set
spec.trustBundle: <configmap-name>on theAnzoCR. - The operator handles mounting, sidecar injection, and live reload on
ConfigMapupdates — no pod restart required.
4. Prerequisites
- cert-manager must be installed in the cluster if you use
spec.certificate(the operator does not install cert-manager itself). See cert-manager installation docs. - An
IssuerorClusterIssuermust already exist in the cluster/namespace before creating theAnzoCR — the operator does not create issuers, it only references one viaspec.certificate.spec.issuerRef. - CA bundle
ConfigMapmust exist before settingspec.trustBundle(create it ahead of, or alongside, theAnzoCR). - The Anzo
ServiceAccountneeds no extra RBAC for these features beyond what the operator's default install grants (it managesCertificate,Secret, andConfigMapobjects it owns). - If relying on the auto-created PKCS12 keystore password secret, no extra setup is needed; if you want to control the keystore password secret/key yourself, set
spec.certificate.spec.keystores.pkcs12explicitly (see snippet below).
5. Custom Resource YAML snippet
5.1 Prerequisite: Issuer (or ClusterIssuer)
apiVersion: cert-manager.io/v1
kind: Issuer # use ClusterIssuer for a cluster-wide issuer
metadata:
name: my-ca-issuer
namespace: "${NAMESPACE}"
spec:
ca:
secretName: my-ca-key-pair # Secret containing tls.crt/tls.key of your CA, created beforehand
5.2 Prerequisite: trust bundle ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: bundle
namespace: "${NAMESPACE}"
data:
ca.pem: |
-----BEGIN CERTIFICATE-----
...PEM-encoded CA certificate(s) to trust...
-----END CERTIFICATE-----
5.3 Anzo CR with certificate + trust bundle configured
apiVersion: anzo.cambridgesemantics.com/v2
kind: Anzo
metadata:
name: anzo
namespace: "${NAMESPACE}"
spec:
nodeConfig:
spec:
replicas: 1
serviceName: anzo
selector:
matchLabels:
app: "anzo"
template:
metadata:
labels:
app: "anzo"
spec:
serviceAccountName: anzo-operator
containers:
- name: anzo
image: artifacts.altair.com/graph-docker/anzo:6.3.1
resources:
requests:
cpu: "1000m"
memory: "4000Mi"
imagePullPolicy: Always
role: AnzoServer
jsonActivation: true
initJSON: |-
{
"sysadminUser": "k8s://anzo-anzo/admin_user",
"password": "k8s://anzo-anzo/admin_password",
"hostname": "anzo",
"serverId": "${SERVER_ID}",
"licenseEncoded": "${CSI_LICENSE}"
}
jvmMemory: 4096m
credentials: mysecret1
# --- Server identity: requested from cert-manager using the Issuer above ---
certificate:
metadata:
name: pkcs12-certs
namespace: "${NAMESPACE}"
spec:
isCA: false
secretName: pkcs12
commonName: what.ever
dnsNames:
- localhost
- anzo-anzo-lb.ns1
- anzo-anzo-lb
issuerRef:
# Issuer/ClusterIssuer must already exist in the cluster (see prerequisites)
name: my-ca-issuer
# kind: ClusterIssuer
group: cert-manager.io
# Optional: control the PKCS12 keystore password secret/key yourself.
# If omitted, the operator auto-creates a keystore and a password secret.
# keystores:
# pkcs12:
# create: true
# passwordSecretRef:
# name: keystorepass
# key: password
# --- Client-side trust store: pool of CA certs Anzo should trust ---
# ConfigMap "bundle" must already exist in the same namespace (see prerequisites)
trustBundle: bundle
# --- Alternative to `certificate`: use a pre-existing TLS secret instead ---
# tlsCerts: pkcs12-secret