Skip to content

Add selfhosted authorization documentation#873

Draft
mhotan wants to merge 6 commits intopeeter/selfhosted-docsfrom
mike/selfhosted-authorization
Draft

Add selfhosted authorization documentation#873
mhotan wants to merge 6 commits intopeeter/selfhosted-docsfrom
mike/selfhosted-authorization

Conversation

@mhotan
Copy link
Contributor

@mhotan mhotan commented Mar 26, 2026

Summary

  • Add authorization page to the selfhosted deployment section covering three modes: Noop, External (BYO), and UserClouds (Union RBAC)
  • Add link card to the selfhosted deployment index page

Content

The page covers:

  • Architecture diagram showing the centralized authorizer service pattern
  • Comparison table of the three modes with trade-offs (when to use each, what you gain/lose)
  • Helm values configuration examples for each mode
  • Terraform authorization_mode variable configuration
  • Observability section referencing the authorizer dashboard metrics and alerts
  • External authorization server contract (gRPC RPC, request/response fields)
  • Verification steps and troubleshooting guide

Related PRs

  • cloud #14943 — TypeExternal authorizer backend
  • helm-charts #291 — TypeAuthorizer routing defaults + dashboard/alerts

🤖 Generated with Claude Code

Covers the three authorization modes:
- Noop: no enforcement (default, development/small teams)
- External: customer-provided gRPC authorization server
- UserClouds: Union built-in RBAC

Includes architecture diagram, trade-offs comparison, Helm and
Terraform configuration examples, observability metrics/alerts
reference, verification steps, and troubleshooting guide.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Mar 26, 2026

Deploying docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: 61e40a4
Status: ✅  Deploy successful!
Preview URL: https://9d591fc5.docs-dog.pages.dev
Branch Preview URL: https://mike-selfhosted-authorizatio.docs-dog.pages.dev

View logs

@mhotan mhotan marked this pull request as draft March 26, 2026 18:20
aviator-app bot pushed a commit to unionai/helm-charts that referenced this pull request Mar 26, 2026
## Summary

Centralizes authorization configuration in the controlplane helm chart so all deployment modes (Noop, External, UserClouds) are configured through values overlays rather than hardcoded logic.

### Key Changes

**TypeAuthorizer routing defaults:**
- All non-authorizer services default to `TypeAuthorizer` with `authorizerClient.grpcConfig` pointing directly to the authorizer service over plaintext gRPC
- The authorizer service itself defaults to `TypeNoop` with documented examples for External and UserClouds backends

**Config refactor:**
- Replace bare `authorizerEndpoint` string with structured `authorizerClient` containing `grpcConfig` (host, insecure, etc.) and `forwardHeaders`
- Merge ingress auth annotations from #293 into base values

**Remove global.AUTHZ_TYPE:**
- Remove the forced Noop override in `_helpers.tpl` that stomped on values overlays when `AUTHZ_TYPE != "union"`
- Remove `AUTHZ_TYPE` global variable — authorization is now purely values-driven
- Gate union-authz sidecar (UserClouds) templates on `services.authorizer.configMap.authorizer.type == "UserClouds"` instead of separate enable flag

**Observability (Phases 4-5):**
- Add 6 dashboard panels to the Authorizer row: Mode stat, External Backend Latency, External Errors by gRPC Code, Fail-Open Activations, Decisions by Action, Error Attribution
- Add 3 PrometheusRule alerts: ExternalErrors (warning), FailOpenActive (critical), HighDenyRate (warning)
- Add recording rule for external error rate

**Service template:**
- Add `grpc-native` port for services with `connectPort` (exposes native gRPC alongside Connect)

### Release Notes

**Authorization configuration is now values-driven.** The `global.AUTHZ_TYPE` variable has been removed. Authorization mode is configured solely through `services.authorizer.configMap.authorizer.type` (`"Noop"`, `"External"`, or `"UserClouds"`).

If you previously set `global.AUTHZ_TYPE: "union"` in your values overlay, migrate to:
```yaml
services:
  authorizer:
    configMap:
      authorizer:
        type: "UserClouds"
```

