Help us shape the future of Go! Take the 2026 Go Developer Survey

innerwall

module
v0.5.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 29, 2026 License: Apache-2.0

README

Innerwall

Open-source microsegmentation for heterogeneous server estates: VMs, bare metal, and cloud instances, no orchestrator required.

A small agent on each workload observes the connections that reach it and programs the operating system's native firewall. A control plane turns label-based policy into per-host rulesets, pushes them over persistent streams, and renders the estate's real traffic as a live dependency map. An operator console embedded in the control plane shows that map, the fleet, the policy, and what enforcing it would break.

Status: v0.5.1. Enrollment and short-lived workload identity, the policy sync stream, flow telemetry with evidence gaps, policy authoring with dry runs, simulation, and enforcement on Linux (nftables), and the operator console all work end to end. Releases ship binaries — downloadable, checksummed, and signed — and a published control-plane image, which the Docker Compose quickstart now runs exactly as published, never rebuilding it from the checkout. Install from a release: docs/reference/versioning-and-install.md. What is deliberately not built yet, and what comes next, is in ROADMAP.md; what changed in each release is in CHANGELOG.md.

The console

Each image puts a screen of the shipped console in its dark theme (left) beside the same state in its light theme. More are in docs/img/console/.

Simulation review. A ruleset's would-block traffic from the workloads simulating it, with the verdict on whether it is safe to enforce, the evidence it rests on, and the promotion to enforcement.

Simulation review, dark and light

Flow map. The estate's real traffic between label groups, colored by what the policy decided or would decide.

Flow map, dark and light

Policy editor. Rules edited live, with every admission finding in place and a dry run that shows each workload's rendered change before anything is written.

Policy editor dry run, dark and light

Workloads. Every workload's mode, sync state against its latest rendered version, and agent health.

Workloads, dark and light

Why

  • East-west traffic is the blind spot. Perimeter controls say nothing about lateral movement, and most estates cannot even see it.
  • You cannot safely enforce what you cannot see. The workflow is visibility, then simulation, then enforcement: visibility is every workload's starting mode, the evidence is shown at each step, and promotion past evidence that does not support it takes an explicit acknowledgment (ADR-0001).
  • The host already has a firewall. Innerwall programs the existing packet filter atomically and observably instead of shipping a datapath (ADR-0003).
  • Central planes fail by being chatty. Agents hold one persistent stream; policy moves as versioned desired state; nothing polls the control plane (ADR-0002).
  • Fail static. Losing the control plane changes nothing on any host. The policy an agent acknowledged is persisted before it is applied and stays enforced from local disk (ADR-0011, ADR-0020).

Quickstart

[!IMPORTANT] Before you start: decide where the agents will run. The agent runs only on Linux, as root, with nftables. If any agent will run on a machine other than the one running the control plane (always the case when Docker runs on macOS or Windows), first read Name the control plane before the first start. The gateway's certificate is generated once, at the first start, and names only that machine's local names, so an agent on another machine cannot enroll against it. If the stack already started without the right names, innerwall ca issue-server reissues the certificate from the same signing authority and a restart presents it; nothing is enrolled again (a stack that has already started).

The supported v1 deployment is one control-plane binary and one Postgres (ADR-0017). Run the released image with Docker Compose, or install the released binaries. These docs describe v0.5.1, and every command below names it.

With Docker Compose
git clone https://github.com/innerwall-dev/innerwall.git
cd innerwall
git checkout v0.5.1     # the release these docs describe; a fresh clone is main
echo 'INNERWALL_IMAGE=ghcr.io/innerwall-dev/innerwall:0.5.1' > .env
docker compose up -d    # pulls the released control-plane image and starts it with Postgres

.env (git ignores it) names the image for every later docker compose command. Compose keys the stack's volumes by the directory's name, so a clone into a directory named innerwall picks up whatever state an earlier innerwall stack left behind, even after that clone was deleted. To start clean beside an earlier stack, add a line COMPOSE_PROJECT_NAME=<a new name> to .env before the first start (how to tell, and the other way out).

Set the operator password (the command line on the host is the only place it can be set):

docker compose exec innerwall /innerwall operator set-password

It prompts twice, without echo: type the password (at least 12 characters) at each prompt. Nothing goes on the command line or into the shell's history. To provision without a terminal, pipe it in on standard input: docker compose exec -T innerwall /innerwall operator set-password < password-file reads one line.

