Using authorization

BuildGrid supports authorization using either JWTs or request headers. When using request headers, the authenticity of the claimed identity is not verifiable by BuildGrid. This means that the headers should be set by (for example) a trusted proxy which does some identity verification rather than the client directly.

Controlling access to individual requests is done by configuring an ACL. This configuration is optional, but if present must completely define access to all instances specified in the main configuration file. Missing instances default to denying all access.

ACL configuration

Regardless of the authorization mode, the acls configuration key can be used to provide the path to an ACL configuration file.

The config is of the format:

<instance-name>:
  allow:
    - actor: .*
      subject: .*
      workflow: .*
      requests:
        # List of request name strings
        - Execute
        - ...

actor, subject, and workflow are optional keys which allow limiting access based on the client’s identity. These keys are regular expressions used to match against the identity information provided by the client.

There can be multiple entries in this allow list, if different client identities need to be able to have different access permissions.

If an ACL configuration file is provided, then all instance names in the main config file must have a corresponding entry defined in the ACL configuration file. Any missing instance names will have all requests denied by default. To ease verbosity if not all instance names actually need authorization, there is a shorthand for “allow all”.

<instance-name>:
  allow: all

An exhaustive example could be as follows.

prod:
  allow:
    # All prod user accounts have CAS write access
    - actor: prod.*
      requests:
        - BatchUpdateBlobs
        - QueryWriteStatus
        - Write

    # Only requests with the correct actor claim can perform read/write
    # requests
    - actor: prodbuilder
      requests:
        - Execute
        - WaitExecution
        - CancelOperation

    # Only workers should be able to connect to the Bots service
    - actor: prodworker
      requests:
        - CreateBotSession
        - UpdateBotSession

    # BuildGrid itself needs to be able to create LogStreams and
    # update ActionResults
    - actor: bgd
      requests:
        - CreateLogStream
        - UpdateActionResult

    # Read-only requests should be allowed regardless of header claims
    - requests:
        - GetCapabilities
        - GetActionResult
        - GetOperation
        - ListOperations
        - Read
        - FindMissingBlobs
        - BatchReadBlobs
        - GetTree

Header-based authorization

authorization:
  mode: headers
  acls: /path/to/acl.yaml
  allow-unauthorized-instances: [ '', 'dev' ]

This authorization method reads the x-request-actor, x-request-subject, and x-request-workflow headers and compares them with the corresponding regular expressions defined in the ACL configuration.

If no ACL is configured then this method does no authorization, and all requests are permitted.

Since there is no way to verify the authenticity of these headers, it is important to only use this method when the requests are from a trusted source. A deployment architecture where this may be useful is deploying BuildGrid strictly behind a reverse proxy, where the reverse proxy is responsible for validating the client identity and setting these headers before forwarding the request.

If you want to allow some instances to skip the authorization you can optionally add your instances in allow-unauthorized-instances. The instances listed here will not be validated in any way

Secret-based JWT authorization

authorization:
  mode: jwt
  algorithm: hs256
  secret: /path/to/secret.key
  acl-config: /path/to/acl.yaml
  allow-unauthorized-instances: [ '', 'dev' ]

Secret-based JWT authorization expects incoming requests to populate the Authorization request header with a JWT containing some claims about the client identity. The JWT must be able to be decoded using the given secret and algorithm.

If an ACL configuration is provided, the act, sub, and aud JWT claims are compared with the actor, subject, and workflow regular expressions respectively for the given instance to determine whether or not the request is permitted.

If no ACL configuration is provided, then this authorization mode only ensures that the JWT is valid and not expired.

If you want to allow some instances to skip the authorization you can optionally add your instances in allow-unauthorized-instances. The instances listed here will not be validated in any way

JWKS-based JWT authorization

authorization:
  mode: jwt
  algorithm: hs256
  jwks-url: http://example.com/jwks
  jwks-fetch-minutes: 30
  acls: /path/to/acl.yaml
  allow-unauthorized-instances: [ '', 'dev' ]

JWKS-based JWT authorization works in the same way as the secret-based JWT approach, except the secret key(s) for decoding JWTs are fetched from a remote server as a JWKS. For a JWT to be valid it must be able to be decoded with one of the keys in the key set returned from the given jwks-url.

The JWKS will be cached locally for jwks-fetch-minutes minutes, which defaults to 60 if unset.

ACLs and unauthorized instances are handled in exactly the same was as in the secret-based JWT approach.