The `protectedIngressAnnotationsGrpc` auth annotations (from #293) are now included in the base chart defaults.

### Related PRs

- cloud [#14943](unionai/cloud#14943) — TypeExternal authorizer backend (merged)
- docs [#873](unionai/unionai-docs#873) — Selfhosted authorization documentation

## Test plan

- [x] `make generate-expected && make test` passes
- [x] `helm template` renders correct configs for ext-authz environment
- [x] Deployed to ext-authz staging — all services running, ListRuns working
- [x] Verified authorizer configmap renders `type: External` with `externalClient`
- [x] Dashboard panels and recording rule render in template output
- [x] Alerts render when `monitoring.alerting.enabled: true`
- [ ] Verify existing BYOC deployments (TypeUserClouds path) are unaffected

🤖 Generated with [Claude Code](https://claude.com/claude-code)
mhotan and others added 5 commits March 27, 2026 08:47
- Add Prerequisites section linking to authentication, mapping OAuth
  apps to identity types and required JWT claims
- Add External authorization server requirements: gRPC contract,
  identity resolution, complete actions table, service account
  permissions for Apps 3/4/5 with warnings about what breaks
- Rename UserClouds to Union (built-in RBAC) in user-facing text,
  note legacy config value with future rename planned
- Reference implementation noted as non-generic example
- Use namespace placeholders in kubectl commands
- Expand troubleshooting with service-account-specific scenarios

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ences

- Replace internal service names (flyteadmin, executions, etc.) with
  generic labels in architecture diagram
- Remove union-authz service name from user-facing text
- Use placeholders for service endpoints and namespaces
- Fix diagram alignment and stray code fence

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

{{< key product_name >}} self-hosted deployments support configurable authorization backends to control who can perform which actions on platform resources. The authorization mode determines how access control decisions are made for API requests from the console, CLI, and SDK.

Unlike serverless and BYOC deployments where {{< key product_name >}} manages RBAC for you, **self-hosted deployments let you choose the authorization model** that fits your organization's security requirements.

Choose a reason for hiding this comment

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

Unlike serverless and BYOC deployments

It was my understanding that we're quietly shutting down serverless. Do we need to mention it here?

Copy link
Contributor

@katrogan katrogan left a comment

Choose a reason for hiding this comment

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

looks great!

| Claim | Values | Used for |
| ---------------------- | ------------------------------------- | ------------------------------------------------------ |
| `sub` | User's internal ID or app's client ID | Primary identity for authorization decisions |
| `identitytype` | `"user"` or `"app"` | Distinguishes human users from service accounts |
Copy link
Contributor

Choose a reason for hiding this comment

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

technically no longer a requirement with the external identity type, but definitely a nice to have when not using an external authorization impl

| `preferred_username` | User login or app client ID | Identity injection ("Owned By" display in the console) |

> [!WARNING]
> Without the `identitytype` claim, the authorizer cannot distinguish users from applications. This may cause all requests to be misclassified or denied. See [Authentication — Authorization server setup]({{< relref "authentication#authorization-server-setup" >}}) for claim configuration details.
Copy link
Contributor

Choose a reason for hiding this comment

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

again, only true if not using the external authz impl

| OAuth App | # | Token `sub` claim | Identity type | Purpose in authorization |
| ------------------ | - | ------------------- | ------------- | ----------------------------------------- |
| Browser login | 1 | User's internal ID | `user` | End-user console/UI actions |
| CLI | 2 | User's internal ID | `user` | End-user CLI actions |
Copy link
Contributor

Choose a reason for hiding this comment

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

nit but maybe not worth elaborating, you can log in with the cli using app creds too

| ------------------ | - | ------------------- | ------------- | ----------------------------------------- |
| Browser login | 1 | User's internal ID | `user` | End-user console/UI actions |
| CLI | 2 | User's internal ID | `user` | End-user CLI actions |
| Service-to-service | 3 | App's client ID | `app` | Internal controlplane calls through NGINX |
Copy link
Contributor

Choose a reason for hiding this comment

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

are 3) onwards internal apps? is it worth distinguishing them here?


## Architecture

All controlplane services route authorization decisions through a centralized **authorizer service**. The authorizer service delegates to a configurable backend:
Copy link
Contributor

Choose a reason for hiding this comment

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

This is all external facing, right? How conservative do we want to be with leaking private implementation details?

The authorizer service resolves the caller's identity before forwarding to your server. Identity arrives through two channels:

1. **gRPC metadata headers** (`authorization` / `flyte-authorization`) — forwarded to your server if configured in `forwardHeaders`. Contains the raw JWT/OIDC token. Your server can decode the JWT payload to read claims (`sub`, `identitytype`, `email`, `groups`, etc.) without signature verification — the token has already been validated by the controlplane's auth middleware.
2. **`AuthorizeRequest.identity` protobuf field** — a structured identity set by the authorizer service. Contains `user_id.subject`, `application_id.subject`, or `external_identity.subject` + `external_identity.token`.
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd put this first, it's the recommended field to use


| OAuth App | # | Subject (`sub` claim) | Required permissions |
| ------------------ | - | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Service-to-service | 3 | `INTERNAL_CLIENT_ID` value | `VIEW_FLYTE_INVENTORY`, `VIEW_FLYTE_EXECUTIONS`, `CREATE_FLYTE_EXECUTIONS`, `MANAGE_CLUSTER` |
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this really all this requires? internally i think we have an expanded permission set

A [Python reference implementation](https://github.com/unionai/cloud/tree/main/examples/external-authz-server) is available as an example. It demonstrates:

- Extracting identity from forwarded JWT metadata headers
- Falling back to the proto `Identity` field when no JWT is present
Copy link
Contributor

Choose a reason for hiding this comment

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

still not a fan of this recommendation :)


### Reference implementation

A [Python reference implementation](https://github.com/unionai/cloud/tree/main/examples/external-authz-server) is available as an example. It demonstrates:
Copy link
Contributor

Choose a reason for hiding this comment

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

this is a link to the private repo, right?

# Expected: Authorization decisions with identity and action details
```

5. **Verify service account access:** Check that internal platform operations are working by navigating the console and triggering a workflow execution. Monitor the external server logs for requests from the service account subjects (Apps 3, 4, 5).
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd also check triggering an execution from the CLI for the non-browser flow

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