Open https://localhost:8080/ and log in. The certificate is self-signed, so the browser warns once. Before you accept it, compare it with the one the control plane logged: docker compose logs innerwall | grep "operator listener certificate" shows its sha256_fingerprint, and the browser shows the same value in the certificate's details (open the certificate from the warning page or the address bar; the SHA-256 fingerprint is listed there). A match means the page comes from your control plane and not from something in between, so the password you type next goes only to it.

docker compose up -d never builds: it runs the image .env names, pulled if it is not already present. Without INNERWALL_IMAGE in .env, every docker compose command stops with an error that names the line to add.

Fallback: build the image from the checkout. make dev builds the control-plane image from the checked-out source, console embedded, and starts the stack in the foreground. It ignores INNERWALL_IMAGE and names its build innerwall:dev, never a release's image name. Use it for a tree with changes, or a platform the released image does not cover. The plain docker compose commands on this page (exec, logs) still read .env, so in a checkout with no release named there, add the line for the dev build first: echo 'INNERWALL_IMAGE=innerwall:dev' >> .env.

With the release binaries

The control plane is one binary, for Linux or macOS: download innerwall_0.5.1_<os>_<arch>.tar.gz, verify it, and install it as versioning and install shows (the agent below takes the same steps). Then, with a reachable Postgres:

export INNERWALL_DATABASE_URL='postgres://innerwall:innerwall@127.0.0.1:5432/innerwall?sslmode=disable'
innerwall migrate
innerwall operator set-password
innerwall serve --init-ca --ca-dir ./state/ca --site lab --gateway-advertise-address localhost:8443

--init-ca creates the signing authority in ./state/ca on first start, with the listeners' certificates beside it; they name --tls-hosts (by default localhost,127.0.0.1), set before the first start as above; innerwall ca issue-server reissues the gateway's from the same authority if they need to change. Open https://localhost:8080/, and compare the fingerprint in the operator listener certificate log line as above.

Fallback: build from source. It needs Go (the version go.mod names) and Node 22 for the console:

make console    # builds the console into ui/dist/
make build      # bin/innerwall and bin/innerwall-agent, the console embedded

Use bin/innerwall and bin/innerwall-agent where this page says innerwall and innerwall-agent. make build-noconsole builds without Node; that binary serves the API and no console.

Enroll an agent

The agent runs on Linux as root, with nftables. It needs a provisioning token and the signing authority's certificate, delivered together out of band. Mint a token in the console (Workloads → Provisioning tokens → Mint token; the shown-once dialog prints the enroll command with your gateway address filled in) or on the command line, and fetch the certificate:

# Docker Compose
docker compose exec innerwall /innerwall token mint --name lab --label app=demo
docker compose cp innerwall:/var/lib/innerwall/ca/ca.crt ./ca.crt
# release binaries
innerwall token mint --name lab --label app=demo
cp ./state/ca/ca.crt ./ca.crt

On the host to protect, download the agent, verify it against the release's signed checksums, and install it (ARCH is amd64 or arm64):

VERSION=0.5.1 ARCH=amd64
ASSET=innerwall-agent_${VERSION}_linux_${ARCH}.tar.gz
base=https://github.com/innerwall-dev/innerwall/releases/download/v$VERSION
for f in "$ASSET" checksums.txt checksums.txt.sig checksums.txt.pem; do curl -fsSLO "$base/$f"; done
cosign verify-blob checksums.txt --signature checksums.txt.sig --certificate checksums.txt.pem \
  --certificate-identity "https://github.com/innerwall-dev/innerwall/.github/workflows/release.yml@refs/tags/v$VERSION" \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com
awk -v f="$ASSET" '$2 == f' checksums.txt | sha256sum -c
tar -xzf "$ASSET" innerwall-agent
sudo install -m 0755 innerwall-agent /usr/local/bin/innerwall-agent

cosign verify-blob (cosign 2.x) prints Verified OK only if checksums.txt was signed by the release workflow at that tag, and sha256sum -c prints OK only if the archive is the one it lists. A host without cosign can download and verify on a machine that has it, then copy over the archive and checksums.txt and repeat the sha256sum line. Neither binary checks for updates or sends telemetry. If no release archive fits the host, build the agent from source. Then enroll and run it:

