Description
To facilitate enterprise authentication gateways (non-oauth) we would like to tell Coder which user has been authenticated along with some details about the type of authentication via a header applied to the proxied gateway request. A scenario where this is useful might be for organizations using Envoy with a custom authentication plugin, where all requests go through Envoy. Envoy will authenticate the request and then forward the request to Coder running on a localhost port.
This is a variation to #5705
Proposal
Add an argument, --allow-external-api-authentication
to coder server
That would get passed to a new AllowExternalAPIAuthentication bool
field in ExtractAPIKeyConfig.
Then in the ExtractAPIKey middleware, if enabled, look for the header defined below to look-up the user via GetUserByEmailOrUsername and validate keys returned from GetAPIKeysByUserID database API. If the header is not present it would fall back to call APITokenFromRequest using the current logic.
Header
Coder-Authorization: Basic Field=Value[, Field=Value]...
Known Fields:
Username=user
UserEmail=user@example.com
ActiveSession=token-type
TokenName=name
The Username
or UserEmail
field would be required and used to fetch the user via GetUserByEmailOrUsername
to identify the Coder user.
Then either ActiveSession
or TokenName
would be required to identify the existing key (returned from GetAPIKeysByUserID
) to use. If ActiveSession
is used, only look for non-expired keys of the specified token type ("oidc", "password", etc) with an empty token name. Alternately if TokenName
is used, call GetAPIKeyByName to fetch and validate the key.
Optionally, if stronger assurances are required, we could expand the Coder-Authorization
header beyond the Basic
type to allow for validation. Similar to the AWS auth headers we could facilitate signatures using a shared secret, for example:
Coder-Authorization: HMAC-SHA256 UserEmail=user@example.com, ActiveSession=oidc, SignedHeaders=header1;header2, Signature=xyz
Note that Basic
will work for my requirements, but I think the design can be expanded if you have customers with different/stronger guarantees here.
There will be a few additional error cases that I think we can handle with the "Detail" content on the SignedOutErrorMessage error
- User not found (user does not exist in database, or has deleted=true set)
- Token not found (when
TokenName
is specified) - No active session (when
ActiveSession
specified and no keys found of token-type)