Configuring BEL's trust-rotation operator
BEL provides automated trust anchor rotation in
the form of a Kubernetes operator that runs on the cluster and a companion
linkerd-trust CLI extension.
This guide walks through installing the operator, bootstrapping the initial trust bundle, verifying everything is healthy, and performing a full trust rotation end to end.
Prerequisites
The trust-rotation operator depends on a cluster that already has cert-manager producing the Linkerd trust anchor and identity issuer. If you are unfamiliar with how cert-manager fits into Linkerd’s identity story, read the cert-manager and trust-manager concepts guide first.
In particular, the operator expects to find the following resources at installation time:
- An
Issuernamedlinkerd-trust-root-issuerin the cert-manager namespace. - A
Certificatenamedlinkerd-trust-anchorin the cert-manager namespace. - A cluster-scoped
ClusterIssuernamedlinkerd-identity-issuer. - A
Certificatenamedlinkerd-identity-issuerin the Linkerd namespace.
The names can be overridden via flags on linkerd trust check, but matching the
defaults keeps the workflow simple.
These resources can be deployed with the help of the linkerd-cert-manager
chart, as explained below.
You will also need:
- Enterprise Linkerd 2.20 or later.
- The BEL CLI installed and configured.
- Cluster permissions sufficient to install Helm charts in the
linkerdnamespace and to create cluster-scoped CRDs.
Installing cert-manager and the Linkerd PKI
Install cert-manager:
helm repo add jetstack https://charts.jetstack.io --force-update
helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--set crds.enabled=true \
--wait
Install the linkerd-cert-manager chart. This bootstraps the cert-manager
Issuer and Certificate resources that produce Linkerd’s trust-anchor and
identity-issuer secrets:
helm install linkerd-cert-manager \
-n linkerd --create-namespace \
oci://ghcr.io/linkerd/charts/linkerd-cert-manager --wait
Installing the linkerd-trust CLI
The linkerd-trust CLI ships with the usual BEL install command, which installs
BEL and the buoyant extension; that now also installs the linkerd-trust
binary as another extension, accessible by invoking linkerd trust:
curl https://enterprise.buoyant.io/install | sh
linkerd trust --help
Bootstrapping the initial trust bundle
Linkerd reads its trust roots from the linkerd-identity-trust-roots ConfigMap.
Before the operator is running, this ConfigMap must be seeded from
cert-manager’s linkerd-trust-anchor Secret. The CLI’s bundle subcommand
renders the right manifest:
linkerd trust bundle | kubectl apply -f -
Installing Linkerd
With the PKI and trust bundle in place, install the Linkerd CRDs and control plane. The relevant settings tell Linkerd to consume the cert-manager-managed secrets:
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.1/experimental-install.yaml
helm repo add linkerd-buoyant https://helm.buoyant.cloud
helm repo update
helm install linkerd-crds \
-n linkerd --create-namespace \
linkerd-buoyant/linkerd-enterprise-crds
helm install linkerd-control-plane -n linkerd \
--set license=$BUOYANT_LICENSE \
--set identity.externalCA=true \
--set identity.issuer.scheme=kubernetes.io/tls \
linkerd-buoyant/linkerd-enterprise-control-plane
linkerd check
Installing the trust-rotation operator
The operator is published as two Helm charts: a CRD chart and the operator chart
proper. Install the CRD chart first; the operator chart assumes the
TrustAnchorRotation CRD already exists.
helm install -n linkerd trust-rotation-operator-crds \
oci://ghcr.io/buoyantio/charts/trust-rotation-operator-crds --devel --wait
helm install -n linkerd trust-rotation-operator \
oci://ghcr.io/buoyantio/charts/trust-rotation-operator --devel --wait
By default the operator chart creates a single TrustAnchorRotation resource
named cluster. You can watch its status in real time (this requires
yq):
watch -d -n 1 'kubectl get trustanchorrotations.trust.linkerd.io cluster \
-o yaml | yq .status'
Verifying the installation
linkerd trust check validates that cert-manager, the cert-manager-managed
Linkerd PKI resources, and the trust-rotation operator itself are all installed
and healthy:
linkerd trust check
The output mirrors linkerd check’s formatting and ends with either
Status check results are √ or Status check results are ×. You can also ask
for JSON output for automation:
linkerd trust check -o json
Because the CLI registers as a linkerd extension, linkerd check will invoke
linkerd trust check automatically and surface the same results alongside the
core Linkerd checks.
If you only want to confirm that the prerequisites for the operator are in place
(cert-manager and the cert-manager-managed resources), without checking whether
the operator itself is installed, use --pre:
linkerd trust check --pre
Performing a trust-anchor rotation
With the operator running, rotating the trust anchor reduces to two manual
cert-manager actions. This walkthrough uses
cert-manager’s cmctl CLI, but
any mechanism that triggers cert-manager renewal will work.
Step 1: Trigger trust-root renewal
cmctl renew -n cert-manager linkerd-trust-anchor
Shortly after this, the operator will detect the new trust root and proceed to:
- Copy the old trust root into
linkerd-previous-anchor. - Reconcile
linkerd-identity-trust-rootsto contain both the old and new roots. - Roll the Linkerd control plane so
linkerd-proxy-injectorobserves the expanded bundle.
TrustAnchorRotation.status.phase will move through RefreshingControlPlane
and into PropagatingTrustRoots.
Step 2: Restart your data plane
Meshed workloads need to be restarted so their newly injected proxies pick up
the expanded bundle. For example, with emojivoto:
kubectl -n emojivoto rollout restart deploy
When every meshed pod has the expanded bundle, the operator advances to
WaitingForIdentityRotation. You can confirm with:
linkerd trust inspect
which summarizes the current phase, convergence counts, and any pods that have not yet converged.
Step 3: Trigger identity-issuer renewal
This is the one intentional manual step that the operator does not automate.
cmctl renew -n linkerd linkerd-identity-issuer
Once the new issuer is in place, the operator advances to
RenewingWorkloadCerts and publishes an accelerated workload-certificate
refresh interval (5 minutes by default). When the data plane operator is also
installed, it honors this interval and pushes it into each meshed pod via
config.linkerd.io/proxy-additional-env, so workloads renew their identity
certificates passively and no explicit restart is needed at this step. See
Pairing with the data plane operator
for the broader picture.
Without the data plane operator, the accelerated interval has no consumer. At this step you can either wait up to 24 hours for proxies to renew their identity certificates at the normal interval, or restart meshed workloads explicitly so their proxies pick up certificates signed by the new issuer right away:
kubectl -n emojivoto rollout restart deploy
Step 4: Bundle reduction
When workloads have converged onto the new issuer, the operator automatically:
- Copies the current trust anchor into
linkerd-previous-anchor, so the two anchors are realigned. - Reduces
linkerd-identity-trust-rootsto a single root. - Rolls the Linkerd control plane onto the reduced bundle.
Phase transitions through RefreshingControlPlane and RemovingOldTrustRoots.
A final data plane restart completes the cleanup:
kubectl -n emojivoto rollout restart deploy
The status returns to Synced and linkerd trust inspect reports a clean
state.
Inspecting cluster state
linkerd trust inspect is the day-to-day tool for understanding where a cluster
is in its rotation lifecycle. It prints the current phase, convergence summary,
blocking message (if any), and a list of meshed non-control-plane pods whose
trust bundle annotation or live workload certificate has not converged.
linkerd trust inspect
linkerd trust inspect --output json
linkerd trust inspect --concurrency 50 --timeout 10s
The probe-based pod check connects to each pod’s proxy admin port over the mesh,
so --concurrency and --timeout let you tune how aggressively the CLI fans
out in large clusters.
Observability
The operator publishes Prometheus metrics on its admin endpoint, mirroring the
TrustAnchorRotation.status surface so you can alert on rotations that stall or
take too long:
trust_rotation_phase{phase="..."}: 1 for the active phase, 0 for every other phase.trust_rotation_trust_bundle_converged_podsandtrust_rotation_trust_bundle_target_pods: trust-bundle propagation progress.trust_rotation_workload_certificates_converged_podsandtrust_rotation_workload_certificates_target_pods: workload-certificate convergence on the active issuer.trust_rotation_active_issuer_info{fingerprint="..."}andtrust_rotation_previous_anchor_info{fingerprint="..."}: fingerprints of the current active issuer and previous anchor.trust_rotation_workload_certificate_refresh_interval_seconds: the accelerated refresh interval currently being pushed into the data plane; 0 when no override is in effect.
Recovery
The operator is designed to be resumable. Phase and progress live in
TrustAnchorRotation.status, so an operator restart picks up where it left off
without rewinding the workflow. If a rollout stalls, the operator parks in the
current phase and surfaces a human-readable blockingMessage on the resource.
Once the underlying issue is resolved (for example, a stuck pod is replaced),
reconciliation continues from the same point on the next loop.