sudo /usr/local/bin/innerwall-agent enroll --server localhost:8443 --token <provisioning-token> --bootstrap-ca ca.crt
sudo /usr/local/bin/innerwall-agent daemon --server localhost:8443

On another host, use the control plane's address in place of localhost; the gateway's certificate must name it (--tls-hosts, set before the control plane first starts: docs/deploy/multi-host-evaluation.md). The daemon's log warns connection byte accounting is off; flow byte counts will be zero on most hosts, because the kernel's per-connection byte accounting is off by default: flows are still counted, with zero bytes. Turn it on with sudo sysctl -w net.netfilter.nf_conntrack_acct=1; connections opened after that carry byte counts (keeping it across reboots is in troubleshooting). The agent stamps its flows with the host's clock, so keep it in sync: a VM on a laptop drifts when the laptop sleeps, and its flows then land at the wrong times until the clock is re-synced (docs/troubleshooting.md). The workload appears in the console's fleet, synced, in visibility mode: observed, never blocked. From there the path is the one the console walks: write a ruleset, move workloads to simulation, read the simulation review, and promote. A rule has no destination of its own: the ruleset's scope is the destination, so write one ruleset per tier you protect and let the dry run show which workloads each change reaches (docs/policy.md). sudo /usr/local/bin/innerwall-agent down removes the agent's firewall table at any time without the control plane. Running it in production, with more than one replica, behind load balancers, is in docs/deploy/README.md.

Layout

Path What lives there
proto/ Source of truth for the agent contract (ADR-0007, ADR-0015)
api/openapi.yaml The operator surface's contract, hand-authored (ADR-0021)
cmd/innerwall, cmd/innerwall-agent Control-plane and agent binaries
internal/ Control-plane services and agent internals, one package per boundary
internal/store/ Hand-written SQL, goose migrations, sqlc output (ADR-0006)
ui/ The operator console: Vite + React, embedded into the control plane (ADR-0008)
docs/adr/ Architecture decision records: the design's source of truth
docs/design/ The console's design package of record: tokens, brand book, component specs, and the record of its amendments and errata
docs/deploy/ Running it: deployment, the operator surface, high availability, and agents on other machines
docs/guides/ The operating loop, task by task: labeling, the first ruleset, the simulation review, promotion and enforcement, credentials, upgrading
docs/reference/ Both command lines, the operator API, workload states and evidence gaps, versioning and install
docs/policy.md The policy model: the scope is the destination, one ruleset per tier, authoring and the dry run
docs/troubleshooting.md Symptom, cause, and remedy for what operators meet, such as an agent whose clock has drifted
docs/development.md Prerequisites, make targets, where things live

Contributing

Read ARCHITECTURE.md, then docs/adr/, then CONTRIBUTING.md. Every authored commit is DCO signed off. Every PR is reviewed against the ADRs, including by an automated pass once it is ready for review (by an @claude mention instead when its author lacks write access). Security reports go to the address in SECURITY.md.

License

Innerwall's source code is licensed under Apache-2.0 (LICENSE). The control-plane binary also embeds the built console, which bundles third-party code and font files under their own licenses: the fonts under the SIL Open Font License 1.1, the code under permissive licenses. Their full texts ship inside the built console; THIRD-PARTY-NOTICES.md explains where. The Innerwall name and marks are retained by the project (ADR-0013).

Directories

