Skip to content

feat(vault): restrict zone-b workflow DON GetSecrets to allowlisted owners#23145

Open
prashantkumar1982 wants to merge 15 commits into
developfrom
vault-zone-b-restriction
Open

feat(vault): restrict zone-b workflow DON GetSecrets to allowlisted owners#23145
prashantkumar1982 wants to merge 15 commits into
developfrom
vault-zone-b-restriction

Conversation

@prashantkumar1982

@prashantkumar1982 prashantkumar1982 commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

What

Block GetSecrets reads originating from a zone-b workflow DON unless the calling workflow owner is allowlisted. Enforced in Capability.Execute before the OCR queue, so non-allowlisted owners get a deterministic rejection and zone-a / gateway paths are unaffected.

  • New zoneBRestrictor (own file) owns the two gate limiters and the check.
  • Zone membership is resolved authoritatively via CapabilitiesRegistry.DONByID on the caller's WorkflowDonID and its Families — never from caller-supplied zone data. Fragile DON.Name matching is not used.
  • DONByID implemented on LocalRegistry and delegated through the concrete Registry.
  • Fails closed if the caller DON cannot be resolved.

Gated by VaultZoneBWorkflowGetSecretsRestrictEnabled (global, default off); allowlist via owner-scoped PerOwner.VaultZoneBGetSecretsAllowed.

Dependencies

Security note

