Skip to content

feat(authz): add authorization mode setting (off/dryRun/enforce) - #13212

Open
sk593 wants to merge 6 commits into
mainfrom
sk593-authz-modes-foundation
Open

sk593 wants to merge 6 commits into
mainfrom
sk593-authz-modes-foundation

Conversation

@sk593

@sk593 sk593 commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Description

Layer 1 of the Stack 0: Foundation stack for the internal component authorization design in #13086 (see CLI Design, Compatibility, and Error codes).

This PR adds a single authorization mode setting that every Radius Go service reads. Nothing checks the mode yet, so runtime behavior is unchanged; later PRs in the stack add the checks.

  • pkg/authz (new)

    • Mode with ModeOff (default), ModeDryRun, ModeEnforce; ParseMode (empty → off, case-sensitive, anything else is an error). Mode validates itself when decoded from YAML, so a typo fails config loading.
    • Decision{Allowed, Code, Reason} and Apply(ctx, mode, decision) (the mode is validated first, so an unknown mode fails closed even for allowed decisions; a denial without a code uses AuthorizationFailed):
      • off: returns nil and does not log.
      • dryRun: logs authorization check would deny request with authzWouldDeny=true, authzCode, authzReason and returns nil.
      • enforce: returns *DeniedError carrying the code and reason.
      • unknown mode: returns an error.
    • LogMode logs authz mode=<mode> once at startup.
  • Config plumbing: an authorization.mode section in hostoptions.ProviderConfig (applications-rp, controller), ucp.Config, and dynamicrp.Config. UCP, applications-rp, dynamic-rp, and controller log the mode at startup.

  • Helm: global.rbac.enabled and global.rbac.dryRun (both default false) render authorization.mode into the four service ConfigMaps through a radius.authz.mode helper. In off mode the section is omitted, so older service binaries (strict YAML decoding) can still load the config during rolling upgrades or with mismatched image tags:

    enabled dryRun mode
    false false off
    false true dryRun
    true false enforce
    true true template fails

    Each of the four deployments carries a checksum/authz-config pod annotation (a hash of the mode), so a helm upgrade that changes the mode rolls the pods. Services read the mode only at startup.

    The values are documented as reserved until checks land. enabled stays false for now; per the design it becomes default-on only in the final rollout PR.

  • Docs: configSettings.md lists the new authorization section.

Services not wired: the deployment engine (bicep-de, .NET, in a separate repo) and the dashboard (Node.js, separate repo) do not load this Go config. They will need their own changes when they participate in the protocol. pre-upgrade and rad are one-shot tools, not services.

Commits are test-forward: each test commit precedes its implementation commit.

How to test

go test ./pkg/authz/... ./pkg/ucp/ ./pkg/dynamicrp/ ./pkg/armrpc/hostoptions/
go build ./cmd/...
make test-helm
go run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.14.0 run ./pkg/authz/... ./pkg/ucp/ ./pkg/dynamicrp/ ./pkg/armrpc/hostoptions/ ./cmd/ucpd/... ./cmd/dynamic-rp/... ./cmd/applications-rp/... ./cmd/controller/...

All of these pass locally (Helm: 152/152 tests).

🔍 Manual verification

Render the chart for each combination:

cd deploy/Chart
helm template radius . | grep -c '^    authorization:'                                   # 0 (section omitted in off mode)
helm template radius . --set global.rbac.dryRun=true  | grep -A1 '^    authorization:'   # mode: "dryRun" (x4)
helm template radius . --set global.rbac.enabled=true | grep -A1 '^    authorization:'   # mode: "enforce" (x4)
helm template radius . --set global.rbac.enabled=true --set global.rbac.dryRun=true
# Error: execution error at (radius/templates/ucp/deployment.yaml:26:34): global.rbac.dryRun=true cannot be
# combined with global.rbac.enabled=true: dry run is a preflight check for installations that are not yet
# enforcing. Set global.rbac.enabled=false to run the dry run.

I checked these locally. I also ran it on a Podman-backed kind cluster (arm64) with the five images built from this branch (ucpd, applications-rp, dynamic-rp, controller, pre-upgrade) loaded via kind load image-archive. For that local-only run, the two hook jobs' imagePullPolicy was set to IfNotPresent in a scratch copy of the chart so they could use the loaded images:

rad install kubernetes --chart <chart> --set global.rbac.dryRun=true <image overrides>
for d in ucp applications-rp dynamic-rp controller; do
  kubectl logs -n radius-system deploy/$d -c $d | grep 'authz mode='
done
# each prints one line with "authz mode=dryRun"

I then switched to off and enforce with helm upgrade --reuse-values --set global.rbac.enabled=... --set global.rbac.dryRun=... and all four services logged the expected mode (before the checksum annotation, these needed a kubectl rollout restart). After adding the annotation, switching from enforce back to dryRun with helm upgrade alone rolled all four deployments, and each new pod logged:

pod/ucp-79c985bc88-xkm2j: "message":"authz mode=dryRun"
pod/applications-rp-846467f87f-s4sm2: "message":"authz mode=dryRun"
pod/dynamic-rp-5478fc7df9-j6c66: "message":"authz mode=dryRun"
pod/controller-9df595997-fkk54: "message":"authz mode=dryRun"

@github-actions

github-actions Bot commented Oct 5, 2026

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@github-actions

github-actions Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

Unit Tests

    2 files  ± 0    461 suites  +1   15m 29s ⏱️ -9s
7 310 tests +54  7 308 ✅ +54  2 💤 ±0  0 ❌ ±0 
8 789 runs  +54  8 787 ✅ +54  2 💤 ±0  0 ❌ ±0 

Results for commit 12cfd85. ± Comparison against base commit ec90522.

♻️ This comment has been updated with latest results.

@codecov

codecov Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 60.46%. Comparing base (ec90522) to head (12cfd85).

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #13212      +/-   ##
==========================================
+ Coverage   60.37%   60.46%   +0.08%     
==========================================
  Files         774      776       +2     
  Lines       45682    45715      +33     
==========================================
+ Hits        27582    27641      +59     
+ Misses      18100    18074      -26     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@sk593
sk593 added this pull request to stack #13217 October 5, 2026 23:19
@sk593
sk593 force-pushed the sk593-authz-modes-foundation branch from 5706483 to fa3ded4 Compare October 6, 2026 20:14
sk593 and others added 4 commits October 6, 2026 13:31
Add failing tests for the authz package (ParseMode, Apply, LogMode), for
reading the authorization mode from UCP, dynamic-rp, and provider config,
and Helm unit tests mapping global.rbac values to the mode.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: sk593 <shruthikumar@microsoft.com>
Add pkg/authz with the Mode type, ParseMode, and an Apply helper that
future authorization checks use to act on a Decision: off ignores
denials, dryRun logs them with authzWouldDeny=true, and enforce returns
a DeniedError carrying the error code.

Read the mode from an authorization section in the UCP, applications-rp,
dynamic-rp, and controller configuration, and log it once at startup.
Render it in the Helm chart from global.rbac.enabled and
global.rbac.dryRun (both default false); combining them fails rendering.

Nothing checks the mode yet, so runtime behavior is unchanged.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: sk593 <shruthikumar@microsoft.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: sk593 <shruthikumar@microsoft.com>
Validate the mode before the allowed fast path, default empty denial codes
to AuthorizationFailed, omit the chart authorization section in off mode so
older binaries can load config, and mark the rbac values as reserved.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: sk593 <shruthikumar@microsoft.com>
@sk593
sk593 force-pushed the sk593-authz-modes-foundation branch from fa3ded4 to 1d1ef33 Compare October 6, 2026 20:31
@sk593 sk593 added the pr:standard Ongoing maintenance, minor improvements, documentation updates, and routine development work label Oct 6, 2026
@sk593
sk593 marked this pull request as ready for review October 6, 2026 21:42
@sk593
sk593 requested review from a team as code owners October 6, 2026 21:42
Copilot AI balanced review requested due to automatic review settings October 6, 2026 21:42
@github-actions github-actions Bot added the pr:waiting-for-review A reviewer owns the next action; required approval is pending or unverifiable label Oct 6, 2026

Copilot AI left a comment

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.

Copilot review overview

🟡 Changes recommended

The unsupported authz: title type will fail the repository’s required Conventional Commit title check.

Review effort: Balanced
Findings: None

What changed in this PR

Adds the shared internal authorization-mode foundation without enabling authorization checks.

Changes:

  • Adds off, dryRun, and enforce modes, decisions, logging, and denial errors.
  • Wires configuration and startup logging into four Go services.
  • Adds Helm rendering, validation, tests, and configuration documentation.

Review note: Rename the PR to feat(authz): add authorization mode setting (off/dryRun/enforce) to satisfy the required Conventional Commit title format.

