Kibotos

Network policy

The mode and destination rules of a network policy decide which addresses a Workspace can reach directly. This page shows how to change them with kibo, how a destination address is matched, and when a change takes effect.

Changing the policy with kibo

kibo workspace network has three subcommands:

CommandEffect
network set <workspace-id> <mode>Replaces the whole policy: what you write on the command line is the complete policy, and lists you leave out are empty
network add <workspace-id>Adds the given entries to the corresponding lists; the mode and other entries stay the same
network remove <workspace-id>Removes the given entries from the corresponding lists; the mode and other entries stay the same

The commands below, in order, allow only one IPv4 range (denying all IPv6), block one address, unblock it, and finally turn off internet access:

kibo workspace network set "$workspace_id" public-internet --deny 0.0.0.0/0 --deny ::/0 --allow 203.0.113.0/24
kibo workspace network add "$workspace_id" --deny 198.51.100.7
kibo workspace network remove "$workspace_id" --deny 198.51.100.7
kibo workspace network set "$workspace_id" deny-all
  • Changing to deny-all clears both lists as well.
  • add works only on public-internet Workspaces. Change the mode with set first.
  • Adding an entry that already exists, or removing one that does not, only prints a notice on stderr and is not a failure.
  • Non-canonical entries, and more than 256 entries across both lists, are rejected before the request is sent, with exit code 2. See Writing entries.

Concurrent changes

The policy has a revision assigned by the server. It is 1 at creation and increments whenever the mode, the destination rules, the Egress, or the Resolver changes.

  • set without --expected-revision does not check the revision.
  • add and remove read the current policy first, then submit with the revision they read. If someone else changed the policy in the meantime, nothing changes and the command exits with 13. Read the policy again before deciding what to do.
  • When a script needs to replay add or remove, pass --command-id together with the --expected-revision read the first time.

Destination matching

PUBLIC_INTERNET allows TCP connections and ping initiated by the guest. DNS queries go only to one address on the guest's link; see Link DNS. Other UDP, such as QUIC (HTTP/3) and NTP to outside servers, is refused in both modes. A destination address is matched in this order:

  1. Private and special-purpose addresses: refused. This is the same in both modes, and allow cannot open them.
  2. In allow: allowed.
  3. In deny: refused. The connection fails immediately instead of timing out.
  4. Everything else: allowed.

The diagram below shows connections that do not go via Egress: those to the internet go direct through the node's uplink, and those to private and special-purpose addresses are refused at the policy check. Connections via Egress are not subject to rule 1; see Where connections go.

For example, deny with 0.0.0.0/0 and allow with 203.0.113.0/24 means "for IPv4, only this range".

  • Each entry applies only to its own address family. 0.0.0.0/0 does not affect IPv6. To narrow both families, also write ::/0.
  • DNS is not affected by allow and deny. Queries to the link DNS address still succeed, even when deny covers the deployment DNS servers or a whole address family. When a resolved address is in deny, the connection that follows fails immediately.

Writing entries

  • Entries must be canonical. CIDR host bits are zero, IPv4 has no leading zeros, and IPv6 uses the lowercase compressed form without a zone. A single address can omit the prefix length.
  • Non-canonical entries are rejected, not rewritten. An entry such as 10.0.0.1/8 is rejected with invalid_argument.
  • The two lists hold at most 256 entries combined. More are rejected. DENY_ALL with any entry is also rejected.
  • Entries are stored in the order given. Order and duplicates do not change the effect, but changing only the order still counts as a content change and increments the revision.

When changes take effect

The effect of a change depends on the Workspace state:

StateEffect
AVAILABLEThe request returns once the node has applied the new policy, waiting at most 1 minute. New connections are matched against it from then on, and existing connections are handled as in the next table
STOPPEDOnly the desired policy is updated; it takes effect at the next start
CREATING, STARTING, STOPPING, DELETING, FAILED, UNKNOWNReturns failed_precondition, and the policy stays the same

After you change the policy of a running Workspace:

ChangeExisting connectionsNew connections
NarrowingConnections whose destination falls in the newly refused range can no longer send or receive data; others are unaffectedMatched against the new policy
Changing to DENY_ALLAll cut offAll refused
WideningUnaffectedAvailable immediately, with no restart needed

Changes that alter where connections go (from direct to via Egress, or the reverse) have a grace period; see Changing where connections go.

A Workspace with allow or deny runs only on nodes that support these two lists, and never falls back to PUBLIC_INTERNET without rules:

  • When no such node is available at creation or start, the request returns failed_precondition with reason set to CAPABILITY_UNAVAILABLE.
  • When you add rules to a running Workspace whose node does not support them, the request returns the same error and the desired policy does not change.

When a change on an AVAILABLE Workspace does not succeed:

  • The node fails to apply it. The request returns the error, and the Workspace becomes FAILED with no applied policy. The guest keeps running, but which policy it is under is unknown. Stop the Workspace with kibo workspace stop --force, then start it.
  • The node does not answer within 1 minute. The request returns a retryable UNAVAILABLE, and the Workspace is UNKNOWN until the node reports again. Resend the change with the same --command-id, or check the result with kibo workspace get.

A successful request covers the policy itself. Check with kibo workspace get after a change to a STOPPED Workspace once it starts, after updating an Egress or Resolver the policy references, and while old connections drain. See Confirming the policy is in effect.

With the API

UpdateWorkspaceNetworkPolicy replaces the whole policy.

  • The revision is revision. The server assigns it: 1 at creation, incremented whenever any of mode, allow, deny, egresses, or resolvers changes. The value in requests is ignored.
  • To change only part of the policy, read the current policy first, edit it, and submit with the revision you read as the expected revision. If someone else changed it in the meantime, the change is rejected and the policy stays the same.
  • expected_revision is optional. When it is 0, no check is made. When it is not 0, a mismatched revision returns aborted, even if the content is the same as the current content.
  • The idempotency check ignores network_policy.revision. See Command IDs.
  • Whether the change is in effect is in the Workspace's network_policy_status.

The capability names are workspace.network_policy.destination_rules for allow and deny, and workspace.network_policy.update.expected_revision for expected_revision.

Warning

Older servers silently drop allow, deny, and expected_revision, and skip the revision check. Confirm that the capability names exist before writing these fields.

Next steps

  • Egress: send some connections out through the caller's own SOCKS5 endpoint.
  • DNS and Resolvers: where the guest's DNS queries go.
  • Network troubleshooting: confirm a change is in effect, and tell causes apart when a connection fails.

On this page