Set up CI/CD pipelines
Connect GitHub Actions, GitLab CI/CD, Jenkins, Azure Pipelines, Bitbucket Pipelines, CircleCI, and Buildkite to the firewall, and trace every package request back to the run that made it.
Route your pipelines through the firewall and every dependency a build installs is checked against the same rules as a developer's install. Each pipeline gets its own token, and each request carries the run's ID. When a build fails on a blocked package, filter the logs on that run and you see which rule blocked what.
Before you start
- The repository has the firewall configured as its registry, reading the token from
BYTESAFE_TOKEN. Commit that configuration and the pipeline uses the firewall the same way a developer's machine does. Setup per package manager, including what differs in CI, is on the ecosystem pages. - You hold
ns:create:service-token, which admins have by default. Both a Service Access Token and a Trusted Builder need it.
Choose a credential
- GitHub Actions: a Trusted Builder. Each run proves its identity with OpenID Connect (OIDC) and exchanges it for a Service Access Token valid for 15 minutes. There is no secret to store in GitHub or to rotate.
- Every other CI system: a Service Access Token, stored as a secret in the CI system. Trusted Builders currently accept GitHub Actions only.
Either way the pipeline has a token of its own. Log entries name it, and revoking it stops that one pipeline.
GitHub Actions
- In the dashboard, open the user menu in the lower-left corner, select Access tokens, switch to Trusted builders, and select Add builder. Enter the GitHub owner and repository, give it
fw:access, and restrict it to the firewalls the workflow installs from. Copy the audience value. - Give the job
id-token: writepermission and add a step that exchanges the run's identity for a token:
- name: Get firewall token
env:
BYTESAFE_ENDPOINT: https://eu-sov-1.bytesafecloud.eu
BYTESAFE_NAMESPACE: <namespace-id>
BYTESAFE_TRUSTED_BUILDER_AUDIENCE: bytesafe:trusted-builder:6f1e9c2a-...
run: |
TOKEN="$(bsfw oidc exchange)::${GITHUB_RUN_ID}"
echo "::add-mask::$TOKEN"
echo "BYTESAFE_TOKEN=$TOKEN" >> "$GITHUB_ENV"Later steps in the job read BYTESAFE_TOKEN. The ::${GITHUB_RUN_ID} suffix tags each request with the run ID, so you can find the run in the logs.
The GitHub Actions tutorial covers the rest: installing bsfw on the runner, the exchange without the CLI, and what to check when the exchange fails.
Other CI systems
GitLab CI/CD, Jenkins, Azure Pipelines, Bitbucket Pipelines, CircleCI, and Buildkite all work the same way: a Service Access Token kept as a CI secret, with the run ID appended in the install step.
Create a Service Access Token
Create the token as described in Manage tokens, with these values for a pipeline:
- Name: the pipeline or build server it is for, such as
gitlab-webshoporjenkins-eu. Log entries show this name. - Validity: how long the pipeline will use it. Every token expires, so plan the replacement before it does.
- Permissions:
fw:accessis enough to install. Add publish permissions only for a pipeline that publishes. - Restrict to firewalls: the firewalls this pipeline installs from.
Copy the value right away; it is shown only once. To see which system made each request, create one token per pipeline or build server, add an interaction ID as described in Identify each run, or both. Separate tokens also let you revoke one system without affecting the others.
Store it as a CI secret
Store the token as a secret named BYTESAFE_TOKEN, and note the variable that identifies a run:
| CI system | Store the token as | Run ID variable |
|---|---|---|
| GitLab CI/CD | A masked variable under Settings > CI/CD > Variables | CI_PIPELINE_ID |
| Jenkins | A Secret text credential, bound with credentials() in the pipeline's environment block | BUILD_TAG |
| Azure Pipelines | A secret pipeline variable or variable group, mapped into each step with env: | BUILD_BUILDID |
| Bitbucket Pipelines | A Secured variable under Repository settings > Pipelines > Repository variables | BITBUCKET_BUILD_NUMBER |
| CircleCI | A project environment variable or a context | CIRCLE_WORKFLOW_ID |
| Buildkite | A Buildkite secret, exposed to the step with the secrets key | BUILDKITE_BUILD_ID |
Check that the secret reaches the install step. Azure Pipelines only passes a secret variable to a step that maps it with env:. A GitLab variable marked Protect variable is only available in pipelines on protected branches and tags.
Identify each run
In the install step, before the package manager runs, append the run ID to the token:
export BYTESAFE_TOKEN="${BYTESAFE_TOKEN}::${CI_PIPELINE_ID}"Swap in the run ID variable for your CI system. Keep the line in the same step as the install, because most CI systems start each step in a new shell.
The firewall splits off the suffix before it checks the token and records it as the request's interaction ID. This works whether the package manager sends the token in a header or inside a URL, such as Go's GOPROXY. In a URL, keep the ID to letters, digits, dots, and dashes. Jenkins' BUILD_TAG includes the job name, so use BUILD_NUMBER if job names contain spaces.
Find a run in the logs
Every request from the run carries its interaction ID:
-
Firewall logs record it on each entry. To see one run, filter on its ID:
bsfw logs --all-users --interaction-id "<run-id>"The CLI matches exactly, so
build-12does not returnbuild-123. In the dashboard, search for the ID on Logs, or open an entry from the run and select its interaction value; the dashboard search also matches part of an ID. -
Audit log entries made with the token carry it as
interactionId. -
Webhook events carry it, as
interactionon firewall events andinteractionIdon audit events. A block notification therefore names the run it came from.
When a build is blocked
The install step fails with the package manager's own error. For a blocked download, the message includes a request ID that leads to the log entry and the rule. Investigate a blocked install covers each kind of block.
If the package should be allowed, the developer whose build failed requests an exception, from the dashboard or with their own Personal Access Token. Service Access Tokens cannot request exceptions, because a request needs a person to notify of the decision. See Set up an exception workflow.
Troubleshooting
The firewall did not get a valid token. Check that the secret reaches the step that installs: Azure Pipelines secrets need an env: mapping, and protected GitLab variables are missing on unprotected branches. Then check on the Access tokens page that the token has not expired or been deleted. On GitHub Actions, a failing exchange is covered in When the exchange fails.
Requests that match no logging rule are not logged, so a run that installed only allowed packages can leave nothing behind. Add a log-only rule to see all traffic, as described in View logs. If the run should have matched a rule, check that its requests reached the firewall at all: a package manager without the firewall configured goes straight to the public registry.
Related
- Tutorial: GitHub Actions
- How-to: Manage tokens, View logs, Enforce firewall use
- Concept: Access and permissions
- Reference: Tokens, CLI, Logs
Set up an exception workflow
Let developers request exceptions when a rule blocks them, and let the team that owns your policy approve or deny each one.
Share configuration across firewalls
Let firewalls inherit rules, exceptions, and upstreams from a baseline firewall, so one policy change applies across the organization.