Revamp Authentication: API tokens, roles, and the oidc rename - #441
Open
olblak wants to merge 14 commits into
Open
Revamp Authentication: API tokens, roles, and the oidc rename#441olblak wants to merge 14 commits into
oidc rename#441olblak wants to merge 14 commits into
Conversation
Signed-off-by: Olivier Vernin <olivier@vernin.me>
Signed-off-by: Olivier Vernin <olivier@vernin.me>
Signed-off-by: Olivier Vernin <olivier@vernin.me>
* Set pagination limit * Use middleware for publicReadOnly endpoint * Zitadel requires a valid token and a configured role * Accept bare url for auth zero issuer URL * Validate timerange param * Allow to filter getscm query based date filter * Correctly close pg connection * fix report query qq Signed-off-by: Olivier Vernin <olivier@vernin.me>
Signed-off-by: Olivier Vernin <olivier@vernin.me>
Signed-off-by: Olivier Vernin <olivier@vernin.me>
Signed-off-by: Olivier Vernin <olivier@vernin.me>
Signed-off-by: Olivier Vernin <olivier@vernin.me>
Signed-off-by: Olivier Vernin <olivier@vernin.me>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Updatecli needs a credential that does not expire so an unattended pipeline
can keep publishing. An identity provider access token always expires, so Udash
now issues its own long-lived tokens and validates them itself.
That needed authorization first. Before this change it was binary and global,
"has a valid token", plus optionally one role. And role checking existed only
in
zitadelmode. Underoauthmode any valid token could write. Withoutfixing that, on any instance where the IdP allows self-registration, everybody who
could sign in could mint a publishing token.
1.
oauthmode renamed tooidcpkg/server/jwt.gowas never Auth0-specific — it is generic OIDC (JWKS caching,RS256, issuer + audience validation) and
auth0/go-jwt-middlewareis just thelibrary name. It works with Keycloak, Okta, Auth0, Dex. It is kept and renamed.
The two modes are complementary, not redundant:
oidc(wasoauth)zitadelThat second row is why a Zitadel machine-user PAT already works as a permanent
credential — PATs are opaque, so only the introspection mode can validate one.
Dropping
oidcwould lose multi-provider support; droppingzitadelwould losePATs.
Renamed:
ModeOauth→ModeOIDC,OauthOptions→OIDCOptions,AuthOptions.Oauth→.OIDC,optionOauth.go→optionAuth.go, viperserver.auth.oauth.*→server.auth.oidc.*, envUDASH_AUTH_OAUTH_*→UDASH_AUTH_OIDC_*, andUDASH_AUTH_ZITADEL_FILEKEY→_KEYFILEto match theKeyFilefield it fills.2. The auth switch no longer fails open
newGinEngine's switch had nodefaultbranch. A typo'd mode registeredzero middleware and left
POST/PUT/DELETEwide open, whileInit()merelylogged an error and let the server boot. An unknown mode or visibility is now
fatal.
Init()returns anerror(wasvoid), threaded throughOptions.Init()andServer.Run().checkJWTtakesAuthOptionsinstead of reading a packageglobal, which is what previously made the middleware untestable.
3. Permissions and roles
Two axes.
Permissions, from IdP roles via
server.auth.roles.mapping:viewerpublisheradminToken scopes, chosen at creation and never exceeding the creator's
permission:
reports:read,reports:write. There is deliberately notokens-management scope, a token can never mint another one.
POST /api/tokensrequirespublisher. This is what stops arbitrary signed-inusers creating publishing tokens in the frontend.
Role claims are provider-agnostic
server.auth.roles.claimwith per-mode defaults. Providers disagree on both nameand shape, and the extractor handles both:
urn:zitadel:iam:org:project:rolesrealm_access.roles(dotted path)https://udash/rolesRoleResolver— the one provider-specific partA request authenticating with an Udash token carries no IdP token, so there
are no claims to read roles from — only the creator's subject. Looking roles up by
subject needs a management API, which is genuinely provider-specific.
zitadel—ListUserGrantsvia the service-account key file udash alreadyholds. Revoking a role in Zitadel downgrades tokens created before it. The
service user must be allowed to read user grants. Cached (
cacheTTL, 60sdefault) so a publish-heavy pipeline does not hammer the IdP.
snapshot— trusts the permission recorded at creation. The only option forother providers; offboarding then means deleting the identity's tokens.
Two invariants, both tested: a resolver never grants more than the token was
created with (promotion does not leak into old tokens), and an IdP outage falls
back to the recorded permission rather than failing every publish.
4. API tokens
Migration
000012_create_api_tokens. 32 random bytes, base64url, prefixedudash_pat_— the prefix makes the middleware branch unambiguous and lets secretscanners spot a leak. Only
sha256(token)is stored; the token is returned once.udashTokenAuthruns before and independently of the mode middleware, soUdash tokens behave identically whichever provider is configured.
/api/tokenspublisher, and rejected if authenticated with a token/api/tokens?all=trueneedsadmin/api/tokens/:idadmin/api/tokens?subject=admin— offboarding/api/whoamiupdatecli udash loginReport write routes gained
requireScope("reports:write").Token routes live on their own group, never
apiPipeline— that group is leftopen for reads under
visibility: public.5. Report attribution
Nothing carried identity before:
CreatePipelineReportstored nothing about thecaller,
CustomClaimswas parsed then discarded, and the Zitadel auth context wasset but never read back.
New
pkg/server/identity.godefinesPrincipaland all three middlewarespopulate it. Migration
000013adds nullablecreated_by_subjectandcreated_by_token_idtopipelineReports, so existing rows andmode: nonedeployments keep working.
Test
To test this pull request, you can run the following commands:
Additional Information
Tradeoff
Potential improvement