From 2862f1c84be147f2b55ced424220a2394edeede6 Mon Sep 17 00:00:00 2001 From: Malte Poll <1780588+malt3@users.noreply.github.com> Date: Mon, 24 Feb 2025 10:53:29 +0100 Subject: [PATCH] document remoteapis --- README.md | 26 ++++ docs/lookup_chain.md | 55 ++++++++ docs/providers/remoteapis.md | 240 +++++++++++++++++++++++++++++++++++ 3 files changed, 321 insertions(+) create mode 100644 docs/lookup_chain.md create mode 100644 docs/providers/remoteapis.md diff --git a/README.md b/README.md index 2a6eef5..8e513e3 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ sequenceDiagram The following providers are supported as of today: +- [Remote Execution & Remote Caching Services](/docs/providers/remoteapis.md) - [AWS S3](/docs/providers/s3.md) - [Cloudflare R2](/docs/providers/r2.md) - [Google Cloud Storage (GCS)](/docs/providers/gcs.md) @@ -142,6 +143,11 @@ Now is a good time to install the credential helper. Simply run `bazel run @twea Alternatively, you can [write custom plugins that are part of your own Bazel workspace and build your own helper][plugins]. Follow the [provider-specific documentation](/docs/providers/) to ensure you can authenticate to the service. +In most cases, you the credential helper can guide you through the required setup for a URL with the following command: + +``` +tools/credential-helper setup-uri +``` You can also look at the [example project](/examples/full/) to see how everything works together. @@ -160,6 +166,7 @@ You can override the config file location using the `$CREDENTIAL_HELPER_CONFIG_F - `.urls[].path`: Path of the url. Matches any path when empty and uses globbing otherwise (a `*` matches any characters). - `.urls[].helper`: Helper to use for this url. Can be one of `s3`, `gcs`, `github`, `oci` or `null`. - `.urls[].config`: Optional helper-specific configuration. Refer to the documentation of the chosen helper for more information. +- `.urls[].config.lookup_chain`: Most helpers support configurable sources for secrets. Consult [the documenation on lookup chains][lookup_chain] for more information. ### Example @@ -182,12 +189,30 @@ You can override the config file location using the `$CREDENTIAL_HELPER_CONFIG_F { "host": "*.oci.acme.corp", "helper": "oci" + }, + { + "host": "bazel-remote.acme.com", + "helper": "remoteapis", + "config": { + "auth_method": "basic_auth", + "lookup_chain": [ + { + "source": "env", + "name": "CREDENTIAL_HELPER_REMOTEAPIS_SECRET" + }, + { + "source": "keyring", + "service": "tweag-credential-helper:remoteapis" + } + ] + } } ] } ``` In this example requests to any path below `https://github.com/tweag/` would use the GitHub helper, any requests to `https://files.acme.corp` that end in `.tar.gz` would use the S3 helper, while any requests to a subdomain of `oci.acme.corp` would use the oci helper. +Additionally, a `baze-remote` instance can be used as a remote cache. ## Environment variables @@ -295,3 +320,4 @@ The agent does not implement additional countermeasures. Consequently, access to [go_duration]: https://pkg.go.dev/time#ParseDuration [plugins]: /docs/plugins.md [bcr]: https://registry.bazel.build/modules/tweag-credential-helper +[lookup_chain]: /docs/lookup_chain.md diff --git a/docs/lookup_chain.md b/docs/lookup_chain.md new file mode 100644 index 0000000..f954f1f --- /dev/null +++ b/docs/lookup_chain.md @@ -0,0 +1,55 @@ +# Secret lookup chains + +The credential helper needs to be flexible when obtaining secrets from the environment. +To support different users with different needs, the configuration file `.tweag-credential-helper.json` allows you to specify where to read secrets from, including the order of preference. + +## Setup steps + +While some servies require specific setup steps, you can login to most services with the following generic steps. +The credential helper tries to explain how to login, based on a given uri. Examples: + +``` +$ credential-helper setup-uri https://github.com/my-org/project/releases/download/v1.2.3/my-artifact.tar.gz +$ credential-helper setup-uri https://raw.githubusercontent.com/my-org/project/6012...a5de28/file.txt +$ credential-helper setup-uri https://storage.googleapis.com/bucket/path/to/object +$ credential-helper setup-uri https://my-bucket.s3.amazonaws.com/path/to/object +$ credential-helper setup-uri https://org-id.r2.cloudflarestorage.com/bucket/path/to/object +$ credential-helper setup-uri https://index.docker.io/v2/library/hello-world/blobs/sha256:d2c94e...7264ac5a +``` + +When using an environment variable, simply `export` the secret value in your shell, like this (replace `SECRET_NAME` with the actual environment variable used for authentication and `secret_value` with the real secret): + +``` +$ export SECRET_NAME=secret_value +``` + +Please note that environment variables easily leak by accident. It is generally more desirable to use a dedicated store for sensitive values. For this purpose, the credential helper can read secrets from the system keyring. +When using the system keyring, you need to know the service name that is used to retrieve the secret. +Simply run the following command to login (replace `secret_value` with the actual secret and `[service-name]` with the name of the secret): + +``` +$ echo -ne "secret_value" | tools/credential-helper setup-keyring [service-name] +``` + + +## Configuration + +Most helpers support lookup chains, unless specifically noted otherwise. +When configuring the helper for a url, you can also define lookup chains. + +When reading sercrets from environment variables, the following options exist: + +- `.urls[].config.lookup_chain[].source`: `"env"` Source of the secret (environment variable) +- `.urls[].config.lookup_chain[].name`: Name of the environment variable to read +- `.urls[].config.lookup_chain[].binding`: Optional binding to a specific secret. If unspecified, it binds to the `"default"` secret. + +When reading sercrets from the system keyring, the following options exist: + +- `.urls[].config.lookup_chain[].source`: `"kering"` Source of the secret (system keyring) +- `.urls[].config.lookup_chain[].service`: Service name used to store the secret in the keyring. +- `.urls[].config.lookup_chain[].binding`: Optional binding to a specific secret. If unspecified, it binds to the `"default"` secret. + +## Secret bindings + +In most cases, you only need a single secret to authenticate. In those cases, the `"default"` binding is used. +For some servies, multiple secrets may be needed. In those cases, the documentation of the servie specifies the name and purpose of a binding. diff --git a/docs/providers/remoteapis.md b/docs/providers/remoteapis.md new file mode 100644 index 0000000..6eac4dc --- /dev/null +++ b/docs/providers/remoteapis.md @@ -0,0 +1,240 @@ +# Remote Build Execution (RBE) services / remote API Authentication + +This document explains how to setup your system for authenticating to remote build execution (RBE) services that are based on [remote api gRPC protocols][remote-apis] for Bazel, Buck2, BuildStream, Reclient, Goma Server, Pants, Please, Recc, Soong, and more. + +Remote APIs include the following: + +- Remote Execution +- Remote Caching +- Build Event UI +- Remote Assets / Remote Downloads + +... and probably more that are offered by a wide range of software and SaaS solutions. + +When using one of the following services, you can directly jump to the matching setup steps: + +- [BuildBuddy Cloud](#section-buildbuddy-cloud) +- [Self-hosted BuildBuddy](#section-buildbuddy-self-hosted) +- [BuildBarn](#section-buildbarn) +- [bazel-remote](#section-bazel-remote) + + +## Configuration + +Configuration depends on the service and authentication mechanism used. +While mTLS cannot be setup using a credential helper, any authentication scheme based on HTTP headers should work. + +The configuration in `.tweag-credential-helper.json` supports the following values: + +- `.urls[].helper`: `"remoteapis"` (name of the helper) +- `.urls[].auth_method`: one of + - `"header"`: Default. Send a HTTP header with the value being the default secret. + - `"basic_auth"` Used by `bazel-remote`. Send the default secret containing username and password (`username:password`) as a basic auth header. +- `.urls[].header_name`: Name of the HTTP header used for authentication. Example: use `"x-buildbuddy_api_key"` for BuildBuddy. +- `.urls[].lookup_chain`: The [lookup chain][lookup_chain] used to find the `default` secret. Defaults to: + ```json + [ + { + "source": "env", + "name": "CREDENTIAL_HELPER_REMOTEAPIS_SECRET", + "binding": "default" + }, + { + "source": "keyring", + "name": "tweag-credential-helper:remoteapis", + "binding": "default" + } + ] + ``` + + +### BuildBuddy Cloud (remote.buildbuddy.io) + +Add to your `.bazelrc`: + +``` +common --credential_helper=remote.buildbuddy.io=%workspace%/tools/credential-helper +``` + +BuildBuddy uses a the `x-buildbuddy-api-key` HTTP header for authentication. +Visit the [setup page][buildbuddy-setup], and copy the secret after `x-buildbuddy-api-key=`. + +If you are not using a configuration file, you can authenticate with an environment variable or a keyring secret: + +- Set `$BUILDBUDDY_API_KEY` to the value of the `x-buildbuddy-api-key` HTTP header. +- Set the `tweag-credential-helper:buildbuddy_api_key` secret to the value of the `x-buildbuddy-api-key` HTTP header: + + ``` + $ echo -ne "$BUILDBUDDY_API_KEY" | tools/credential-helper setup-keyring tweag-credential-helper:buildbuddy_api_key + ``` + +If you need to customize the HTTP header or secret used, read the next section on setting up self-hosted BuildBuddy instead: + +### Self-hosted BuildBuddy + +In the following snippets, we assume that your BuildBuddy instance is hosted under `buildbuddy.acme.com`. Replace this hostname with your own. + +Add to your `.bazelrc`: + +``` +common --credential_helper=buildbuddy.acme.com=%workspace%/tools/credential-helper +``` + +Add to your `.tweag-credential-helper.json`: +```json +{ + "urls": [ + { + "host": "buildbuddy.acme.com", + "helper": "remoteapis", + "config": { + "auth_method": "header", + "header_name": "x-buildbuddy-api-key", + "lookup_chain": [ + { + "source": "env", + "name": "BUILDBUDDY_API_KEY" + }, + { + "source": "keyring", + "service": "tweag-credential-helper:buildbuddy_api_key" + } + ] + } + } + ] +} +``` + +### BuildBarn + +BuildBarn supports a variety of authentication mechanisms specified in the Jsonnet key `authenticationPolicy`. +Only the polcies `jwt` and `remote` can be used to authenticate using HTTP headers (at the time of writing). +In the following snippets, we assume that your BuildBarn instance is hosted under `buildbarn.acme.com`. Replace this hostname with your own. + +#### JWT authentication + +Configure the BuildBarn Jsonnet for `jwt` (more setup needed - setting up and distributing keys is out of the scope of this document). It is also assumed that the user of Bazel already has access to a jwt in the `$BUILDBARN_API_KEY` environment variable, which must be encoded as follows: `Bearer `. + +```Jsonnet +authenticationPolicy: { + jwt: { + jwksFile: "some/file/path.jwks" + ... + } +} +``` + +#### Custom auth middleware / remote auth + +Configure the BuildBarn Jsonnet for `remote` (more setup needed - setting up the authentication middleware is out of the scope of this document). We assume that `x-buildbarn-api-key` is the header forwarded to the authentication middleware. It is also assumed that the user of Bazel already has access to a token in the `$BUILDBARN_API_KEY` environment variable, which must be encoded as-is. +Replace the endpoint address with the address of your custom authentication middleware. + +```Jsonnet +authenticationPolicy: { + remote: { + headers: ["x-buildbarn-api-key"] + endpoint: { + address: "address:port" + ... + } + ... + } +} +``` + +#### Bazel and credential-helper Configuration + +Add to your `.bazelrc`: + +``` +common --credential_helper=buildbarn.acme.com=%workspace%/tools/credential-helper +``` + +Add to your `.tweag-credential-helper.json`: +```json +{ + "urls": [ + { + "host": "buildbarn.acme.com", + "helper": "remoteapis", + "config": { + "auth_method": "header", + "header_name": "Authorization", + "lookup_chain": [ + { + "source": "env", + "name": "BUILDBARN_API_KEY" + }, + { + "source": "keyring", + "service": "tweag-credential-helper:buildbarn_api_key" + } + ] + } + } + ] +} +``` + +When using the system keyring, login with the following command: + +``` +$ echo -ne "$BUILDBARN_API_KEY" | tools/credential-helper setup-keyring tweag-credential-helper:buildbarn_api_key +``` + +### bazel-remote + +The only header-based authentication scheme [bazel-remote][bazel-remote] supports at the time of writing is basic auth (username and password). + +In the following snippets, we assume that your bazel-remote instance is hosted under `bazel-remote.acme.com`. Replace this hostname with your own. +Additionally, we assume that the user already created a `.htpasswd` file under `/etc/bazel-remote/.htpasswd` for bazel-remote that contains credentials for the user. + +Add to your bazel-remote configuration yaml: + +```yaml +htpasswd_file: /etc/bazel-remote/.htpasswd +``` + +Add to your `.bazelrc`: + +``` +common --credential_helper=bazel-remote.acme.com=%workspace%/tools/credential-helper +``` + +Add to your `.tweag-credential-helper.json`: +```json +{ + "urls": [ + { + "host": "bazel-remote.acme.com", + "helper": "remoteapis", + "config": { + "auth_method": "basic_auth", + "lookup_chain": [ + { + "source": "env", + "name": "CREDENTIAL_HELPER_REMOTEAPIS_SECRET" + }, + { + "source": "keyring", + "service": "tweag-credential-helper:remoteapis" + } + ] + } + } + ] +} +``` + +Users can either export the `$CREDENTIAL_HELPER_REMOTEAPIS_SECRET` environment variable, or login with the system keyring using the following command: + +``` +$ echo -ne "username:password" | tools/credential-helper setup-keyring tweag-credential-helper:remoteapis +``` + + +[remote-apis]: https://github.com/bazelbuild/remote-apis +[buildbuddy-setup]: https://app.buildbuddy.io/docs/setup/ +[lookup_chain]: /docs/lookup_chain.md +[bazel-remote]: https://github.com/buchgr/bazel-remote