Path Synopsis
cmd
innerwall command
Command innerwall is the control plane: one binary containing the API service, agent gateway, policy compiler, flow ingestion, and signing authority.
Command innerwall is the control plane: one binary containing the API service, agent gateway, policy compiler, flow ingestion, and signing authority.
innerwall-agent command
Command innerwall-agent runs on each workload.
Command innerwall-agent runs on each workload.
internal
agent
Package agent holds the agent internals as independent pieces sharing local state (ADR-0011): the sync daemon (sync/), which holds the stream, sends heartbeats and inventory, and applies each policy synchronously through the installed-policy store (enforce/); the credential holder and its renewal timer (credential/); and the flow collector and reporter (collect/).
Package agent holds the agent internals as independent pieces sharing local state (ADR-0011): the sync daemon (sync/), which holds the stream, sends heartbeats and inventory, and applies each policy synchronously through the installed-policy store (enforce/); the credential holder and its renewal timer (credential/); and the flow collector and reporter (collect/).
agent/collect
Package collect is the agent's flow collection loop: a Source observes connections on the host, an Aggregator folds them into one record per (source, destination, port, protocol, decision, rule) over the reporting window the control plane configures, holding at most a bounded number of distinct keys, a bounded Buffer holds closed windows until the Reporter ships them over ReportFlows, and overflow at either bound drops what does not fit and records the loss as an evidence gap.
Package collect is the agent's flow collection loop: a Source observes connections on the host, an Aggregator folds them into one record per (source, destination, port, protocol, decision, rule) over the reporting window the control plane configures, holding at most a bounded number of distinct keys, a bounded Buffer holds closed windows until the Reporter ships them over ReportFlows, and overflow at either bound drops what does not fit and records the loss as an evidence gap.
agent/collect/conntrack
Package conntrack observes inbound connections through the kernel's connection tracking over netlink (ADR-0003).
Package conntrack observes inbound connections through the kernel's connection tracking over netlink (ADR-0003).
agent/collect/nflog
Package nflog observes the packets the terminal rule of the owned table logs: what the policy did not permit.
Package nflog observes the packets the terminal rule of the owned table logs: what the policy did not permit.
agent/credential
Package credential is the agent's side of enrollment and renewal: it generates the workload keypair, builds certificate signing requests, calls the control plane, and keeps the resulting credential in a state directory the daemon reads (ADR-0016).
Package credential is the agent's side of enrollment and renewal: it generates the workload keypair, builds certificate signing requests, calls the control plane, and keeps the resulting credential in a state directory the daemon reads (ADR-0016).
agent/enforce
Package enforce holds the agent's installed-policy boundary.
Package enforce holds the agent's installed-policy boundary.
agent/enforce/nft
Package nft is the Linux enforcement backend: it installs a rendered WorkloadPolicy into one nftables table this agent owns, as a single atomic transaction, and never touches state outside that table (ADR-0003, ADR-0020).
Package nft is the Linux enforcement backend: it installs a rendered WorkloadPolicy into one nftables table this agent owns, as a single atomic transaction, and never touches state outside that table (ADR-0003, ADR-0020).
agent/health
Package health is reserved for a whole-process resource budget, which is deferred (ADR-0011 as amended); it holds no code.
Package health is reserved for a whole-process resource budget, which is deferred (ADR-0011 as amended); it holds no code.
agent/inventory
Package inventory collects the descriptive facts the agent reports: host facts (hostname, operating system, interfaces and their addresses) and a best-effort list of listening services.
Package inventory collects the descriptive facts the agent reports: host facts (hostname, operating system, interfaces and their addresses) and a best-effort list of listening services.
agent/sync
Package sync maintains the agent's single persistent stream to the control plane and applies versioned desired-state updates in order (ADR-0002, ADR-0015).
Package sync maintains the agent's single persistent stream to the control plane and applies versioned desired-state updates in order (ADR-0002, ADR-0015).
api
Package api serves the operator surface: the public REST/JSON API consumed by the console and by automation, on a listener of its own (ADR-0021).
Package api serves the operator surface: the public REST/JSON API consumed by the console and by automation, on a listener of its own (ADR-0021).
authn
Package authn is the authentication boundary of the operator surface (ADR-0021).
Package authn is the authentication boundary of the operator surface (ADR-0021).
buildinfo
Package buildinfo names the build a binary came from.
Package buildinfo names the build a binary came from.
ca
Package ca is the signing boundary for workload credentials.
Package ca is the signing boundary for workload credentials.
ca/fileca
Package fileca is the file-backed signing authority: a private key and a self-signed root certificate on local disk.
Package fileca is the file-backed signing authority: a private key and a self-signed root certificate on local disk.
cli
Package cli holds what the two command lines, innerwall and innerwall-agent, share in reading their arguments.
Package cli holds what the two command lines, innerwall and innerwall-agent, share in reading their arguments.
compiler
Package compiler renders the authored policy model plus registry state into each workload's concrete WorkloadPolicy and decides which versions advance (ADR-0018).
Package compiler renders the authored policy model plus registry state into each workload's concrete WorkloadPolicy and decides which versions advance (ADR-0018).
enroll
Package enroll is the enrollment domain: provisioning tokens and the exchange of a token plus a certificate signing request for a workload identity and credential, and the renewal of that credential by an already identified workload (ADR-0016).
Package enroll is the enrollment domain: provisioning tokens and the exchange of a token plus a certificate signing request for a workload identity and credential, and the renewal of that credential by an already identified workload (ADR-0016).
enroll/enrolltest
Package enrolltest holds test doubles for the enrollment domain.
Package enrolltest holds test doubles for the enrollment domain.
fleet
Package fleet is the operator's write domain over the registry and the renderer: editing a workload's labels, changing the enforcement mode of a set of workloads, previewing what a selector resolves to, and rendering a hypothetical policy set without persisting it.
Package fleet is the operator's write domain over the registry and the renderer: editing a workload's labels, changing the enforcement mode of a set of workloads, previewing what a selector resolves to, and rendering a hypothetical policy set without persisting it.
fleet/fleettest
Package fleettest holds an in-memory double of the stores the authoring and fleet domains write through (policy.Store, fleet.Store, and the compiler's render transaction), for tests of those domains and of the transports above them.
Package fleettest holds an in-memory double of the stores the authoring and fleet domains write through (policy.Store, fleet.Store, and the compiler's render transaction), for tests of those domains and of the transports above them.
flowstore
Package flowstore defines the FlowStore interface and its Postgres implementation.
Package flowstore defines the FlowStore interface and its Postgres implementation.
gateway
Package gateway is the agent-facing gRPC surface of the control plane.
Package gateway is the agent-facing gRPC surface of the control plane.
identity
Package identity is the single definition of workload identity as it appears in credentials.
Package identity is the single definition of workload identity as it appears in credentials.
ingest
Package ingest receives pre-aggregated flow windows from agents, resolves each record's peer at ingest (address → workload identity via the registry), and writes the windows and their evidence gaps through the FlowStore interface (ADR-0009, ADR-0019).
Package ingest receives pre-aggregated flow windows from agents, resolves each record's peer at ingest (address → workload identity via the registry), and writes the windows and their evidence gaps through the FlowStore interface (ADR-0009, ADR-0019).
operator
Package operator is the operator-surface authentication domain (ADR-0021): the single operator's password, browser sessions, and operator tokens.
Package operator is the operator-surface authentication domain (ADR-0021): the single operator's password, browser sessions, and operator tokens.
operator/operatortest
Package operatortest holds test doubles for the operator domain.
Package operatortest holds test doubles for the operator domain.
policy
Package policy is the authored policy domain: services, address groups, and rulesets as operators write them, the admission rules every mutation passes before it is persisted, and the persistence interface the store implements (ADR-0018).
Package policy is the authored policy domain: services, address groups, and rulesets as operators write them, the admission rules every mutation passes before it is persisted, and the persistence interface the store implements (ADR-0018).
readmodel
Package readmodel is the operator read model: the pure reads over persisted state that the console's screens and the command line issue.
Package readmodel is the operator read model: the pure reads over persisted state that the console's screens and the command line issue.
readmodel/readmodeltest
Package readmodeltest holds in-memory doubles of the read model's store and flow store for tests of the transports above it.
Package readmodeltest holds in-memory doubles of the read model's store and flow store for tests of the transports above it.
registry
Package registry is the inventory of workloads: their labels, enforcement mode, reported host facts and the addresses derived from them, listening services, agent details, and the convergence state the sync stream reports.
Package registry is the inventory of workloads: their labels, enforcement mode, reported host facts and the addresses derived from them, listening services, agent details, and the convergence state the sync stream reports.
rendered
Package rendered is the algebra of the rendered policy model: the canonical form of a WorkloadPolicy, the diff between two consecutive versions expressed as the wire contract's DeltaChange set, and the application of such a delta to a policy (ADR-0015, ADR-0018).
Package rendered is the algebra of the rendered policy model: the canonical form of a WorkloadPolicy, the diff between two consecutive versions expressed as the wire contract's DeltaChange set, and the application of such a delta to a policy (ADR-0015, ADR-0018).
store
Package store is the relational data layer: hand-written SQL in queries/, goose migrations in migrations/, and sqlc-generated Go in db/.
Package store is the relational data layer: hand-written SQL in queries/, goose migrations in migrations/, and sqlc-generated Go in db/.
storetest
Package storetest opens the Postgres-backed store for tests.
Package storetest opens the Postgres-backed store for tests.
Package ui carries the built operator console into the control-plane binary.
Package ui carries the built operator console into the control-plane binary.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL