Permissions
checkfleet permissions
What each check needs on the system it watches, and what it does not. Derived from the queries and endpoints the modules actually issue.
checkfleet perms --config checkfleet.yml prints the subset below for the
modules you actually run, in text, markdown or JSON — send that to whoever
owns the system instead of this whole page.
Every module is read-only: no check writes to the system it inspects.
Credentials always come from the environment (*_env, ${VAR}), never
from the config file.
Needs no credential (17)
These reach the target over the network and read what it already exposes.
cassandra
Speaks the CQL native handshake (OPTIONS/STARTUP) and stops at READY or AUTHENTICATE.
Not needed: No credential and no keyspace access: reaching the AUTHENTICATE frame already proves the node accepts CQL.
certs
Opens a TLS connection to the port and reads the presented certificate. No credential.
Not needed: No account, no API access. The chain is not validated (the expiry is read even from an untrusted chain), so no trust store changes either.
dns
Sends DNS queries to the configured resolvers. No credential.
Not needed: No zone transfer (AXFR) and no write: only ordinary lookups.
grpc
Calls the standard gRPC Health Checking service over HTTP/2.
Not needed: No access to any application RPC.
haproxy
GETs the stats page in CSV form (/stats;csv), which must be enabled in haproxy.cfg.
Not needed: No admin access to the stats socket: the check reads, it never enables or disables a server.
The exact policy depends on how the target is deployed, so treat the above as guidance rather than a recipe.
http
Issues the configured request (GET by default) to the URL.
Not needed: Whatever the endpoint itself requires is the operator’s choice; checkfleet asks for no privilege of its own.
ingest
RTMP or SRT handshake only — it stops before publishing a stream.
Not needed: No stream key and no publish permission: the check answers ‘can a streamer connect’, not ‘can it publish’.
keycloak
Reads the health endpoint and the public OIDC discovery document of each realm (/realms/<realm>/.well-known/openid-configuration).
Not needed: No admin API access, no client secret, no service account: both endpoints are public by design.
memcached
Sends the text-protocol stats command.
Not needed: No key is read or written. If SASL is enabled the check needs an account that may run stats.
nats
Reads the HTTP monitoring endpoints /varz and /jsz?meta=1 on the monitoring port (8222 by default).
Not needed: No NATS client credential: the monitoring port is separate from the client port, and no subject is subscribed or published.
ntp
One SNTP request per server. No credential.
Not needed: The local clock is never set — checkfleet reports the offset, it does not correct it.
patroni
GETs the Patroni REST API /cluster endpoint.
Not needed: No database credential, and none of Patroni’s write endpoints (switchover, restart, reinitialise) is ever called.
The exact policy depends on how the target is deployed, so treat the above as guidance rather than a recipe.
smtp
Connects, reads the greeting, sends EHLO and optionally negotiates STARTTLS.
Not needed: It never authenticates and never sends mail — no mailbox, no relay permission.
stream
HTTP GET of the HLS/DASH manifest, and of the variant playlists it references.
Not needed: No publishing credential: the check reads the delivery side, never the ingest side.
tcp
Opens a TCP connection (optionally TLS) and optionally reads the banner. No credential.
Not needed: Nothing is sent to the service beyond the connection itself.
tls
TLS handshake against the target. No credential.
Not needed: No account and no server-side configuration.
vault
Reads /v1/sys/seal-status and /v1/sys/health, which Vault serves unauthenticated.
Not needed: No token is required. One may be configured, and if set it is sent, but the two endpoints used need no policy — no secret engine, no read of any path.
The exact policy depends on how the target is deployed, so treat the above as guidance rather than a recipe.
Needs an account (12)
clickhouse
Calls /ping, runs SELECT version() and reads system.replicas.
CREATE USER checkfleet IDENTIFIED BY '<from your secret store>';
GRANT SELECT ON system.replicas TO checkfleet;
Not needed: No access to any user database or table, and no SYSTEM privileges (no restart, no replica manipulation).
consul
Reads /v1/status/leader, /v1/status/peers, /v1/health/state/<state> and any configured /v1/kv/<key>. With ACLs on, a token whose policy grants read on those.
# consul acl policy create -name checkfleet -rules -
agent_prefix "" { policy = "read" }
node_prefix "" { policy = "read" }
service_prefix "" { policy = "read" }
key_prefix "<only the keys in kv_keys>" { policy = "read" }
Not needed: No write on anything, no operator policy, and key read scoped to the keys you actually configured rather than the whole KV tree.
The exact policy depends on how the target is deployed, so treat the above as guidance rather than a recipe.
elasticsearch
GETs /_cluster/health and /_cat/allocation. The built-in cluster privilege monitor covers both.
PUT /_security/role/checkfleet {"cluster":["monitor"]}
Not needed: No index privilege at all: no document is read, and no index is created, written or deleted.
etcd
Calls /health, /v3/maintenance/status and /v3/cluster/member/list over the JSON gateway. With auth enabled it first calls /v3/auth/authenticate.
etcdctl role add checkfleet
etcdctl user add checkfleet
etcdctl user grant-role checkfleet checkfleet
Not needed: No key read or write: the endpoints used report cluster state, not data. Grant no key range to the role.
The exact policy depends on how the target is deployed, so treat the above as guidance rather than a recipe.
kafka
Reads cluster metadata and, when consumer groups are configured, their committed offsets and lag.
kafka-acls --add --allow-principal User:checkfleet --operation Describe --cluster
kafka-acls --add --allow-principal User:checkfleet --operation Describe --topic '*'
kafka-acls --add --allow-principal User:checkfleet --operation Describe --group '*'
Not needed: No Read or Write on any topic: the check never consumes or produces a message, it reads metadata and offsets.
ldap
Binds (anonymously, or with the configured account) and optionally runs one search under base_dn.
Not needed: No write of any kind, and read scoped to the subtree you point it at. When no sanity search is configured, the bind alone is enough and the account needs no read at all.
The exact policy depends on how the target is deployed, so treat the above as guidance rather than a recipe.
mongodb
Runs the serverStatus and replSetGetStatus admin commands. The built-in clusterMonitor role covers both.
db.getSiblingDB("admin").createUser({user:"checkfleet", pwd:"<from your secret store>", roles:[{role:"clusterMonitor", db:"admin"}]})
Not needed: No read on any application database, no clusterManager, no write. clusterMonitor cannot see document data.
mysql
Runs SELECT VERSION(), SELECT @@global.read_only, SHOW GLOBAL STATUS, SHOW GLOBAL VARIABLES and, on a replica, SHOW REPLICA STATUS.
CREATE USER 'checkfleet'@'%' IDENTIFIED BY '<from your secret store>';
GRANT PROCESS, REPLICATION CLIENT ON *.* TO 'checkfleet'@'%';
Not needed: No SELECT on any schema, no SUPER, no RELOAD, no write. REPLICATION CLIENT grants the status view only — not the ability to change replication.
postgres
Connects to one database and reads server statistics: pg_is_in_recovery(), pg_database, pg_stat_activity, pg_replication_slots, pg_stat_replication and max_connections. The built-in pg_monitor role covers all of it. Without it the check still connects, but a non-superuser sees the replication views empty — so the replica-lag and inactive-slot findings would report nothing wrong on a primary that has a problem.
CREATE ROLE checkfleet LOGIN PASSWORD '<from your secret store>';
GRANT pg_monitor TO checkfleet;
GRANT CONNECT ON DATABASE postgres TO checkfleet;
Not needed: No SELECT on any user table, no schema access, no SUPERUSER, no write of any kind. pg_monitor is read-only by construction.
The exact policy depends on how the target is deployed, so treat the above as guidance rather than a recipe.
rabbitmq
GETs the management API /api/overview, /api/nodes and /api/queues. The monitoring tag is exactly this level.
rabbitmqctl add_user checkfleet '<from your secret store>'
rabbitmqctl set_user_tags checkfleet monitoring
Not needed: No administrator or management tag, and no configure/write/read permission on any vhost: queues are counted, never consumed from.
redis
Sends INFO. On Redis 6+ an ACL user restricted to that one command is enough.
ACL SETUSER checkfleet on >'<from your secret store>' ~ -@all +info
Not needed: No keyspace access (~ matches no key), no CONFIG, no KEYS, no administrative or write command.
s3
HEADs the bucket and, when a sentinel object is configured, reads its metadata.
{"Effect":"Allow","Action":["s3:ListBucket"],"Resource":"arn:aws:s3:::<bucket>"}
{"Effect":"Allow","Action":["s3:GetObject"],"Resource":"arn:aws:s3:::<bucket>/<sentinel object>"}
Not needed: No s3:PutObject, no s3:DeleteObject, and GetObject scoped to the single sentinel key rather than the bucket.