docs(README, metrics): announce JKS/JCEKS support and x509_jks_passphrase_failures_total

This commit is contained in:
Thibault VINCENT
2026-05-13 17:55:30 +02:00
committed by Thibault VINCENT
parent 17bf1dca2c
commit a163963eeb
5 changed files with 56 additions and 28 deletions
+4
View File
@@ -41,6 +41,7 @@ cluster it observes, but equally happy as a standalone binary.
- **Memory-safe Kubernetes watch** — RAM stays flat instead of spiking; on Secret-heavy clusters, memory limits drop ~10×.
- **Richer PKCS#12 wiring** — full keystore + truststore coverage, flexible passphrase sourcing.
- **DER consumption** — raw cert / CRL blobs as served by HTTP CRL Distribution Points are now first-class inputs.
- **JKS / JCEKS support** — Java KeyStore and JCEKS stores.
- **CRL freshness monitoring** — Certificate Revocation Lists are tracked alongside certs, with alerts before they go stale.
- **Surface workload metadata** — lift watched resource labels onto emitted certificate series.
- **Supply-chain hardened** — SLSA Build L3 provenance, cosign-signed binaries, images and chart, SBOM attestations.
@@ -55,6 +56,9 @@ cluster it observes, but equally happy as a standalone binary.
- **PKCS#12** keystores and truststores, with passphrase pulled from a
sibling key in the same Secret, an external file, a cross-namespace
Secret reference, or none (`tryEmptyPassphrase`).
- **JKS / JCEKS** keystores and truststores — magic-byte auto-detection
between JKS and JCEKS; passphrase from a sibling key, external file,
or `tryEmptyPassphrase`.
- **Certificate Revocation Lists** — `X509 CRL` PEM blocks (intermixed
freely with `CERTIFICATE` blocks) and raw DER `*.crl` files
(`format: der`) are parsed into the dedicated `x509_crl_*` family so
+8 -5
View File
@@ -50,6 +50,7 @@ cluster it observes, but equally happy as a standalone binary.
- **Memory-safe Kubernetes watch** — RAM stays flat instead of spiking; on Secret-heavy clusters, memory limits drop ~10×.
- **Richer PKCS#12 wiring** — full keystore + truststore coverage, flexible passphrase sourcing.
- **DER consumption** — raw cert / CRL blobs as served by HTTP CRL Distribution Points are now first-class inputs.
- **JKS / JCEKS support** — Java KeyStore and JCEKS stores.
- **CRL freshness monitoring** — Certificate Revocation Lists are tracked alongside certs, with alerts before they go stale.
- **Surface workload metadata** — lift watched resource labels onto emitted certificate series.
- **Supply-chain hardened** — SLSA Build L3 provenance, cosign-signed binaries, images and chart, SBOM attestations.
@@ -64,6 +65,9 @@ cluster it observes, but equally happy as a standalone binary.
- **PKCS#12** keystores and truststores, with passphrase pulled from a
sibling key in the same Secret, an external file, a cross-namespace
Secret reference, or none (`tryEmptyPassphrase`).
- **JKS / JCEKS** keystores and truststores — magic-byte auto-detection
between JKS and JCEKS; passphrase from a sibling key, external file,
or `tryEmptyPassphrase`.
- **Certificate Revocation Lists** — `X509 CRL` PEM blocks (intermixed
freely with `CERTIFICATE` blocks) and raw DER `*.crl` files
(`format: der`) are parsed into the dedicated `x509_crl_*` family so
@@ -165,15 +169,14 @@ The default install runs a single Deployment watching
`kubernetes.io/tls` Secrets across all namespaces — disable with
`secretsExporter.enabled: false`.
### Multiple Secret types, PKCS#12, and JKS
### Multiple Secret types and PKCS#12
`secretsExporter.secretTypes` accepts any mix of types and keys: a
literal `key` (regex `^<key>$` is built for you) or a `keyPatterns`
list for full regex control, with optional `format: pkcs12` plus a
`pkcs12:` block, or `format: jks` plus a `jks:` block. Passphrases
are pulled from a sibling Secret key (`pkcs12.passphraseKey` /
`jks.passphraseKey`), an external file, a cross-namespace Secret ref
(pkcs12 only), or skipped entirely with `tryEmptyPassphrase: true` for
`pkcs12:` block. Passphrases are pulled from a sibling Secret key
(`pkcs12.passphraseKey`), an external file, a cross-namespace Secret
ref, or skipped entirely with `tryEmptyPassphrase: true` for
passwordless keystores.
### Watching ConfigMaps
+4
View File
@@ -50,6 +50,7 @@ cluster it observes, but equally happy as a standalone binary.
- **Memory-safe Kubernetes watch** — RAM stays flat instead of spiking; on Secret-heavy clusters, memory limits drop ~10×.
- **Richer PKCS#12 wiring** — full keystore + truststore coverage, flexible passphrase sourcing.
- **DER consumption** — raw cert / CRL blobs as served by HTTP CRL Distribution Points are now first-class inputs.
- **JKS / JCEKS support** — Java KeyStore and JCEKS stores.
- **CRL freshness monitoring** — Certificate Revocation Lists are tracked alongside certs, with alerts before they go stale.
- **Surface workload metadata** — lift watched resource labels onto emitted certificate series.
- **Supply-chain hardened** — SLSA Build L3 provenance, cosign-signed binaries, images and chart, SBOM attestations.
@@ -64,6 +65,9 @@ cluster it observes, but equally happy as a standalone binary.
- **PKCS#12** keystores and truststores, with passphrase pulled from a
sibling key in the same Secret, an external file, a cross-namespace
Secret reference, or none (`tryEmptyPassphrase`).
- **JKS / JCEKS** keystores and truststores — magic-byte auto-detection
between JKS and JCEKS; passphrase from a sibling key, external file,
or `tryEmptyPassphrase`.
- **Certificate Revocation Lists** — `X509 CRL` PEM blocks (intermixed
freely with `CERTIFICATE` blocks) and raw DER `*.crl` files
(`format: der`) are parsed into the dedicated `x509_crl_*` family so
+19 -19
View File
@@ -1188,6 +1188,25 @@
],
"required": []
},
"jks": {
"additionalProperties": false,
"properties": {
"passphrase": {
"type": "string"
},
"passphraseFile": {
"type": "string"
},
"passphraseKey": {
"type": "string"
},
"tryEmptyPassphrase": {
"type": "boolean"
}
},
"required": [],
"type": "object"
},
"key": {
"type": "string"
},
@@ -1235,25 +1254,6 @@
"required": [],
"type": "object"
},
"jks": {
"additionalProperties": false,
"properties": {
"passphrase": {
"type": "string"
},
"passphraseFile": {
"type": "string"
},
"passphraseKey": {
"type": "string"
},
"tryEmptyPassphrase": {
"type": "boolean"
}
},
"required": [],
"type": "object"
},
"type": {
"minLength": 1,
"type": "string"
+21 -4
View File
@@ -37,6 +37,7 @@ The exporter splits its output into four families:
| Per-source | `x509_source_errors_total` | counter | always |
| Per-source | `x509_kube_watch_resyncs_total` | counter | Kubernetes sources only |
| Per-source | `x509_pkcs12_passphrase_failures_total` | counter | auto: when any source declares `format: pkcs12` |
| Per-source | `x509_jks_passphrase_failures_total` | counter | auto: when any source declares `format: jks` |
| Per-source | `x509_cert_collision_total` | counter | always |
| Diagnostic | `x509_parse_duration_seconds` | histogram | `metrics.exposeDiagnostics: true` |
| Diagnostic | `x509_kube_request_duration_seconds` | histogram | `metrics.exposeDiagnostics: true`, Kubernetes sources only |
@@ -410,6 +411,21 @@ was wrong.
A spike usually means a Secret was rotated but the sibling passphrase
key wasn't, or a `passphraseFile` was stale.
### `x509_jks_passphrase_failures_total`
JKS / JCEKS keystore decoding attempts that failed because the passphrase
was wrong.
- **Type**: counter
- **Labels**: `source_name`
- **Auto-gated**: registered only when at least one source declares
`format: jks` (file source `formats:`, kubernetes source
`secrets.types[].format`, or `configMaps.format`). Deployments
without JKS don't see the metric in `/metrics` at all.
A spike usually means a Secret was rotated but the sibling passphrase
key wasn't, or a `passphraseFile` was stale.
### `x509_cert_collision_total`
Number of times the registry detected two distinct certificates that
@@ -512,9 +528,9 @@ etc.) into the internal certificate representation.
- **Buckets**: `0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 5` seconds
- **Emitted only when `metrics.exposeDiagnostics` is `true`.**
`format` takes one of `pem` or `pkcs12`. PKCS#12 is meaningfully slower
because of the KDF — expect millisecond-range parse times on PEM and
double-digit-millisecond on PKCS#12.
`format` takes one of `pem`, `pkcs12`, `der`, or `jks`. PKCS#12 and JKS are
meaningfully slower because of their KDF — expect millisecond-range parse
times on PEM/DER and double-digit-millisecond on PKCS#12/JKS.
### `x509_kube_request_duration_seconds`
@@ -604,7 +620,8 @@ metrics provider with the synthetic `source_kind="kubernetes"`,
| `bad_pem` | any source running the PEM parser (file, kubeconfig, kube-secret with `format: pem`, kube-configmap) | PEM block present but malformed |
| `no_certificate_found` | same | The bundle decoded successfully but contained no `CERTIFICATE` block |
| `bad_pkcs12` | any source running the PKCS#12 parser (file with `formats: [pkcs12]`, kube-secret / kube-configmap with `format: pkcs12`) | PKCS#12 archive malformed or uses an unsupported algorithm |
| `bad_passphrase` | same | PKCS#12 archive structurally valid but the configured passphrase was wrong |
| `bad_jks` | any source running the JKS parser (file with `formats: [jks]`, kube-secret / kube-configmap with `format: jks`) | JKS / JCEKS archive malformed or magic bytes not recognised |
| `bad_passphrase` | PKCS#12 or JKS parser | Archive structurally valid but the configured passphrase was wrong |
| `read_failed` | `file`, `kubeconfig` | Generic I/O error opening or reading a file |
| `permission_denied` | `file` | EACCES on a watched path |
| `not_found` | `file` | Path disappeared between announcement and read |