Skip to content

fix: prevent cross-namespace secret read via DmsAPIKeySecretRef - #341

Open
anispate wants to merge 5 commits into
openshift:masterfrom
anispate:fix/rosaeng-61327-cross-namespace-secret-read
Open

fix: prevent cross-namespace secret read via DmsAPIKeySecretRef#341
anispate wants to merge 5 commits into
openshift:masterfrom
anispate:fix/rosaeng-61327-cross-namespace-secret-read

Conversation

@anispate

@anispate anispate commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes the confused-deputy vulnerability reported in ROSAENG-61327.

`DeadmansSnitchIntegration.Spec.DmsAPIKeySecretRef` is a `corev1.SecretReference` (Name + Namespace). The reconciler was passing the CR-supplied `Namespace` directly to `utils.LoadSecretData`, which runs a cluster-wide `Get` using the operator's broad secret-read privilege. A principal with `create` on `DeadmansSnitchIntegration` could set `DmsAPIKeySecretRef.Namespace` to any namespace (e.g. hive credentials, cloud-provider creds) and have the operator transmit that secret's value to `api.deadmanssnitch.com` (CWE-441, CWE-639, CWE-200 — CVSS 7.7).

Changes

  • `deadmanssnitchintegration_controller.go`: always read the DMS API key from `config.OperatorNamespace`, ignoring the CR-supplied `Namespace`. All production DMSI CRs already set `namespace: deadmanssnitch-operator`, so there is no behaviour change for legitimate use.
  • `deadmanssnitchintegration_controller_test.go`: adds `TestCrossNamespaceSecretRefRejected` — places the API-key secret only in a foreign namespace (not in `config.OperatorNamespace`) and asserts reconcile returns a `NotFound` error, proving the cross-namespace read path is closed.

Ticket remediation checklist

Requirement Status
Ignore `DmsAPIKeySecretRef.Namespace`, force `config.OperatorNamespace` ✅ Done
Regression test (cross-namespace ref rejected with NotFound) ✅ Done
CEL/admission validation on `DmsAPIKeySecretRef.Namespace` ⚠️ Not in this PR — requires `make generate` inside the FIPS container to regenerate CRD YAML; the controller fix fully closes the attack vector, CEL is additional defence-in-depth and can be tracked as a follow-up
`TargetSecretRef` hardening (FIND-005) ⚠️ Not in this PR — `TargetSecretRef` is used only as the destination reference in a `SyncSet` (no local `Get` is performed with it), so it is a separate concern and should be assessed under its own ticket

Test plan

  • `go test ./controllers/deadmanssnitchintegration/...` — all 11 existing tests pass, new `TestCrossNamespaceSecretRefRejected` passes
  • No behaviour change for production DMSI CRs (all set `dmsAPIKeySecretRef.namespace: deadmanssnitch-operator`)

Fixes: ROSAENG-61327

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Secret references for Dead Mans Snitch integrations now use the operator’s namespace, preventing cross-namespace secret access.
    • Reconciliation behavior remains the same when the secret is missing or cannot be read.
  • Documentation

    • Clarified that only the secret name is used for this setting, and any namespace value is ignored.
    • Updated schema and API docs to reflect the new lookup behavior.

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@anispate, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 16 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 0eefcf88-6e81-4c0f-a59e-38e5926c277b

📥 Commits

Reviewing files that changed from the base of the PR and between fe4e5f0 and 14d109a.

