Skip to content

feat: dedicated least-privilege replication ACL user - #34

Merged
melancholictheory merged 1 commit into
mainfrom
feat/repl-user
Aug 3, 2026
Merged

feat: dedicated least-privilege replication ACL user#34
melancholictheory merged 1 commit into
mainfrom
feat/repl-user

Conversation

@melancholictheory

Copy link
Copy Markdown
Owner

Replicas authenticated to their primary as the full-access default user (masterauth only). This adds a dedicated replicator ACL user granting only +psync +replconf +ping with no key access, and points replicas at it via masteruser. A leaked replication credential can now do nothing but replicate, not read or write your data. It mirrors the Sentinel user (S1) and the upstream community operator's dedicated replication user.

The user is seeded in users.acl for every replicating topology (Replication, Cluster, Sentinel). Standalone has no replica link and gets neither the user nor masteruser. The operator's own control connections keep using the default user, so nothing about failover, survey, or the ValkeyACL reconciler changes.

Two safety issues a cross-model (Grok) review surfaced, fixed here

  • Password rotation now re-keys the managed non-default users (the replication user, and the Sentinel user) alongside default, additive-then-cutover. Without it, masteruser=replicator would WRONGPASS the moment a live rotation dropped the old password. That is a regression this change would otherwise introduce, and it was already a latent gap for the Sentinel user.
  • replicator and sentinel-user are reserved: the ValkeyACL webhook rejects them and the reconciler never DELUSERs them, so a user-defined ACL cannot wipe the credential the operator depends on.

Verification

  • Live on a dedicated k3d cluster: a Replication cluster's replicas link as replicator, master_link_status:up, data replicates, no NOPERM in the logs.
  • Docker harness for the rotation sequence: after a full add-new plus cutover rotation, a forced replica re-handshake re-authenticates as replicator under the new password with no WRONGPASS.
  • Unit tests cover the render/seed/masteruser scoping (all topologies plus a Standalone negative and a no-key-glob assertion), the reserved-name webhook rejections, and the managed-user set.
  • Full envtest and make lint are clean.

Replicas authenticated to their primary as the full-access `default` user
(masterauth only). Seed a dedicated `replicator` ACL user instead — granting just
`+psync +replconf +ping` with no key access — and point replicas at it via
`masteruser`. A leaked replication credential can now do nothing but replicate,
not read or write your data. It mirrors the Sentinel user (S1) and the upstream
community operator's dedicated replication user.

Seeded in users.acl for every replicating topology (Replication, Cluster,
Sentinel); Standalone has no replica link and gets neither the user nor
masteruser. The operator's own control connections keep using the default user.

Two safety issues a cross-model (Grok) review surfaced are fixed here:

- Password rotation now re-keys the managed non-default users (replicator, and
  the Sentinel user) alongside default, additive-then-cutover. Without this,
  masteruser=replicator would WRONGPASS the moment a live rotation dropped the old
  password — a regression this change would otherwise introduce, and a pre-existing
  gap for the Sentinel user.
- `replicator` and `sentinel-user` are reserved: the ValkeyACL webhook rejects
  them and the reconciler never DELUSERs them, so a user-defined ACL can't wipe
  the credential the operator depends on.

Verified live on a dedicated k3d cluster (a Replication cluster's replicas link
as replicator, master_link_status:up, data replicates, no NOPERM) and with a
Docker harness for the rotation sequence (after a full add-new + cutover rotation,
a forced replica re-handshake re-authenticates as replicator under the new
password with no WRONGPASS). Unit tests cover the render/seed/masteruser scoping,
the reserved-name webhook rejections, and the managed-user set. Full envtest +
lint clean.
@melancholictheory
melancholictheory merged commit b625331 into main Aug 3, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant