Skip to content

(feat) support Mutual TLS (mTLS) certificate-based ACL authentication - #242

Open
sandeepkunusoth wants to merge 5 commits into
valkey-io:mainfrom
sandeepkunusoth:mtls_client_auth
Open

(feat) support Mutual TLS (mTLS) certificate-based ACL authentication#242
sandeepkunusoth wants to merge 5 commits into
valkey-io:mainfrom
sandeepkunusoth:mtls_client_auth

Conversation

@sandeepkunusoth

@sandeepkunusoth sandeepkunusoth commented Jun 10, 2026

Copy link
Copy Markdown
Member

This PR closes (#243)

Summary

This PR extends the spec.tls configuration options for ValkeyCluster resources to support client certificate enforcement (mTLS) and automatic user mapping based on the client certificate's Common Name (CN).

Features

  • added mTLS client auth support

Implementation

  • Added two optional fields to TLSConfig in api/v1alpha1/valkeycluster_types.go backed by validated string enums:
    • authClients: Optional / Required / Disabled (Defaults to Optional). Maps to Valkey directive tls-auth-clients.
    • authClientsUser: CN/ DNS/ Disabled (Defaults to Disabled). Maps to Valkey directive tls-auth-clients-user.

Testing

  • Added an e2e test case inside test/e2e/valkeycluster_tls_test.go running a scenario that validates successful mTLS connections and tests using client certificate.

Checklist

Before submitting the PR make sure the following are checked:

  • This Pull Request is related to one issue.
  • Commit message explains what changed and why
  • Tests are added or updated.
  • Documentation files are updated.
  • I have run pre-commit locally (pre-commit run --all-files or hooks on commit)

@sandeepkunusoth sandeepkunusoth changed the title (feat) support strict Mutual TLS (mTLS) certificate-based ACL authentication (feat) support Mutual TLS (mTLS) certificate-based ACL authentication Jun 10, 2026
@sandeepkunusoth
sandeepkunusoth marked this pull request as ready for review June 10, 2026 07:31
@greptile-apps

greptile-apps Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds mTLS controls for Valkey TLS client authentication. The main changes are:

  • New spec.tls.authClients and spec.tls.authClientsUser fields with CRD defaults, enums, and validation.
  • Valkey config rendering for tls-auth-clients and tls-auth-clients-user.
  • Controller and metrics exporter TLS client certificates for mTLS-enabled clusters.
  • Documentation and e2e coverage for CN-based certificate ACL mapping.

Confidence Score: 4/5

This PR is close, with one contained compatibility bug to fix before merging.

The main mTLS implementation is coherent and covered by docs, CRD validation, controller updates, and e2e tests. The score is limited by the empty AuthClients rendering path, which changes behavior for existing or un-defaulted TLS specs.

Files Needing Attention: internal/controller/config.go; internal/controller/valkeynode_resources_test.go

T-Rex T-Rex Logs

What T-Rex did

  • I reproduced TLS default rendering using a focused Go harness; the empty AuthClients path renders TLS directives but omits tls-auth-clients, while the explicit Optional path renders tls-auth-clients optional, isolating the failure to the empty-field path.
  • I collected and inspected environment and test artifacts, noting that the capability check failed due to missing tools, while the API test passed, the focused controller test passed, and the directive probe produced the expected explicit mTLS directives.

View all artifacts

T-Rex Ran code and verified through T-Rex

Important Files Changed

Filename Overview
api/v1alpha1/valkeycluster_types.go Adds TLS auth enum types, directive mapping helpers, defaults, and CEL validation for certificate user mapping.
config/crd/bases/valkey.io_valkeyclusters.yaml Regenerates the ValkeyCluster CRD schema with TLS auth defaults, enums, and validation.
config/crd/bases/valkey.io_valkeynodes.yaml Regenerates the ValkeyNode CRD schema with the shared TLS auth fields and validation.
internal/controller/config.go Renders new Valkey TLS auth directives, but omits the previous tls-auth-clients optional behavior when the new field is empty.
internal/controller/metrics_exporter.go Passes the mounted TLS certificate and key to the exporter so it can connect when mTLS is required.
internal/controller/utils.go Loads the TLS certificate and key into controller Valkey client TLS configs so internal connections can satisfy mTLS.
internal/controller/valkeynode_resources_test.go Adds standalone ValkeyNode mTLS URI rendering coverage, but removes coverage for empty TLS config preserving tls-auth-clients optional.
test/e2e/valkeycluster_tls_test.go Adds end-to-end coverage for TLS auth defaults, CN-based ACL mapping, mTLS rejection without certs, exporter, and replication paths.

Sequence Diagram

sequenceDiagram
participant User as Operator user
participant API as Kubernetes API
participant Reconciler as ValkeyCluster/ValkeyNode reconcilers
participant Config as ConfigMap valkey.conf
participant Pod as Valkey pod
participant Client as TLS client/exporter/operator

User->>API: Apply TLS spec with authClients/authClientsUser
API->>API: Default enums and validate disabled+mapping rule
API->>Reconciler: Reconcile TLS-enabled resource
Reconciler->>Config: Render tls-auth-clients and tls-auth-clients-user
Reconciler->>Pod: Mount TLS Secret and roll/update pod
Client->>Pod: Connect with CA and optional client cert
Pod-->>Client: Enforce mTLS and map CN/URI to ACL user when configured
Loading

Reviews (8): Last reviewed commit: "fixed review comments" | Re-trigger Greptile

Comment thread api/v1alpha1/valkeycluster_types.go
@sandeepkunusoth
sandeepkunusoth marked this pull request as draft June 10, 2026 07:39
@melancholictheory

Copy link
Copy Markdown
Contributor

nice, the two-enum shape (authClients + authClientsUser) maps cleanly onto the valkey directives. one thing worth calling out in the design, since it bit us: turning on authClients: Required with authClientsUser: CN authenticates every client connection, including the operator's own and a couple of internal ones, so each of those needs a cert whose CN maps to an ACL user with the right grants. concretely:

so the feature is really "every internal connection becomes authenticated", and the CRD probably wants the operator/probe/replication certs provisioned and CN-mapped before Required can be safely set, otherwise enabling it bricks the cluster it's managing.

two smaller notes:

  • tls-auth-clients-user is valkey 9.0+, so authClientsUser: CN should be version-gated (rendered only on >= 9.0), since older servers reject the unknown directive on boot.
  • CN to user mapping is sensitive to cert rotation: cert-manager renewals have to preserve the CN, or the mapping breaks and the client drops to the default user on renew. worth a line in docs/tls.md.

happy to share how we wired the operator's own client cert if useful.

@sandeepkunusoth

Copy link
Copy Markdown
Member Author

Sorry for delay in response.

tls-auth-clients-user is valkey 9.0+, so authClientsUser: CN should be version-gated (rendered only on >= 9.0), since older servers reject the unknown directive on boot.

The operator currently only supports Valkey 9.0+, so authClientsUser isn't introducing a new compatibility issue today. That said, we will be adding explicit version gating as part of a separate follow-up for the upcoming 9.1.0+ features.

coming to operator users, health checks, and replication

i fixed this by reusing valkey tls server certs on clients side for operator user, redis exporter. i think we need to check more on if we want to move operator user to use mtls client cert as part of seperate Issue. Health checks already pass client certs. updated e2e tests to test scenario with TLSAuthClients yes scenario and tls-auth-clients-user: yes. added point to docs/tls.md.

@sandeepkunusoth
sandeepkunusoth marked this pull request as ready for review July 5, 2026 09:14
Comment thread api/v1alpha1/valkeycluster_types.go Outdated
Comment thread test/e2e/valkeycluster_tls_test.go

@bjosv bjosv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a quick look as we will have this under spec.networking.tls, but avoiding yes/no and using Required/Optional/Disabled as discussed in the issue has the additional benefit of minimizing the yaml-parser annoyance (bool vs string).

Comment thread docs/mtls.md
Comment thread docs/tls.md Outdated
Comment thread docs/tls.md Outdated
Signed-off-by: Sandeep Kunusoth <sandeepkunsoth000@gmail.com>
… to use valkey server certs. and updated CRD values to match valkey.conf directives

Signed-off-by: Sandeep Kunusoth <sandeepkunsoth000@gmail.com>
…ated docs

Signed-off-by: Sandeep Kunusoth <sandeepkunsoth000@gmail.com>
Signed-off-by: Sandeep Kunusoth <sandeepkunsoth000@gmail.com>
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

mTLS authentication

Layer / File(s) Summary
TLS API and CRD contract
api/v1alpha1/valkeycluster_types.go, config/crd/bases/valkey.io_valkeyclusters.yaml, config/crd/bases/valkey.io_valkeynodes.yaml
Adds client-authentication modes, certificate-to-ACL-user mapping, defaults, enum constraints, and CEL validation.
Controller TLS wiring
internal/controller/config.go, internal/controller/utils.go, internal/controller/metrics_exporter.go
Renders TLS directives, validates client certificate/key pairs, and passes client credentials to the metrics exporter.
Controller validation and rendering tests
internal/controller/config_test.go, internal/controller/valkeynode_resources_test.go
Tests admission validation, defaulting, TLS directive rendering, unset TLS behavior, and URI-based authentication.
End-to-end mTLS coverage
test/e2e/valkeycluster_tls_test.go
Creates certificates, verifies CN-based ACL authentication and replication, and rejects clients without certificates.
TLS configuration documentation
docs/mtls.md, docs/valkeycluster.md
Documents settings, certificate issuance, client connections, rendered directives, security requirements, and the mTLS guide link.

Sequence Diagram(s)

sequenceDiagram
  participant E2ETest
  participant Kubernetes
  participant ValkeyCluster
  participant TLSClient
  E2ETest->>Kubernetes: Create CA and TLS certificates
  E2ETest->>ValkeyCluster: Apply required client authentication and CN mapping
  TLSClient->>ValkeyCluster: Connect with client certificate
  ValkeyCluster->>TLSClient: Map certificate CN to ACL user
  TLSClient->>ValkeyCluster: Run ACL WHOAMI and replication write
  TLSClient->>ValkeyCluster: Connect without client certificate
  ValkeyCluster-->>TLSClient: Reject connection
Loading

Possibly related issues

  • valkey-io/valkey-operator issue 243: The pull request implements the issue’s mTLS certificate-authentication feature, including authClients and authClientsUser.

Suggested reviewers: jdheyburn

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly identifies the main change: support for mutual TLS certificate-based ACL authentication.
Description check ✅ Passed The description covers the issue, summary, features, implementation, testing, and checklist, but omits limitations and lists DNS instead of the implemented URI value.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Nitpick comments (5)
internal/controller/config.go (1)

83-90: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Fix the spelling in the comment.

"cetificate" must be "certificate". The conditional rendering itself is correct: when AuthClients is empty the operator emits no directive and Valkey applies its own default, which matches the API default.

✏️ Proposed fix
 		if tls.AuthClientsUser != "" {
-			// Automatically authenticate TLS clients as ACL users based on their cetificate fields.
+			// Automatically authenticate TLS clients as ACL users based on their certificate fields.
 			config["tls-auth-clients-user"] = string(tls.AuthClientsUser)
 		}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/controller/config.go` around lines 83 - 90, Correct the spelling in
the comment above the tls.AuthClientsUser conditional: change “cetificate” to
“certificate”. Leave the conditional logic and configuration rendering
unchanged.
internal/controller/config_test.go (2)

122-163: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a case for an unset AuthClients.

buildManagedConfig skips tls-auth-clients when AuthClients is the empty string. No test covers that branch. A regression that always emits the directive would pass the current suite.

🧪 Proposed test
+	It("omits tls-auth-clients directives when the fields are unset", func() {
+		cluster := getSampleCluster()
+		cluster.Spec.TLS = &valkeyiov1alpha1.TLSConfig{
+			Certificate: valkeyiov1alpha1.CertificateRef{SecretName: "tls-secret"},
+		}
+		conf := buildServerConfig(cluster)
+		Expect(conf).To(ContainSubstring("tls-port"))
+		Expect(conf).NotTo(ContainSubstring("tls-auth-clients"))
+	})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/controller/config_test.go` around lines 122 - 163, Add a test case
within the TLS client-auth Describe block covering a TLSConfig with a
certificate and AuthClients left unset, then call buildServerConfig and assert
that tls-auth-clients is absent. Keep TLS configured so the assertion
specifically exercises the empty AuthClients branch in buildManagedConfig.

89-101: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Align the two rejection assertions.

Line 93 checks authClientsUser=CN while line 100 checks authClientsUser=CN/URI. Both substrings match the same CEL message, so the CN case asserts less than the URI case. Use the same substring in both tests so a message change fails both consistently.

♻️ Proposed change
-		Expect(err.Error()).To(ContainSubstring("authClientsUser=CN"))
+		Expect(err.Error()).To(ContainSubstring("authClientsUser=CN/URI"))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/controller/config_test.go` around lines 89 - 101, Update the
rejection assertion in the “rejects authClients=no with authClientsUser=CN” test
to use the same “authClientsUser=CN/URI” substring as the URI case, keeping both
tests aligned with the shared CEL validation message.
test/e2e/valkeycluster_tls_test.go (2)

478-481: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Loosen the ACL WHOAMI output assertion.

utils.Run returns CombinedOutput, so any warning that valkey-cli writes to stderr is included. A single warning line makes Equal("alice") fail even though the mapping worked. Match the user name instead.

🧪 Proposed fix
-		Expect(strings.TrimSpace(out)).To(Equal("alice"),
+		Expect(strings.TrimSpace(out)).To(ContainSubstring("alice"),
 			"ACL WHOAMI should resolve to the user mapped from the certificate's CN")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/e2e/valkeycluster_tls_test.go` around lines 478 - 481, Update the ACL
WHOAMI assertion in the mTLS client log check to match the expected user name
within the combined output rather than requiring an exact "alice" string. Keep
the existing trimmed output and error validation, and preserve the
certificate-CN mapping expectation.

486-532: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Clarify which ACL identity the in-pod valkey-cli uses.

This test execs valkey-cli inside the server container with /tls/tls.crt, which is the server certificate. The cluster runs with authClientsUser: CN, so Valkey maps this connection to an ACL user named after the server certificate CN (valkey-cluster-mtls.default.svc.cluster.local). No ACL user with that name exists in the manifest at lines 392-396.

If this test passes, it documents the fallback behavior for an unmapped CN, which is the same behavior the operator and the probes depend on. Add a short comment stating the expected identity, or assert ACL WHOAMI here as well so the fallback is explicit rather than incidental.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/e2e/valkeycluster_tls_test.go` around lines 486 - 532, The mTLS client
identity used by the in-pod valkey-cli is implicit and should be made explicit.
In the test case around the primary-pod replication flow, document that the
server certificate maps to the expected CN-based ACL identity and that this
unmapped identity relies on the intended fallback behavior, or add an ACL WHOAMI
assertion using the same TLS command options before validating replication.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@api/v1alpha1/valkeycluster_types.go`:
- Around line 305-307: Correct the typo in the comment for TLSAuthClientsUserURI
by changing “natches” to “matches”; do not modify the constant or its behavior.
- Around line 323-338: Update the TLS documentation in docs/tls.md to include an
upgrade/migration note for existing clusters that omit spec.tls.authClients: the
default changes from optional to yes, enabling mTLS, unless the CR explicitly
sets authClients: optional. Keep the existing description of the yes default and
authentication behavior intact.

In `@docs/tls.md`:
- Line 124: Update the subsection heading beginning “Never use nopass: true”
from level four to level three so it uses `###` and preserves the hierarchy
under the surrounding `## Security considerations` section.
- Around line 99-106: Update the cert-manager Certificate example for
valkey-client-alice by adding spec.usages with client auth alongside the
existing certificate configuration. Preserve the current metadata, secretName,
commonName, and issuerRef values.
- Around line 32-34: Expand the mTLS ACL documentation around the
authClients/authClientsUser example to cover every internal Valkey connection:
replication must use the _replication CN or URI, the exporter must use its
_exporter identity, and probes must have a matching certificate identity when
password AUTH is unavailable. State that certificate rotation must preserve the
mapped CN or URI for each identity.

In `@internal/controller/utils.go`:
- Around line 337-354: Define and use a dedicated operator client certificate
whose CN maps to an existing privileged ACL user instead of reusing the Valkey
server certificate in the TLS setup around tls.X509KeyPair; confirm and handle
the behavior when no matching ACL user exists. Apply the same client-identity
decision to internal/controller/utils.go lines 337-354 and
internal/controller/metrics_exporter.go lines 43-47, including how the
exporter's REDIS_USER/REDIS_PASSWORD interact with certificate-derived ACL
mapping.

In `@test/e2e/valkeycluster_tls_test.go`:
- Line 216: Restore explicit timeout and polling interval arguments on both
Eventually assertions in the Valkey TLS end-to-end test, including the readiness
check and metrics/exporter assertion near the referenced blocks. Use the longer
timeout and polling interval established by the surrounding or prior test
patterns rather than relying on Gomega defaults.
- Around line 363-376: Set an explicit timeout for the final
Eventually(verifyReady) readiness wait, using the existing 2-minute default or
an explicit 10-minute timeout consistent with the mTLS test’s intended bounds.
Keep the certificate and deployment readiness checks unchanged.

---

Nitpick comments:
In `@internal/controller/config_test.go`:
- Around line 122-163: Add a test case within the TLS client-auth Describe block
covering a TLSConfig with a certificate and AuthClients left unset, then call
buildServerConfig and assert that tls-auth-clients is absent. Keep TLS
configured so the assertion specifically exercises the empty AuthClients branch
in buildManagedConfig.
- Around line 89-101: Update the rejection assertion in the “rejects
authClients=no with authClientsUser=CN” test to use the same
“authClientsUser=CN/URI” substring as the URI case, keeping both tests aligned
with the shared CEL validation message.

In `@internal/controller/config.go`:
- Around line 83-90: Correct the spelling in the comment above the
tls.AuthClientsUser conditional: change “cetificate” to “certificate”. Leave the
conditional logic and configuration rendering unchanged.

In `@test/e2e/valkeycluster_tls_test.go`:
- Around line 478-481: Update the ACL WHOAMI assertion in the mTLS client log
check to match the expected user name within the combined output rather than
requiring an exact "alice" string. Keep the existing trimmed output and error
validation, and preserve the certificate-CN mapping expectation.
- Around line 486-532: The mTLS client identity used by the in-pod valkey-cli is
implicit and should be made explicit. In the test case around the primary-pod
replication flow, document that the server certificate maps to the expected
CN-based ACL identity and that this unmapped identity relies on the intended
fallback behavior, or add an ACL WHOAMI assertion using the same TLS command
options before validating replication.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ebc8c63e-5da3-47d7-9a23-b6468b1a5c3a

📥 Commits

Reviewing files that changed from the base of the PR and between b7c947f and 7cf1429.

📒 Files selected for processing (10)
  • api/v1alpha1/valkeycluster_types.go
  • config/crd/bases/valkey.io_valkeyclusters.yaml
  • config/crd/bases/valkey.io_valkeynodes.yaml
  • docs/tls.md
  • internal/controller/config.go
  • internal/controller/config_test.go
  • internal/controller/metrics_exporter.go
  • internal/controller/utils.go
  • internal/controller/valkeynode_resources_test.go
  • test/e2e/valkeycluster_tls_test.go

Comment thread api/v1alpha1/valkeycluster_types.go
Comment thread api/v1alpha1/valkeycluster_types.go
Comment thread docs/tls.md Outdated
Comment thread docs/mtls.md
Comment thread docs/mtls.md
Comment thread internal/controller/utils.go
Comment thread test/e2e/valkeycluster_tls_test.go
Comment thread test/e2e/valkeycluster_tls_test.go
Signed-off-by: Sandeep Kunusoth <sandeepkunsoth000@gmail.com>
Comment on lines +83 to +87
if tls.AuthClients != "" {
if directive, ok := tls.AuthClients.AuthClientsDirective(); ok {
config["tls-auth-clients"] = directive
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Preserve TLS default rendering
When TLSConfig.AuthClients is empty, this now omits tls-auth-clients. Valkey's default is yes, so existing stored TLS CRs created before this CRD default, or standalone ValkeyNode specs built without admission defaulting, will start requiring client certificates instead of keeping the operator's previous optional behavior.

Suggested change
if tls.AuthClients != "" {
if directive, ok := tls.AuthClients.AuthClientsDirective(); ok {
config["tls-auth-clients"] = directive
}
}
if tls.AuthClients == "" {
config["tls-auth-clients"] = "optional"
} else if directive, ok := tls.AuthClients.AuthClientsDirective(); ok {
config["tls-auth-clients"] = directive
}
Artifacts

Repro: focused Go harness source

  • Evidence file captured while the check ran.

Repro: failing Go harness output showing missing tls-auth-clients optional

  • The full command output behind this check.

View artifacts

T-Rex Ran code and verified through T-Rex

Comment thread docs/mtls.md
By default, Valkey uses mutual TLS and requires clients to present a valid certificate verified against trusted root CAs configured via `tls-ca-cert-file` or `tls-ca-cert-dir`. You may use `tls-auth-clients no` to disable client authentication.

When `spec.tls.authClients` is omitted, the operator defaults it to `Optional` and renders `tls-auth-clients optional` so TLS clients can connect without presenting a client certificate. Set `authClients: Required` to enforce mTLS (`tls-auth-clients yes`), or `authClients: Disabled` to turn client certificate processing off (`tls-auth-clients no`).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we set default value of "tls-auth-clients"] to "Required" inside operator or stick with current "Optional"? when spec.tlsAuthClients is empty in spec as by default valkey 9.* uses tls-auth-clients to yes

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
test/e2e/valkeycluster_tls_test.go (4)

502-523: 🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Use a CN-matched ACL user for server-side TLS replication connections.

authClientsUser: CN requires the client certificate CN to match an enabled ACL user. The replica connects using the server certificate with CN valkey-cluster-mtls.default.svc.cluster.local, while only alice exists as an ACL user. Add a matching internal ACL user or use a dedicated CN-based client certificate for replication traffic. Valkey does not map TLS clients to ACL users when the CN has no enabled ACL match.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/e2e/valkeycluster_tls_test.go` around lines 502 - 523, The mTLS
replication test must provision an enabled ACL user matching the server
certificate CN valkey-cluster-mtls.default.svc.cluster.local before validating
replication. Update the test setup around the replication case to add or
configure that internal CN-based user, while preserving alice for regular client
authentication.

476-483: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Project only server-tls/ca.crt into client pods.

The client commands read ca.crt, but these test Secret mounts expose the full serverCertSecret, including tls.key. Apply a Secret items projection for server-tls at lines 482 and 564. Keep the separate client vol mounts for client-tls because those commands also need the client cert/key.

Proposed Secret projection
 "secret": {
-  "secretName": "%s"
+  "secretName": "%s",
+  "items": [{"key": "ca.crt", "path": "ca.crt"}]
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/e2e/valkeycluster_tls_test.go` around lines 476 - 483, Update the Secret
volume definitions in the client pod manifests generated by the relevant test
setup blocks to project only server-tls/ca.crt from the server certificate
Secret via Secret items. Apply this at both server-tls volume definitions, while
preserving the separate client-tls volume mounts unchanged because client
commands require the certificate and key.

384-392: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Wait for the leaf Certificate resources to become Ready.

kubectl get secret only proves the Secret exists; it does not prove cert-manager generated a fresh, valid certificate pair for these mTLS names. Add waits for the two leaf Certificates, such as kubectl wait --for=condition=Ready certificate/<name> --timeout=<duration>, before creating the ValkeyCluster.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/e2e/valkeycluster_tls_test.go` around lines 384 - 392, Update the
certificate readiness waits in the test setup before creating the ValkeyCluster
to wait for both leaf Certificate resources, not just their Secrets. In the
Eventually blocks around serverCertSecret and clientCertSecret, use kubectl wait
for condition=Ready on each corresponding certificate name with an appropriate
timeout, while preserving the existing retry behavior.

346-370: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Declare client auth on the client certificate.

Cert-manager uses only TLS Web Server Authentication EKU by default when usages is omitted. clientCertSecret is presented as a client certificate, so add client auth to prevent client certificate validation failures. If the server certificate is still shared, declare both TLS Web Server Authentication and TLS Web Client Authentication on that Certificate as well.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/e2e/valkeycluster_tls_test.go` around lines 346 - 370, Update the client
Certificate manifest for the certificate with commonName alice to declare TLS
Web Client Authentication in its usages. If the server certificate is shared for
client authentication, also declare both TLS Web Server Authentication and TLS
Web Client Authentication on the valkey certificate, preserving its existing
server usage.
♻️ Duplicate comments (1)
test/e2e/valkeycluster_tls_test.go (1)

225-232: 🩺 Stability & Availability | 🟠 Major

Restore explicit timeouts for external waits.

The first TLS suite still relies on default Eventually timing after the five-minute timeout was removed. The new mTLS readiness, configuration, primary lookup, and replication waits repeat the same pattern. The replication callback can block for the full WAIT 1 5000 duration. Pass explicit timeout and polling values for these Kubernetes and Valkey operations.

Also applies to: 271-288, 421-427, 452-462, 506-514, 529-539

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/e2e/valkeycluster_tls_test.go` around lines 225 - 232, Restore explicit
timeout and polling arguments on every Eventually wait in the TLS suite,
including the pod readiness block around the visible kubectl command and the
mTLS readiness, configuration, primary lookup, and replication waits identified
by the comment. Choose values that accommodate external Kubernetes/Valkey
operations, including the replication callback’s WAIT 1 5000 duration, rather
than relying on Gomega defaults.
🧹 Nitpick comments (1)
test/e2e/valkeycluster_tls_test.go (1)

394-413: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Exercise the metrics exporter under strict mTLS.

This mTLS manifest enables authClients: Required and authClientsUser: CN, but it does not enable the exporter. The earlier exporter tests do not explicitly exercise this authentication mode. Add exporter coverage to this fixture, or add a separate test that verifies client credentials and redis_up=1.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/e2e/valkeycluster_tls_test.go` around lines 394 - 413, Update the mTLS
ValkeyCluster fixture in the test around clusterManifest to enable the metrics
exporter under authClients: Required and authClientsUser: CN, then verify the
exporter connects with the required client credentials and reports redis_up=1.
Reuse the existing exporter test helpers and credential configuration rather
than creating unrelated coverage.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/mtls.md`:
- Around line 134-136: Update the strict mTLS guidance to state that resetpass
alone is insufficient: require restricting the default user or document that
prerequisite, and add coverage for a certificate with an unmatched CN/URI to
verify it cannot access default-user permissions.
- Around line 64-65: Update the rendered configuration example in the mTLS
documentation to match the operator output: remove quotes from the
tls-auth-clients value and show separate tls-auth-clients-user directives for CN
and URI instead of the combined CN/URI placeholder.
- Around line 38-40: Update the mTLS documentation around the
authClients/authClientsUser guidance to explicitly state that operator
connections, health checks, the exporter, and tls-replication links must present
certificates whose mapped CN or URI matches an enabled ACL user with the
required permissions. Also document that reused server-certificate rotation must
preserve this identity to avoid internal authentication failures or incorrect
ACL mapping.

In `@test/e2e/valkeycluster_tls_test.go`:
- Around line 570-573: Strengthen the assertion around the mtlsNoCertPodName
failure by inspecting the failed container’s termination reason and its logs,
rather than asserting only the Kubernetes Pod phase. Require the output to
contain the expected TLS client-certificate/authClients=Required error, while
preserving the existing failure expectation and timeout handling.

---

Outside diff comments:
In `@test/e2e/valkeycluster_tls_test.go`:
- Around line 502-523: The mTLS replication test must provision an enabled ACL
user matching the server certificate CN
valkey-cluster-mtls.default.svc.cluster.local before validating replication.
Update the test setup around the replication case to add or configure that
internal CN-based user, while preserving alice for regular client
authentication.
- Around line 476-483: Update the Secret volume definitions in the client pod
manifests generated by the relevant test setup blocks to project only
server-tls/ca.crt from the server certificate Secret via Secret items. Apply
this at both server-tls volume definitions, while preserving the separate
client-tls volume mounts unchanged because client commands require the
certificate and key.
- Around line 384-392: Update the certificate readiness waits in the test setup
before creating the ValkeyCluster to wait for both leaf Certificate resources,
not just their Secrets. In the Eventually blocks around serverCertSecret and
clientCertSecret, use kubectl wait for condition=Ready on each corresponding
certificate name with an appropriate timeout, while preserving the existing
retry behavior.
- Around line 346-370: Update the client Certificate manifest for the
certificate with commonName alice to declare TLS Web Client Authentication in
its usages. If the server certificate is shared for client authentication, also
declare both TLS Web Server Authentication and TLS Web Client Authentication on
the valkey certificate, preserving its existing server usage.

---

Duplicate comments:
In `@test/e2e/valkeycluster_tls_test.go`:
- Around line 225-232: Restore explicit timeout and polling arguments on every
Eventually wait in the TLS suite, including the pod readiness block around the
visible kubectl command and the mTLS readiness, configuration, primary lookup,
and replication waits identified by the comment. Choose values that accommodate
external Kubernetes/Valkey operations, including the replication callback’s WAIT
1 5000 duration, rather than relying on Gomega defaults.

---

Nitpick comments:
In `@test/e2e/valkeycluster_tls_test.go`:
- Around line 394-413: Update the mTLS ValkeyCluster fixture in the test around
clusterManifest to enable the metrics exporter under authClients: Required and
authClientsUser: CN, then verify the exporter connects with the required client
credentials and reports redis_up=1. Reuse the existing exporter test helpers and
credential configuration rather than creating unrelated coverage.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f678663a-acd9-4135-8af7-34132b75c9a4

📥 Commits

Reviewing files that changed from the base of the PR and between 7cf1429 and b9c4a4d.

📒 Files selected for processing (8)
  • api/v1alpha1/valkeycluster_types.go
  • config/crd/bases/valkey.io_valkeyclusters.yaml
  • config/crd/bases/valkey.io_valkeynodes.yaml
  • docs/mtls.md
  • docs/valkeycluster.md
  • internal/controller/config.go
  • internal/controller/config_test.go
  • test/e2e/valkeycluster_tls_test.go
🚧 Files skipped from review as they are similar to previous changes (4)
  • config/crd/bases/valkey.io_valkeynodes.yaml
  • internal/controller/config_test.go
  • internal/controller/config.go
  • config/crd/bases/valkey.io_valkeyclusters.yaml

Comment thread docs/mtls.md
Comment on lines +38 to +40
With `authClients: Required` + `authClientsUser: CN`, any TLS client whose certificate has `CN=alice` is automatically authenticated as the ACL user `alice` -- no `AUTH` command required. Pass `resetpass: true` with this configuration so authentication relies exclusively on the client certificate.

With `authClients: Required`, Valkey requires a valid client certificate at the TLS handshake, but that does not disable password-based ACL authentication. Clients can still authenticate with `AUTH` as long as they present a client certificate signed by the configured CA. Today operator user, health check probes, redis exporter all present the server certificate to satisfy this.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -C 5 \
  'tls-auth-clients-user|tls-auth-clients|client auth|server certificate|health|exporter|replication' \
  --glob '*.go' --glob '*.md' .

Repository: valkey-io/valkey-operator

Length of output: 50384


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== docs/mtls.md relevant lines =="
sed -n '30,42p' docs/mtls.md

echo
echo "== TLS client/auth config constants and usage =="
rg -n -C 4 'TLSAuthClientsUser|authClientsUser|tls-auth-clients-user|tls-auth-clients|AuthClients|Certificate.*tls-auth|client cert|ClientTLS|tls-cert-file|tls-key-file' internal cmd api docs --glob '*.go' --glob '*.md'

echo
echo "== replica TLS config references =="
rg -n -C 4 'tls-replication|cluster-tls|replica.*tls|tls-client' internal docs --glob '*.go' --glob '*.md'

echo
echo "== certificate extension / key usage generation references =="
rg -n -C 4 'ExtendedKeyUsage|KeyUsage|ExtendedKeyUsageClientAuth|server certificate|client certificate|client auth|TLSAuth|authClients' internal controller internal valkey api docs --glob '*.go' --glob '*.md'

Repository: valkey-io/valkey-operator

Length of output: 50383


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== users.go outline =="
ast-grep outline internal/controller/users.go --view expanded || true

echo
echo "== users.go relevant sections =="
sed -n '1,260p' internal/controller/users.go

echo
echo "== cluster/client TLS client references =="
rg -n -C 4 'NewClient|Client(\(|[[:space:]]|:)|ClientTLS|Username|Password\b|User|Password|client-go|InClusterConfig|ServiceAccount' internal/valkey internal/controller/valkeycluster_controller.go internal/controller/valkeynode_controller.go internal/controller/metrics_exporter.go --glob '*.go'

echo
echo "== buildClusterClient definitions/usages =="
rg -n -C 6 'func .*build.*Client|Build.*Client|buildNodeClientOption|ClusterClient|NodeClient' internal --glob '*.go'

Repository: valkey-io/valkey-operator

Length of output: 35853


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== read-only verifier: TLS auth mapping and internal client identities =="
python3 - <<'PY'
from pathlib import Path
import re

docs = Path("docs/mtls.md").read_text()
users = Path("internal/controller/users.go").read_text()
config = Path("internal/controller/config.go").read_text()

checks = {
    "docs states replica links require internal client auth": bool(re.search(r"tls-replication yes|replica|TLS clients|certificate", config) and re.search(r"replica|Replicas|replication|Replica", users)),
    "docs states server certificate is reused by operator/probes/exporter": bool(re.search(r"operator user, health check probes, redis exporter all present the server certificate", docs)),
    "docs mentions client auth usage requirement": bool(re.search(r"\bclient auth\b|client certificate|cert-mapped|CN/URI", docs)),
    "ACL system users include internal mTLS targets": bool(re.search(r"_operator\b", users) and re.search(r"_exporter\b", users) and re.search(r"_replication\b", users)),
    "server renders tls-auth-clients-user from API": bool(re.search(r'tls-auth-clients-user"\s*= directive', config)),
}
for name, ok in checks.items():
    print(f"{name}: {ok}")

print("docs internal client mention count:", len(re.findall(r".*operator user, health check probes, redis exporter all present the server certificate to satisfy this\.", docs)), "expected:", 1)
print("docs mentions client auth client-certificate requirements:", bool(re.search(r"client auth|client-certificate|certificate-to-user|CN/URI|rotation|server certificate", docs)))
PY

echo
echo "== focused source excerpts =="
sed -n '560,615p' internal/controller/valkeynode_controller.go
sed -n '70,95p' internal/controller/config.go
sed -n '40,105p' internal/controller/users.go
sed -n '35,45p' docs/mtls.md

Repository: valkey-io/valkey-operator

Length of output: 7752


🌐 Web query:

Valkey 9.0 tls-auth-clients-user ACL client certificate authentication tls-replication

💡 Result:

In Valkey 9.0, the tls-auth-clients-user configuration directive enables automatic authentication of TLS clients as Valkey ACL users based on fields extracted from their client certificates [1][2][3]. When this feature is enabled, the server inspects the client's TLS certificate during the handshake and attempts to map a specific field to an existing Valkey ACL user [2][4]. If a match is found, the connection is automatically authenticated as that user, eliminating the need for an explicit AUTH command [2][3]. If no matching user is found, the connection defaults to the unauthenticated default user [1][3]. Key details include: - Configuration Options: Supported values for tls-auth-clients-user include CN (Common Name from the certificate's Subject field), URI (URI from the certificate's Subject Alternative Name), and off (the default) to disable the feature [4][5]. - ACL Integration: It is recommended to configure the associated ACL users without passwords (e.g., using the nopass directive) when using this feature [3][6][4]. This ensures that authentication is enforced exclusively through mTLS certificates [3][4]. - Replication: Valkey treats replica servers and standard clients in the same way regarding TLS connections [7]. To use TLS for replication, the replica must be configured with tls-replication yes [7][8]. If tls-auth-clients-user is enabled on the primary, a replica presenting a certificate with a valid CN or URI that matches a Valkey user (configured with appropriate replication permissions) will be automatically authenticated as that user [3][4]. This feature simplifies mTLS-based infrastructure integration and enhances security by tightly coupling certificate identity with Valkey's Access Control List (ACL) system [2]. If authentication fails via this method, it may be logged in the ACL log with the reason tls-cert, and failures are tracked in the INFO stats under acl_access_denied_tls_cert [2].

Citations:


Document internal TLS client identity requirements.

With authClients: Required + authClientsUser, operator connections, health checks, the exporter, and tls-replication links are TLS clients. The identity mapped from their certificate must match an enabled ACL user with the required permissions, and rotating a reused server certificate must preserve that CN or URI. This prevents internal links from becoming unauthenticated or authenticating as the wrong ACL user.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/mtls.md` around lines 38 - 40, Update the mTLS documentation around the
authClients/authClientsUser guidance to explicitly state that operator
connections, health checks, the exporter, and tls-replication links must present
certificates whose mapped CN or URI matches an enabled ACL user with the
required permissions. Also document that reused server-certificate rotation must
preserve this identity to avoid internal authentication failures or incorrect
ACL mapping.

Source: MCP tools

Comment thread docs/mtls.md
Comment on lines +64 to +65
tls-auth-clients "yes" # rendered from authClients: Required
tls-auth-clients-user CN/URI # rendered from authClientsUser: CN or authClientsUser: URI

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== files =="
git ls-files | sed -n '1,200p' | rg 'docs/mtls.md|mtls|tls-auth|config.c|valkey|docs' || true

echo "== docs/mtls.md lines 50-75 =="
if [ -f docs/mtls.md ]; then
  nl -ba docs/mtls.md | sed -n '50,75p'
fi

echo "== schema/controller references =="
rg -n "tls-auth-clients|authClients|authClientsUser|tls.auth.clients|authClientsUser" -S . --glob '!**/.git/**' --glob '!**/vendor/**' --glob '!**/node_modules/**' | sed -n '1,220p'

Repository: valkey-io/valkey-operator

Length of output: 2172


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== docs/mtls.md lines 50-75 =="
awk 'NR>=50 && NR<=75 {printf "%6d\t%s\n", NR, $0}' docs/mtls.md

echo "== tls/auth config references =="
rg -n "tls-auth-clients|tls-auth-clients-user|authClients|authClientsUser|tls.auth.clients|AuthClients" -S internal api docs --glob '!**/.git/**' | sed -n '1,260p'

echo "== relevant source slices =="
python3 - <<'PY'
import os, pathlib
for p in pathlib.Path('.').rglob('*'):
    if p.is_file() and p.suffix in {'.go','.yaml','.md'}:
        try:
            txt=p.read_text(errors='ignore')
        except: continue
        if any(s in txt for s in ['tls-auth-clients','authClientsUser','authClients:']):
            print(f'\n--- {p} ---')
            lines=txt.splitlines()
            for i,l in enumerate(lines,1):
                if any(s in l for s in ['tls-auth-clients','authClientsUser','authClients:', 'CN', 'URI']):
                    lo=max(1,i-4); hi=min(len(lines),i+5)
                    for n in range(lo,hi+1):
                        print(f'{n:5d}\t{lines[n-1]}')
PY

Repository: valkey-io/valkey-operator

Length of output: 50383


Show the exact controller-rendered directive values.

The rendered config block shows tls-auth-clients "yes" and tls-auth-clients-user CN/URI, but the operator renders tls-auth-clients yes and separate CN or URI values. Use matching unquoted values and list the two tls-auth-clients-user alternatives separately.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/mtls.md` around lines 64 - 65, Update the rendered configuration example
in the mTLS documentation to match the operator output: remove quotes from the
tls-auth-clients value and show separate tls-auth-clients-user directives for CN
and URI instead of the combined CN/URI placeholder.

Source: MCP tools

Comment thread docs/mtls.md
Comment on lines +134 to +136
To enforce strict mTLS authentication:

Always set `resetpass: true` instead. This flushes all passwords and disables `nopass`, making password-based `AUTH` impossible. The user can then only be authenticated via the CN/URI from the client certificate.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -C 5 \
  'user default|nopass|resetpass|tls-auth-clients-user|ACL WHOAMI' \
  --glob '*.go' --glob '*.md' .

Repository: valkey-io/valkey-operator

Length of output: 19977


🌐 Web query:

Valkey TLS mTLS tls-auth-clients-user unmatched certificate identity default user documentation

💡 Result:

In Valkey, the tls-auth-clients-user configuration directive allows the server to automatically authenticate clients as specific ACL users based on fields extracted from their presented TLS certificates [1][2][3]. When this feature is enabled, the server performs the following logic during the TLS handshake [2][3]: 1. It extracts the specified field (e.g., Common Name or Subject Alternative Name URI) from the client's TLS certificate [2][4][3]. 2. It attempts to find a matching Valkey ACL user whose username corresponds to that extracted value [2][3]. 3. If a match is found and the user is valid, the client is automatically authenticated as that user [2][3]. 4. If no matching user is found, or if the client certificate authentication fails to map to an enabled user, the client is not authenticated as the intended user and instead remains as the default user [1][2][3]. As a result, an unmatched certificate identity means the client will proceed as the default user [3]. This behavior is why it is recommended to configure users without passwords (e.g., ACL SETUSER on allcommands allkeys) when using this feature; this ensures that authentication is enforced strictly through the mTLS certificate identity rather than falling back to potentially permissive default user settings [1][3]. Supported configuration values for tls-auth-clients-user include: - CN: Uses the Common Name from the certificate's Subject field [2][3]. - URI: Uses the first URI entry from the certificate's Subject Alternative Name (SAN) extension [4][3]. - off: Disables the feature (default) [2][3]. Administrators can monitor these events using the INFO field acl_access_denied_tls_cert, which tracks the number of failed certificate-based authentication attempts [2].

Citations:


🌐 Web query:

Valkey client X509 authentication no matching user default user

💡 Result:

The message indicating "no matching user" in Valkey occurs when the server is configured to automatically authenticate clients using TLS certificate fields (via the tls-auth-clients-user configuration directive), but it cannot find a Valkey ACL user that matches the extracted value from the client's certificate [1][2][3]. When this happens, the following behavior occurs: 1. Automatic Authentication Failure: The TLS handshake completes successfully (assuming mTLS is configured), but the automatic association of the connection with a specific ACL user fails [1][2][3]. 2. Default User Fallback: The connection remains associated with the "default" user [1][2][3]. If the default user is not configured to be automatically authenticated (e.g., via nopass), the client will remain in an unauthenticated state and must perform a manual authentication step (e.g., using the AUTH command) to access restricted functionality [1][3][4]. 3. Logging: This event is recorded in the ACL log with the reason "tls-cert," which helps administrators identify certificate-based authentication failures [2][5]. To resolve this issue, ensure that a Valkey user exists with a name that exactly matches the field being extracted from the certificate (e.g., the Common Name or a URI from the SAN extension) [6][2][7]. You can verify your current configuration and create the necessary users using the ACL SETUSER command [1][8]. Additionally, if you intend for certificate authentication to be the only method for a specific user, you can use the resetpass command to remove existing passwords and ensure the user is authenticated exclusively via their certificate [4].

Citations:


Do not claim that resetpass alone enforces strict mTLS.

resetpass removes passwords and nopass from the named ACL user. It does not reject a valid certificate whose CN or URI has no matching user; Valkey leaves that connection on the default user. If the default user remains privileged or otherwise accessible, an unknown certificate identity can still reach default-user permissions. Restrict the default user or document this prerequisite and test an unmatched CN/URI certificate.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/mtls.md` around lines 134 - 136, Update the strict mTLS guidance to
state that resetpass alone is insufficient: require restricting the default user
or document that prerequisite, and add coverage for a certificate with an
unmatched CN/URI to verify it cannot access default-user permissions.

Source: MCP tools

Comment on lines +570 to +573
_, err = utils.Run(exec.Command("kubectl", "wait", fmt.Sprintf("pod/%s", mtlsNoCertPodName),
"--for=jsonpath={.status.phase}=Failed", "--timeout=120s"))
Expect(err).NotTo(HaveOccurred(),
"client without a certificate should fail under authClients=Required")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Assert the failure reason, not only the Pod phase.

A Failed phase does not prove that the missing certificate caused the failure. Image, DNS, CA, and command errors can also fail the pod. Inspect the container termination reason and logs, and require the expected TLS client-certificate error.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/e2e/valkeycluster_tls_test.go` around lines 570 - 573, Strengthen the
assertion around the mtlsNoCertPodName failure by inspecting the failed
container’s termination reason and its logs, rather than asserting only the
Kubernetes Pod phase. Require the output to contain the expected TLS
client-certificate/authClients=Required error, while preserving the existing
failure expectation and timeout handling.

@jdheyburn

jdheyburn commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

@sandeepkunusoth Can you help me understand how this ties in with the wider TLS API design to be able to support additional TLS configurations like split-TLS configurations (see this comment too).

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.

4 participants