File Description
pkg/​ucp/​config.go Adds authorization configuration.
pkg/​ucp/​config_test.go Tests UCP mode decoding.
pkg/​dynamicrp/​config.go Adds authorization configuration.
pkg/​dynamicrp/​config_test.go Tests Dynamic RP mode decoding.
pkg/​authz/​mode.go Defines modes, parsing, options, and logging.
pkg/​authz/​mode_test.go Tests mode behavior.
pkg/​authz/​doc.go Documents the package.
pkg/​authz/​decision.go Implements authorization decision handling.
pkg/​authz/​decision_test.go Tests decisions and denial errors.
pkg/​armrpc/​hostoptions/​providerconfig.go Adds shared provider authorization options.
pkg/​armrpc/​hostoptions/​providerconfig_test.go Tests provider configuration decoding.
docs/​contributing/​contributing-code/​contributing-code-control-plane/​configSettings.md Documents authorization settings.
deploy/​Chart/​values.yaml Adds reserved RBAC values.
deploy/​Chart/​tests/​authz_mode_test.yaml Tests Helm mode rendering.
deploy/​Chart/​templates/​ucp/​configmaps.yaml Renders UCP authorization mode.
deploy/​Chart/​templates/​rp/​configmaps.yaml Renders Applications RP mode.
deploy/​Chart/​templates/​dynamic-rp/​configmaps.yaml Renders Dynamic RP mode.
deploy/​Chart/​templates/​controller/​configmaps.yaml Renders controller mode.
deploy/​Chart/​templates/​_helpers.tpl Derives and validates the Helm mode.
cmd/​ucpd/​cmd/​root.go Logs UCP mode at startup.
cmd/​dynamic-rp/​cmd/​root.go Logs Dynamic RP mode at startup.
cmd/​controller/​cmd/​root.go Logs controller mode at startup.
cmd/​applications-rp/​cmd/​root.go Logs Applications RP mode at startup.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

sk593 and others added 2 commits October 6, 2026 14:51
…loyments

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: sk593 <shruthikumar@microsoft.com>
Services read the authorization mode only at startup, so annotate each pod template with a checksum of the mode. A helm upgrade that changes global.rbac now rolls the ucp, applications-rp, dynamic-rp, and controller deployments.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: sk593 <shruthikumar@microsoft.com>
@sk593 sk593 changed the title authz: add authorization mode setting (off/dryRun/enforce) feat(authz): add authorization mode setting (off/dryRun/enforce) Oct 6, 2026
@radius-functional-tests

radius-functional-tests Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Radius functional test overview

🔍 Go to test action run

Click here to see the test run details
Name Value
Repository radius-project/radius
Commit ref 12cfd85
Unique ID funcd1058be51f
Image tag pr-funcd1058be51f
  • Dapr: 1.14.4
  • Azure KeyVault CSI driver: 1.4.2
  • Azure Workload identity webhook: 1.3.0
  • Bicep recipe location ghcr.io/radius-project/dev/test/testrecipes/test-bicep-recipes/<name>:pr-funcd1058be51f
  • Terraform recipe location http://tf-module-server.radius-test-tf-module-server.svc.cluster.local/<name>.zip (in cluster)
  • applications-rp test image location: ghcr.io/radius-project/dev/applications-rp:pr-funcd1058be51f
  • dynamic-rp test image location: ghcr.io/radius-project/dev/dynamic-rp:pr-funcd1058be51f
  • controller test image location: ghcr.io/radius-project/dev/controller:pr-funcd1058be51f
  • ucp test image location: ghcr.io/radius-project/dev/ucpd:pr-funcd1058be51f
  • deployment-engine test image location: ghcr.io/radius-project/deployment-engine:latest

Test Status

⌛ Building Radius and pushing container images for functional tests...
✅ Container images build succeeded
⌛ Publishing Bicep Recipes for functional tests...
✅ Recipe publishing succeeded
⌛ Starting ucp-cloud functional tests...
⌛ Starting corerp-cloud functional tests...
✅ ucp-cloud functional tests succeeded
✅ corerp-cloud functional tests succeeded

@sk593
sk593 requested a review from willdavsmith October 6, 2026 22:26

This branch has not been deployed

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

Labels

pr:standard Ongoing maintenance, minor improvements, documentation updates, and routine development work pr:waiting-for-review A reviewer owns the next action; required approval is pending or unverifiable

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants