Kubernetes
The Kubernetes collector reads the certificates cert-manager manages in your clusters, so workload certificates — the ones issued and renewed automatically, without anyone requesting them — count toward your post-quantum readiness reporting.
It is read-only, and it never reads Kubernetes Secrets, so the private keys your certificates reference are out of reach. That is a structural property of the connector, not a setting you need to get right.
What it collects
| Resource | What Mesh takes from it |
|---|---|
Certificate (cert-manager) | The certificate inventory — key algorithm, key size, validity and renewal settings |
Issuer / ClusterIssuer (cert-manager) | What signed each certificate. Resolved by name for every certificate; listing them in full is optional |
Pod | Container image references, so a certificate can be tied to the workload using it |
ReplicaSet (apps) | One owner hop, Pod → ReplicaSet → Deployment, so an image is attributed to a stable workload name instead of a pod hash that changes on every rollout |
Namespace (kube-system) | Cluster identity, so two clusters are not confused for one another. Optional — if it is not granted, collection continues |
Beyond certificates and issuers, the collector reads Pod container image references and resolves the workload that owns them. Worth knowing before you approve a cluster-wide credential — it reads what is running, not only what is issued.
Certificates removed from a cluster are retired in Mesh after the next complete collection.
Before you start
- cert-manager installed in the cluster. If its custom resources are not registered, Mesh reports that it found none, rather than failing.
- An API server URL reachable from Mesh, over HTTPS.
- A read-only credential — a service account token, or a client certificate and key. Creating one is covered below.
Decide your scope first
One decision shapes everything else: which namespaces you want inventoried. It determines the Kubernetes permission you create, so it is worth settling before you start.
| You want | Leave Namespaces | You grant |
|---|---|---|
| The whole cluster | Empty | A ClusterRole and ClusterRoleBinding |
| Only certain namespaces | A comma-separated list | A Role and RoleBinding in each one |
Leaving Namespaces empty makes one cluster-wide request per resource kind.
The Kubernetes API server does not quietly narrow that to the namespaces
your credential happens to cover — it refuses the whole request with 403, and
the collection fails.
So if you grant per-namespace Roles, you must also list those namespaces in the Namespaces field. Granting narrowly and leaving the field empty is the most common way this connector fails its first run.
Create the read-only access
First create the service account Mesh will authenticate as. This is the same for either scope.
apiVersion: v1
kind: ServiceAccount
metadata:
name: axiad-mesh-crypto
namespace: kube-system
Then apply one of the following, matching the scope you chose above.
Whole cluster
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: axiad-mesh-crypto-reader
rules:
- apiGroups: ["cert-manager.io"]
resources: ["certificates", "issuers", "clusterissuers"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
- apiGroups: ["apps"]
resources: ["replicasets"]
verbs: ["get"]
- apiGroups: [""]
resources: ["namespaces"]
verbs: ["get"]
- apiGroups: ["apiextensions.k8s.io"]
resources: ["customresourcedefinitions"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: axiad-mesh-crypto-reader
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: axiad-mesh-crypto-reader
subjects:
- kind: ServiceAccount
name: axiad-mesh-crypto
namespace: kube-system
Selected namespaces
Apply a Role and RoleBinding in each namespace you want inventoried,
and list those same namespaces in the Namespaces field.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: axiad-mesh-crypto-reader
namespace: my-namespace
rules:
- apiGroups: ["cert-manager.io"]
resources: ["certificates", "issuers"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
- apiGroups: ["apps"]
resources: ["replicasets"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: axiad-mesh-crypto-reader
namespace: my-namespace
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: axiad-mesh-crypto-reader
subjects:
- kind: ServiceAccount
name: axiad-mesh-crypto
namespace: kube-system
ClusterIssuer is cluster-scoped, so it cannot be granted by a namespaced
Role. If you are scoping to namespaces, leave Enable Cluster Issuers off.
Get a token for the service account
kubectl -n kube-system create token axiad-mesh-crypto --duration=8760h
--duration is a request, not a guaranteeThe API server may issue a token that expires sooner than you asked for — many clusters cap bound-token lifetimes well below a year. Do not work out the renewal date from the flag you typed.
Read the real expiry from the token's own exp claim, and set your reminder
from that. Decode it locally — the token is a live credential, so do not paste
it into an online decoder:
TOKEN=$(kubectl -n kube-system create token axiad-mesh-crypto --duration=8760h)
echo "$TOKEN" | python3 -c '
import base64, datetime, json, sys
payload = sys.stdin.read().strip().split(".")[1]
payload += "=" * (-len(payload) % 4)
exp = json.loads(base64.urlsafe_b64decode(payload))["exp"]
print(datetime.datetime.fromtimestamp(exp, datetime.timezone.utc))'
An expired token stops collection, and the connector cannot warn you in advance — so replace it before that date.
Add the connector in Mesh
- Go to Settings › Connectors, then select Add connector.
- Under Crypto collectors, choose Kubernetes.
- Fill in the fields below.
- Select Test configuration, then Add & connect.
Connection fields
| Field | Required | What to enter |
|---|---|---|
| API Server URL | Yes | The cluster's API server, for example https://host:6443. Must be https:// — the credential travels with every request, so plain HTTP is refused |
| Bearer Token | One of | A service account token. Use either this or the client certificate and key — not both |
| Client Certificate (PEM) | One of | Sign in with a client certificate instead of a token. Supply the key below as well |
| Client Key (PEM) | With cert | The private key for that client certificate |
| CA Certificate (PEM) | No | The cluster's CA, so Mesh can verify it. Leave empty if the API server presents a certificate that is already publicly trusted |
| Skip TLS Verification | No | Default off. Lab use only — never enable it against a production cluster |
| Namespaces | No | Comma-separated. Empty means cluster-wide — see Decide your scope first |
| Enable Issuers | No | Default off. Also list namespaced Issuer resources |
| Enable Cluster Issuers | No | Default off. Also list cluster-scoped ClusterIssuer resources |
| cert-manager API Group | No | Default cert-manager.io. Change only for a forked or pre-GA cert-manager |
| cert-manager API Version | No | Default v1. Change only for a pre-GA cert-manager |
| Collection frequency | No | How often Mesh re-reads the cluster, as a duration such as 1h |
Paste credentials as text, not file paths — Mesh has no access to your cluster's filesystem. The token and client key are write-only: once saved, they are never shown again.
Enable Issuers and Enable Cluster Issuers control whether Mesh lists issuers in full. The issuer behind each certificate is resolved by name regardless, so leaving both off does not cost you the issuer of a certificate you collected.
Check the first collection
After Add & connect, open Data source syncs and find the connector's first run. A healthy first run reports success for each part it was granted.
Then look for the certificates themselves in your crypto asset inventory, and in the PQC Readiness Index widget on your dashboard. A cluster with cert-manager installed but no certificates issued yet reports a successful run that collected nothing — that is the expected result, not a failure.
Troubleshooting
| What you see | What it means |
|---|---|
| Run fails with a permission error, and you granted per-namespace Roles | Namespaces was left empty, so Mesh made a cluster-wide request. List your namespaces in that field, or grant a ClusterRole |
| One namespace missing, the rest fine | The credential has no Role in that namespace. Mesh records it as inaccessible and continues with the others |
| Certificates collected, but not attributed to a workload | get on replicasets was not granted. Images are still collected; only the owning Deployment is unresolved |
| "No certificates found", but you know they exist | cert-manager's custom resources are not registered in this cluster, or they are registered under a non-default API group or version. Check cert-manager API Group and API Version |
| Collection worked, then stopped | The token expired. Issue a new one and update the connector |
| TLS or certificate-verification errors | The API server presents a certificate Mesh does not trust. Paste the cluster CA into CA Certificate (PEM). Do not reach for Skip TLS Verification against production |
If a run still fails after these, see Troubleshooting & support.