Skip to content

Proposal for external user authentication #8889

@coryb

Description

@coryb

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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions