README
¶
OpenTelemetry Collector PKI engine receiver
This OpenTelemetry Collector Receiver scrapes metrics for OpenBao and Vault PKI engines by auto-discovering mounts, issuers and certificate revocation lists (CRLs). It supports setups where the CRLs are hosted outside of the secret store, e.g., in multi-tier PKI setups with an offline root.
flowchart LR
OTEL[OTEL Collector]
subgraph Vault [OpenBao/Vault]
direction TB
subgraph PKI1 [PKI engine]
direction LR
I1[Issuer]
C1[CRL]
end
end
subgraph External [External]
direction TB
style External stroke-dasharray: 5 5
CRL_Ext[CRL]
end
OTEL -- "1. Scrape" --> Vault
I1 -- "2. Reference" --> CRL_Ext
OTEL -- "3. Scrape" --> CRL_Ext
Features
- Auto discover engines of type
pki, issuers and CRLs (base & delta). - Collect referenced CRLs hosted outside of the secret store.
- Tested against OpenBao and Vault.
- Support for namespaces.
- Resolve AIA URL templating.
- Implemented CRL protocols:
- HTTP
- LDAP
- Efficient CRL fetching:
- Prevents thundering hurds.
- Respects
ETagandLast-ModifiedHTTP headers.
- Authenticate via:
- Token
- AppRole
- Kubernetes
- JWT
Metrics
For collected metrics and attributes, see documentation.md.
Considerations
-
This receiver doesn't cover leaf certificates. It's recommended to monitor leaf certificates where they are actively used via e.g. tlscheckreceiver. When using cert-manager on Kubernetes consider collecting
Certificateresources via the k8sobjectsreceiver. -
Tidy metrics which includes counters for issued and revoked certificates can be collected via the exposed telemetry endpoints by the secret store and scraped via e.g. Prometheus jobs. See
secrets.pki.tidy.*metrics (OpenBao | Vault). For extra large deployments consider disabling metricpkiengine.mount.certificates_storedand rely on Tidy metrics as secret stores efficiently track changes to maintain internal counters.
Installation
Adding components to an OTeL Collector requires building a custom collector via OpenTelemetry Collector builder (or ocb for short).
When building a custom collector you can add this receiver to the manifest file like the following:
receivers:
- gomod: github.com/cvdtang/pkienginereceiver v0.150.0
Configuration
Example
receivers:
pkiengine:
address: https://openbao.example.com
namespace: tenant-a
collection_interval: 5m
crl:
retries: 1
auth:
type: approle
approle:
role_id: "my-role-id"
secret_id: "my-secret-id"
Options
address(string): (default =http://127.0.0.1:8200) Address of secret store. Must be formatted as{protocol}://{host}.collection_interval(string): (default =5m) How frequently the scraper should be called. This value must be a string readable by Golang's time.ParseDuration. Valid time units arens,us(orµs),ms,s,m,h.initial_delay(string): (default =0s) Initial start delay for the scraper.timeout(string): Optional value used to set scraper's context deadline.namespace(string): (default ="") Secret store namespace path.match_regex(string): (default =".*") Regular expression in RE2 syntax of allowed mount paths, e.g.pki/v1/ica/v\d.concurrency_limit(uint): Maximum number of concurrent worker tasks (mount/issuer/CRL). Defaults to the number of CPU cores determined by GOMAXPROCS.
CRL
crl.enabled(bool): (default =true) Enable CRL processing.crl.scrape_parent(bool): (default =true) Enable scraping issuer-role (parent) CRLs referenced in issuer certificates. Whenfalse, only subject-role CRLs from issuer API fields are scraped.crl.cache_size(uint): (default =50) Maximum number of entries in the LRU cache for processed CRLs. Set to0to disable CRL caching.crl.timeout(string): (default =5s) Maximum time to wait for a CRL fetch response.crl.retries(uint): (default =0) Number of retry attempts for CRL fetching after the initial attempt.crl.retry_interval(string): (default =3s) Wait interval between CRL fetch retry attempts.
Authentication
auth.type(string): (default =token) Authentication method to use. Allowed values:token,approle,kubernetesandjwt.
Token
auth.token.token(string): Static authentication token.
receivers:
pkiengine:
auth:
type: token
token:
token: ${env:TOKEN}
AppRole
auth.approle.role_id(string): AppRole RoleID.auth.approle.secret_id(string): AppRole SecretID.auth.approle.wrapping_token(bool): (default =false) Use single-use token that prevents the underlying credential from being exposed in transit.auth.approle.mount_path(string): (default =approle) Mount path of the AppRole auth engine.
receivers:
pkiengine:
auth:
type: approle
approle:
role_id: ${env:APPROLE_ROLE_ID}
secret_id: ${env:APPROLE_SECRET_ID}
Kubernetes
auth.kubernetes.role_name(string): Name of the secret store role with Kubernetes service account bound to it.auth.kubernetes.service_account_token(string): Override Kubernetes service account JWT.auth.kubernetes.service_account_token_path(string): Path where the Kubernetes service account token is mounted in the pod.auth.kubernetes.mount_path(string): (default =kubernetes) Mount path of the Kubernetes auth engine.
The kubernetes auth method can be used to authenticate with the secret stores using a Bound Service Account Token. Defaults to /var/run/secrets/kubernetes.io/serviceaccount/token:
receivers:
pkiengine:
auth:
type: kubernetes
kubernetes:
role_name: my-role
Alternatively, long-lived tokens can be used:
receivers:
pkiengine:
auth:
type: kubernetes
kubernetes:
role_name: my-role
service_account_token: ${env:SERVICE_ACCOUNT_TOKEN}
JWT
auth.jwt.role_name(string): Name of the role in OpenBao/Vault with JWT claims bound to it.auth.jwt.token(string): JWT token to use for authentication.auth.jwt.token_path(string): Path to a file containing the JWT token.auth.jwt.mount_path(string): (default =jwt) Mount path of the JWT auth engine.
From value:
receivers:
pkiengine:
auth:
type: jwt
jwt:
role_name: my-role
token: ${env:JWT_TOKEN}
From file:
receivers:
pkiengine:
auth:
type: jwt
jwt:
role_name: my-role
token_path: /my/token
Metrics & Resource Attributes
metrics.<name>.enabled(bool): (default =true) Enable/disable emitting the specified metric.resource_attributes.<name>.enabled(bool): (default =true) Enable/disable emitting the specified resource attribute.
Additionally, the Vault Go SDK environment variables can be set, e.g. VAULT_SKIP_VERIFY.
Authorization policy
Required permissions used by the receiver.
Note that the pki/* paths can differ depending on where the PKI engines are mounted.
# ref: https://developer.hashicorp.com/vault/api-docs/system/mounts#list-mounted-secrets-engines
path "sys/mounts" {
capabilities = [ "read" ]
}
# ref: https://developer.hashicorp.com/vault/api-docs/secret/pki#read-cluster-configuration
path "pki/config/cluster" {
capabilities = [ "read" ]
}
# ref: https://developer.hashicorp.com/vault/api-docs/secret/pki#list-certificates
path "pki/certs" {
capabilities = [ "list" ]
}
# ref: https://developer.hashicorp.com/vault/api-docs/secret/pki#read-issuer
path "pki/issuer/+" {
capabilities = [ "read" ]
}
Troubleshooting
Enable OTeL Collector debug logging:
receivers:
pkiengine:
address: http://127.0.0.1:8200
initial_delay: 0s
collection_interval: 1m
service:
telemetry:
logs:
level: debug
pipelines:
metrics:
receivers: [pkiengine]
exporters: [debug]
Development
For development, internals and testing, see DEVELOPMENT.md.