Trusting WorkflowDonID assumes the transport binds it to the authenticated caller DON. A colluding zone-b DON could otherwise spoof it. The complementary transport-layer binding is a separate change (chainlink-common#2257 + the corresponding chainlink PR) and should be enabled in the same rollout.

https://smartcontract-it.atlassian.net/browse/PRIV-593

…wners

Block GetSecrets reads originating from a zone-b workflow DON unless the calling
workflow owner is allowlisted. Enforced in Capability.Execute before the OCR
queue, so non-allowlisted owners get a deterministic rejection and zone-a /
gateway paths are unaffected.

- zoneBRestrictor (new file) owns the two gate limiters and the check; zone
  membership is resolved authoritatively via CapabilitiesRegistry.DONByID on the
  caller's WorkflowDonID, never from caller-supplied zone data.
- Implement DONByID on LocalRegistry and delegate through the concrete Registry.
- Fails closed if the caller DON cannot be resolved.

Note: trusting WorkflowDonID assumes the transport binds it to the authenticated
caller DON; see follow-up transport-layer binding change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

👋 prashantkumar1982, thanks for creating this pull request!

To help reviewers, please consider creating future PRs as drafts first. This allows you to self-review and make any final changes before notifying the team.

Once you're ready, you can mark it as "Ready for review" to request feedback. Thanks!

@github-actions

Copy link
Copy Markdown
Contributor

✅ No conflicts with other open PRs targeting develop

@prashantkumar1982
prashantkumar1982 marked this pull request as draft July 16, 2026 02:47
@github-actions

Copy link
Copy Markdown
Contributor

I see you updated files related to core. Please run make gocs in the root directory to add a changeset as well as in the text include at least one of the following tags:

  • #added For any new functionality added.
  • #breaking_change For any functionality that requires manual action for the node to boot.
  • #bugfix For bug fixes.
  • #changed For any change to the existing functionality.
  • #db_update For any feature that introduces updates to database schema.
  • #deprecation_notice For any upcoming deprecation functionality.
  • #internal For changesets that need to be excluded from the final changelog.
  • #nops For any feature that is NOP facing and needs to be in the official Release Notes for the release.
  • #removed For any functionality/config that is removed.
  • #updated For any functionality that is updated.
  • #wip For any change that is not ready yet and external communication about it should be held off till it is feature complete.

@trunk-io

trunk-io Bot commented Jul 16, 2026

Copy link
Copy Markdown

Static BadgeStatic BadgeStatic BadgeStatic Badge

View Full Report ↗︎Docs

@github-actions

github-actions Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

CORA - Analysis Skipped

Reason: The number of code owners (4) is less than the minimum required (5) and/or the number of CODEOWNERS entries with changed files (4) is less than the minimum required (2).

@prashantkumar1982
prashantkumar1982 marked this pull request as ready for review July 16, 2026 06:08
@prashantkumar1982
prashantkumar1982 requested review from a team as code owners July 16, 2026 06:08
@prashantkumar1982

Copy link
Copy Markdown
Contributor Author

/vault-audit

@app-token-issuer-foundations

app-token-issuer-foundations Bot commented Jul 16, 2026

Copy link
Copy Markdown

Vault audit failed to run for 2dbfda79. A maintainer should check the Actions logs in cre-docs and re-run /vault-audit.

@russell-stern

Copy link
Copy Markdown
Contributor

/vault-audit model=haiku

@app-token-issuer-foundations

app-token-issuer-foundations Bot commented Jul 17, 2026

Copy link
Copy Markdown

Vault audit complete for 2dbfda79 — no blocking findings.

📋 View the full report and findings — private tracking issue, visible to chainlink team members only. Resolve blocking findings there with /resolved <FINDING-ID> <reason>.

@russell-stern

Copy link
Copy Markdown
Contributor

/vault-audit

@app-token-issuer-foundations

app-token-issuer-foundations Bot commented Jul 18, 2026

Copy link
Copy Markdown

⚠️ Vault audit complete for 2dbfda791 blocking finding(s) (CRITICAL/MUST FIX) must be addressed before merge.

📋 View the full report and findings — private tracking issue, visible to chainlink team members only. Resolve blocking findings there with /resolved <FINDING-ID> <reason>.

prashantkumar1982 and others added 2 commits July 20, 2026 10:27
Set RequestMetadata.WorkflowDonID to the local (calling) workflow DON ID for
the vault GetSecrets and confidential-workflows capability requests, gated on
the RemoteExecutableWorkflowDONBindingEnabled setting so the remote executable
server's binding check accepts the request. Gating on the dynamic setting
(rather than setting unconditionally) keeps the F+1 aggregated request payloads
byte-identical across a mixed-binary rollout. Any failure reading the setting or
resolving the local node fails the whole call rather than sending a zero
WorkflowDonID.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@prashantkumar1982

Copy link
Copy Markdown
Contributor Author

/vault-audit

@app-token-issuer-foundations

app-token-issuer-foundations Bot commented Jul 20, 2026

Copy link
Copy Markdown

⚠️ Vault audit complete for 6dc13ab23 blocking finding(s) (CRITICAL/MUST FIX) must be addressed before merge.

📋 View the full report and findings — private tracking issue, visible to chainlink team members only. Resolve blocking findings there with /resolved <FINDING-ID> <reason>.

prashantkumar1982 and others added 3 commits July 20, 2026 12:56
Add a new local CRE topology that enables RemoteExecutableWorkflowDONBindingEnabled
on the workflow (caller) and capabilities (vault remote-executable server) nodes,
so the DON2DON WorkflowDonID binding check is exercised end-to-end by the existing
Vault secrets smoke flow. Selected via TOPOLOGY_NAME containing
"vault-workflow-don-binding-enabled".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rename the inner LocalNode error to lnErr in confidential_module.go and
secrets.go so it no longer shadows the outer err declaration (govet shadow).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
MUST-2: cache last-known zone-b membership per WorkflowDonID so a transient
nil/empty capabilities-registry snapshot (startup or empty sync) does not fail
every vault GetSecrets read DON-wide. Only a never-before-resolved DON fails
closed. The zone-b restrictor now takes a logger and warns on cache fallback.

MUST-3: add a test with a mixed-case ("Zone-B") registry family so the
case-insensitive family match has CI coverage — a regression to an exact (==)
comparison would silently disable the zone-b check and now fails this test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@prashantkumar1982

Copy link
Copy Markdown
Contributor Author

/vault-audit

@app-token-issuer-foundations

app-token-issuer-foundations Bot commented Jul 20, 2026

Copy link
Copy Markdown

⚠️ Vault audit complete for 9e2ab2e45 blocking finding(s) (CRITICAL/MUST FIX) must be addressed before merge.

📋 View the full report and findings — private tracking issue, visible to chainlink team members only. Resolve blocking findings there with /resolved <FINDING-ID> <reason>.

prashantkumar1982 and others added 3 commits July 20, 2026 20:27
Split the registry-outage test into subtests and add the missing zone-b case:
a previously-resolved zone-b DON must remain denied (allowlist enforced from
cache) during a registry outage, not slip through via a resolve failure. Covers
both cache directions plus the cold-DON fail-closed path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a test proving a zone-b caller supplying a 0x-prefixed, mixed-case owner is
allowed against an allowlist keyed by the normalized (0x-stripped, lowercased)
address. Guards against a regression to bare string comparison, which would
silently deny every standard-format allowlisted caller.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add an Execute()-level test for the allow path: an allowlisted zone-b owner
passes the gate and reaches the OCR handler (times out with no oracle in the
unit test) instead of being denied. Exercises the CRE-context population wiring
that the direct enforce() tests bypass, so a breakage there is now detectable.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@prashantkumar1982

Copy link
Copy Markdown
Contributor Author

/vault-audit

@app-token-issuer-foundations

app-token-issuer-foundations Bot commented Jul 21, 2026

Copy link
Copy Markdown

⚠️ Vault audit complete for 53984b673 blocking finding(s) (CRITICAL/MUST FIX) must be addressed before merge.

📋 View the full report and findings — private tracking issue, visible to chainlink team members only. Resolve blocking findings there with /resolved <FINDING-ID> <reason>.

@cl-sonarqube-production

Copy link
Copy Markdown

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.

3 participants