Skip to content

feat: enforce isolation between WonderNets with empty ACL policy#87

Merged
STRRL merged 4 commits intomasterfrom
STRRL/e2e-test-issue-84
Feb 1, 2026
Merged

feat: enforce isolation between WonderNets with empty ACL policy#87
STRRL merged 4 commits intomasterfrom
STRRL/e2e-test-issue-84

Conversation

@STRRL
Copy link
Copy Markdown
Owner

@STRRL STRRL commented Jan 30, 2026

Summary

  • Switch from autogroup:self ACL policy (which allows all traffic with *:*) to empty policy (deny all by default) to enforce network isolation between different users' WonderNets
  • Add E2E isolation test (e2e/test-isolation.sh) that verifies both API and network isolation
  • Add test infrastructure: worker-4/5 containers and testuser2 for multi-user testing

Closes #84

Test plan

  • Run ./e2e/test-isolation.sh to verify isolation works
  • Verify API isolation: each user only sees their own nodes via /coordinator/api/v1/nodes
  • Verify network isolation: workers from User 1's WonderNet cannot ping workers from User 2's WonderNet
  • Verify intra-WonderNet connectivity still works (workers in same WonderNet can communicate)

Switch from autogroup:self ACL policy (allows all traffic) to empty
policy (deny all by default) to enforce network isolation between
different users' WonderNets.

Add E2E isolation test that verifies:
- API isolation: users see only their own nodes
- Network isolation: workers from different WonderNets cannot communicate

Closes #84
Copilot AI review requested due to automatic review settings January 30, 2026 04:53
chatgpt-codex-connector[bot]

This comment was marked as resolved.

This comment was marked as resolved.

STRRL added 2 commits January 29, 2026 21:03
Use SetWonderNetIsolationPolicy instead of SetEmptyPolicy to preserve
connectivity for already-joined workers after coordinator restart.
Add a new GitHub Actions job that runs the isolation E2E tests
to verify that nodes in different WonderNets cannot communicate
with each other.
Copilot AI review requested due to automatic review settings February 1, 2026 00:11
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

pkg/headscale/acl.go:100

  • The functions GenerateEmptyPolicy and SetEmptyPolicy are not used anywhere in the codebase. The actual implementation uses SetWonderNetIsolationPolicy which generates proper isolation rules. These functions appear to be dead code that should either be removed or properly integrated if they serve a future purpose.
// SetEmptyPolicy sets an empty ACL policy (deny all by default, isolation enforced)
func (am *ACLManager) SetEmptyPolicy(ctx context.Context) error {
	am.mu.Lock()
	defer am.mu.Unlock()

	policy := GenerateEmptyPolicy()
	policyJSON, err := json.Marshal(policy)
	if err != nil {
		return fmt.Errorf("marshal policy: %w", err)
	}

	_, err = am.client.SetPolicy(ctx, &v1.SetPolicyRequest{Policy: string(policyJSON)})
	return err

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Remove unused functions superseded by the meshBackend interface:
- WonderNetManager.GetWonderNetNodes, GetNode, DeleteNode
- ACLManager.SetEmptyPolicy and GenerateEmptyPolicy

These methods were legacy implementations from before the meshBackend
abstraction layer was introduced. The codebase now uses the abstracted
versions in pkg/meshbackend/tailscale.
@STRRL STRRL merged commit fcb06a0 into master Feb 1, 2026
6 checks passed
@STRRL STRRL deleted the STRRL/e2e-test-issue-84 branch February 1, 2026 01:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

tailnet isolation

2 participants