BytesafeDependency Firewall

Manage config as code

Run firewall policy from a git repository. Repository layout, review flow, applying from CI, drift detection, and rollback.

Once policy lives in git (walked through once in the config as code tutorial), the remaining questions are operational: how to organize the files, who applies them, and how to notice when reality and git disagree. This page is the working setup.

Repository layout

One JSON file per firewall, exported with the CLI:

firewall-config/
  npm-firewall.json
  pypi-firewall.json
  maven-firewall.json
  README.md

Keep the files exactly as bsfw config export writes them. Hand-formatting invites noisy diffs; the export format is the canonical one.

The change flow

  1. Branch, edit the JSON (add a rule, change an exception, adjust an upstream).
  2. Open a pull request. The diff is the policy change; review it like code.
  3. On merge, apply:
bsfw config import --file firewall-config/npm-firewall.json

Import is a full upsert: the file replaces the firewall's configuration and the config version increments. A rule or exception deleted from the file is deleted on the firewall, and any change made in the dashboard since the file was exported is overwritten. Whoever (or whatever) runs the import needs the matching permissions, fw:update:rule and fw:update:exception for policy edits, fw:update:config for upstream changes, fw:create if the file's firewall ID is new.

Applying from CI

Run the import step on merge to the main branch. Two ways to authenticate:

  • Trusted Builder (recommended on GitHub Actions). No stored secret; grant the builder the update permissions and restrict it to the config repo. See GitHub Actions.
  • Service Access Token. Store it as a CI secret, scope it to the firewalls the repo manages, and give it only the update permissions it needs.

Append an interaction ID to the token (::${CI_PIPELINE_ID}) so each applied change is traceable to a pipeline run in the audit log.

Credentials stay out of the repo

Exports contain placeholders for upstream credentials and imports reject plaintext values, so the repo never carries secrets. On an existing firewall and upstream, imports keep the stored values untouched. A placeholder imported under a new firewall ID or for a new upstream resolves to empty. Set credentials once per environment with bsfw config credentials. See Manage upstream credentials.

Prevent and detect drift

Anyone with the right permissions on a firewall can still change it directly in the dashboard, and then git no longer matches reality. Three countermeasures, in order of how much they save you:

  • Grant write access only to the pipeline. Firewall permissions are granted per firewall to teams, and a user gets only what the firewall's map grants their teams. Namespace-level admin does not override it. Leave fw:update:config, fw:update:rule, and fw:update:exception out of the grants for everyday teams, and the dashboard becomes read-only for them: the import is then the only way policy changes. Service Access Tokens are not subject to the map, so the CI token keeps working. Two limits: the lockout guard requires at least one team to keep fw:update:config, so keep that team small, and anyone who can manage team membership can add themselves to it, which the audit log records.

  • Compare on a schedule or before each apply:

bsfw config export --firewall <firewall-id> | diff - firewall-config/npm-firewall.json

A non-empty diff means someone changed the firewall outside git. Decide per case: export and commit the change, or re-import the file to overrule it.

  • Watch the audit log for firewall.config.upsert, firewall.rule.upsert, and firewall.exception.upsert events whose actor is not the CI identity. See Review the audit log.

Note that the export includes the server-maintained version and updatedAt fields, which advance on every change; a diff that touches only those is not policy drift.

Roll back

Git is the primary rollback path: check out the previous file and import it. The server additionally keeps the last 20 config versions per firewall, with rollback via API (PUT /v1/<namespace-id>/config/<firewall-id>/version/{version}), useful when a bad change came from outside git. Both paths create a new version; nothing is rewritten. See the API reference.

Verify

After an apply, confirm the live config matches the file:

bsfw config export --firewall <firewall-id> | diff - firewall-config/npm-firewall.json && echo "in sync"

Expect a diff on version/updatedAt only (see above); anything else means the apply did not do what the file says.

On this page