6.7.5 Build Identities and Secrets
A Bazel build can succeed without printing a token and still copy that token into an action definition, a cache request, a build event, or a service log. Preventing credential leakage therefore requires two views at once: where secret bytes can travel, and which identity is allowed to perform each operation. A single “CI service account” hides both questions.
Draw the authority map before choosing credentials
Treat these as separate roles even when the first implementation happens to run them in one CI job:
| Role | Necessary authority | Authority it should not inherit |
|---|---|---|
| Bazel client | Request the intended build and read permitted results | Sign or publish merely because it started the build |
| Remote executor | Execute assigned actions and exchange their declared inputs and outputs | Reuse a publisher or signer credential inside an action |
| Cache writer | Bind reusable action results to the cache population it may write | Approve a release or write every cache namespace |
| Provenance builder | Make an attributable claim about the build and its immutable subject | Turn that claim into a signature from a different authority |
| Signer | Sign an already identified immutable subject or attestation | Publish it or rebuild it while holding signing authority |
| Publisher | Mutate the intended destination for an eligible, approved subject | Sign, rebuild, or write cache entries merely because it can publish |
The cache-writer row is developed in 6.2.3 Securing a Shared Remote Cache: authentication identifies a caller, authorization grants operations, and a cache instance or namespace is not an ACL by itself. Here the important extension is that cache-write authority does not imply builder, signer, or publisher authority. Conversely, trusting a builder does not authorize it to mutate a release destination.
Use distinct workload identities when a boundary has a different compromise consequence. If an executor credential is stolen, you should be able to revoke execution access without disabling signing. If a publisher is compromised, the cache should not automatically become writable. If separate credentials are not yet practical, document that coupling explicitly as blast radius rather than calling one broad identity “least privilege.”
H.9.3 Credentials takes this map into organizational ownership, distribution, rotation, and exception policy. At the build-infrastructure layer, your job is to define the technical handoffs and prove that one role cannot silently exercise another role's authority.
Audit persistence, not just process memory
A secret becomes dangerous when it crosses from a credential boundary into a surface retained, shared, or replayed by the build system. Audit each of these surfaces independently:
- Invocation and configuration. Inspect wrapper arguments,
.bazelrcexpansion, environment injection, and CI command logging. A value passed as a command-line header or environment variable is not private merely because the terminal UI later redacts it. - Action definition. Inspect action argv, environment, declared input files,
param files, and generated scripts. If secret bytes enter this description,
they may affect action identity or be sent to an executor. They may also be
recoverable from action-graph or execution diagnostics. In REAPI, the command
arguments and environment are content-addressed as a
Command; anActionrefers to that command and the input root, while cachedActionResultmetadata refers onward to output blobs.1 - Remote transfer and storage. Inspect client-to-executor requests, cache metadata, uploaded blobs, and backend request logs. Instance isolation may constrain reuse, but it does not make secret-bearing inputs acceptable.
- Build evidence. Inspect binary, JSON, and text BEP output, BES records, stdout and stderr attachments, profiles, execution logs, invocation metadata, and artifact links. Console redaction is only one renderer; it proves nothing about these retained representations. BEP is designed for programmatic build and test data, and BES transports those event bytes to a backend; profiles are retained files with invocation metadata.2,3
- Downstream handoff. Inspect provenance, signing requests, publication manifests, and destination audit logs. Pass an immutable artifact digest and the minimum evidence required by the next role, not the credential that authorized the previous role.
This audit separates a secret value from a non-secret identity claim. An invocation ID, authenticated principal name, or builder identity often needs to remain visible for attribution. A bearer token, private key, session cookie, or authorization header does not. Removing all identity from evidence makes incidents harder to investigate; retaining authentication material makes the evidence itself hazardous.
Put credentials at supported boundaries
For authenticated repository downloads, use the downloader's credential-helper
boundary instead of embedding tokens in repository rule attributes or performing
an action-time wget. Bazel selects a helper for the matching domain, passes it
the request URI, and receives HTTP headers from the helper. The configured build
surface contains the helper mapping rather than the token value.4
4.9.9 Credential Helper Protocol covers the helper protocol and host-matching rules;
the infrastructure concern here is preventing its output from crossing into
retained build surfaces.
That pattern solves a narrow problem: providing download authentication without
placing the credential in the build graph. It does not make the helper harmless.
The helper mapping and executable are privileged client configuration. Bazel can
load the mapping from rc files and accepts %workspace%-relative helper paths,
so an untrusted checkout must not get to select code that runs in the credential
context. Supply both the mapping and executable from a trusted user- or
CI-controlled boundary; treat a workspace-relative helper as checkout-controlled
executable code unless your trust model proves otherwise.5 Scope it to the
required hosts, review its output handling, and ensure its own stderr and service
logs do not print the returned header. Keep integrity verification as a separate
control; authentication says who served the request, not which bytes the build
intended to use.
Apply the same boundary rule elsewhere. Give the remote client a supported transport credential rather than a secret input file consumed by ordinary actions. Let an external signer receive the immutable subject digest established by 6.7.4 From Build to Release Candidate, rather than mounting a signing key into a cacheable packaging action. Let a publisher consume the eligible subject and evidence through its explicit handoff, rather than inheriting the entire build job's environment.
Prove absence with a seeded-secret test
Configuration review cannot prove that wrappers, plugins, error paths, and backends preserve the intended boundary. Create a canary credential containing a unique high-entropy marker, grant it only the smallest test permission, and run a fixture through both success and deliberate failure paths.
Collect the exact artifacts your production path retains:
- client and worker process arguments and sanitized environment inventories;
- action descriptions and execution logs;
- AC/CAS objects reachable from the test invocation;
- BEP files, BES records, profiles, stdout, and stderr;
- proxy, remote-cache, executor, credential-helper, signer, and publisher logs;
- generated provenance and publication manifests.
Search decoded structured fields and downloaded blobs, not only rendered text. Record which stores were inaccessible to the test identity; “not scanned” is not the same result as “secret absent.” The test passes only when the marker is absent from every in-scope retained surface and access tests show that each identity can perform its intended operation but not adjacent operations.
The runnable identity and secret boundary fixture
turns that contract into a deployment-neutral verifier. Its
retained-surface inventory and role matrix
keep signer and publisher separate, decode plain and base64 fields, and return
unknown for an inaccessible store. Its
negative controls
inject a canary into action and CAS-shaped records, grant a cache writer
publication authority, and merge signing with publication; every mutation is
rejected. The fixture does not simulate real IAM, a secret broker, AC/CAS, BES,
an executor, a signer, or a registry. Production adapters must enumerate and
retrieve those services' native retained surfaces and test their real permission
boundaries.
Include negative paths because they commonly log more context than successful ones. Make the helper fail, reject a remote request, fail an action after it reads its inputs, interrupt evidence upload, reject signing, and separately reject publication. Use a canary credential, never a production secret, because the purpose of this test is to discover persistence.
Contain compromise by identity and evidence
Revocation stops future use of a credential; it does not erase cached results, artifacts, logs, or attestations already produced under that identity. Prepare a response for each role:
- revoke the compromised authority without revoking unrelated roles;
- preserve authentication, authorization, invocation, digest, and time evidence;
- quarantine the affected producer cohort, cache population, artifacts, or release candidates using that evidence;
- rebuild the affected immutable subjects through an independently trusted path;
- reissue provenance, signatures, or publication state only where their own trust boundary was affected; and
- scan retained build and backend surfaces for the credential marker or known secret material and rotate any secondary credential exposed with it.
Do not infer that every artifact is bad merely because one client credential was stolen, but do not infer that artifacts are sound merely because the credential has been revoked. The authority map and retained evidence determine the suspect set. 6.7.6 Build Provenance and Attestations continues with what a builder can truthfully claim about a subject; this article supplies the identity separation needed to decide whether that claim is trustworthy.
Credential safety in Bazel is a data-flow and authority problem. Separate the client, executor, cache writer, provenance builder, signer, and publisher roles; then audit invocation configuration, action definitions, remote transfer, AC/CAS, BEP/BES, diagnostics, and downstream handoffs for secret persistence.
Use supported credential boundaries such as a domain-scoped downloader helper and external signing or publication handoffs. Prove the design with a unique canary secret, retained-surface scanning, and access-denial tests. After a compromise, revoke future authority, preserve evidence, quarantine the bounded suspect set, and rebuild through an independently trusted path—revocation alone does not repair results already produced.
Check your understanding · 4 questions
1.A repository's .bazelrc selects a %workspace% credential-helper executable. Why should release CI reject this arrangement for an untrusted checkout?
Select one answer
2.Match each release role to its narrowly permitted operation:
Drag each answer onto the matching prompt, or click an answer and then click a prompt
3.Which checks belong in a credible seeded-canary exercise? Select all that apply.
Select all that apply
4.All accessible build surfaces are free of the canary, but the test identity could not read the publisher's audit log. What is the correct result?
Select one answer
Footnotes
-
Remote APIs —
Command,Action,ActionResult, Action Cache, and CAS data-flow boundaries ↩ -
Build Event Protocol — programmatic event contents, BES transport, and referenced build files ↩
-
JSON Trace Profile — retained profile files and invocation metadata ↩
-
Fetching private data with Repo Rules and MODULE Extensions — downloader credential-helper flow, domain scoping, URL input, returned HTTP headers, and the danger of hard-coded credentials ↩
-
Bazel command-line reference — rc-configured
--credential_helpermappings and%workspace%-relative executables ↩