⛔ Files ignored due to path filters (3)
  • deploy_pko/.test-fixtures/default/CustomResourceDefinition-deadmanssnitchintegrations.deadmanssnitch.managed.openshift.io.yaml is excluded by !**/.test-fixtures/**
  • deploy_pko/.test-fixtures/empty-silent-ids/CustomResourceDefinition-deadmanssnitchintegrations.deadmanssnitch.managed.openshift.io.yaml is excluded by !**/.test-fixtures/**
  • deploy_pko/.test-fixtures/fedramp/CustomResourceDefinition-deadmanssnitchintegrations.deadmanssnitch.managed.openshift.io.yaml is excluded by !**/.test-fixtures/**
📒 Files selected for processing (7)
  • CLAUDE.md
  • api/v1alpha1/deadmanssnitchintegration_types.go
  • controllers/deadmanssnitchintegration/deadmanssnitchintegration_controller.go
  • controllers/deadmanssnitchintegration/deadmanssnitchintegration_controller_test.go
  • deploy/crds/deadmanssnitch.managed.openshift.io_deadmanssnitchintegrations.yaml
  • deploy_pko/CustomResourceDefinition-deadmanssnitchintegrations.deadmanssnitch.managed.openshift.io.yaml
  • pkg/utils/secrets.go

Walkthrough

The reconciler now loads the Dead Mans Snitch API key secret from the operator namespace instead of the namespace in DmsAPIKeySecretRef. The helper utilities, controller test, and CRD/type documentation were updated to match that behavior.

Changes

Operator namespace secret lookup

Layer / File(s) Summary
Secret helper namespace handling
pkg/utils/secrets.go
LoadSecretData now takes a context.Context, and LoadOperatorSecretData loads a secret key from config.OperatorNamespace by delegating to it.
Reconcile and cross-namespace test
controllers/deadmanssnitchintegration/deadmanssnitchintegration_controller.go, controllers/deadmanssnitchintegration/deadmanssnitchintegration_controller_test.go
Reconcile now uses the operator-namespace secret loader, and a new test verifies a secret only present in a foreign namespace is not accepted.
CRD and type documentation
api/v1alpha1/deadmanssnitchintegration_types.go, deploy/crds/deadmanssnitch.managed.openshift.io_deadmanssnitchintegrations.yaml, deploy_pko/CustomResourceDefinition-deadmanssnitchintegrations.deadmanssnitch.managed.openshift.io.yaml
Field comments and generated CRD descriptions now say only the secret name is used and the namespace is ignored.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 15
✅ Passed checks (15 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Stable And Deterministic Test Names ✅ Passed Added test names are static; no Ginkgo titles or dynamic subtest names were introduced.
Test Structure And Quality ✅ Passed Uses stdlib testing/fake client, tests one behavior, cleans up mock controller, has a diagnostic error assertion, and adds no waits or cluster resources.
Microshift Test Compatibility ✅ Passed The new test is a plain Go unit test using a fake client, with no Ginkgo/e2e wrappers or MicroShift-unsupported OpenShift APIs.
Single Node Openshift (Sno) Test Compatibility ✅ Passed No new Ginkgo/e2e tests were added; the new test is a plain Go unit test using testing.T and has no SNO assumptions.
Topology-Aware Scheduling Compatibility ✅ Passed Only secret-namespace handling and a unit test changed; no pod scheduling, replicas, affinity, selectors, or topology-aware constraints were added.
Ote Binary Stdout Contract ✅ Passed No process-level stdout writes were added; the new test has no suite hooks, and the only fmt.Printf found is in a test helper.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed Not applicable: the PR adds a plain unit test, not a Ginkgo e2e test, and it contains no IPv4-only or external connectivity assumptions.
No-Weak-Crypto ✅ Passed No weak crypto, custom crypto, or secret-comparison code was added; the PR only changes secret namespace lookup and adds a regression test.
Container-Privileges ✅ Passed PR only changes controller/test Go code; no manifests or container privilege settings (privileged, hostPID/network/IPC, SYS_ADMIN, allowPrivilegeEscalation) were introduced.
No-Sensitive-Data-In-Logs ✅ Passed The PR only changes the secret lookup namespace and adds a non-logging regression test; no new logs expose secrets, tokens, or PII.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately summarizes the main fix: blocking cross-namespace secret reads via DmsAPIKeySecretRef.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@openshift-ci

openshift-ci Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: anispate

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jul 7, 2026

@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.

🧹 Nitpick comments (1)
controllers/deadmanssnitchintegration/deadmanssnitchintegration_controller_test.go (1)

826-829: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert the not-found failure mode

assert.Error is too broad here; add errors.IsNotFound(reconcileErr) so the test only passes when the API key secret lookup fails in config.OperatorNamespace.

🤖 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
`@controllers/deadmanssnitchintegration/deadmanssnitchintegration_controller_test.go`
around lines 826 - 829, The test around the deadmanssnitchintegration reconcile
path is too broad because it only checks for any error. Update the assertion in
the test that exercises the DmsAPIKeySecretRef namespace case to specifically
verify the secret lookup fails with a not-found error using
errors.IsNotFound(reconcileErr), alongside the existing error check, so it only
passes when the secret is missing from config.OperatorNamespace.
🤖 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.

Nitpick comments:
In
`@controllers/deadmanssnitchintegration/deadmanssnitchintegration_controller_test.go`:
- Around line 826-829: The test around the deadmanssnitchintegration reconcile
path is too broad because it only checks for any error. Update the assertion in
the test that exercises the DmsAPIKeySecretRef namespace case to specifically
verify the secret lookup fails with a not-found error using
errors.IsNotFound(reconcileErr), alongside the existing error check, so it only
passes when the secret is missing from config.OperatorNamespace.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 34c46264-f9ae-4882-a15e-4b67650808fc

📥 Commits

Reviewing files that changed from the base of the PR and between 7f8a2d6 and fe4e5f0.

📒 Files selected for processing (2)
  • controllers/deadmanssnitchintegration/deadmanssnitchintegration_controller.go
  • controllers/deadmanssnitchintegration/deadmanssnitchintegration_controller_test.go

@codecov-commenter

codecov-commenter commented Jul 7, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 43.89%. Comparing base (7f8a2d6) to head (14d109a).

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #341      +/-   ##
==========================================
+ Coverage   43.28%   43.89%   +0.61%     
==========================================
  Files          11       11              
  Lines         834      836       +2     
==========================================
+ Hits          361      367       +6     
+ Misses        424      422       -2     
+ Partials       49       47       -2     
Files with missing lines Coverage Δ
api/v1alpha1/deadmanssnitchintegration_types.go 100.00% <ø> (ø)
...ntegration/deadmanssnitchintegration_controller.go 63.14% <100.00%> (+0.60%) ⬆️
pkg/utils/secrets.go 81.81% <100.00%> (+26.26%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@openshift-ci openshift-ci Bot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jul 7, 2026
anispate and others added 4 commits July 7, 2026 17:03
The DmsAPIKeySecretRef field accepts a corev1.SecretReference with both
Name and Namespace. The reconciler was passing the CR-supplied Namespace
directly to utils.LoadSecretData, which executes a cluster-wide Get using
the operator's broad secret-read privilege. A principal with create rights
on DeadmansSnitchIntegration could point the Namespace at any namespace
(e.g. hive credentials) and have the operator transmit that secret's value
to api.deadmanssnitch.com — a confused-deputy / CWE-441 attack.

Fix: always read the DMS API key from config.OperatorNamespace, ignoring
whatever namespace the CR author specifies. Adds a regression test that
places the API-key secret only in a foreign namespace and asserts that
reconcile returns an error, proving the cross-namespace path is closed.

Fixes: ROSAENG-61327

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
assert.Error is too broad — the reconcile could fail for unrelated
reasons and the test would still pass. Use errors.IsNotFound to
confirm specifically that the secret lookup in config.OperatorNamespace
failed because the secret isn't there, not for any other reason.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
api/v1alpha1/deadmanssnitchintegration_types.go:
  Document that DmsAPIKeySecretRef.Namespace is intentionally ignored to
  prevent confused-deputy attacks; makes the security contract explicit at
  the API level.

pkg/utils/secrets.go:
  Add LoadOperatorSecretData — a namespace-free wrapper around LoadSecretData
  that always reads from config.OperatorNamespace. Removes the ability for
  callers to accidentally supply an arbitrary namespace when reading operator
  credentials with the operator's elevated cluster-wide secret-read privilege.

controllers/deadmanssnitchintegration/deadmanssnitchintegration_controller.go:
  Switch DMS API key lookup from LoadSecretData (caller-supplied namespace)
  to LoadOperatorSecretData (namespace fixed to config.OperatorNamespace),
  eliminating the confused-deputy attack surface at the call site.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
pkg/utils/secrets.go:
  Add ctx context.Context to LoadSecretData and LoadOperatorSecretData so
  context propagates correctly through the call chain (fixes contextcheck
  lint violation).

controllers/.../deadmanssnitchintegration_controller.go:
  Pass reconciler ctx to LoadOperatorSecretData.

deploy/crds/..., deploy_pko/...:
  Commit CRD YAML regenerated by make generate — updates dmsAPIKeySecretRef
  description to reflect that Namespace is intentionally ignored.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@anispate
anispate force-pushed the fix/rosaeng-61327-cross-namespace-secret-read branch from acc957e to a8d15e8 Compare July 7, 2026 21:09
@openshift-ci openshift-ci Bot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jul 7, 2026
@anispate

anispate commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

/retest

The agentic-sdlc-check pipeline (ROSA-730) validates that CLAUDE.md
contains build/test commands and architecture sections directly in the
file. The previous content was just '@AGENTS.md' (a Claude Code include
directive not readable by shell scripts). Inline the content from
AGENTS.md so both Claude Code and SDLC tooling can find the required
sections.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@openshift-ci

openshift-ci Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

@anispate: all tests passed!

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

@openshift-ci openshift-ci Bot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jul 11, 2026
@openshift-ci

openshift-ci Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

PR needs rebase.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants