Compare commits

...

30 Commits

Author SHA1 Message Date
Kristoffer Dalby dcd95698e4 integration,ci: remove TestSubnetToSubnetACL
The integration test cannot prove end-to-end subnet-to-subnet data
plane in Docker-in-Docker: forwarding from eth0 through the
Tailscale tunnel interface requires Linux policy routing that
doesn't work in the hi test runner's container environment.

The #3157 fix (CIDR-only ACL making subnet routers peers) is
validated by the golden data compat tests (f10-f16) which compare
headscale's filter compilation and peer visibility against SaaS.

Updates #3157
2026-04-13 14:58:10 +00:00
Kristoffer Dalby 073f11b6bf testdata,policy/v2: add f16/f18 golden captures and fix compat test
f16: CIDR-only bidirectional ACL — proves SaaS makes subnet routers
peers with CIDR-only rules and generates correct filter rules.

f18: CIDR + tag-based ACL — adds tag:ha ↔ tag:router rules.

Fix TestRoutesCompatReduceRoutes to pair src↔dst per-rule instead
of cross-product across all rules. Tag-based rules resolve to node
IPs in filter dests, not subnet CIDRs — a source in the tag rule
should only be tested against that rule's destinations.

Updates #3157
2026-04-13 14:57:55 +00:00
Kristoffer Dalby 9b6bfd05bc servertest: approve only SaaS-approved routes in via compat tests
Use topology approved_routes instead of approving all advertised
routes. Nodes with unapproved exit routes were incorrectly getting
exit routes approved, causing AllowedIPs mismatches.

Updates #3157
2026-04-13 14:57:39 +00:00
Kristoffer Dalby fa94bd949c state: include approved exit routes in RoutesForPeer
SaaS golden data (routes-ea* captures) proves that approved exit
routes appear in every peer's AllowedIPs. The previous commit
incorrectly dropped them based on a via-grant scenario where
exit routes were not approved.

TestRoutesCompatPeerAllowedIPs validates this against all captured
netmaps: peer AllowedIPs = node IPs + HA primary routes + exit
routes, filtered through ReduceRoutes.

Updates #3157
2026-04-12 21:40:07 +00:00
Kristoffer Dalby cad0cb2f5c ci,lint: fix lint issues and add TestSubnetToSubnetACL to workflow
Updates #3157
2026-04-12 21:39:27 +00:00
Kristoffer Dalby c278418b94 policy/v2: add exit node auto-approval compat tests
15 scenarios (ea1-ea15) covering exitNode field, routes map, both,
wrong tags, dual nodes, and baselines.

SaaS only approves exit routes via exitNode field. Exit routes in
the routes map are ignored for exit approval but still wildcard
subnet approval. Headscale already matches this behavior.

Remove IsExitRoute skip from TestRoutesCompatAutoApproval.

Updates #3157
Updates #3178
2026-04-12 20:46:14 +00:00
Kristoffer Dalby 3a81dbd1c0 testdata: add tscap golden captures for all corpora
Updates #3157
2026-04-12 19:28:28 +00:00
Kristoffer Dalby 9d4af0009d policy/v2: derive exit node names from topology
Updates #3157
2026-04-12 19:23:52 +00:00
Kristoffer Dalby 077621eef3 state: drop exit routes from RoutesForPeer
Updates #3157
2026-04-12 19:23:52 +00:00
Kristoffer Dalby d11be77f1f testcapture: type captured data with tailcfg types
Updates #3157
2026-04-12 19:23:52 +00:00
Kristoffer Dalby f60f89647b policyutil: reduce filter rules by approved routes
Updates #3157
2026-04-12 19:23:52 +00:00
Kristoffer Dalby 387dcd679e policy/v2: ignore SSH check action implementation diffs
Updates #3157
2026-04-12 19:23:52 +00:00
Kristoffer Dalby f2f7c5704a hscontrol/types: silence zerolog by default in tests
Updates #3157
2026-04-12 19:23:52 +00:00
Kristoffer Dalby c26cf2f2d8 compat tests: switch to anonymized names
Updates #3157
2026-04-12 19:05:12 +00:00
Kristoffer Dalby f34765ad1e testcapture: add capture format package
Updates #3157
2026-04-12 19:05:12 +00:00
Kristoffer Dalby 7feb5a52e4 policy/v2: build ACL compat nodes from golden file topology
Updates #3157
2026-04-12 19:05:12 +00:00
Kristoffer Dalby 0cb9536784 policy/v2: remove obsolete equivalence tests
Updates #3157
2026-04-12 19:05:12 +00:00
Kristoffer Dalby 960219e52c policy/v2: make ACL error validation strict
Updates #3157
2026-04-12 19:05:12 +00:00
Kristoffer Dalby 8201be9b4b policy: document CanAccessRoute and filterForNodeLocked design
Updates #3157
2026-04-12 19:05:12 +00:00
Kristoffer Dalby f55d6c3cb0 policy/v2: wire PolicyManager through compiledGrant
Updates #3157
2026-04-12 19:05:12 +00:00
Kristoffer Dalby 1ea3b676f2 policyutil: fix reduceCapGrantRule and add reduction tests
Updates #3157
2026-04-12 19:05:12 +00:00
Kristoffer Dalby ac8fc70e7d policy/v2: add false-positive peer test for all golden files
Updates #3157
2026-04-12 19:05:12 +00:00
Kristoffer Dalby f678bcb6c2 policy/v2: add filter compilation equivalence tests
Updates #3157
2026-04-12 19:05:12 +00:00
Kristoffer Dalby 3e2dd93c33 servertest: improve via compat test infrastructure
Updates #3157
2026-04-12 19:05:12 +00:00
Kristoffer Dalby 8038c39e23 policy/matcher: add unit tests
Updates #3157
2026-04-12 19:05:12 +00:00
Kristoffer Dalby b9a9b5026f policy/v2: add auto-approval and route access compat tests
Updates #3157
2026-04-12 19:05:12 +00:00
Kristoffer Dalby 5816a5a8b1 policy/v2: add peer visibility compat tests for subnet ACLs
Updates #3157
2026-04-12 19:05:12 +00:00
Ubuntu 1d57358314 integration: add subnet-to-subnet ACL routing test
Updates #3157
2026-04-10 13:11:12 +00:00
Ubuntu 3c125e62a3 types: consider subnet routes as source identity in ACL matching
CanAccess and CanAccessRoute now check approved subnet routes
alongside Tailscale IPs when matching ACL source sets.

Fixes #3157
Fixes #3169
2026-04-10 13:11:11 +00:00
Ubuntu 8d3ae36675 types,policy: add tests for subnet-to-subnet route visibility
Updates #3157
2026-04-10 13:11:11 +00:00
1218 changed files with 8800402 additions and 128916 deletions
-2
View File
@@ -9,7 +9,6 @@ import (
"testing"
"github.com/juanfont/headscale/hscontrol/types"
"github.com/rs/zerolog"
"zombiezen.com/go/postgrestest"
)
@@ -20,7 +19,6 @@ func newSQLiteTestDB() (*HSDatabase, error) {
}
log.Printf("database path: %s", tmpDir+"/headscale_test.db")
zerolog.SetGlobalLevel(zerolog.Disabled)
db, err := NewHeadscaleDatabase(
&types.Config{
-43
View File
@@ -18,7 +18,6 @@ import (
"github.com/juanfont/headscale/hscontrol/types"
"github.com/juanfont/headscale/hscontrol/types/change"
"github.com/puzpuzpuz/xsync/v4"
"github.com/rs/zerolog"
"tailscale.com/tailcfg"
)
@@ -182,9 +181,6 @@ func benchBatcher(nodeCount, bufferSize int) (*Batcher, map[types.NodeID]chan *t
// BenchmarkAddToBatch_Broadcast measures the cost of broadcasting a change
// to all nodes via addToBatch (no worker processing, just queuing).
func BenchmarkAddToBatch_Broadcast(b *testing.B) {
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
for _, nodeCount := range []int{10, 100, 1000} {
b.Run(fmt.Sprintf("%dnodes", nodeCount), func(b *testing.B) {
batcher, _ := benchBatcher(nodeCount, 10)
@@ -213,9 +209,6 @@ func BenchmarkAddToBatch_Broadcast(b *testing.B) {
// BenchmarkAddToBatch_Targeted measures the cost of adding a targeted change
// to a single node.
func BenchmarkAddToBatch_Targeted(b *testing.B) {
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
for _, nodeCount := range []int{10, 100, 1000} {
b.Run(fmt.Sprintf("%dnodes", nodeCount), func(b *testing.B) {
batcher, _ := benchBatcher(nodeCount, 10)
@@ -251,9 +244,6 @@ func BenchmarkAddToBatch_Targeted(b *testing.B) {
// BenchmarkAddToBatch_FullUpdate measures the cost of a FullUpdate broadcast.
func BenchmarkAddToBatch_FullUpdate(b *testing.B) {
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
for _, nodeCount := range []int{10, 100, 1000} {
b.Run(fmt.Sprintf("%dnodes", nodeCount), func(b *testing.B) {
batcher, _ := benchBatcher(nodeCount, 10)
@@ -275,9 +265,6 @@ func BenchmarkAddToBatch_FullUpdate(b *testing.B) {
// BenchmarkProcessBatchedChanges measures the cost of moving pending changes
// to the work queue.
func BenchmarkProcessBatchedChanges(b *testing.B) {
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
for _, nodeCount := range []int{10, 100, 1000} {
b.Run(fmt.Sprintf("%dpending", nodeCount), func(b *testing.B) {
batcher, _ := benchBatcher(nodeCount, 10)
@@ -311,9 +298,6 @@ func BenchmarkProcessBatchedChanges(b *testing.B) {
// BenchmarkBroadcastToN measures end-to-end broadcast: addToBatch + processBatchedChanges
// to N nodes. Does NOT include worker processing (MapResponse generation).
func BenchmarkBroadcastToN(b *testing.B) {
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
for _, nodeCount := range []int{10, 100, 1000} {
b.Run(fmt.Sprintf("%dnodes", nodeCount), func(b *testing.B) {
batcher, _ := benchBatcher(nodeCount, 10)
@@ -339,9 +323,6 @@ func BenchmarkBroadcastToN(b *testing.B) {
// BenchmarkMultiChannelBroadcast measures the cost of sending a MapResponse
// to N nodes each with varying connection counts.
func BenchmarkMultiChannelBroadcast(b *testing.B) {
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
for _, nodeCount := range []int{10, 100, 1000} {
b.Run(fmt.Sprintf("%dnodes", nodeCount), func(b *testing.B) {
batcher, _ := benchBatcher(nodeCount, b.N+1)
@@ -387,9 +368,6 @@ func BenchmarkMultiChannelBroadcast(b *testing.B) {
// BenchmarkConcurrentAddToBatch measures addToBatch throughput under
// concurrent access from multiple goroutines.
func BenchmarkConcurrentAddToBatch(b *testing.B) {
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
for _, nodeCount := range []int{10, 100, 1000} {
b.Run(fmt.Sprintf("%dnodes", nodeCount), func(b *testing.B) {
batcher, _ := benchBatcher(nodeCount, 10)
@@ -440,9 +418,6 @@ func BenchmarkConcurrentAddToBatch(b *testing.B) {
// BenchmarkIsConnected measures the read throughput of IsConnected checks.
func BenchmarkIsConnected(b *testing.B) {
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
for _, nodeCount := range []int{10, 100, 1000} {
b.Run(fmt.Sprintf("%dnodes", nodeCount), func(b *testing.B) {
batcher, _ := benchBatcher(nodeCount, 1)
@@ -464,9 +439,6 @@ func BenchmarkIsConnected(b *testing.B) {
// BenchmarkConnectedMap measures the cost of building the full connected map.
func BenchmarkConnectedMap(b *testing.B) {
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
for _, nodeCount := range []int{10, 100, 1000} {
b.Run(fmt.Sprintf("%dnodes", nodeCount), func(b *testing.B) {
batcher, channels := benchBatcher(nodeCount, 1)
@@ -499,9 +471,6 @@ func BenchmarkConnectedMap(b *testing.B) {
// BenchmarkConnectionChurn measures the cost of add/remove connection cycling
// which simulates client reconnection patterns.
func BenchmarkConnectionChurn(b *testing.B) {
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
for _, nodeCount := range []int{10, 100, 1000} {
b.Run(fmt.Sprintf("%dnodes", nodeCount), func(b *testing.B) {
batcher, channels := benchBatcher(nodeCount, 10)
@@ -545,9 +514,6 @@ func BenchmarkConnectionChurn(b *testing.B) {
// BenchmarkConcurrentSendAndChurn measures the combined cost of sends happening
// concurrently with connection churn - the hot path in production.
func BenchmarkConcurrentSendAndChurn(b *testing.B) {
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
for _, nodeCount := range []int{10, 100} {
b.Run(fmt.Sprintf("%dnodes", nodeCount), func(b *testing.B) {
batcher, channels := benchBatcher(nodeCount, 100)
@@ -620,9 +586,6 @@ func BenchmarkAddNode(b *testing.B) {
b.Skip("skipping full pipeline benchmark in short mode")
}
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
for _, nodeCount := range []int{10, 100} {
b.Run(fmt.Sprintf("%dnodes", nodeCount), func(b *testing.B) {
testData, cleanup := setupBatcherWithTestData(b, NewBatcherAndMapper, 1, nodeCount, largeBufferSize)
@@ -683,9 +646,6 @@ func BenchmarkFullPipeline(b *testing.B) {
b.Skip("skipping full pipeline benchmark in short mode")
}
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
for _, nodeCount := range []int{10, 100} {
b.Run(fmt.Sprintf("%dnodes", nodeCount), func(b *testing.B) {
testData, cleanup := setupBatcherWithTestData(b, NewBatcherAndMapper, 1, nodeCount, largeBufferSize)
@@ -738,9 +698,6 @@ func BenchmarkMapResponseFromChange(b *testing.B) {
b.Skip("skipping full pipeline benchmark in short mode")
}
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
for _, nodeCount := range []int{10, 100} {
b.Run(fmt.Sprintf("%dnodes", nodeCount), func(b *testing.B) {
testData, cleanup := setupBatcherWithTestData(b, NewBatcherAndMapper, 1, nodeCount, largeBufferSize)
@@ -22,7 +22,6 @@ import (
"github.com/juanfont/headscale/hscontrol/types/change"
"github.com/juanfont/headscale/hscontrol/util"
"github.com/puzpuzpuz/xsync/v4"
"github.com/rs/zerolog"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"tailscale.com/tailcfg"
@@ -473,9 +472,6 @@ func TestProcessBatchedChanges_BundlesChangesPerNode(t *testing.T) {
// could process bundles from tick N and tick N+1 concurrently for the same
// node, causing out-of-order delivery and races on lastSentPeers.
func TestWorkMu_PreventsInterTickRace(t *testing.T) {
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
mc := newMultiChannelNodeConn(1, nil)
ch := make(chan *tailcfg.MapResponse, 100)
entry := &connectionEntry{
@@ -848,9 +844,6 @@ func TestBug3_CleanupOfflineNodes_TOCTOU(t *testing.T) {
// BUG: batcher_lockfree.go worker() - no nil check after b.nodes.Load()
// FIX: Add nil guard: `exists && nc != nil` in both sync and async paths.
func TestBug5_WorkerPanicKillsWorkerPermanently(t *testing.T) {
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
lb := setupLightweightBatcher(t, 3, 10)
defer lb.cleanup()
@@ -926,9 +919,6 @@ func TestBug5_WorkerPanicKillsWorkerPermanently(t *testing.T) {
// BUG: batcher_lockfree.go:163-166 - Start() has no "already started" check
// FIX: Add sync.Once or atomic.Bool to prevent multiple Start() calls.
func TestBug6_StartCalledMultipleTimes_GoroutineLeak(t *testing.T) {
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
lb := setupLightweightBatcher(t, 3, 10)
lb.b.workers = 2
@@ -1041,9 +1031,6 @@ func TestBug7_CleanupOfflineNodes_PendingChangesCleanedStructurally(t *testing.T
// (timeouts happen here), then write-lock only to remove failed connections.
// The lock is now held only for O(N) pointer copies, not for N*50ms I/O.
func TestBug8_SerialTimeoutUnderWriteLock(t *testing.T) {
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
mc := newMultiChannelNodeConn(1, nil)
// Add 5 stale connections (unbuffered, no reader = will timeout at 50ms each)
@@ -1147,9 +1134,6 @@ func TestScale1000_AddToBatch_Broadcast(t *testing.T) {
t.Skip("skipping 1000-node test in short mode")
}
zerolog.SetGlobalLevel(zerolog.ErrorLevel)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
lb := setupLightweightBatcher(t, 1000, 10)
defer lb.cleanup()
@@ -1180,9 +1164,6 @@ func TestScale1000_ProcessBatchedWithConcurrentAdd(t *testing.T) {
t.Skip("skipping 1000-node test in short mode")
}
zerolog.SetGlobalLevel(zerolog.ErrorLevel)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
lb := setupLightweightBatcher(t, 1000, 10)
defer lb.cleanup()
@@ -1235,9 +1216,6 @@ func TestScale1000_MultiChannelBroadcast(t *testing.T) {
t.Skip("skipping 1000-node test in short mode")
}
zerolog.SetGlobalLevel(zerolog.ErrorLevel)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
const (
nodeCount = 1000
bufferSize = 5
@@ -1338,9 +1316,6 @@ func TestScale1000_ConnectionChurn(t *testing.T) {
t.Skip("skipping 1000-node test in short mode")
}
zerolog.SetGlobalLevel(zerolog.ErrorLevel)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
lb := setupLightweightBatcher(t, 1000, 20)
defer lb.cleanup()
@@ -1440,9 +1415,6 @@ func TestScale1000_ConcurrentAddRemove(t *testing.T) {
t.Skip("skipping 1000-node test in short mode")
}
zerolog.SetGlobalLevel(zerolog.ErrorLevel)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
lb := setupLightweightBatcher(t, 1000, 10)
defer lb.cleanup()
@@ -1484,9 +1456,6 @@ func TestScale1000_IsConnectedConsistency(t *testing.T) {
t.Skip("skipping 1000-node test in short mode")
}
zerolog.SetGlobalLevel(zerolog.ErrorLevel)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
lb := setupLightweightBatcher(t, 1000, 10)
defer lb.cleanup()
@@ -1553,9 +1522,6 @@ func TestScale1000_BroadcastDuringNodeChurn(t *testing.T) {
t.Skip("skipping 1000-node test in short mode")
}
zerolog.SetGlobalLevel(zerolog.ErrorLevel)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
lb := setupLightweightBatcher(t, 1000, 10)
defer lb.cleanup()
@@ -1640,9 +1606,6 @@ func TestScale1000_WorkChannelSaturation(t *testing.T) {
t.Skip("skipping 1000-node test in short mode")
}
zerolog.SetGlobalLevel(zerolog.ErrorLevel)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
// Create batcher with SMALL work channel to force saturation
b := &Batcher{
tick: time.NewTicker(10 * time.Millisecond),
@@ -1718,9 +1681,6 @@ func TestScale1000_FullUpdate_AllNodesGetPending(t *testing.T) {
t.Skip("skipping 1000-node test in short mode")
}
zerolog.SetGlobalLevel(zerolog.ErrorLevel)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
lb := setupLightweightBatcher(t, 1000, 10)
defer lb.cleanup()
@@ -1756,9 +1716,6 @@ func TestScale1000_AllToAll_FullPipeline(t *testing.T) {
t.Skip("skipping 1000-node test with race detector (bcrypt setup too slow)")
}
zerolog.SetGlobalLevel(zerolog.ErrorLevel)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
t.Logf("setting up 1000-node test environment (this may take a minute)...")
testData, cleanup := setupBatcherWithTestData(t, NewBatcherAndMapper, 1, 1000, 200)
@@ -21,7 +21,6 @@ import (
"github.com/juanfont/headscale/hscontrol/types"
"github.com/juanfont/headscale/hscontrol/types/change"
"github.com/rs/zerolog"
"tailscale.com/tailcfg"
)
@@ -40,9 +39,6 @@ var (
// BenchmarkScale_IsConnected tests single-node lookup at increasing map sizes.
func BenchmarkScale_IsConnected(b *testing.B) {
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
for _, n := range scaleCountsO1 {
b.Run(strconv.Itoa(n), func(b *testing.B) {
batcher, _ := benchBatcher(n, 1)
@@ -65,9 +61,6 @@ func BenchmarkScale_IsConnected(b *testing.B) {
// BenchmarkScale_AddToBatch_Targeted tests single-node targeted change at
// increasing map sizes. The map size should not affect per-operation cost.
func BenchmarkScale_AddToBatch_Targeted(b *testing.B) {
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
for _, n := range scaleCountsO1 {
b.Run(strconv.Itoa(n), func(b *testing.B) {
batcher, _ := benchBatcher(n, 10)
@@ -104,9 +97,6 @@ func BenchmarkScale_AddToBatch_Targeted(b *testing.B) {
// BenchmarkScale_ConnectionChurn tests add/remove connection cycle.
// The map size should not affect per-operation cost for a single node.
func BenchmarkScale_ConnectionChurn(b *testing.B) {
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
for _, n := range scaleCountsO1 {
b.Run(strconv.Itoa(n), func(b *testing.B) {
batcher, channels := benchBatcher(n, 10)
@@ -152,9 +142,6 @@ func BenchmarkScale_ConnectionChurn(b *testing.B) {
// BenchmarkScale_AddToBatch_Broadcast tests broadcasting a change to ALL nodes.
// Cost should scale linearly with node count.
func BenchmarkScale_AddToBatch_Broadcast(b *testing.B) {
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
for _, n := range scaleCountsLinear {
b.Run(strconv.Itoa(n), func(b *testing.B) {
batcher, _ := benchBatcher(n, 10)
@@ -182,9 +169,6 @@ func BenchmarkScale_AddToBatch_Broadcast(b *testing.B) {
// BenchmarkScale_AddToBatch_FullUpdate tests FullUpdate broadcast cost.
func BenchmarkScale_AddToBatch_FullUpdate(b *testing.B) {
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
for _, n := range scaleCountsLinear {
b.Run(strconv.Itoa(n), func(b *testing.B) {
batcher, _ := benchBatcher(n, 10)
@@ -205,9 +189,6 @@ func BenchmarkScale_AddToBatch_FullUpdate(b *testing.B) {
// BenchmarkScale_ProcessBatchedChanges tests draining pending changes into work queue.
func BenchmarkScale_ProcessBatchedChanges(b *testing.B) {
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
for _, n := range scaleCountsLinear {
b.Run(strconv.Itoa(n), func(b *testing.B) {
batcher, _ := benchBatcher(n, 10)
@@ -238,9 +219,6 @@ func BenchmarkScale_ProcessBatchedChanges(b *testing.B) {
// BenchmarkScale_BroadcastToN tests end-to-end: addToBatch + processBatchedChanges.
func BenchmarkScale_BroadcastToN(b *testing.B) {
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
for _, n := range scaleCountsLinear {
b.Run(strconv.Itoa(n), func(b *testing.B) {
batcher, _ := benchBatcher(n, 10)
@@ -267,9 +245,6 @@ func BenchmarkScale_BroadcastToN(b *testing.B) {
// This isolates the multiChannelNodeConn.send() cost.
// Uses large buffered channels to avoid goroutine drain overhead.
func BenchmarkScale_SendToAll(b *testing.B) {
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
for _, n := range scaleCountsLinear {
b.Run(strconv.Itoa(n), func(b *testing.B) {
// b.N+1 buffer so sends never block
@@ -300,9 +275,6 @@ func BenchmarkScale_SendToAll(b *testing.B) {
// BenchmarkScale_ConnectedMap tests building the full connected/disconnected map.
func BenchmarkScale_ConnectedMap(b *testing.B) {
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
for _, n := range scaleCountsHeavy {
b.Run(strconv.Itoa(n), func(b *testing.B) {
batcher, channels := benchBatcher(n, 1)
@@ -335,9 +307,6 @@ func BenchmarkScale_ConnectedMap(b *testing.B) {
// BenchmarkScale_ComputePeerDiff tests peer diff computation at scale.
// Each node tracks N-1 peers, with 10% removed.
func BenchmarkScale_ComputePeerDiff(b *testing.B) {
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
for _, n := range scaleCountsHeavy {
b.Run(strconv.Itoa(n), func(b *testing.B) {
mc := newMultiChannelNodeConn(1, nil)
@@ -366,9 +335,6 @@ func BenchmarkScale_ComputePeerDiff(b *testing.B) {
// BenchmarkScale_UpdateSentPeers_Full tests full peer list update.
func BenchmarkScale_UpdateSentPeers_Full(b *testing.B) {
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
for _, n := range scaleCountsHeavy {
b.Run(strconv.Itoa(n), func(b *testing.B) {
mc := newMultiChannelNodeConn(1, nil)
@@ -391,9 +357,6 @@ func BenchmarkScale_UpdateSentPeers_Full(b *testing.B) {
// BenchmarkScale_UpdateSentPeers_Incremental tests incremental peer updates (10% new).
func BenchmarkScale_UpdateSentPeers_Incremental(b *testing.B) {
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
for _, n := range scaleCountsHeavy {
b.Run(strconv.Itoa(n), func(b *testing.B) {
mc := newMultiChannelNodeConn(1, nil)
@@ -428,9 +391,6 @@ func BenchmarkScale_UpdateSentPeers_Incremental(b *testing.B) {
// ~1.6 connections on average (every 3rd node has 3 connections).
// Uses large buffered channels to avoid goroutine drain overhead.
func BenchmarkScale_MultiChannelBroadcast(b *testing.B) {
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
for _, n := range scaleCountsHeavy {
b.Run(strconv.Itoa(n), func(b *testing.B) {
// Use b.N+1 buffer so sends never block
@@ -480,9 +440,6 @@ func BenchmarkScale_MultiChannelBroadcast(b *testing.B) {
// BenchmarkScale_ConcurrentAddToBatch tests parallel addToBatch throughput.
func BenchmarkScale_ConcurrentAddToBatch(b *testing.B) {
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
for _, n := range scaleCountsConc {
b.Run(strconv.Itoa(n), func(b *testing.B) {
batcher, _ := benchBatcher(n, 10)
@@ -529,9 +486,6 @@ func BenchmarkScale_ConcurrentAddToBatch(b *testing.B) {
// sending to all nodes while 10% of connections are churning concurrently.
// Uses large buffered channels to avoid goroutine drain overhead.
func BenchmarkScale_ConcurrentSendAndChurn(b *testing.B) {
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
for _, n := range scaleCountsConc {
b.Run(strconv.Itoa(n), func(b *testing.B) {
batcher, channels := benchBatcher(n, b.N+1)
@@ -602,9 +556,6 @@ func BenchmarkScale_ConcurrentSendAndChurn(b *testing.B) {
// - 10% full updates (broadcast with full map)
// All while 10% of connections are churning.
func BenchmarkScale_MixedWorkload(b *testing.B) {
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
for _, n := range scaleCountsConc {
b.Run(strconv.Itoa(n), func(b *testing.B) {
batcher, channels := benchBatcher(n, 10)
@@ -722,9 +673,6 @@ func BenchmarkScale_AddAllNodes(b *testing.B) {
b.Skip("skipping full pipeline benchmark in short mode")
}
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
for _, nodeCount := range []int{10, 50, 100, 200, 500} {
b.Run(strconv.Itoa(nodeCount), func(b *testing.B) {
testData, cleanup := setupBatcherWithTestData(b, NewBatcherAndMapper, 1, nodeCount, largeBufferSize)
@@ -785,9 +733,6 @@ func BenchmarkScale_SingleAddNode(b *testing.B) {
b.Skip("skipping full pipeline benchmark in short mode")
}
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
for _, nodeCount := range []int{10, 50, 100, 200, 500, 1000} {
b.Run(strconv.Itoa(nodeCount), func(b *testing.B) {
testData, cleanup := setupBatcherWithTestData(b, NewBatcherAndMapper, 1, nodeCount, largeBufferSize)
@@ -851,9 +796,6 @@ func BenchmarkScale_MapResponse_DERPMap(b *testing.B) {
b.Skip("skipping full pipeline benchmark in short mode")
}
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
for _, nodeCount := range []int{10, 50, 100, 200, 500} {
b.Run(strconv.Itoa(nodeCount), func(b *testing.B) {
testData, cleanup := setupBatcherWithTestData(b, NewBatcherAndMapper, 1, nodeCount, largeBufferSize)
@@ -903,9 +845,6 @@ func BenchmarkScale_MapResponse_FullUpdate(b *testing.B) {
b.Skip("skipping full pipeline benchmark in short mode")
}
zerolog.SetGlobalLevel(zerolog.Disabled)
defer zerolog.SetGlobalLevel(zerolog.DebugLevel)
for _, nodeCount := range []int{10, 50, 100, 200, 500} {
b.Run(strconv.Itoa(nodeCount), func(b *testing.B) {
testData, cleanup := setupBatcherWithTestData(b, NewBatcherAndMapper, 1, nodeCount, largeBufferSize)
+430
View File
@@ -1 +1,431 @@
package matcher
import (
"net/netip"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"tailscale.com/tailcfg"
)
func TestMatchFromStrings(t *testing.T) {
t.Parallel()
tests := []struct {
name string
srcs []string
dsts []string
wantSrc netip.Addr
wantDst netip.Addr
srcIn bool
dstIn bool
}{
{
name: "basic CIDR match",
srcs: []string{"10.0.0.0/8"},
dsts: []string{"192.168.1.0/24"},
wantSrc: netip.MustParseAddr("10.1.2.3"),
wantDst: netip.MustParseAddr("192.168.1.100"),
srcIn: true,
dstIn: true,
},
{
name: "basic CIDR no match",
srcs: []string{"10.0.0.0/8"},
dsts: []string{"192.168.1.0/24"},
wantSrc: netip.MustParseAddr("172.16.0.1"),
wantDst: netip.MustParseAddr("10.0.0.1"),
srcIn: false,
dstIn: false,
},
{
name: "wildcard matches everything",
srcs: []string{"*"},
dsts: []string{"*"},
wantSrc: netip.MustParseAddr("8.8.8.8"),
wantDst: netip.MustParseAddr("1.1.1.1"),
srcIn: true,
dstIn: true,
},
{
name: "wildcard matches IPv6",
srcs: []string{"*"},
dsts: []string{"*"},
wantSrc: netip.MustParseAddr("2001:db8::1"),
wantDst: netip.MustParseAddr("fd7a:115c:a1e0::1"),
srcIn: true,
dstIn: true,
},
{
name: "single IP source",
srcs: []string{"100.64.0.1"},
dsts: []string{"10.0.0.0/8"},
wantSrc: netip.MustParseAddr("100.64.0.1"),
wantDst: netip.MustParseAddr("10.33.0.1"),
srcIn: true,
dstIn: true,
},
{
name: "single IP source no match",
srcs: []string{"100.64.0.1"},
dsts: []string{"10.0.0.0/8"},
wantSrc: netip.MustParseAddr("100.64.0.2"),
wantDst: netip.MustParseAddr("10.33.0.1"),
srcIn: false,
dstIn: true,
},
{
name: "multiple CIDRs",
srcs: []string{"10.0.0.0/8", "172.16.0.0/12"},
dsts: []string{"192.168.0.0/16", "100.64.0.0/10"},
wantSrc: netip.MustParseAddr("172.20.0.1"),
wantDst: netip.MustParseAddr("100.100.0.1"),
srcIn: true,
dstIn: true,
},
{
name: "IPv6 CIDR",
srcs: []string{"fd7a:115c:a1e0::/48"},
dsts: []string{"2001:db8::/32"},
wantSrc: netip.MustParseAddr("fd7a:115c:a1e0::1"),
wantDst: netip.MustParseAddr("2001:db8::1"),
srcIn: true,
dstIn: true,
},
{
name: "empty sources and destinations",
srcs: []string{},
dsts: []string{},
wantSrc: netip.MustParseAddr("10.0.0.1"),
wantDst: netip.MustParseAddr("10.0.0.1"),
srcIn: false,
dstIn: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
m := MatchFromStrings(tt.srcs, tt.dsts)
assert.Equal(t, tt.srcIn, m.SrcsContainsIPs(tt.wantSrc),
"SrcsContainsIPs(%s)", tt.wantSrc)
assert.Equal(t, tt.dstIn, m.DestsContainsIP(tt.wantDst),
"DestsContainsIP(%s)", tt.wantDst)
})
}
}
func TestMatchFromFilterRule(t *testing.T) {
t.Parallel()
tests := []struct {
name string
rule tailcfg.FilterRule
checkSrc netip.Addr
checkDst netip.Addr
srcMatch bool
dstMatch bool
}{
{
name: "standard rule with port range",
rule: tailcfg.FilterRule{
SrcIPs: []string{"100.64.0.1", "fd7a:115c:a1e0::1"},
DstPorts: []tailcfg.NetPortRange{
{IP: "10.33.0.0/16", Ports: tailcfg.PortRange{First: 0, Last: 65535}},
},
},
checkSrc: netip.MustParseAddr("100.64.0.1"),
checkDst: netip.MustParseAddr("10.33.0.50"),
srcMatch: true,
dstMatch: true,
},
{
name: "wildcard destination",
rule: tailcfg.FilterRule{
SrcIPs: []string{"10.0.0.0/8"},
DstPorts: []tailcfg.NetPortRange{
{IP: "*"},
},
},
checkSrc: netip.MustParseAddr("10.1.1.1"),
checkDst: netip.MustParseAddr("8.8.8.8"),
srcMatch: true,
dstMatch: true,
},
{
name: "multiple DstPorts entries",
rule: tailcfg.FilterRule{
SrcIPs: []string{"100.64.0.1"},
DstPorts: []tailcfg.NetPortRange{
{IP: "10.33.0.0/16"},
{IP: "192.168.1.0/24"},
},
},
checkSrc: netip.MustParseAddr("100.64.0.1"),
checkDst: netip.MustParseAddr("192.168.1.50"),
srcMatch: true,
dstMatch: true,
},
{
name: "empty DstPorts",
rule: tailcfg.FilterRule{
SrcIPs: []string{"100.64.0.1"},
DstPorts: nil,
},
checkSrc: netip.MustParseAddr("100.64.0.1"),
checkDst: netip.MustParseAddr("10.0.0.1"),
srcMatch: true,
dstMatch: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
m := MatchFromFilterRule(tt.rule)
assert.Equal(t, tt.srcMatch, m.SrcsContainsIPs(tt.checkSrc),
"SrcsContainsIPs(%s)", tt.checkSrc)
assert.Equal(t, tt.dstMatch, m.DestsContainsIP(tt.checkDst),
"DestsContainsIP(%s)", tt.checkDst)
})
}
}
func TestMatchesFromFilterRules(t *testing.T) {
t.Parallel()
rules := []tailcfg.FilterRule{
{
SrcIPs: []string{"10.0.0.0/8"},
DstPorts: []tailcfg.NetPortRange{{IP: "192.168.1.0/24"}},
},
{
SrcIPs: []string{"172.16.0.0/12"},
DstPorts: []tailcfg.NetPortRange{{IP: "10.33.0.0/16"}},
},
}
matches := MatchesFromFilterRules(rules)
require.Len(t, matches, 2)
// First matcher: 10.0.0.0/8 -> 192.168.1.0/24
assert.True(t, matches[0].SrcsContainsIPs(netip.MustParseAddr("10.1.2.3")))
assert.False(t, matches[0].SrcsContainsIPs(netip.MustParseAddr("172.16.0.1")))
assert.True(t, matches[0].DestsContainsIP(netip.MustParseAddr("192.168.1.100")))
// Second matcher: 172.16.0.0/12 -> 10.33.0.0/16
assert.True(t, matches[1].SrcsContainsIPs(netip.MustParseAddr("172.20.0.1")))
assert.True(t, matches[1].DestsContainsIP(netip.MustParseAddr("10.33.0.1")))
assert.False(t, matches[1].DestsContainsIP(netip.MustParseAddr("192.168.1.1")))
}
func TestSrcsOverlapsPrefixes(t *testing.T) {
t.Parallel()
tests := []struct {
name string
srcs []string
prefixes []netip.Prefix
want bool
}{
{
name: "exact match",
srcs: []string{"10.33.0.0/16"},
prefixes: []netip.Prefix{netip.MustParsePrefix("10.33.0.0/16")},
want: true,
},
{
name: "parent contains child",
srcs: []string{"10.0.0.0/8"},
prefixes: []netip.Prefix{netip.MustParsePrefix("10.33.0.0/16")},
want: true,
},
{
name: "child overlaps parent",
srcs: []string{"10.33.0.0/16"},
prefixes: []netip.Prefix{netip.MustParsePrefix("10.0.0.0/8")},
want: true,
},
{
name: "no overlap",
srcs: []string{"10.0.0.0/8"},
prefixes: []netip.Prefix{netip.MustParsePrefix("192.168.1.0/24")},
want: false,
},
{
name: "multiple prefixes one overlaps",
srcs: []string{"10.0.0.0/8"},
prefixes: []netip.Prefix{
netip.MustParsePrefix("192.168.1.0/24"),
netip.MustParsePrefix("10.33.0.0/16"),
},
want: true,
},
{
name: "IPv6 overlap",
srcs: []string{"fd7a:115c:a1e0::/48"},
prefixes: []netip.Prefix{netip.MustParsePrefix("fd7a:115c:a1e0:ab12::/64")},
want: true,
},
{
name: "empty prefixes",
srcs: []string{"10.0.0.0/8"},
prefixes: []netip.Prefix{},
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
m := MatchFromStrings(tt.srcs, nil)
got := m.SrcsOverlapsPrefixes(tt.prefixes...)
assert.Equal(t, tt.want, got)
})
}
}
func TestDestsOverlapsPrefixes(t *testing.T) {
t.Parallel()
tests := []struct {
name string
dsts []string
prefixes []netip.Prefix
want bool
}{
{
name: "exact match",
dsts: []string{"10.33.0.0/16"},
prefixes: []netip.Prefix{netip.MustParsePrefix("10.33.0.0/16")},
want: true,
},
{
name: "parent contains child",
dsts: []string{"10.0.0.0/8"},
prefixes: []netip.Prefix{netip.MustParsePrefix("10.33.0.0/16")},
want: true,
},
{
name: "no overlap",
dsts: []string{"10.0.0.0/8"},
prefixes: []netip.Prefix{netip.MustParsePrefix("192.168.0.0/16")},
want: false,
},
{
name: "wildcard overlaps everything",
dsts: []string{"*"},
prefixes: []netip.Prefix{
netip.MustParsePrefix("0.0.0.0/0"),
},
want: true,
},
{
name: "wildcard overlaps exit route",
dsts: []string{"*"},
prefixes: []netip.Prefix{netip.MustParsePrefix("::/0")},
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
m := MatchFromStrings(nil, tt.dsts)
got := m.DestsOverlapsPrefixes(tt.prefixes...)
assert.Equal(t, tt.want, got)
})
}
}
func TestDestsIsTheInternet(t *testing.T) {
t.Parallel()
tests := []struct {
name string
dsts []string
want bool
}{
{
name: "all IPv4 is the internet",
dsts: []string{"0.0.0.0/0"},
want: true,
},
{
name: "all IPv6 is the internet",
dsts: []string{"::/0"},
want: true,
},
{
name: "wildcard is the internet",
dsts: []string{"*"},
want: true,
},
{
name: "private range is not the internet",
dsts: []string{"10.0.0.0/8"},
want: false,
},
{
name: "CGNAT range is not the internet",
dsts: []string{"100.64.0.0/10"},
want: false,
},
{
name: "single public IP is not the internet",
dsts: []string{"8.8.8.8"},
want: false,
},
{
name: "empty dests is not the internet",
dsts: []string{},
want: false,
},
{
name: "multiple private ranges are not the internet",
dsts: []string{
"10.0.0.0/8",
"172.16.0.0/12",
"192.168.0.0/16",
},
want: false,
},
{
name: "all IPv4 combined with subnet is the internet",
dsts: []string{"0.0.0.0/0", "10.33.0.0/16"},
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
m := MatchFromStrings(nil, tt.dsts)
got := m.DestsIsTheInternet()
assert.Equal(t, tt.want, got,
"DestsIsTheInternet() for dsts=%v", tt.dsts)
})
}
}
func TestDebugString(t *testing.T) {
t.Parallel()
m := MatchFromStrings(
[]string{"10.0.0.0/8"},
[]string{"192.168.1.0/24"},
)
s := m.DebugString()
assert.Contains(t, s, "Match:")
assert.Contains(t, s, "Sources:")
assert.Contains(t, s, "Destinations:")
assert.Contains(t, s, "10.0.0.0/8")
assert.Contains(t, s, "192.168.1.0/24")
}
+180
View File
@@ -768,6 +768,65 @@ func TestReduceNodes(t *testing.T) {
},
},
},
// Subnet-to-subnet: routers must see each other when ACL
// uses only subnet CIDRs. Issue #3157.
{
name: "subnet-to-subnet-routers-see-each-other-3157",
args: args{
nodes: []*types.Node{
{
ID: 1,
IPv4: ap("100.64.0.1"),
Hostname: "router-a",
User: &types.User{Name: "router-a"},
Hostinfo: &tailcfg.Hostinfo{
RoutableIPs: []netip.Prefix{netip.MustParsePrefix("10.88.8.0/24")},
},
ApprovedRoutes: []netip.Prefix{netip.MustParsePrefix("10.88.8.0/24")},
},
{
ID: 2,
IPv4: ap("100.64.0.2"),
Hostname: "router-b",
User: &types.User{Name: "router-b"},
Hostinfo: &tailcfg.Hostinfo{
RoutableIPs: []netip.Prefix{netip.MustParsePrefix("10.99.9.0/24")},
},
ApprovedRoutes: []netip.Prefix{netip.MustParsePrefix("10.99.9.0/24")},
},
},
rules: []tailcfg.FilterRule{
{
SrcIPs: []string{"10.88.8.0/24"},
DstPorts: []tailcfg.NetPortRange{
{IP: "10.99.9.0/24", Ports: tailcfg.PortRangeAny},
},
},
},
node: &types.Node{
ID: 1,
IPv4: ap("100.64.0.1"),
Hostname: "router-a",
User: &types.User{Name: "router-a"},
Hostinfo: &tailcfg.Hostinfo{
RoutableIPs: []netip.Prefix{netip.MustParsePrefix("10.88.8.0/24")},
},
ApprovedRoutes: []netip.Prefix{netip.MustParsePrefix("10.88.8.0/24")},
},
},
want: []*types.Node{
{
ID: 2,
IPv4: ap("100.64.0.2"),
Hostname: "router-b",
User: &types.User{Name: "router-b"},
Hostinfo: &tailcfg.Hostinfo{
RoutableIPs: []netip.Prefix{netip.MustParsePrefix("10.99.9.0/24")},
},
ApprovedRoutes: []netip.Prefix{netip.MustParsePrefix("10.99.9.0/24")},
},
},
},
}
for _, tt := range tests {
@@ -2230,6 +2289,127 @@ func TestReduceRoutes(t *testing.T) {
netip.MustParsePrefix("192.168.1.0/14"),
},
},
// Subnet-to-subnet tests for issue #3157.
// When an ACL references subnet CIDRs as both source and destination,
// the subnet routers for those subnets must receive routes to each
// other's subnets.
{
name: "subnet-to-subnet-src-router-gets-dst-route-3157",
args: args{
node: &types.Node{
ID: 1,
IPv4: ap("100.64.0.1"),
User: &types.User{Name: "router-a"},
Hostinfo: &tailcfg.Hostinfo{
RoutableIPs: []netip.Prefix{
netip.MustParsePrefix("10.88.8.0/24"),
},
},
ApprovedRoutes: []netip.Prefix{
netip.MustParsePrefix("10.88.8.0/24"),
},
},
routes: []netip.Prefix{
netip.MustParsePrefix("10.99.9.0/24"),
},
rules: []tailcfg.FilterRule{
{
SrcIPs: []string{"10.88.8.0/24"},
DstPorts: []tailcfg.NetPortRange{
{IP: "10.99.9.0/24", Ports: tailcfg.PortRangeAny},
},
},
},
},
want: []netip.Prefix{
netip.MustParsePrefix("10.99.9.0/24"),
},
},
{
name: "subnet-to-subnet-dst-router-gets-src-route-3157",
args: args{
node: &types.Node{
ID: 2,
IPv4: ap("100.64.0.2"),
User: &types.User{Name: "router-b"},
Hostinfo: &tailcfg.Hostinfo{
RoutableIPs: []netip.Prefix{
netip.MustParsePrefix("10.99.9.0/24"),
},
},
ApprovedRoutes: []netip.Prefix{
netip.MustParsePrefix("10.99.9.0/24"),
},
},
routes: []netip.Prefix{
netip.MustParsePrefix("10.88.8.0/24"),
},
rules: []tailcfg.FilterRule{
{
SrcIPs: []string{"10.88.8.0/24"},
DstPorts: []tailcfg.NetPortRange{
{IP: "10.99.9.0/24", Ports: tailcfg.PortRangeAny},
},
},
},
},
want: []netip.Prefix{
netip.MustParsePrefix("10.88.8.0/24"),
},
},
{
name: "subnet-to-subnet-regular-node-no-route-leak-3157",
args: args{
node: &types.Node{
ID: 3,
IPv4: ap("100.64.0.3"),
User: &types.User{Name: "regular-node"},
},
routes: []netip.Prefix{
netip.MustParsePrefix("10.88.8.0/24"),
netip.MustParsePrefix("10.99.9.0/24"),
},
rules: []tailcfg.FilterRule{
{
SrcIPs: []string{"10.88.8.0/24"},
DstPorts: []tailcfg.NetPortRange{
{IP: "10.99.9.0/24", Ports: tailcfg.PortRangeAny},
},
},
},
},
want: nil,
},
{
name: "subnet-to-subnet-unrelated-router-no-route-leak-3157",
args: args{
node: &types.Node{
ID: 4,
IPv4: ap("100.64.0.4"),
User: &types.User{Name: "router-c"},
Hostinfo: &tailcfg.Hostinfo{
RoutableIPs: []netip.Prefix{
netip.MustParsePrefix("172.16.0.0/24"),
},
},
ApprovedRoutes: []netip.Prefix{
netip.MustParsePrefix("172.16.0.0/24"),
},
},
routes: []netip.Prefix{
netip.MustParsePrefix("10.88.8.0/24"),
},
rules: []tailcfg.FilterRule{
{
SrcIPs: []string{"10.88.8.0/24"},
DstPorts: []tailcfg.NetPortRange{
{IP: "10.99.9.0/24", Ports: tailcfg.PortRangeAny},
},
},
},
},
want: nil,
},
}
for _, tt := range tests {
+23 -46
View File
@@ -2,10 +2,10 @@ package policyutil
import (
"net/netip"
"slices"
"github.com/juanfont/headscale/hscontrol/types"
"github.com/juanfont/headscale/hscontrol/util"
"tailscale.com/net/tsaddr"
"tailscale.com/tailcfg"
)
@@ -47,32 +47,15 @@ func ReduceFilterRules(node types.NodeView, rules []tailcfg.FilterRule) []tailcf
continue DEST_LOOP
}
// If the node exposes routes, ensure they are not removed
// when the filters are reduced. Exit routes (0.0.0.0/0, ::/0)
// are skipped here because exit nodes handle traffic via
// AllowedIPs/routing, not packet filter rules. This matches
// Tailscale SaaS behavior where exit nodes do not receive
// filter rules for destinations that only overlap via exit routes.
if node.Hostinfo().Valid() {
routableIPs := node.Hostinfo().RoutableIPs()
if routableIPs.Len() > 0 {
for _, routableIP := range routableIPs.All() {
if tsaddr.IsExitRoute(routableIP) {
continue
}
if expanded.OverlapsPrefix(routableIP) {
dests = append(dests, dest)
continue DEST_LOOP
}
}
}
}
// Also check approved subnet routes - nodes should have access
// to subnets they're approved to route traffic for.
subnetRoutes := node.SubnetRoutes()
for _, subnetRoute := range subnetRoutes {
// If the node has approved subnet routes, preserve
// filter rules targeting those routes. SubnetRoutes()
// returns only approved, non-exit routes — matching
// Tailscale SaaS behavior, which does not generate
// filter rules for advertised-but-unapproved routes.
// Exit routes (0.0.0.0/0, ::/0) are excluded by
// SubnetRoutes() and handled separately via
// AllowedIPs/routing.
for _, subnetRoute := range node.SubnetRoutes() {
if expanded.OverlapsPrefix(subnetRoute) {
dests = append(dests, dest)
continue DEST_LOOP
@@ -113,8 +96,9 @@ func reduceCapGrantRule(
for _, dst := range cg.Dsts {
if dst.IsSingleIP() {
// Already a specific IP — keep it if it matches.
if dst.Addr() == nodeIPs[0] || (len(nodeIPs) > 1 && dst.Addr() == nodeIPs[1]) {
// Already a specific IP — keep it if it matches
// any of the node's IPs.
if slices.Contains(nodeIPs, dst.Addr()) {
matchingDsts = append(matchingDsts, dst)
}
} else {
@@ -127,23 +111,16 @@ func reduceCapGrantRule(
}
}
// Also check routable IPs (subnet routes) — nodes that
// advertise routes should receive CapGrant rules for
// destinations that overlap their routes.
if node.Hostinfo().Valid() {
routableIPs := node.Hostinfo().RoutableIPs()
if routableIPs.Len() > 0 {
for _, dst := range cg.Dsts {
for _, routableIP := range routableIPs.All() {
if tsaddr.IsExitRoute(routableIP) {
continue
}
if dst.Overlaps(routableIP) {
// For route overlaps, keep the original prefix.
matchingDsts = append(matchingDsts, dst)
}
}
// Also check approved subnet routes — nodes serving
// approved routes should receive CapGrant rules for
// destinations that overlap those routes. SubnetRoutes()
// excludes both unapproved and exit routes, matching
// Tailscale SaaS behavior.
for _, dst := range cg.Dsts {
for _, subnetRoute := range node.SubnetRoutes() {
if dst.Overlaps(subnetRoute) {
// For route overlaps, keep the original prefix.
matchingDsts = append(matchingDsts, dst)
}
}
}
+452 -2
View File
@@ -196,6 +196,9 @@ func TestReduceFilterRules(t *testing.T) {
netip.MustParsePrefix("10.33.0.0/16"),
},
},
ApprovedRoutes: []netip.Prefix{
netip.MustParsePrefix("10.33.0.0/16"),
},
},
peers: types.Nodes{
&types.Node{
@@ -518,6 +521,7 @@ func TestReduceFilterRules(t *testing.T) {
Hostinfo: &tailcfg.Hostinfo{
RoutableIPs: []netip.Prefix{netip.MustParsePrefix("8.0.0.0/16"), netip.MustParsePrefix("16.0.0.0/16")},
},
ApprovedRoutes: []netip.Prefix{netip.MustParsePrefix("8.0.0.0/16"), netip.MustParsePrefix("16.0.0.0/16")},
},
peers: types.Nodes{
&types.Node{
@@ -601,6 +605,7 @@ func TestReduceFilterRules(t *testing.T) {
Hostinfo: &tailcfg.Hostinfo{
RoutableIPs: []netip.Prefix{netip.MustParsePrefix("8.0.0.0/8"), netip.MustParsePrefix("16.0.0.0/8")},
},
ApprovedRoutes: []netip.Prefix{netip.MustParsePrefix("8.0.0.0/8"), netip.MustParsePrefix("16.0.0.0/8")},
},
peers: types.Nodes{
&types.Node{
@@ -676,7 +681,8 @@ func TestReduceFilterRules(t *testing.T) {
Hostinfo: &tailcfg.Hostinfo{
RoutableIPs: []netip.Prefix{netip.MustParsePrefix("172.16.0.0/24")},
},
Tags: []string{"tag:access-servers"},
ApprovedRoutes: []netip.Prefix{netip.MustParsePrefix("172.16.0.0/24")},
Tags: []string{"tag:access-servers"},
},
peers: types.Nodes{
&types.Node{
@@ -759,7 +765,9 @@ func TestReduceFilterRules(t *testing.T) {
}
for _, tt := range tests {
for idx, pmf := range policy.PolicyManagerFuncsForTest([]byte(tt.pol)) {
for idx, pmf := range policy.PolicyManagerFuncsForTest(
[]byte(tt.pol),
) {
t.Run(fmt.Sprintf("%s-index%d", tt.name, idx), func(t *testing.T) {
var (
pm policy.PolicyManager
@@ -781,3 +789,445 @@ func TestReduceFilterRules(t *testing.T) {
}
}
}
// TestReduceFilterRulesPartialApproval verifies that ReduceFilterRules
// only preserves filter rules for routes that are both advertised
// (RoutableIPs) AND approved (ApprovedRoutes), matching Tailscale
// SaaS behavior. Advertised-but-unapproved routes do not cause rule
// preservation: SaaS never generates filter rules for unapproved
// routes, and headscale consults node.SubnetRoutes() (which filters
// by approval) rather than Hostinfo.RoutableIPs() (which does not).
func TestReduceFilterRulesPartialApproval(t *testing.T) {
tests := []struct {
name string
node *types.Node
rules []tailcfg.FilterRule
wantCount int
wantRoutes []string
}{
{
name: "approved-route-included",
node: &types.Node{
IPv4: ap("100.64.0.1"),
IPv6: ap("fd7a:115c:a1e0::1"),
Hostinfo: &tailcfg.Hostinfo{
RoutableIPs: []netip.Prefix{
netip.MustParsePrefix("10.33.0.0/16"),
},
},
ApprovedRoutes: []netip.Prefix{
netip.MustParsePrefix("10.33.0.0/16"),
},
},
rules: []tailcfg.FilterRule{
{
SrcIPs: []string{"*"},
DstPorts: []tailcfg.NetPortRange{
{IP: "10.33.0.0/16", Ports: tailcfg.PortRangeAny},
},
},
},
wantCount: 1,
wantRoutes: []string{"10.33.0.0/16"},
},
{
name: "unapproved-route-excluded",
node: &types.Node{
IPv4: ap("100.64.0.1"),
IPv6: ap("fd7a:115c:a1e0::1"),
Hostinfo: &tailcfg.Hostinfo{
RoutableIPs: []netip.Prefix{
netip.MustParsePrefix("10.33.0.0/16"),
// Advertised but NOT approved:
netip.MustParsePrefix("172.16.0.0/24"),
},
},
ApprovedRoutes: []netip.Prefix{
// Only 10.33.0.0/16 approved
netip.MustParsePrefix("10.33.0.0/16"),
},
},
rules: []tailcfg.FilterRule{
{
SrcIPs: []string{"*"},
DstPorts: []tailcfg.NetPortRange{
// Targets the unapproved route
{IP: "172.16.0.0/24", Ports: tailcfg.PortRangeAny},
},
},
},
// SubnetRoutes() does NOT contain 172.16.0.0/24
// (only approved routes), and the ACL dst does not
// overlap the node's own IPs, so the rule is
// dropped. This matches Tailscale SaaS behavior.
wantCount: 0,
},
{
name: "neither-advertised-nor-approved-excluded",
node: &types.Node{
IPv4: ap("100.64.0.1"),
IPv6: ap("fd7a:115c:a1e0::1"),
Hostinfo: &tailcfg.Hostinfo{
RoutableIPs: []netip.Prefix{
netip.MustParsePrefix("10.33.0.0/16"),
},
},
ApprovedRoutes: []netip.Prefix{
netip.MustParsePrefix("10.33.0.0/16"),
},
},
rules: []tailcfg.FilterRule{
{
SrcIPs: []string{"*"},
DstPorts: []tailcfg.NetPortRange{
// Not advertised, not approved
{IP: "192.168.0.0/16", Ports: tailcfg.PortRangeAny},
},
},
},
wantCount: 0,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := policyutil.ReduceFilterRules(
tt.node.View(), tt.rules,
)
require.Len(t, got, tt.wantCount,
"rule count mismatch")
if tt.wantCount > 0 {
var gotRoutes []string
for _, dp := range got[0].DstPorts {
gotRoutes = append(gotRoutes, dp.IP)
}
require.Equal(t, tt.wantRoutes, gotRoutes)
}
})
}
}
// TestReduceFilterRulesCapGrant tests the CapGrant branch of
// ReduceFilterRules, which was previously untested. All existing
// test cases use ACL-only policies with DstPorts rules.
func TestReduceFilterRulesCapGrant(t *testing.T) {
tests := []struct {
name string
node *types.Node
rules []tailcfg.FilterRule
want []tailcfg.FilterRule
}{
{
name: "capgrant-matches-node-ip-narrowed",
node: &types.Node{
IPv4: ap("100.64.0.1"),
IPv6: ap("fd7a:115c:a1e0::1"),
},
rules: []tailcfg.FilterRule{
{
SrcIPs: []string{"10.0.0.0/8"},
CapGrant: []tailcfg.CapGrant{
{
Dsts: []netip.Prefix{
// Broad IPv4 prefix containing node IP
netip.MustParsePrefix("100.64.0.0/10"),
},
CapMap: tailcfg.PeerCapMap{
"tailscale.com/cap/drive-sharer": nil,
},
},
},
},
},
want: []tailcfg.FilterRule{
{
SrcIPs: []string{"10.0.0.0/8"},
CapGrant: []tailcfg.CapGrant{
{
Dsts: []netip.Prefix{
// Only IPv4 narrowed (IPv6 not in /10)
netip.MustParsePrefix("100.64.0.1/32"),
},
CapMap: tailcfg.PeerCapMap{
"tailscale.com/cap/drive-sharer": nil,
},
},
},
},
},
},
{
name: "capgrant-no-match-filtered-out",
node: &types.Node{
IPv4: ap("100.64.0.1"),
IPv6: ap("fd7a:115c:a1e0::1"),
},
rules: []tailcfg.FilterRule{
{
SrcIPs: []string{"10.0.0.0/8"},
CapGrant: []tailcfg.CapGrant{
{
Dsts: []netip.Prefix{
// Different IP — doesn't match this node
netip.MustParsePrefix("100.64.0.99/32"),
},
CapMap: tailcfg.PeerCapMap{
"tailscale.com/cap/drive-sharer": nil,
},
},
},
},
},
want: []tailcfg.FilterRule{},
},
{
name: "capgrant-with-subnet-route-overlap",
node: &types.Node{
IPv4: ap("100.64.0.1"),
IPv6: ap("fd7a:115c:a1e0::1"),
Hostinfo: &tailcfg.Hostinfo{
RoutableIPs: []netip.Prefix{
netip.MustParsePrefix("10.33.0.0/16"),
},
},
ApprovedRoutes: []netip.Prefix{
netip.MustParsePrefix("10.33.0.0/16"),
},
},
rules: []tailcfg.FilterRule{
{
SrcIPs: []string{"*"},
CapGrant: []tailcfg.CapGrant{
{
Dsts: []netip.Prefix{
// Subnet route overlap
netip.MustParsePrefix("10.0.0.0/8"),
},
CapMap: tailcfg.PeerCapMap{
"tailscale.com/cap/relay-target": nil,
},
},
},
},
},
want: []tailcfg.FilterRule{
{
SrcIPs: []string{"*"},
CapGrant: []tailcfg.CapGrant{
{
Dsts: []netip.Prefix{
// 10.0.0.0/8 doesn't contain node's
// CGNAT IP (100.64.0.1), so no IP
// narrowing. Only route overlap kept
// as original prefix.
netip.MustParsePrefix("10.0.0.0/8"),
},
CapMap: tailcfg.PeerCapMap{
"tailscale.com/cap/relay-target": nil,
},
},
},
},
},
},
{
name: "capgrant-exit-route-skipped",
node: &types.Node{
IPv4: ap("100.64.0.1"),
IPv6: ap("fd7a:115c:a1e0::1"),
Hostinfo: &tailcfg.Hostinfo{
RoutableIPs: tsaddr.ExitRoutes(),
},
ApprovedRoutes: tsaddr.ExitRoutes(),
},
rules: []tailcfg.FilterRule{
{
SrcIPs: []string{"*"},
CapGrant: []tailcfg.CapGrant{
{
Dsts: []netip.Prefix{
// 0.0.0.0/0 overlaps the exit route
// but exit routes should be skipped
netip.MustParsePrefix("0.0.0.0/0"),
},
CapMap: tailcfg.PeerCapMap{
"tailscale.com/cap/drive-sharer": nil,
},
},
},
},
},
want: []tailcfg.FilterRule{
{
SrcIPs: []string{"*"},
CapGrant: []tailcfg.CapGrant{
{
Dsts: []netip.Prefix{
// Node IP narrowed (0.0.0.0/0
// contains the node's IP)
netip.MustParsePrefix("100.64.0.1/32"),
},
CapMap: tailcfg.PeerCapMap{
"tailscale.com/cap/drive-sharer": nil,
},
},
},
},
},
},
{
name: "mixed-dstports-and-capgrant-rules",
node: &types.Node{
IPv4: ap("100.64.0.1"),
IPv6: ap("fd7a:115c:a1e0::1"),
},
rules: []tailcfg.FilterRule{
{
// DstPorts rule that matches
SrcIPs: []string{"10.0.0.0/8"},
DstPorts: []tailcfg.NetPortRange{
{IP: "100.64.0.1", Ports: tailcfg.PortRangeAny},
},
},
{
// CapGrant rule that matches
SrcIPs: []string{"10.0.0.0/8"},
CapGrant: []tailcfg.CapGrant{
{
Dsts: []netip.Prefix{
netip.MustParsePrefix("100.64.0.1/32"),
},
CapMap: tailcfg.PeerCapMap{
"tailscale.com/cap/drive-sharer": nil,
},
},
},
},
{
// CapGrant rule that doesn't match
SrcIPs: []string{"10.0.0.0/8"},
CapGrant: []tailcfg.CapGrant{
{
Dsts: []netip.Prefix{
netip.MustParsePrefix("100.64.0.99/32"),
},
CapMap: tailcfg.PeerCapMap{
"tailscale.com/cap/drive-sharer": nil,
},
},
},
},
},
want: []tailcfg.FilterRule{
{
SrcIPs: []string{"10.0.0.0/8"},
DstPorts: []tailcfg.NetPortRange{
{IP: "100.64.0.1", Ports: tailcfg.PortRangeAny},
},
},
{
SrcIPs: []string{"10.0.0.0/8"},
CapGrant: []tailcfg.CapGrant{
{
Dsts: []netip.Prefix{
netip.MustParsePrefix("100.64.0.1/32"),
},
CapMap: tailcfg.PeerCapMap{
"tailscale.com/cap/drive-sharer": nil,
},
},
},
},
// Third rule filtered out — doesn't match node
},
},
{
name: "capgrant-ipv4-only-node",
node: &types.Node{
IPv4: ap("100.64.0.1"),
// IPv6 is nil, single-IP node
},
rules: []tailcfg.FilterRule{
{
SrcIPs: []string{"10.0.0.0/8"},
CapGrant: []tailcfg.CapGrant{
{
Dsts: []netip.Prefix{
netip.MustParsePrefix("100.64.0.1/32"),
},
CapMap: tailcfg.PeerCapMap{
"tailscale.com/cap/drive-sharer": nil,
},
},
},
},
},
want: []tailcfg.FilterRule{
{
SrcIPs: []string{"10.0.0.0/8"},
CapGrant: []tailcfg.CapGrant{
{
Dsts: []netip.Prefix{
netip.MustParsePrefix("100.64.0.1/32"),
},
CapMap: tailcfg.PeerCapMap{
"tailscale.com/cap/drive-sharer": nil,
},
},
},
},
},
},
{
name: "capgrant-zero-ip-node-no-panic",
node: &types.Node{
// Both IPv4 and IPv6 are nil, zero IPs.
// Must not panic.
},
rules: []tailcfg.FilterRule{
{
SrcIPs: []string{"10.0.0.0/8"},
CapGrant: []tailcfg.CapGrant{
{
Dsts: []netip.Prefix{
netip.MustParsePrefix("100.64.0.1/32"),
},
CapMap: tailcfg.PeerCapMap{
"tailscale.com/cap/drive-sharer": nil,
},
},
},
},
},
want: []tailcfg.FilterRule{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := policyutil.ReduceFilterRules(tt.node.View(), tt.rules)
require.Len(t, got, len(tt.want),
"rule count mismatch")
for i := range tt.want {
require.Equal(t, tt.want[i].SrcIPs, got[i].SrcIPs,
"rule[%d] SrcIPs", i)
require.Len(t, got[i].DstPorts, len(tt.want[i].DstPorts),
"rule[%d] DstPorts count", i)
require.Len(t, got[i].CapGrant, len(tt.want[i].CapGrant),
"rule[%d] CapGrant count", i)
for j := range tt.want[i].CapGrant {
require.ElementsMatch(t,
tt.want[i].CapGrant[j].Dsts,
got[i].CapGrant[j].Dsts,
"rule[%d].CapGrant[%d] Dsts", i, j,
)
}
}
})
}
}
+725
View File
@@ -0,0 +1,725 @@
package v2
import (
"net/netip"
"slices"
"github.com/juanfont/headscale/hscontrol/types"
"github.com/rs/zerolog/log"
"go4.org/netipx"
"tailscale.com/tailcfg"
"tailscale.com/types/views"
)
// grantCategory classifies a grant by what per-node work it needs.
type grantCategory int
const (
// grantCategoryRegular requires no per-node work. The pre-compiled
// rules are complete and only need ReduceFilterRules.
grantCategoryRegular grantCategory = iota
// grantCategorySelf has autogroup:self destinations that must be
// expanded per-node to same-user untagged device IPs.
grantCategorySelf
// grantCategoryVia has Via tags that route rules to specific
// nodes based on their tags and advertised routes.
grantCategoryVia
)
// compiledGrant is a grant with its sources already resolved to IP
// addresses. The expensive work (alias → IP resolution) is done once
// here. Extracting rules for a specific node reads from pre-resolved
// data without re-resolving.
type compiledGrant struct {
category grantCategory
// srcIPStrings is the final SrcIPs for non-self rules, with
// nonWildcardSrcs appended to match Tailscale SaaS behavior.
srcIPStrings []string
hasWildcard bool
hasDangerAll bool
// rules are the pre-compiled filter rules for non-self, non-via
// destinations. For regular grants this is the complete output.
// For self grants with mixed destinations (self + other), this
// is the non-self portion only.
rules []tailcfg.FilterRule
// self is non-nil when the grant has autogroup:self destinations.
self *selfGrantData
// via is non-nil when the grant has Via tags.
via *viaGrantData
}
// selfGrantData holds data needed for per-node autogroup:self
// compilation. Sources are already resolved.
type selfGrantData struct {
resolvedSrcs []ResolvedAddresses
internetProtocols []ProtocolPort
app tailcfg.PeerCapMap
}
// viaGrantData holds data needed for per-node via-grant compilation.
// Sources are already resolved into srcIPStrings.
type viaGrantData struct {
viaTags []Tag
destinations Aliases
internetProtocols []ProtocolPort
srcIPStrings []string
}
// userNodeIndex maps user IDs to their untagged nodes. Precomputed
// once per node-set change, used by compileAutogroupSelf to avoid
// O(N) scans per self-grant per node.
type userNodeIndex map[uint][]types.NodeView
func buildUserNodeIndex(
nodes views.Slice[types.NodeView],
) userNodeIndex {
idx := make(userNodeIndex)
for _, n := range nodes.All() {
if !n.IsTagged() && n.User().Valid() {
uid := n.User().ID()
idx[uid] = append(idx[uid], n)
}
}
return idx
}
// compileGrants resolves all policy grants into compiledGrant structs.
// Source resolution and non-self destination resolution happens once
// here. This is the single resolution path that replaces the
// duplicated work in compileFilterRules and compileGrantWithAutogroupSelf.
func (pol *Policy) compileGrants(
users types.Users,
nodes views.Slice[types.NodeView],
) []compiledGrant {
if pol == nil || (pol.ACLs == nil && len(pol.Grants) == 0) {
return nil
}
grants := pol.Grants
for _, acl := range pol.ACLs {
grants = append(grants, aclToGrants(acl)...)
}
compiled := make([]compiledGrant, 0, len(grants))
for _, grant := range grants {
cg, err := pol.compileOneGrant(grant, users, nodes)
if err != nil {
log.Trace().Err(err).Msg("compiling grant")
continue
}
if cg != nil {
compiled = append(compiled, *cg)
}
}
return compiled
}
// compileOneGrant resolves a single grant into a compiledGrant.
// All source resolution happens here. Non-self, non-via destination
// resolution also happens here. Per-node data (self dests, via
// matching) is stored for deferred compilation.
//
//nolint:gocyclo,cyclop
func (pol *Policy) compileOneGrant(
grant Grant,
users types.Users,
nodes views.Slice[types.NodeView],
) (*compiledGrant, error) {
// Via grants: resolve sources, store deferred data.
if len(grant.Via) > 0 {
return pol.compileOneViaGrant(grant, users, nodes)
}
// Split destinations into self vs other.
var autogroupSelfDests, otherDests []Alias
for _, dest := range grant.Destinations {
if ag, ok := dest.(*AutoGroup); ok && ag.Is(AutoGroupSelf) {
autogroupSelfDests = append(autogroupSelfDests, dest)
} else {
otherDests = append(otherDests, dest)
}
}
// Resolve sources per-alias, tracking non-wildcard sources
// separately so we can preserve their IPs alongside the
// wildcard CGNAT ranges (matching Tailscale SaaS behavior).
resolvedSrcs, nonWildcardSrcs, err := resolveSources(
pol, grant.Sources, users, nodes,
)
if err != nil {
return nil, err
}
// Literally empty src=[] or dst=[] produces no rules.
if len(grant.Sources) == 0 || len(grant.Destinations) == 0 {
return nil, nil //nolint:nilnil
}
if len(resolvedSrcs) == 0 && grant.App == nil {
return nil, nil //nolint:nilnil
}
hasWildcard := sourcesHaveWildcard(grant.Sources)
hasDangerAll := sourcesHaveDangerAll(grant.Sources)
srcIPStrings := buildSrcIPStrings(
resolvedSrcs, nonWildcardSrcs,
hasWildcard, hasDangerAll, nodes,
)
cg := &compiledGrant{
srcIPStrings: srcIPStrings,
hasWildcard: hasWildcard,
hasDangerAll: hasDangerAll,
}
// Compile non-self destination rules (done once, shared).
if len(otherDests) > 0 {
cg.rules = pol.compileOtherDests(
users, nodes, grant, otherDests,
resolvedSrcs, srcIPStrings,
)
}
// Classify and store deferred self data.
switch {
case len(autogroupSelfDests) > 0:
cg.category = grantCategorySelf
cg.self = &selfGrantData{
resolvedSrcs: resolvedSrcs,
internetProtocols: grant.InternetProtocols,
app: grant.App,
}
default:
cg.category = grantCategoryRegular
}
return cg, nil
}
// compileOneViaGrant resolves sources for a via grant and stores the
// deferred per-node data. The actual via-node matching and route
// intersection happens in compileViaForNode.
func (pol *Policy) compileOneViaGrant(
grant Grant,
users types.Users,
nodes views.Slice[types.NodeView],
) (*compiledGrant, error) {
if len(grant.InternetProtocols) == 0 {
return nil, nil //nolint:nilnil
}
resolvedSrcs, _, err := resolveSources(
pol, grant.Sources, users, nodes,
)
if err != nil {
return nil, err
}
if len(resolvedSrcs) == 0 {
return nil, nil //nolint:nilnil
}
// Build merged SrcIPs.
var srcIPs netipx.IPSetBuilder
for _, ips := range resolvedSrcs {
for _, pref := range ips.Prefixes() {
srcIPs.AddPrefix(pref)
}
}
srcResolved, err := newResolved(&srcIPs)
if err != nil {
return nil, err
}
if srcResolved.Empty() {
return nil, nil //nolint:nilnil
}
hasWildcard := sourcesHaveWildcard(grant.Sources)
hasDangerAll := sourcesHaveDangerAll(grant.Sources)
return &compiledGrant{
category: grantCategoryVia,
via: &viaGrantData{
viaTags: grant.Via,
destinations: grant.Destinations,
internetProtocols: grant.InternetProtocols,
srcIPStrings: srcIPsWithRoutes(
srcResolved, hasWildcard, hasDangerAll, nodes,
),
},
}, nil
}
// resolveSources resolves grant sources per-alias, returning the
// resolved addresses and a separate slice of non-wildcard sources.
// This is the shared source resolution used by all grant categories.
func resolveSources(
pol *Policy,
sources Aliases,
users types.Users,
nodes views.Slice[types.NodeView],
) ([]ResolvedAddresses, []ResolvedAddresses, error) {
var all, nonWild []ResolvedAddresses
for i, src := range sources {
if ag, ok := src.(*AutoGroup); ok && ag.Is(AutoGroupSelf) {
return nil, nil, errSelfInSources
}
ips, err := src.Resolve(pol, users, nodes)
if err != nil {
log.Trace().Caller().Err(err).
Msg("resolving source ips")
}
if ips != nil {
all = append(all, ips)
if _, isWildcard := sources[i].(Asterix); !isWildcard {
nonWild = append(nonWild, ips)
}
}
}
return all, nonWild, nil
}
// buildSrcIPStrings builds the final SrcIPs string slice from
// resolved sources, preserving non-wildcard IPs alongside wildcard
// CGNAT ranges to match Tailscale SaaS behavior.
func buildSrcIPStrings(
resolvedSrcs, nonWildcardSrcs []ResolvedAddresses,
hasWildcard, hasDangerAll bool,
nodes views.Slice[types.NodeView],
) []string {
var merged netipx.IPSetBuilder
for _, ips := range resolvedSrcs {
for _, pref := range ips.Prefixes() {
merged.AddPrefix(pref)
}
}
srcResolved, err := newResolved(&merged)
if err != nil {
return nil
}
if srcResolved.Empty() {
return nil
}
srcIPStrs := srcIPsWithRoutes(
srcResolved, hasWildcard, hasDangerAll, nodes,
)
// When sources include a wildcard (*) alongside explicit
// sources (tags, groups, etc.), Tailscale preserves the
// individual IPs from non-wildcard sources alongside the
// merged CGNAT ranges rather than absorbing them.
if hasWildcard && len(nonWildcardSrcs) > 0 {
seen := make(map[string]bool, len(srcIPStrs))
for _, s := range srcIPStrs {
seen[s] = true
}
for _, ips := range nonWildcardSrcs {
for _, s := range ips.Strings() {
if !seen[s] {
seen[s] = true
srcIPStrs = append(srcIPStrs, s)
}
}
}
}
return srcIPStrs
}
// compileOtherDests compiles filter rules for non-self, non-via
// destinations. This produces both DstPorts rules (from
// InternetProtocols) and CapGrant rules (from App).
func (pol *Policy) compileOtherDests(
users types.Users,
nodes views.Slice[types.NodeView],
grant Grant,
otherDests Aliases,
resolvedSrcs []ResolvedAddresses,
srcIPStrings []string,
) []tailcfg.FilterRule {
var rules []tailcfg.FilterRule
// DstPorts rules from InternetProtocols.
for _, ipp := range grant.InternetProtocols {
destPorts := pol.destinationsToNetPortRange(
users, nodes, otherDests, ipp.Ports,
)
if len(destPorts) > 0 && len(srcIPStrings) > 0 {
rules = append(rules, tailcfg.FilterRule{
SrcIPs: srcIPStrings,
DstPorts: destPorts,
IPProto: ipp.Protocol.toIANAProtocolNumbers(),
})
}
}
// CapGrant rules from App.
if grant.App != nil {
capSrcIPStrs := srcIPStrings
// When sources resolved to empty but App is set,
// Tailscale still produces the CapGrant rule with
// empty SrcIPs.
if capSrcIPStrs == nil {
capSrcIPStrs = []string{}
}
var (
capGrants []tailcfg.CapGrant
dstIPStrings []string
)
for _, dst := range otherDests {
ips, err := dst.Resolve(pol, users, nodes)
if err != nil {
continue
}
capGrants = append(capGrants, tailcfg.CapGrant{
Dsts: ips.Prefixes(),
CapMap: grant.App,
})
dstIPStrings = append(dstIPStrings, ips.Strings()...)
}
if len(capGrants) > 0 {
srcPrefixes := make([]netip.Prefix, 0, len(resolvedSrcs)*2)
for _, ips := range resolvedSrcs {
srcPrefixes = append(
srcPrefixes, ips.Prefixes()...,
)
}
rules = append(rules, tailcfg.FilterRule{
SrcIPs: capSrcIPStrs,
CapGrant: capGrants,
})
dstsHaveWildcard := sourcesHaveWildcard(otherDests)
if dstsHaveWildcard {
dstIPStrings = append(
dstIPStrings,
approvedSubnetRoutes(nodes)...,
)
}
rules = append(
rules,
companionCapGrantRules(
dstIPStrings, srcPrefixes, grant.App,
)...,
)
}
}
return rules
}
// hasPerNodeGrants reports whether any compiled grant requires
// per-node filter compilation (via grants or autogroup:self).
func hasPerNodeGrants(grants []compiledGrant) bool {
for i := range grants {
if grants[i].category != grantCategoryRegular {
return true
}
}
return false
}
// globalFilterRules extracts global filter rules from compiled
// grants. Only includes pre-compiled rules from non-via grants.
// Via grants produce no global rules (they are per-node only).
func globalFilterRules(grants []compiledGrant) []tailcfg.FilterRule {
var rules []tailcfg.FilterRule
for i := range grants {
if grants[i].category == grantCategoryVia {
continue
}
rules = append(rules, grants[i].rules...)
}
return mergeFilterRules(rules)
}
// filterRulesForNode produces unreduced filter rules for a specific
// node by combining pre-compiled global rules with per-node self and
// via rules. Regular grants emit their pre-compiled rules as-is.
// Self grants add autogroup:self expansion. Via grants add
// tag-matched, route-intersected rules.
func filterRulesForNode(
grants []compiledGrant,
node types.NodeView,
userIdx userNodeIndex,
) []tailcfg.FilterRule {
var rules []tailcfg.FilterRule
for i := range grants {
cg := &grants[i]
// Pre-compiled rules apply to all grant categories
// (empty for via-only grants).
rules = append(rules, cg.rules...)
switch cg.category {
case grantCategoryRegular:
// Nothing more to do.
case grantCategorySelf:
rules = append(
rules,
compileAutogroupSelf(cg, node, userIdx)...,
)
case grantCategoryVia:
rules = append(
rules,
compileViaForNode(cg, node)...,
)
}
}
return mergeFilterRules(rules)
}
// compileAutogroupSelf produces filter rules for autogroup:self
// destinations for a specific node. Only called for grants with
// self destinations and only produces rules for untagged nodes.
func compileAutogroupSelf(
cg *compiledGrant,
node types.NodeView,
userIdx userNodeIndex,
) []tailcfg.FilterRule {
if node.IsTagged() || cg.self == nil {
return nil
}
if !node.User().Valid() {
return nil
}
sameUserNodes := userIdx[node.User().ID()]
if len(sameUserNodes) == 0 {
return nil
}
var rules []tailcfg.FilterRule
// Filter sources to only same-user untagged devices.
srcResolved := filterSourcesToSameUser(
cg.self.resolvedSrcs, sameUserNodes,
)
if srcResolved == nil || srcResolved.Empty() {
return nil
}
// DstPorts rules from InternetProtocols.
for _, ipp := range cg.self.internetProtocols {
var destPorts []tailcfg.NetPortRange
for _, n := range sameUserNodes {
for _, port := range ipp.Ports {
for _, ip := range n.IPs() {
destPorts = append(
destPorts,
tailcfg.NetPortRange{
IP: ip.String(),
Ports: port,
},
)
}
}
}
if len(destPorts) > 0 {
rules = append(rules, tailcfg.FilterRule{
SrcIPs: srcResolved.Strings(),
DstPorts: destPorts,
IPProto: ipp.Protocol.toIANAProtocolNumbers(),
})
}
}
// CapGrant rules from App.
if cg.self.app != nil {
var (
capGrants []tailcfg.CapGrant
dstIPStrings []string
)
for _, n := range sameUserNodes {
var dsts []netip.Prefix
for _, ip := range n.IPs() {
dsts = append(
dsts,
netip.PrefixFrom(ip, ip.BitLen()),
)
dstIPStrings = append(
dstIPStrings, ip.String(),
)
}
capGrants = append(capGrants, tailcfg.CapGrant{
Dsts: dsts,
CapMap: cg.self.app,
})
}
if len(capGrants) > 0 {
rules = append(rules, tailcfg.FilterRule{
SrcIPs: srcResolved.Strings(),
CapGrant: capGrants,
})
rules = append(
rules,
companionCapGrantRules(
dstIPStrings,
srcResolved.Prefixes(),
cg.self.app,
)...,
)
}
}
return rules
}
// filterSourcesToSameUser intersects resolved source addresses with
// same-user untagged device IPs, returning only the addresses that
// belong to those devices.
func filterSourcesToSameUser(
resolvedSrcs []ResolvedAddresses,
sameUserNodes []types.NodeView,
) ResolvedAddresses {
var srcIPs netipx.IPSetBuilder
for _, ips := range resolvedSrcs {
for _, n := range sameUserNodes {
if slices.ContainsFunc(n.IPs(), ips.Contains) {
n.AppendToIPSet(&srcIPs)
}
}
}
srcResolved, err := newResolved(&srcIPs)
if err != nil {
return nil
}
return srcResolved
}
// compileViaForNode produces via-grant filter rules for a specific
// node. Only produces rules when the node matches one of the via
// tags and advertises routes that match the grant destinations.
func compileViaForNode(
cg *compiledGrant,
node types.NodeView,
) []tailcfg.FilterRule {
if cg.via == nil {
return nil
}
// Check if node matches any via tag.
matchesVia := false
for _, viaTag := range cg.via.viaTags {
if node.HasTag(string(viaTag)) {
matchesVia = true
break
}
}
if !matchesVia {
return nil
}
// Find matching destination prefixes.
nodeSubnetRoutes := node.SubnetRoutes()
if len(nodeSubnetRoutes) == 0 {
return nil
}
var viaDstPrefixes []netip.Prefix
for _, dst := range cg.via.destinations {
switch d := dst.(type) {
case *Prefix:
dstPrefix := netip.Prefix(*d)
if slices.Contains(nodeSubnetRoutes, dstPrefix) {
viaDstPrefixes = append(
viaDstPrefixes, dstPrefix,
)
}
case *AutoGroup:
// autogroup:internet via grants do not produce
// PacketFilter rules on exit nodes.
}
}
if len(viaDstPrefixes) == 0 {
return nil
}
// Build rules using pre-resolved srcIPStrings.
var rules []tailcfg.FilterRule
for _, ipp := range cg.via.internetProtocols {
var destPorts []tailcfg.NetPortRange
for _, prefix := range viaDstPrefixes {
for _, port := range ipp.Ports {
destPorts = append(
destPorts,
tailcfg.NetPortRange{
IP: prefix.String(),
Ports: port,
},
)
}
}
if len(destPorts) > 0 {
rules = append(rules, tailcfg.FilterRule{
SrcIPs: cg.via.srcIPStrings,
DstPorts: destPorts,
IPProto: ipp.Protocol.toIANAProtocolNumbers(),
})
}
}
return rules
}
+30 -602
View File
@@ -141,88 +141,7 @@ func (pol *Policy) compileFilterRules(
return tailcfg.FilterAllowAll, nil
}
var rules []tailcfg.FilterRule
grants := pol.Grants
for _, acl := range pol.ACLs {
grants = append(grants, aclToGrants(acl)...)
}
for _, grant := range grants {
// Via grants are compiled per-node in compileViaGrant,
// not in the global filter set.
if len(grant.Via) > 0 {
continue
}
srcIPs, err := grant.Sources.Resolve(pol, users, nodes)
if err != nil {
log.Trace().Caller().Err(err).Msgf("resolving source ips")
}
if srcIPs.Empty() {
continue
}
hasWildcard := sourcesHaveWildcard(grant.Sources)
hasDangerAll := sourcesHaveDangerAll(grant.Sources)
for _, ipp := range grant.InternetProtocols {
destPorts := pol.destinationsToNetPortRange(users, nodes, grant.Destinations, ipp.Ports)
if len(destPorts) > 0 {
rules = append(rules, tailcfg.FilterRule{
SrcIPs: srcIPsWithRoutes(srcIPs, hasWildcard, hasDangerAll, nodes),
DstPorts: destPorts,
IPProto: ipp.Protocol.toIANAProtocolNumbers(),
})
}
}
if grant.App != nil {
var (
capGrants []tailcfg.CapGrant
dstIPStrings []string
)
for _, dst := range grant.Destinations {
ips, err := dst.Resolve(pol, users, nodes)
if err != nil {
continue
}
dstPrefixes := ips.Prefixes()
capGrants = append(capGrants, tailcfg.CapGrant{
Dsts: dstPrefixes,
CapMap: grant.App,
})
dstIPStrings = append(dstIPStrings, ips.Strings()...)
}
srcIPStrs := srcIPsWithRoutes(srcIPs, hasWildcard, hasDangerAll, nodes)
rules = append(rules, tailcfg.FilterRule{
SrcIPs: srcIPStrs,
CapGrant: capGrants,
})
// Companion rules use reversed direction: SrcIPs are
// destination IPs and CapGrant Dsts are source IPs.
// When destinations include a wildcard, add subnet
// routes to companion SrcIPs (same as main rule).
dstsHaveWildcard := sourcesHaveWildcard(grant.Destinations)
if dstsHaveWildcard {
dstIPStrings = append(dstIPStrings, approvedSubnetRoutes(nodes)...)
}
rules = append(
rules,
companionCapGrantRules(dstIPStrings, srcIPs.Prefixes(), grant.App)...,
)
}
}
return mergeFilterRules(rules), nil
return globalFilterRules(pol.compileGrants(users, nodes)), nil
}
func (pol *Policy) destinationsToNetPortRange(
@@ -293,509 +212,10 @@ func (pol *Policy) compileFilterRulesForNode(
return tailcfg.FilterAllowAll, nil
}
var rules []tailcfg.FilterRule
grants := pol.compileGrants(users, nodes)
userIdx := buildUserNodeIndex(nodes)
grants := pol.Grants
for _, acl := range pol.ACLs {
grants = append(grants, aclToGrants(acl)...)
}
for _, grant := range grants {
res, err := pol.compileGrantWithAutogroupSelf(grant, users, node, nodes)
if err != nil {
log.Trace().Err(err).Msgf("compiling ACL")
continue
}
rules = append(rules, res...)
}
return mergeFilterRules(rules), nil
}
// compileViaGrant compiles a grant with a "via" field. Via grants
// produce filter rules ONLY on nodes matching a via tag that actually
// advertise (and have approved) the destination subnets. All other
// nodes receive no rules. App-only via grants (no ip field) produce
// no packet filter rules.
func (pol *Policy) compileViaGrant(
grant Grant,
users types.Users,
node types.NodeView,
nodes views.Slice[types.NodeView],
) ([]tailcfg.FilterRule, error) {
// Check if the current node matches any of the via tags.
matchesVia := false
for _, viaTag := range grant.Via {
if node.HasTag(string(viaTag)) {
matchesVia = true
break
}
}
if !matchesVia {
return nil, nil
}
// App-only via grants produce no packet filter rules.
if len(grant.InternetProtocols) == 0 {
return nil, nil
}
// Find which grant destination subnets/exit routes this node actually advertises.
nodeSubnetRoutes := node.SubnetRoutes()
nodeExitRoutes := node.ExitRoutes()
if len(nodeSubnetRoutes) == 0 && len(nodeExitRoutes) == 0 {
return nil, nil
}
// Collect destination prefixes that match the node's approved routes.
var viaDstPrefixes []netip.Prefix
for _, dst := range grant.Destinations {
switch d := dst.(type) {
case *Prefix:
dstPrefix := netip.Prefix(*d)
if slices.Contains(nodeSubnetRoutes, dstPrefix) {
viaDstPrefixes = append(viaDstPrefixes, dstPrefix)
}
case *AutoGroup:
// autogroup:internet via grants do NOT produce PacketFilter rules
// on the exit node. Tailscale SaaS handles exit traffic forwarding
// through the client's exit node selection mechanism (AllowedIPs +
// ExitNodeOption), not through PacketFilter rules. Verified by
// golden captures GRANT-V14 through GRANT-V36.
}
}
if len(viaDstPrefixes) == 0 {
return nil, nil
}
// Resolve source IPs.
var resolvedSrcs []ResolvedAddresses
for _, src := range grant.Sources {
if ag, ok := src.(*AutoGroup); ok && ag.Is(AutoGroupSelf) {
return nil, errSelfInSources
}
ips, err := src.Resolve(pol, users, nodes)
if err != nil {
log.Trace().Caller().Err(err).Msgf("resolving source ips")
}
if ips != nil {
resolvedSrcs = append(resolvedSrcs, ips)
}
}
if len(resolvedSrcs) == 0 {
return nil, nil
}
// Build merged SrcIPs from all sources.
var srcIPs netipx.IPSetBuilder
for _, ips := range resolvedSrcs {
for _, pref := range ips.Prefixes() {
srcIPs.AddPrefix(pref)
}
}
srcResolved, err := newResolved(&srcIPs)
if err != nil {
return nil, err
}
if srcResolved.Empty() {
return nil, nil
}
hasWildcard := sourcesHaveWildcard(grant.Sources)
hasDangerAll := sourcesHaveDangerAll(grant.Sources)
srcIPStrs := srcIPsWithRoutes(srcResolved, hasWildcard, hasDangerAll, nodes)
// Build DstPorts from the matching via prefixes.
var rules []tailcfg.FilterRule
for _, ipp := range grant.InternetProtocols {
var destPorts []tailcfg.NetPortRange
for _, prefix := range viaDstPrefixes {
for _, port := range ipp.Ports {
destPorts = append(destPorts, tailcfg.NetPortRange{
IP: prefix.String(),
Ports: port,
})
}
}
if len(destPorts) > 0 {
rules = append(rules, tailcfg.FilterRule{
SrcIPs: srcIPStrs,
DstPorts: destPorts,
IPProto: ipp.Protocol.toIANAProtocolNumbers(),
})
}
}
return rules, nil
}
// compileGrantWithAutogroupSelf compiles a single Grant rule, handling
// autogroup:self per-node while supporting all other alias types normally.
// It returns a slice of filter rules because when an Grant has both autogroup:self
// and other destinations, they need to be split into separate rules with different
// source filtering logic.
//
//nolint:gocyclo,cyclop // complex ACL compilation logic
func (pol *Policy) compileGrantWithAutogroupSelf(
grant Grant,
users types.Users,
node types.NodeView,
nodes views.Slice[types.NodeView],
) ([]tailcfg.FilterRule, error) {
// Handle via route grants — filter rules only go to the node
// matching the via tag that actually advertises the destination subnets.
if len(grant.Via) > 0 {
return pol.compileViaGrant(grant, users, node, nodes)
}
var (
autogroupSelfDests []Alias
otherDests []Alias
)
for _, dest := range grant.Destinations {
if ag, ok := dest.(*AutoGroup); ok && ag.Is(AutoGroupSelf) {
autogroupSelfDests = append(autogroupSelfDests, dest)
} else {
otherDests = append(otherDests, dest)
}
}
var rules []tailcfg.FilterRule
var resolvedSrcs []ResolvedAddresses
// Track non-wildcard source IPs separately. When the grant has a
// wildcard (*) source plus explicit sources (tags, groups, etc.),
// Tailscale preserves the explicit IPs alongside the wildcard
// CGNAT ranges rather than merging them into the IPSet.
var nonWildcardSrcs []ResolvedAddresses
for i, src := range grant.Sources {
if ag, ok := src.(*AutoGroup); ok && ag.Is(AutoGroupSelf) {
return nil, errSelfInSources
}
ips, err := src.Resolve(pol, users, nodes)
if err != nil {
log.Trace().Caller().Err(err).Msgf("resolving source ips")
}
if ips != nil {
resolvedSrcs = append(resolvedSrcs, ips)
if _, isWildcard := grant.Sources[i].(Asterix); !isWildcard {
nonWildcardSrcs = append(nonWildcardSrcs, ips)
}
}
}
// When the grant has literally empty src=[] or dst=[], produce no rules
// at all — Tailscale returns null for these. This is distinct from sources
// that resolve to empty (e.g., group:empty) where Tailscale still produces
// CapGrant rules with empty SrcIPs.
if len(grant.Sources) == 0 || len(grant.Destinations) == 0 {
return rules, nil
}
if len(resolvedSrcs) == 0 && grant.App == nil {
return rules, nil
}
hasWildcard := sourcesHaveWildcard(grant.Sources)
hasDangerAll := sourcesHaveDangerAll(grant.Sources)
for _, ipp := range grant.InternetProtocols {
// Handle non-self destinations first to match Tailscale's
// rule ordering in the FilterRule wire format.
if len(otherDests) > 0 {
var srcIPs netipx.IPSetBuilder
for _, ips := range resolvedSrcs {
for _, pref := range ips.Prefixes() {
srcIPs.AddPrefix(pref)
}
}
srcResolved, err := newResolved(&srcIPs)
if err != nil {
return nil, err
}
if !srcResolved.Empty() {
destPorts := pol.destinationsToNetPortRange(users, nodes, otherDests, ipp.Ports)
if len(destPorts) > 0 {
srcIPStrs := srcIPsWithRoutes(srcResolved, hasWildcard, hasDangerAll, nodes)
// When sources include a wildcard (*) alongside
// explicit sources (tags, groups, etc.), Tailscale
// preserves the individual IPs from non-wildcard
// sources alongside the merged wildcard CGNAT
// ranges rather than absorbing them.
if hasWildcard && len(nonWildcardSrcs) > 0 {
seen := make(map[string]bool, len(srcIPStrs))
for _, s := range srcIPStrs {
seen[s] = true
}
for _, ips := range nonWildcardSrcs {
for _, s := range ips.Strings() {
if !seen[s] {
seen[s] = true
srcIPStrs = append(srcIPStrs, s)
}
}
}
}
rules = append(rules, tailcfg.FilterRule{
SrcIPs: srcIPStrs,
DstPorts: destPorts,
IPProto: ipp.Protocol.toIANAProtocolNumbers(),
})
}
}
}
// Handle autogroup:self destinations (if any)
// Tagged nodes don't participate in autogroup:self (identity is tag-based, not user-based)
if len(autogroupSelfDests) > 0 && !node.IsTagged() {
// Pre-filter to same-user untagged devices once - reuse for both sources and destinations
sameUserNodes := make([]types.NodeView, 0)
for _, n := range nodes.All() {
if !n.IsTagged() && n.User().ID() == node.User().ID() {
sameUserNodes = append(sameUserNodes, n)
}
}
if len(sameUserNodes) > 0 {
// Filter sources to only same-user untagged devices
var srcIPs netipx.IPSetBuilder
for _, ips := range resolvedSrcs {
for _, n := range sameUserNodes {
// Check if any of this node's IPs are in the source set
if slices.ContainsFunc(n.IPs(), ips.Contains) {
n.AppendToIPSet(&srcIPs)
}
}
}
srcResolved, err := newResolved(&srcIPs)
if err != nil {
return nil, err
}
if !srcResolved.Empty() {
var destPorts []tailcfg.NetPortRange
for _, n := range sameUserNodes {
for _, port := range ipp.Ports {
for _, ip := range n.IPs() {
destPorts = append(destPorts, tailcfg.NetPortRange{
IP: ip.String(),
Ports: port,
})
}
}
}
if len(destPorts) > 0 {
rules = append(rules, tailcfg.FilterRule{
SrcIPs: srcResolved.Strings(),
DstPorts: destPorts,
IPProto: ipp.Protocol.toIANAProtocolNumbers(),
})
}
}
}
}
}
// Handle app grants (CapGrant rules) — these are separate from
// InternetProtocols and produce FilterRules with CapGrant instead
// of DstPorts. A grant with both ip and app fields produces rules
// for each independently.
if grant.App != nil {
// Handle non-self destinations for CapGrant
if len(otherDests) > 0 {
var srcIPStrs []string
if len(resolvedSrcs) > 0 {
var srcIPs netipx.IPSetBuilder
for _, ips := range resolvedSrcs {
for _, pref := range ips.Prefixes() {
srcIPs.AddPrefix(pref)
}
}
srcResolved, err := newResolved(&srcIPs)
if err != nil {
return nil, err
}
if !srcResolved.Empty() {
srcIPStrs = srcIPsWithRoutes(srcResolved, hasWildcard, hasDangerAll, nodes)
if hasWildcard && len(nonWildcardSrcs) > 0 {
seen := make(map[string]bool, len(srcIPStrs))
for _, s := range srcIPStrs {
seen[s] = true
}
for _, ips := range nonWildcardSrcs {
for _, s := range ips.Strings() {
if !seen[s] {
seen[s] = true
srcIPStrs = append(srcIPStrs, s)
}
}
}
}
}
}
var (
capGrants []tailcfg.CapGrant
dstIPStrings []string
)
for _, dst := range otherDests {
ips, err := dst.Resolve(pol, users, nodes)
if err != nil {
continue
}
capGrants = append(capGrants, tailcfg.CapGrant{
Dsts: ips.Prefixes(),
CapMap: grant.App,
})
dstIPStrings = append(dstIPStrings, ips.Strings()...)
}
if len(capGrants) > 0 {
// When sources resolved to empty (e.g. empty group),
// Tailscale still produces the CapGrant rule with
// empty SrcIPs.
if srcIPStrs == nil {
srcIPStrs = []string{}
}
// Collect source prefixes for reversed companion rules.
var srcPrefixes []netip.Prefix
for _, ips := range resolvedSrcs {
srcPrefixes = append(srcPrefixes, ips.Prefixes()...)
}
rules = append(rules, tailcfg.FilterRule{
SrcIPs: srcIPStrs,
CapGrant: capGrants,
})
// Companion rules use reversed direction: companion
// SrcIPs are the destination IPs. When destinations
// include a wildcard, add subnet routes to companion
// SrcIPs to match main rule behavior.
dstsHaveWildcard := sourcesHaveWildcard(otherDests)
if dstsHaveWildcard {
dstIPStrings = append(dstIPStrings, approvedSubnetRoutes(nodes)...)
}
rules = append(
rules,
companionCapGrantRules(dstIPStrings, srcPrefixes, grant.App)...,
)
}
}
// Handle autogroup:self destinations for CapGrant
if len(autogroupSelfDests) > 0 && !node.IsTagged() {
sameUserNodes := make([]types.NodeView, 0)
for _, n := range nodes.All() {
if !n.IsTagged() && n.User().ID() == node.User().ID() {
sameUserNodes = append(sameUserNodes, n)
}
}
if len(sameUserNodes) > 0 {
var srcIPs netipx.IPSetBuilder
for _, ips := range resolvedSrcs {
for _, n := range sameUserNodes {
if slices.ContainsFunc(n.IPs(), ips.Contains) {
n.AppendToIPSet(&srcIPs)
}
}
}
srcResolved, err := newResolved(&srcIPs)
if err != nil {
return nil, err
}
if !srcResolved.Empty() {
var (
capGrants []tailcfg.CapGrant
dstIPStrings []string
)
for _, n := range sameUserNodes {
var dsts []netip.Prefix
for _, ip := range n.IPs() {
dsts = append(
dsts,
netip.PrefixFrom(ip, ip.BitLen()),
)
dstIPStrings = append(dstIPStrings, ip.String())
}
capGrants = append(capGrants, tailcfg.CapGrant{
Dsts: dsts,
CapMap: grant.App,
})
}
if len(capGrants) > 0 {
srcIPStrs := srcResolved.Strings()
rules = append(rules, tailcfg.FilterRule{
SrcIPs: srcIPStrs,
CapGrant: capGrants,
})
rules = append(
rules,
companionCapGrantRules(
dstIPStrings,
srcResolved.Prefixes(),
grant.App,
)...,
)
}
}
}
}
}
return rules, nil
return filterRulesForNode(grants, node, userIdx), nil
}
var sshAccept = tailcfg.SSHAction{
@@ -994,9 +414,20 @@ func (pol *Policy) compileSSHPolicy(
appendRules(taggedPrincipals, 0, false)
}
} else {
if principals := resolvedAddrsToPrincipals(srcIPs); len(principals) > 0 {
// Merge user and tagged principals into a
// single list. Tagged principals preserve
// per-tag duplication (a node with N tags
// appears N times, matching SaaS behavior).
var allPrincipals []*tailcfg.SSHPrincipal
for _, uid := range userIDs {
allPrincipals = append(allPrincipals, principalsByUser[uid]...)
}
allPrincipals = append(allPrincipals, taggedPrincipals...)
if len(allPrincipals) > 0 {
rules = append(rules, &tailcfg.SSHRule{
Principals: principals,
Principals: allPrincipals,
SSHUsers: baseUserMap,
Action: &action,
AcceptEnv: acceptEnv,
@@ -1137,9 +568,7 @@ func groupSourcesByUser(
) ([]uint, map[uint][]*tailcfg.SSHPrincipal, []*tailcfg.SSHPrincipal) {
userIPSets := make(map[uint]*netipx.IPSetBuilder)
var taggedIPSet netipx.IPSetBuilder
hasTagged := false
var taggedPrincipals []*tailcfg.SSHPrincipal
for _, n := range nodes.All() {
if !slices.ContainsFunc(n.IPs(), srcIPs.Contains) {
@@ -1147,9 +576,17 @@ func groupSourcesByUser(
}
if n.IsTagged() {
n.AppendToIPSet(&taggedIPSet)
hasTagged = true
// Tailscale SaaS resolves autogroup:tagged by
// iterating tag membership lists. A node with N
// tags produces N copies of its IPs in the
// principal list. Match that behavior so the SSH
// wire format is identical.
for range n.Tags().Len() {
for _, ip := range n.IPs() {
taggedPrincipals = append(taggedPrincipals,
&tailcfg.SSHPrincipal{NodeIP: ip.String()})
}
}
continue
}
@@ -1185,16 +622,7 @@ func groupSourcesByUser(
slices.Sort(userIDs)
var tagged []*tailcfg.SSHPrincipal
if hasTagged {
taggedSet, err := taggedIPSet.IPSet()
if err == nil && taggedSet != nil {
tagged = ipSetToPrincipals(taggedSet)
}
}
return userIDs, principalsByUser, tagged
return userIDs, principalsByUser, taggedPrincipals
}
func ipSetToPrefixStringList(ips *netipx.IPSet) []string {
+16 -3
View File
@@ -3832,7 +3832,7 @@ func TestCompileViaGrant(t *testing.T) {
nodeView := tt.node.View()
nodesSlice := tt.nodes.ViewSlice()
got, err := tt.pol.compileViaGrant(tt.grant, users, nodeView, nodesSlice)
cg, err := tt.pol.compileOneGrant(tt.grant, users, nodesSlice)
if tt.wantErr != nil {
require.ErrorIs(t, err, tt.wantErr)
@@ -3842,6 +3842,11 @@ func TestCompileViaGrant(t *testing.T) {
require.NoError(t, err)
var got []tailcfg.FilterRule
if cg != nil {
got = compileViaForNode(cg, nodeView)
}
if tt.name == "wildcard sources include subnet routes in SrcIPs" {
// Wildcard resolves to CGNAT ranges; just check the route is appended.
require.Len(t, got, 1)
@@ -3997,9 +4002,10 @@ func TestCompileGrantWithAutogroupSelf_GrantPaths(t *testing.T) {
nodeView := tt.node.View()
nodesSlice := allNodes.ViewSlice()
userIdx := buildUserNodeIndex(nodesSlice)
got, err := tt.pol.compileGrantWithAutogroupSelf(
tt.grant, users, nodeView, nodesSlice,
cg, err := tt.pol.compileOneGrant(
tt.grant, users, nodesSlice,
)
if tt.wantErr != nil {
@@ -4010,6 +4016,13 @@ func TestCompileGrantWithAutogroupSelf_GrantPaths(t *testing.T) {
require.NoError(t, err)
var got []tailcfg.FilterRule
if cg != nil {
got = append(got, cg.rules...)
got = append(got, compileAutogroupSelf(cg, nodeView, userIdx)...)
got = mergeFilterRules(got)
}
switch tt.name {
case "autogroup:self destination for untagged node produces same-user devices":
// Should produce rules; sources and destinations should only
+70 -112
View File
@@ -46,16 +46,17 @@ type PolicyManager struct {
// Lazy map of SSH policies
sshPolicyMap map[types.NodeID]*tailcfg.SSHPolicy
// Lazy map of per-node compiled filter rules (unreduced, for autogroup:self)
compiledFilterRulesMap map[types.NodeID][]tailcfg.FilterRule
// Lazy map of per-node filter rules (reduced, for packet filters)
filterRulesMap map[types.NodeID][]tailcfg.FilterRule
usesAutogroupSelf bool
// compiledGrants are the grants with sources pre-resolved.
// The single source of truth for filter compilation. Both
// global and per-node filter rules are derived from these.
compiledGrants []compiledGrant
userNodeIdx userNodeIndex
// needsPerNodeFilter is true when filter rules must be compiled
// per-node rather than globally. This is required when the policy
// uses autogroup:self (node-relative destinations) or via grants
// (per-router filter rules for steered traffic).
// Lazy map of per-node filter rules (reduced, for packet filters)
filterRulesMap map[types.NodeID][]tailcfg.FilterRule
// needsPerNodeFilter is true when any compiled grant requires
// per-node work (autogroup:self or via grants).
needsPerNodeFilter bool
}
@@ -77,14 +78,11 @@ func NewPolicyManager(b []byte, users []types.User, nodes views.Slice[types.Node
}
pm := PolicyManager{
pol: policy,
users: users,
nodes: nodes,
sshPolicyMap: make(map[types.NodeID]*tailcfg.SSHPolicy, nodes.Len()),
compiledFilterRulesMap: make(map[types.NodeID][]tailcfg.FilterRule, nodes.Len()),
filterRulesMap: make(map[types.NodeID][]tailcfg.FilterRule, nodes.Len()),
usesAutogroupSelf: policy.usesAutogroupSelf(),
needsPerNodeFilter: policy.usesAutogroupSelf() || policy.hasViaGrants(),
pol: policy,
users: users,
nodes: nodes,
sshPolicyMap: make(map[types.NodeID]*tailcfg.SSHPolicy, nodes.Len()),
filterRulesMap: make(map[types.NodeID][]tailcfg.FilterRule, nodes.Len()),
}
_, err = pm.updateLocked()
@@ -98,18 +96,17 @@ func NewPolicyManager(b []byte, users []types.User, nodes views.Slice[types.Node
// updateLocked updates the filter rules based on the current policy and nodes.
// It must be called with the lock held.
func (pm *PolicyManager) updateLocked() (bool, error) {
// Check if policy uses autogroup:self or via grants
pm.usesAutogroupSelf = pm.pol.usesAutogroupSelf()
pm.needsPerNodeFilter = pm.usesAutogroupSelf || pm.pol.hasViaGrants()
// Compile all grants once. Both global and per-node filter
// rules are derived from these compiled grants.
pm.compiledGrants = pm.pol.compileGrants(pm.users, pm.nodes)
pm.userNodeIdx = buildUserNodeIndex(pm.nodes)
pm.needsPerNodeFilter = hasPerNodeGrants(pm.compiledGrants)
var filter []tailcfg.FilterRule
var err error
// Standard compilation for all policies
filter, err = pm.pol.compileFilterRules(pm.users, pm.nodes)
if err != nil {
return false, fmt.Errorf("compiling filter rules: %w", err)
if pm.pol == nil || (pm.pol.ACLs == nil && len(pm.pol.Grants) == 0) {
filter = tailcfg.FilterAllowAll
} else {
filter = globalFilterRules(pm.compiledGrants)
}
// Hash both the compiled filter AND the policy content together.
@@ -209,7 +206,6 @@ func (pm *PolicyManager) updateLocked() (bool, error) {
// policies for nodes that have changed. Particularly if the only difference is
// that nodes has been added or removed.
clear(pm.sshPolicyMap)
clear(pm.compiledFilterRulesMap)
clear(pm.filterRulesMap)
}
@@ -414,16 +410,8 @@ func (pm *PolicyManager) BuildPeerMap(nodes views.Slice[types.NodeView]) map[typ
// but peer relationships require the full bidirectional access rules.
nodeMatchers := make(map[types.NodeID][]matcher.Match, nodes.Len())
for _, node := range nodes.All() {
filter, err := pm.compileFilterRulesForNodeLocked(node)
if err != nil {
continue
}
// Include all nodes in nodeMatchers, even those with empty filters.
// Empty filters result in empty matchers where CanAccess() returns false,
// but the node still needs to be in the map so hasFilterX is true.
// This ensures symmetric visibility works correctly: if node A can access
// node B, both should see each other regardless of B's filter rules.
nodeMatchers[node.ID()] = matcher.MatchesFromFilterRules(filter)
unreduced := pm.filterRulesForNodeLocked(node)
nodeMatchers[node.ID()] = matcher.MatchesFromFilterRules(unreduced)
}
// Check each node pair for peer relationships.
@@ -464,75 +452,50 @@ func (pm *PolicyManager) BuildPeerMap(nodes views.Slice[types.NodeView]) map[typ
return ret
}
// compileFilterRulesForNodeLocked returns the unreduced compiled filter rules for a node
// when using autogroup:self. This is used by BuildPeerMap to determine peer relationships.
// For packet filters sent to nodes, use filterForNodeLocked which returns reduced rules.
func (pm *PolicyManager) compileFilterRulesForNodeLocked(node types.NodeView) ([]tailcfg.FilterRule, error) {
if pm == nil {
return nil, nil
}
// Check if we have cached compiled rules
if rules, ok := pm.compiledFilterRulesMap[node.ID()]; ok {
return rules, nil
}
// Compile per-node rules with autogroup:self expanded
rules, err := pm.pol.compileFilterRulesForNode(pm.users, node, pm.nodes)
if err != nil {
return nil, fmt.Errorf("compiling filter rules for node: %w", err)
}
// Cache the unreduced compiled rules
pm.compiledFilterRulesMap[node.ID()] = rules
return rules, nil
// filterRulesForNodeLocked returns the unreduced compiled filter rules
// for a node, combining pre-compiled global rules with per-node self
// and via rules from the stored compiled grants.
func (pm *PolicyManager) filterRulesForNodeLocked(
node types.NodeView,
) []tailcfg.FilterRule {
return filterRulesForNode(
pm.compiledGrants, node, pm.userNodeIdx,
)
}
// filterForNodeLocked returns the filter rules for a specific node, already reduced
// to only include rules relevant to that node.
// This is a lock-free version of FilterForNode for internal use when the lock is already held.
// BuildPeerMap already holds the lock, so we need a version that doesn't re-acquire it.
func (pm *PolicyManager) filterForNodeLocked(node types.NodeView) ([]tailcfg.FilterRule, error) {
// filterForNodeLocked returns the filter rules for a specific node,
// already reduced to only include rules relevant to that node.
//
// Fast path (!needsPerNodeFilter): reduces global filter per-node.
// Slow path (needsPerNodeFilter): combines global + self + via rules
// from the stored compiled grants, then reduces.
//
// Both paths derive from the same compiledGrants, ensuring there is
// no divergence between global and per-node filter output.
//
// Lock-free version for internal use when the lock is already held.
func (pm *PolicyManager) filterForNodeLocked(
node types.NodeView,
) []tailcfg.FilterRule {
if pm == nil {
return nil, nil
return nil
}
if !pm.needsPerNodeFilter {
// For global filters, reduce to only rules relevant to this node.
// Cache the reduced filter per node for efficiency.
if rules, ok := pm.filterRulesMap[node.ID()]; ok {
return rules, nil
}
// Use policyutil.ReduceFilterRules for global filter reduction.
reducedFilter := policyutil.ReduceFilterRules(node, pm.filter)
pm.filterRulesMap[node.ID()] = reducedFilter
return reducedFilter, nil
}
// Per-node compilation is needed when the policy uses autogroup:self
// (node-relative destinations) or via grants (per-router filter rules).
// Check if we have cached reduced rules for this node.
if rules, ok := pm.filterRulesMap[node.ID()]; ok {
return rules, nil
return rules
}
// Get unreduced compiled rules
compiledRules, err := pm.compileFilterRulesForNodeLocked(node)
if err != nil {
return nil, err
var unreduced []tailcfg.FilterRule
if !pm.needsPerNodeFilter {
unreduced = pm.filter
} else {
unreduced = pm.filterRulesForNodeLocked(node)
}
// Reduce the compiled rules to only destinations relevant to this node
reducedFilter := policyutil.ReduceFilterRules(node, compiledRules)
reduced := policyutil.ReduceFilterRules(node, unreduced)
pm.filterRulesMap[node.ID()] = reduced
// Cache the reduced filter
pm.filterRulesMap[node.ID()] = reducedFilter
return reducedFilter, nil
return reduced
}
// FilterForNode returns the filter rules for a specific node, already reduced
@@ -547,7 +510,7 @@ func (pm *PolicyManager) FilterForNode(node types.NodeView) ([]tailcfg.FilterRul
pm.mu.Lock()
defer pm.mu.Unlock()
return pm.filterForNodeLocked(node)
return pm.filterForNodeLocked(node), nil
}
// MatchersForNode returns the matchers for peer relationship determination for a specific node.
@@ -571,14 +534,11 @@ func (pm *PolicyManager) MatchersForNode(node types.NodeView) ([]matcher.Match,
return pm.matchers, nil
}
// For autogroup:self or via grants, get unreduced compiled rules and create matchers
compiledRules, err := pm.compileFilterRulesForNodeLocked(node)
if err != nil {
return nil, err
}
// For autogroup:self or via grants, derive matchers from
// the stored compiled grants for this specific node.
unreduced := pm.filterRulesForNodeLocked(node)
// Create matchers from unreduced rules for peer relationship determination
return matcher.MatchesFromFilterRules(compiledRules), nil
return matcher.MatchesFromFilterRules(unreduced), nil
}
// SetUsers updates the users in the policy manager and updates the filter rules.
@@ -649,7 +609,6 @@ func (pm *PolicyManager) SetNodes(nodes views.Slice[types.NodeView]) (bool, erro
if !needsUpdate {
// This ensures fresh filter rules are generated for all nodes
clear(pm.sshPolicyMap)
clear(pm.compiledFilterRulesMap)
clear(pm.filterRulesMap)
}
// Always return true when nodes changed, even if filter hash didn't change
@@ -1151,12 +1110,10 @@ func (pm *PolicyManager) invalidateAutogroupSelfCache(oldNodes, newNodes views.S
// If we found the user and they're affected, clear this cache entry
if found {
if _, affected := affectedUsers[nodeUserID]; affected {
delete(pm.compiledFilterRulesMap, nodeID)
delete(pm.filterRulesMap, nodeID)
}
} else {
// Node not found in either old or new list, clear it
delete(pm.compiledFilterRulesMap, nodeID)
delete(pm.filterRulesMap, nodeID)
}
}
@@ -1171,13 +1128,14 @@ func (pm *PolicyManager) invalidateAutogroupSelfCache(oldNodes, newNodes views.S
// invalidateNodeCache invalidates cache entries based on what changed.
func (pm *PolicyManager) invalidateNodeCache(newNodes views.Slice[types.NodeView]) {
if pm.usesAutogroupSelf {
// For autogroup:self, a node's filter depends on its peers (same user).
// When any node in a user changes, all nodes for that user need invalidation.
if pm.needsPerNodeFilter {
// For autogroup:self or via grants, a node's filter depends
// on its peers. When any node changes, invalidate affected
// users' caches.
pm.invalidateAutogroupSelfCache(pm.nodes, newNodes)
} else {
// For global policies, a node's filter depends only on its own properties.
// Only invalidate nodes whose properties actually changed.
// For global policies, a node's filter depends only on its
// own properties. Only invalidate changed nodes.
pm.invalidateGlobalPolicyCache(newNodes)
}
}
+4 -5
View File
@@ -355,9 +355,8 @@ func TestInvalidateGlobalPolicyCache(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
pm := &PolicyManager{
nodes: tt.oldNodes.ViewSlice(),
filterRulesMap: tt.initialCache,
usesAutogroupSelf: false,
nodes: tt.oldNodes.ViewSlice(),
filterRulesMap: tt.initialCache,
}
pm.invalidateGlobalPolicyCache(tt.newNodes.ViewSlice())
@@ -399,7 +398,7 @@ func TestAutogroupSelfReducedVsUnreducedRules(t *testing.T) {
pm, err := NewPolicyManager([]byte(policyStr), users, nodes.ViewSlice())
require.NoError(t, err)
require.True(t, pm.usesAutogroupSelf, "policy should use autogroup:self")
require.True(t, pm.needsPerNodeFilter, "policy should need per-node filter")
// Test FilterForNode returns reduced rules
// For node1: should have rules where node1 is in destinations (its own IP)
@@ -572,7 +571,7 @@ func TestAutogroupSelfPolicyUpdateTriggersMapResponse(t *testing.T) {
pm, err := NewPolicyManager([]byte(initialPolicy), users, nodes.ViewSlice())
require.NoError(t, err)
require.True(t, pm.usesAutogroupSelf, "policy should use autogroup:self")
require.True(t, pm.needsPerNodeFilter, "policy should need per-node filter")
// Get initial filter rules for test-1 (should be cached)
rules1, err := pm.FilterForNode(test1Node.View())
@@ -1,22 +1,22 @@
// This file implements a data-driven test runner for ACL compatibility tests.
// It loads JSON golden files from testdata/acl_results/ACL-*.json and compares
// headscale's ACL engine output against the expected packet filter rules.
// It loads HuJSON golden files from testdata/acl_results/acl-*.hujson and
// compares headscale's ACL engine output against the expected packet filter
// rules captured from Tailscale SaaS by the tscap tool.
//
// The JSON files were converted from the original inline Go struct test cases
// in tailscale_acl_compat_test.go. Each file contains:
// - A full policy (groups, tagOwners, hosts, acls)
// - Expected packet_filter_rules per node (5 nodes)
// - Or an error response for invalid policies
// Each file is a testcapture.Capture containing:
// - The full policy that was POSTed to the Tailscale SaaS API
// - The 8-node topology used for the capture run
// - Expected packet_filter_rules per node (or error metadata for
// scenarios that the SaaS rejected)
//
// Test data source: testdata/acl_results/ACL-*.json
// Original source: Tailscale SaaS API captures + headscale-generated expansions
// Test data source: testdata/acl_results/acl-*.hujson
// Source format: github.com/juanfont/headscale/hscontrol/types/testcapture
package v2
import (
"encoding/json"
"net/netip"
"os"
"path/filepath"
"strings"
"testing"
@@ -25,9 +25,8 @@ import (
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/juanfont/headscale/hscontrol/policy/policyutil"
"github.com/juanfont/headscale/hscontrol/types"
"github.com/stretchr/testify/assert"
"github.com/juanfont/headscale/hscontrol/types/testcapture"
"github.com/stretchr/testify/require"
"github.com/tailscale/hujson"
"gorm.io/gorm"
"tailscale.com/tailcfg"
)
@@ -40,55 +39,56 @@ func ptrAddr(s string) *netip.Addr {
}
// setupACLCompatUsers returns the 3 test users for ACL compatibility tests.
// Email addresses use @example.com domain, matching the converted Tailscale
// policy format (Tailscale uses @passkey and @dalby.cc).
// Names and emails match the anonymized identifiers tscap writes into the
// capture files (see github.com/kradalby/tscap/anonymize): users get
// norse-god names and nodes get original-151 pokémon names.
func setupACLCompatUsers() types.Users {
return types.Users{
{Model: gorm.Model{ID: 1}, Name: "kratail2tid", Email: "kratail2tid@example.com"},
{Model: gorm.Model{ID: 2}, Name: "kristoffer", Email: "kristoffer@example.com"},
{Model: gorm.Model{ID: 3}, Name: "monitorpasskeykradalby", Email: "monitorpasskeykradalby@example.com"},
{Model: gorm.Model{ID: 1}, Name: "odin", Email: "odin@example.com"},
{Model: gorm.Model{ID: 2}, Name: "thor", Email: "thor@example.org"},
{Model: gorm.Model{ID: 3}, Name: "freya", Email: "freya@example.com"},
}
}
// setupACLCompatNodes returns the 8 test nodes for ACL compatibility tests.
// Uses the same topology as the grants compat tests.
// Node GivenNames match tscap's anonymized pokémon naming.
func setupACLCompatNodes(users types.Users) types.Nodes {
return types.Nodes{
{
ID: 1, GivenName: "user1",
ID: 1, GivenName: "bulbasaur",
User: &users[0], UserID: &users[0].ID,
IPv4: ptrAddr("100.90.199.68"), IPv6: ptrAddr("fd7a:115c:a1e0::2d01:c747"),
Hostinfo: &tailcfg.Hostinfo{},
},
{
ID: 2, GivenName: "user-kris",
ID: 2, GivenName: "ivysaur",
User: &users[1], UserID: &users[1].ID,
IPv4: ptrAddr("100.110.121.96"), IPv6: ptrAddr("fd7a:115c:a1e0::1737:7960"),
Hostinfo: &tailcfg.Hostinfo{},
},
{
ID: 3, GivenName: "user-mon",
ID: 3, GivenName: "venusaur",
User: &users[2], UserID: &users[2].ID,
IPv4: ptrAddr("100.103.90.82"), IPv6: ptrAddr("fd7a:115c:a1e0::9e37:5a52"),
Hostinfo: &tailcfg.Hostinfo{},
},
{
ID: 4, GivenName: "tagged-server",
ID: 4, GivenName: "beedrill",
IPv4: ptrAddr("100.108.74.26"), IPv6: ptrAddr("fd7a:115c:a1e0::b901:4a87"),
Tags: []string{"tag:server"}, Hostinfo: &tailcfg.Hostinfo{},
},
{
ID: 5, GivenName: "tagged-prod",
ID: 5, GivenName: "kakuna",
IPv4: ptrAddr("100.103.8.15"), IPv6: ptrAddr("fd7a:115c:a1e0::5b37:80f"),
Tags: []string{"tag:prod"}, Hostinfo: &tailcfg.Hostinfo{},
},
{
ID: 6, GivenName: "tagged-client",
ID: 6, GivenName: "weedle",
IPv4: ptrAddr("100.83.200.69"), IPv6: ptrAddr("fd7a:115c:a1e0::c537:c845"),
Tags: []string{"tag:client"}, Hostinfo: &tailcfg.Hostinfo{},
},
{
ID: 7, GivenName: "subnet-router",
ID: 7, GivenName: "squirtle",
IPv4: ptrAddr("100.92.142.61"), IPv6: ptrAddr("fd7a:115c:a1e0::3e37:8e3d"),
Tags: []string{"tag:router"},
Hostinfo: &tailcfg.Hostinfo{
@@ -97,7 +97,7 @@ func setupACLCompatNodes(users types.Users) types.Nodes {
ApprovedRoutes: []netip.Prefix{netip.MustParsePrefix("10.33.0.0/16")},
},
{
ID: 8, GivenName: "exit-node",
ID: 8, GivenName: "charmander",
IPv4: ptrAddr("100.85.66.106"), IPv6: ptrAddr("fd7a:115c:a1e0::7c37:426a"),
Tags: []string{"tag:exit"}, Hostinfo: &tailcfg.Hostinfo{},
},
@@ -140,27 +140,6 @@ func cmpOptions() []cmp.Option {
return a.Bits() < b.Bits()
}),
// Compare json.RawMessage semantically rather than by exact
// bytes to handle indentation differences between the policy
// source and the golden capture data.
cmp.Comparer(func(a, b json.RawMessage) bool {
var va, vb any
err := json.Unmarshal(a, &va)
if err != nil {
return string(a) == string(b)
}
err = json.Unmarshal(b, &vb)
if err != nil {
return string(a) == string(b)
}
ja, _ := json.Marshal(va)
jb, _ := json.Marshal(vb)
return string(ja) == string(jb)
}),
// Compare tailcfg.RawMessage semantically (it's a string type
// containing JSON) to handle indentation differences.
cmp.Comparer(func(a, b tailcfg.RawMessage) bool {
@@ -184,53 +163,95 @@ func cmpOptions() []cmp.Option {
}
}
// aclTestFile represents the JSON structure of a captured ACL test file.
type aclTestFile struct {
TestID string `json:"test_id"`
Source string `json:"source"` // "tailscale_saas" or "headscale_adapted"
Error bool `json:"error"`
HeadscaleDiffers bool `json:"headscale_differs"`
ParentTest string `json:"parent_test"`
Input struct {
FullPolicy json.RawMessage `json:"full_policy"`
APIResponseCode int `json:"api_response_code"`
APIResponseBody *struct {
Message string `json:"message"`
} `json:"api_response_body"`
} `json:"input"`
Topology struct {
Nodes map[string]struct {
Hostname string `json:"hostname"`
Tags []string `json:"tags"`
IPv4 string `json:"ipv4"`
IPv6 string `json:"ipv6"`
User string `json:"user"`
RoutableIPs []string `json:"routable_ips"`
ApprovedRoutes []string `json:"approved_routes"`
} `json:"nodes"`
} `json:"topology"`
Captures map[string]struct {
PacketFilterRules json.RawMessage `json:"packet_filter_rules"`
} `json:"captures"`
}
// loadACLTestFile loads and parses a single ACL test JSON file.
func loadACLTestFile(t *testing.T, path string) aclTestFile {
// buildACLUsersAndNodes constructs users and nodes from an ACL
// golden file's topology. This ensures the test creates the same
// nodes that were present during the Tailscale SaaS capture.
func buildACLUsersAndNodes(
t *testing.T,
tf *testcapture.Capture,
) (types.Users, types.Nodes) {
t.Helper()
content, err := os.ReadFile(path)
users := setupACLCompatUsers()
nodes := make(types.Nodes, 0, len(tf.Topology.Nodes))
autoID := 1
for name, nodeDef := range tf.Topology.Nodes {
node := &types.Node{
ID: types.NodeID(autoID), //nolint:gosec
GivenName: name,
IPv4: ptrAddr(nodeDef.IPv4),
IPv6: ptrAddr(nodeDef.IPv6),
Tags: nodeDef.Tags,
}
autoID++
hostinfo := &tailcfg.Hostinfo{}
if len(nodeDef.RoutableIPs) > 0 {
routableIPs := make(
[]netip.Prefix, 0, len(nodeDef.RoutableIPs),
)
for _, r := range nodeDef.RoutableIPs {
routableIPs = append(
routableIPs, netip.MustParsePrefix(r),
)
}
hostinfo.RoutableIPs = routableIPs
}
node.Hostinfo = hostinfo
if len(nodeDef.ApprovedRoutes) > 0 {
approved := make(
[]netip.Prefix, 0, len(nodeDef.ApprovedRoutes),
)
for _, r := range nodeDef.ApprovedRoutes {
approved = append(
approved, netip.MustParsePrefix(r),
)
}
node.ApprovedRoutes = approved
} else {
node.ApprovedRoutes = []netip.Prefix{}
}
// Assign user — untagged nodes get user1
if len(nodeDef.Tags) == 0 {
if nodeDef.User != "" {
for i := range users {
if users[i].Name == nodeDef.User {
node.User = &users[i]
node.UserID = &users[i].ID
break
}
}
} else {
node.User = &users[0]
node.UserID = &users[0].ID
}
}
nodes = append(nodes, node)
}
return users, nodes
}
// loadACLTestFile loads and parses a single ACL capture HuJSON file.
func loadACLTestFile(t *testing.T, path string) *testcapture.Capture {
t.Helper()
c, err := testcapture.Read(path)
require.NoError(t, err, "failed to read test file %s", path)
ast, err := hujson.Parse(content)
require.NoError(t, err, "failed to parse HuJSON in %s", path)
ast.Standardize()
var tf aclTestFile
err = json.Unmarshal(ast.Pack(), &tf)
require.NoError(t, err, "failed to unmarshal test file %s", path)
return tf
return c
}
// aclSkipReasons documents WHY tests are expected to fail and WHAT needs to be
@@ -260,20 +281,17 @@ func TestACLCompat(t *testing.T) {
t.Parallel()
files, err := filepath.Glob(
filepath.Join("testdata", "acl_results", "ACL-*.hujson"),
filepath.Join("testdata", "acl_results", "acl-*.hujson"),
)
require.NoError(t, err, "failed to glob test files")
require.NotEmpty(
t,
files,
"no ACL-*.hujson test files found in testdata/acl_results/",
"no acl-*.hujson test files found in testdata/acl_results/",
)
t.Logf("Loaded %d ACL test files", len(files))
users := setupACLCompatUsers()
nodes := setupACLCompatNodes(users)
for _, file := range files {
tf := loadACLTestFile(t, file)
@@ -296,29 +314,39 @@ func TestACLCompat(t *testing.T) {
return
}
// Build nodes per-scenario from this file's topology.
// tscap uses clean-slate mode, so each scenario has
// different node IPs; using a shared topology would
// cause IP mismatches in filter rule comparisons.
users, nodes := buildACLUsersAndNodes(t, tf)
require.NotEmpty(t, nodes, "%s: topology is empty", tf.TestID)
testACLSuccess(t, tf, users, nodes)
})
}
}
// aclErrorMessageMap maps Tailscale SaaS error substrings to headscale
// equivalents. Populated as mismatches are discovered.
var aclErrorMessageMap = map[string]string{
// Add known wording differences here as they are discovered.
// Example: "tag not found" -> "undefined tag",
}
// testACLError verifies that an invalid policy produces the expected error.
func testACLError(t *testing.T, tf aclTestFile) {
func testACLError(t *testing.T, tf *testcapture.Capture) {
t.Helper()
policyJSON := convertPolicyUserEmails(tf.Input.FullPolicy)
pol, err := unmarshalPolicy(policyJSON)
if err != nil {
// Parse-time error — valid for some error tests
// Parse-time error.
if tf.Input.APIResponseBody != nil {
wantMsg := tf.Input.APIResponseBody.Message
if wantMsg != "" {
assert.Contains(
t,
err.Error(),
wantMsg,
"%s: error message should contain expected substring",
tf.TestID,
assertACLErrorContains(
t, err, wantMsg, tf.TestID,
)
}
}
@@ -331,64 +359,82 @@ func testACLError(t *testing.T, tf aclTestFile) {
if tf.Input.APIResponseBody != nil {
wantMsg := tf.Input.APIResponseBody.Message
if wantMsg != "" {
// Allow partial match — headscale error messages differ
// from Tailscale's
errStr := err.Error()
if !strings.Contains(errStr, wantMsg) {
// Try matching key parts
matched := false
for _, part := range []string{
"autogroup:self",
"not valid on the src",
"port range",
"tag not found",
"undefined",
} {
if strings.Contains(wantMsg, part) &&
strings.Contains(errStr, part) {
matched = true
break
}
}
if !matched {
t.Logf(
"%s: error message difference\n want (tailscale): %q\n got (headscale): %q",
tf.TestID,
wantMsg,
errStr,
)
}
}
assertACLErrorContains(
t, err, wantMsg, tf.TestID,
)
}
}
return
}
// For headscale_differs tests, headscale may accept what Tailscale rejects
if tf.HeadscaleDiffers {
t.Logf(
"%s: headscale accepts this policy (Tailscale rejects it)",
tf.TestID,
)
return
}
t.Errorf(
"%s: expected error but policy parsed and validated successfully",
tf.TestID,
)
}
// assertACLErrorContains checks that an error message matches the
// expected Tailscale SaaS message, using progressive fallbacks:
// 1. Direct substring match
// 2. Mapped equivalent from aclErrorMessageMap
// 3. Key-part extraction (tags, autogroups, port, undefined)
// 4. t.Errorf on no match (strict)
func assertACLErrorContains(
t *testing.T,
err error,
wantMsg string,
testID string,
) {
t.Helper()
errStr := err.Error()
// 1. Direct substring match.
if strings.Contains(errStr, wantMsg) {
return
}
// 2. Mapped equivalent.
for tsKey, hsKey := range aclErrorMessageMap {
if strings.Contains(wantMsg, tsKey) &&
strings.Contains(errStr, hsKey) {
return
}
}
// 3. Key-part extraction.
for _, part := range []string{
"autogroup:self",
"not valid on the src",
"port range",
"tag not found",
"tag:",
"undefined",
"capability",
} {
if strings.Contains(wantMsg, part) &&
strings.Contains(errStr, part) {
return
}
}
// 4. No match — strict failure.
t.Errorf(
"%s: error message mismatch\n"+
" want (tailscale): %q\n"+
" got (headscale): %q",
testID,
wantMsg,
errStr,
)
}
// testACLSuccess verifies that a valid policy produces the expected
// packet filter rules for each node.
func testACLSuccess(
t *testing.T,
tf aclTestFile,
tf *testcapture.Capture,
users types.Users,
nodes types.Nodes,
) {
@@ -415,9 +461,6 @@ func testACLSuccess(
for nodeName, capture := range tf.Captures {
t.Run(nodeName, func(t *testing.T) {
captureIsNull := len(capture.PacketFilterRules) == 0 ||
string(capture.PacketFilterRules) == "null" //nolint:goconst
node := findNodeByGivenName(nodes, nodeName)
if node == nil {
t.Skipf(
@@ -447,21 +490,7 @@ func testACLSuccess(
compiledRules,
)
// Parse expected rules from JSON
var wantRules []tailcfg.FilterRule
if !captureIsNull {
err = json.Unmarshal(
capture.PacketFilterRules,
&wantRules,
)
require.NoError(
t,
err,
"%s/%s: failed to unmarshal expected rules",
tf.TestID,
nodeName,
)
}
wantRules := capture.PacketFilterRules
// Compare
opts := append(
@@ -1,27 +1,24 @@
// This file is "generated" by Claude.
// It contains a data-driven test that reads 237 GRANT-*.json test files
// captured from Tailscale SaaS. Each file contains:
// - A policy with grants (and optionally ACLs)
// - The expected packet_filter_rules for each of 8 test nodes
// This file implements a data-driven test runner for grant compatibility
// tests. It loads HuJSON golden files from testdata/grant_results/grant-*.hujson
// and via-grant-*.hujson, captured from Tailscale SaaS by tscap, and compares
// headscale's grants engine output against the captured packet filter rules.
//
// Each file is a testcapture.Capture containing:
// - A full policy with grants (and optionally ACLs)
// - The expected packet_filter_rules for each of 8-15 test nodes
// - Or an error response for invalid policies
//
// The test loads each JSON file, applies the policy through headscale's
// grants engine, and compares the output against Tailscale's actual behavior.
// Tests known to fail due to unimplemented features or known differences are
// skipped with a TODO comment explaining the root cause. As headscale's grants
// implementation improves, tests should be removed from the skip list.
//
// Tests that are known to fail due to unimplemented features or known
// differences are skipped with a TODO comment explaining the root cause.
// As headscale's grants implementation improves, tests should be removed
// from the skip list.
//
// Test data source: testdata/grant_results/GRANT-*.json
// Captured from: Tailscale SaaS API + tailscale debug localapi
// Test data source: testdata/grant_results/{grant,via-grant}-*.hujson
// Source format: github.com/juanfont/headscale/hscontrol/types/testcapture
package v2
import (
"encoding/json"
"net/netip"
"os"
"path/filepath"
"strings"
"testing"
@@ -30,54 +27,33 @@ import (
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/juanfont/headscale/hscontrol/policy/policyutil"
"github.com/juanfont/headscale/hscontrol/types"
"github.com/juanfont/headscale/hscontrol/types/testcapture"
"github.com/stretchr/testify/require"
"github.com/tailscale/hujson"
"gorm.io/gorm"
"tailscale.com/tailcfg"
)
// grantTestFile represents the JSON structure of a captured grant test file.
type grantTestFile struct {
TestID string `json:"test_id"`
Error bool `json:"error"`
Input struct {
FullPolicy json.RawMessage `json:"full_policy"`
APIResponseCode int `json:"api_response_code"`
APIResponseBody *struct {
Message string `json:"message"`
} `json:"api_response_body"`
} `json:"input"`
Topology struct {
Nodes map[string]struct {
Hostname string `json:"hostname"`
Tags []string `json:"tags"`
IPv4 string `json:"ipv4"`
IPv6 string `json:"ipv6"`
} `json:"nodes"`
} `json:"topology"`
Captures map[string]struct {
PacketFilterRules json.RawMessage `json:"packet_filter_rules"`
} `json:"captures"`
}
// setupGrantsCompatUsers returns the 3 test users for grants compatibility tests.
// Email addresses use @example.com domain, matching the converted Tailscale policy format.
// Users get norse-god names; nodes get original-151 pokémon names — matching
// the anonymized identifiers tscap writes into the capture files
// (see github.com/kradalby/tscap/anonymize).
func setupGrantsCompatUsers() types.Users {
return types.Users{
{Model: gorm.Model{ID: 1}, Name: "kratail2tid", Email: "kratail2tid@example.com"},
{Model: gorm.Model{ID: 2}, Name: "kristoffer", Email: "kristoffer@example.com"},
{Model: gorm.Model{ID: 3}, Name: "monitorpasskeykradalby", Email: "monitorpasskeykradalby@example.com"},
{Model: gorm.Model{ID: 1}, Name: "odin", Email: "odin@example.com"},
{Model: gorm.Model{ID: 2}, Name: "thor", Email: "thor@example.org"},
{Model: gorm.Model{ID: 3}, Name: "freya", Email: "freya@example.com"},
}
}
// setupGrantsCompatNodes returns the 8 test nodes for grants compatibility tests.
// setupGrantsCompatNodes returns the 15 test nodes for grants compatibility tests.
// The node configuration matches the Tailscale test environment:
// - 3 user-owned nodes (user1, user-kris, user-mon)
// - 5 tagged nodes (tagged-server, tagged-prod, tagged-client, subnet-router, exit-node)
// - 3 user-owned nodes (bulbasaur, ivysaur, venusaur)
// - 12 tagged nodes (beedrill, kakuna, weedle, squirtle, charmander,
// pidgey, pidgeotto, rattata, raticate, spearow, fearow, blastoise)
func setupGrantsCompatNodes(users types.Users) types.Nodes {
nodeUser1 := &types.Node{
nodeBulbasaur := &types.Node{
ID: 1,
GivenName: "user1",
GivenName: "bulbasaur",
User: &users[0],
UserID: &users[0].ID,
IPv4: ptrAddr("100.90.199.68"),
@@ -85,9 +61,9 @@ func setupGrantsCompatNodes(users types.Users) types.Nodes {
Hostinfo: &tailcfg.Hostinfo{},
}
nodeUserKris := &types.Node{
nodeIvysaur := &types.Node{
ID: 2,
GivenName: "user-kris",
GivenName: "ivysaur",
User: &users[1],
UserID: &users[1].ID,
IPv4: ptrAddr("100.110.121.96"),
@@ -95,9 +71,9 @@ func setupGrantsCompatNodes(users types.Users) types.Nodes {
Hostinfo: &tailcfg.Hostinfo{},
}
nodeUserMon := &types.Node{
nodeVenusaur := &types.Node{
ID: 3,
GivenName: "user-mon",
GivenName: "venusaur",
User: &users[2],
UserID: &users[2].ID,
IPv4: ptrAddr("100.103.90.82"),
@@ -105,36 +81,36 @@ func setupGrantsCompatNodes(users types.Users) types.Nodes {
Hostinfo: &tailcfg.Hostinfo{},
}
nodeTaggedServer := &types.Node{
nodeBeedrill := &types.Node{
ID: 4,
GivenName: "tagged-server",
GivenName: "beedrill",
IPv4: ptrAddr("100.108.74.26"),
IPv6: ptrAddr("fd7a:115c:a1e0::b901:4a87"),
Tags: []string{"tag:server"},
Hostinfo: &tailcfg.Hostinfo{},
}
nodeTaggedProd := &types.Node{
nodeKakuna := &types.Node{
ID: 5,
GivenName: "tagged-prod",
GivenName: "kakuna",
IPv4: ptrAddr("100.103.8.15"),
IPv6: ptrAddr("fd7a:115c:a1e0::5b37:80f"),
Tags: []string{"tag:prod"},
Hostinfo: &tailcfg.Hostinfo{},
}
nodeTaggedClient := &types.Node{
nodeWeedle := &types.Node{
ID: 6,
GivenName: "tagged-client",
GivenName: "weedle",
IPv4: ptrAddr("100.83.200.69"),
IPv6: ptrAddr("fd7a:115c:a1e0::c537:c845"),
Tags: []string{"tag:client"},
Hostinfo: &tailcfg.Hostinfo{},
}
nodeSubnetRouter := &types.Node{
nodeSquirtle := &types.Node{
ID: 7,
GivenName: "subnet-router",
GivenName: "squirtle",
IPv4: ptrAddr("100.92.142.61"),
IPv6: ptrAddr("fd7a:115c:a1e0::3e37:8e3d"),
Tags: []string{"tag:router"},
@@ -144,9 +120,9 @@ func setupGrantsCompatNodes(users types.Users) types.Nodes {
ApprovedRoutes: []netip.Prefix{netip.MustParsePrefix("10.33.0.0/16")},
}
nodeExitNode := &types.Node{
nodeCharmander := &types.Node{
ID: 8,
GivenName: "exit-node",
GivenName: "charmander",
IPv4: ptrAddr("100.85.66.106"),
IPv6: ptrAddr("fd7a:115c:a1e0::7c37:426a"),
Tags: []string{"tag:exit"},
@@ -164,9 +140,9 @@ func setupGrantsCompatNodes(users types.Users) types.Nodes {
// --- New nodes for expanded via grant topology ---
nodeExitA := &types.Node{
nodePidgey := &types.Node{
ID: 9,
GivenName: "exit-a",
GivenName: "pidgey",
IPv4: ptrAddr("100.124.195.93"),
IPv6: ptrAddr("fd7a:115c:a1e0::7837:c35d"),
Tags: []string{"tag:exit-a"},
@@ -182,9 +158,9 @@ func setupGrantsCompatNodes(users types.Users) types.Nodes {
},
}
nodeExitB := &types.Node{
nodePidgeotto := &types.Node{
ID: 10,
GivenName: "exit-b",
GivenName: "pidgeotto",
IPv4: ptrAddr("100.116.18.24"),
IPv6: ptrAddr("fd7a:115c:a1e0::ff37:1218"),
Tags: []string{"tag:exit-b"},
@@ -200,27 +176,27 @@ func setupGrantsCompatNodes(users types.Users) types.Nodes {
},
}
nodeGroupA := &types.Node{
nodeRattata := &types.Node{
ID: 11,
GivenName: "group-a-client",
GivenName: "rattata",
IPv4: ptrAddr("100.107.162.14"),
IPv6: ptrAddr("fd7a:115c:a1e0::a237:a20e"),
Tags: []string{"tag:group-a"},
Hostinfo: &tailcfg.Hostinfo{},
}
nodeGroupB := &types.Node{
nodeRaticate := &types.Node{
ID: 12,
GivenName: "group-b-client",
GivenName: "raticate",
IPv4: ptrAddr("100.77.135.18"),
IPv6: ptrAddr("fd7a:115c:a1e0::4b37:8712"),
Tags: []string{"tag:group-b"},
Hostinfo: &tailcfg.Hostinfo{},
}
nodeRouterA := &types.Node{
nodeSpearow := &types.Node{
ID: 13,
GivenName: "router-a",
GivenName: "spearow",
IPv4: ptrAddr("100.109.43.124"),
IPv6: ptrAddr("fd7a:115c:a1e0::a537:2b7c"),
Tags: []string{"tag:router-a"},
@@ -230,9 +206,9 @@ func setupGrantsCompatNodes(users types.Users) types.Nodes {
ApprovedRoutes: []netip.Prefix{netip.MustParsePrefix("10.44.0.0/16")},
}
nodeRouterB := &types.Node{
nodeFearow := &types.Node{
ID: 14,
GivenName: "router-b",
GivenName: "fearow",
IPv4: ptrAddr("100.65.172.123"),
IPv6: ptrAddr("fd7a:115c:a1e0::5a37:ac7c"),
Tags: []string{"tag:router-b"},
@@ -242,9 +218,9 @@ func setupGrantsCompatNodes(users types.Users) types.Nodes {
ApprovedRoutes: []netip.Prefix{netip.MustParsePrefix("10.55.0.0/16")},
}
nodeMultiExitRouter := &types.Node{
nodeBlastoise := &types.Node{
ID: 15,
GivenName: "multi-exit-router",
GivenName: "blastoise",
IPv4: ptrAddr("100.105.127.107"),
IPv6: ptrAddr("fd7a:115c:a1e0::9537:7f6b"),
Tags: []string{"tag:exit", "tag:router"},
@@ -263,21 +239,21 @@ func setupGrantsCompatNodes(users types.Users) types.Nodes {
}
return types.Nodes{
nodeUser1,
nodeUserKris,
nodeUserMon,
nodeTaggedServer,
nodeTaggedProd,
nodeTaggedClient,
nodeSubnetRouter,
nodeExitNode,
nodeExitA,
nodeExitB,
nodeGroupA,
nodeGroupB,
nodeRouterA,
nodeRouterB,
nodeMultiExitRouter,
nodeBulbasaur,
nodeIvysaur,
nodeVenusaur,
nodeBeedrill,
nodeKakuna,
nodeWeedle,
nodeSquirtle,
nodeCharmander,
nodePidgey,
nodePidgeotto,
nodeRattata,
nodeRaticate,
nodeSpearow,
nodeFearow,
nodeBlastoise,
}
}
@@ -292,41 +268,87 @@ func findGrantsNode(nodes types.Nodes, name string) *types.Node {
return nil
}
// convertPolicyUserEmails converts Tailscale SaaS user email formats to
// headscale-compatible @example.com format in the raw policy JSON.
//
// Tailscale uses provider-specific email formats:
// - kratail2tid@passkey (passkey auth)
// - kristoffer@dalby.cc (email auth)
// - monitorpasskeykradalby@passkey (passkey auth)
//
// Headscale resolves users by Email field, so we convert all to @example.com.
func convertPolicyUserEmails(policyJSON []byte) []byte {
s := string(policyJSON)
s = strings.ReplaceAll(s, "kratail2tid@passkey", "kratail2tid@example.com")
s = strings.ReplaceAll(s, "kristoffer@dalby.cc", "kristoffer@example.com")
s = strings.ReplaceAll(s, "monitorpasskeykradalby@passkey", "monitorpasskeykradalby@example.com")
// buildGrantsNodesFromCapture constructs types.Nodes from a capture's
// topology section. Each scenario in tscap uses clean-slate mode, so
// node IPs differ between scenarios; this builds the node set with
// the IPs that were actually present during that capture.
func buildGrantsNodesFromCapture(
users types.Users,
tf *testcapture.Capture,
) types.Nodes {
nodes := make(types.Nodes, 0, len(tf.Topology.Nodes))
autoID := 1
return []byte(s)
for _, nodeDef := range tf.Topology.Nodes {
node := &types.Node{
ID: types.NodeID(autoID), //nolint:gosec
GivenName: nodeDef.Hostname,
IPv4: ptrAddr(nodeDef.IPv4),
IPv6: ptrAddr(nodeDef.IPv6),
Tags: nodeDef.Tags,
}
autoID++
hostinfo := &tailcfg.Hostinfo{}
if len(nodeDef.RoutableIPs) > 0 {
routableIPs := make([]netip.Prefix, 0, len(nodeDef.RoutableIPs))
for _, r := range nodeDef.RoutableIPs {
routableIPs = append(routableIPs, netip.MustParsePrefix(r))
}
hostinfo.RoutableIPs = routableIPs
}
node.Hostinfo = hostinfo
if len(nodeDef.ApprovedRoutes) > 0 {
approved := make([]netip.Prefix, 0, len(nodeDef.ApprovedRoutes))
for _, r := range nodeDef.ApprovedRoutes {
approved = append(approved, netip.MustParsePrefix(r))
}
node.ApprovedRoutes = approved
} else {
node.ApprovedRoutes = []netip.Prefix{}
}
// Assign user — untagged nodes look up by User field.
if len(nodeDef.Tags) == 0 && nodeDef.User != "" {
for i := range users {
if users[i].Name == nodeDef.User {
node.User = &users[i]
node.UserID = &users[i].ID
break
}
}
}
nodes = append(nodes, node)
}
return nodes
}
// loadGrantTestFile loads and parses a single grant test JSON file.
func loadGrantTestFile(t *testing.T, path string) grantTestFile {
// convertPolicyUserEmails used to map SaaS-side emails to @example.com.
// tscap now anonymizes the policy JSON at write time (kratail2tid -> odin,
// kristoffer -> thor, monitorpasskeykradalby -> freya), so the captured
// FullPolicy is already in its final form and this is a passthrough that
// just adapts the captured string value to the []byte that the policy
// parser expects.
func convertPolicyUserEmails(policyJSON string) []byte {
return []byte(policyJSON)
}
// loadGrantTestFile loads and parses a single grant capture HuJSON file.
func loadGrantTestFile(t *testing.T, path string) *testcapture.Capture {
t.Helper()
content, err := os.ReadFile(path)
c, err := testcapture.Read(path)
require.NoError(t, err, "failed to read test file %s", path)
ast, err := hujson.Parse(content)
require.NoError(t, err, "failed to parse HuJSON in %s", path)
ast.Standardize()
var tf grantTestFile
err = json.Unmarshal(ast.Pack(), &tf)
require.NoError(t, err, "failed to unmarshal test file %s", path)
return tf
return c
}
// Skip categories document WHY tests are expected to differ from Tailscale SaaS.
@@ -341,8 +363,8 @@ var grantSkipReasons = map[string]string{
// Tailscale SaaS policies can use user:*@passkey as a wildcard matching
// all passkey-authenticated users. headscale does not support passkey
// authentication and has no equivalent for this wildcard pattern.
"GRANT-K20": "USER_PASSKEY_WILDCARD: src=user:*@passkey not supported in headscale",
"GRANT-K21": "USER_PASSKEY_WILDCARD: dst=user:*@passkey not supported in headscale",
"grant-k20": "USER_PASSKEY_WILDCARD: src=user:*@passkey not supported in headscale",
"grant-k21": "USER_PASSKEY_WILDCARD: dst=user:*@passkey not supported in headscale",
}
// TestGrantsCompat is a data-driven test that loads all GRANT-*.json
@@ -354,22 +376,21 @@ var grantSkipReasons = map[string]string{
// - For success cases: expected packet_filter_rules per node
// - For error cases: expected error message
//
// The test converts Tailscale user email formats (@passkey, @dalby.cc) to
// headscale format (@example.com) and runs the policy through unmarshalPolicy,
// The test converts Tailscale user email formats to headscale format
// (@example.com, @example.org) and runs the policy through unmarshalPolicy,
// validate, compileFilterRulesForNode, and ReduceFilterRules.
//
// 2 tests are skipped for user:*@passkey wildcard (not supported in headscale).
func TestGrantsCompat(t *testing.T) {
t.Parallel()
files, err := filepath.Glob(filepath.Join("testdata", "grant_results", "GRANT-*.hujson"))
files, err := filepath.Glob(filepath.Join("testdata", "grant_results", "*-*.hujson"))
require.NoError(t, err, "failed to glob test files")
require.NotEmpty(t, files, "no GRANT-*.hujson test files found in testdata/grant_results/")
require.NotEmpty(t, files, "no grant test files found in testdata/grant_results/")
t.Logf("Loaded %d grant test files", len(files))
users := setupGrantsCompatUsers()
allNodes := setupGrantsCompatNodes(users)
for _, file := range files {
tf := loadGrantTestFile(t, file)
@@ -383,17 +404,13 @@ func TestGrantsCompat(t *testing.T) {
return
}
// Determine which node set to use based on the test's topology.
// Tests captured with the expanded 15-node topology (V26+) have
// nodes like exit-a, group-a-client, etc. Tests from the original
// 8-node topology should only use the first 8 nodes to avoid
// resolving extra IPs from nodes that weren't present during capture.
nodes := allNodes
if _, hasNewNodes := tf.Captures["exit-a"]; !hasNewNodes {
nodes = allNodes[:8]
}
// Build nodes per-scenario from this file's topology.
// tscap uses clean-slate mode, so each scenario has
// different node IPs.
nodes := buildGrantsNodesFromCapture(users, tf)
// Convert Tailscale user emails to headscale @example.com format
// Use the captured full policy verbatim (anonymization
// in tscap already rewrote SaaS emails).
policyJSON := convertPolicyUserEmails(tf.Input.FullPolicy)
if tf.Input.APIResponseCode == 400 || tf.Error {
@@ -407,7 +424,7 @@ func TestGrantsCompat(t *testing.T) {
}
// testGrantError verifies that an invalid policy produces the expected error.
func testGrantError(t *testing.T, policyJSON []byte, tf grantTestFile) {
func testGrantError(t *testing.T, policyJSON []byte, tf *testcapture.Capture) {
t.Helper()
wantMsg := ""
@@ -523,7 +540,7 @@ func extractErrorKeyParts(msg string) []string {
func testGrantSuccess(
t *testing.T,
policyJSON []byte,
tf grantTestFile,
tf *testcapture.Capture,
users types.Users,
nodes types.Nodes,
) {
@@ -538,13 +555,10 @@ func testGrantSuccess(
for nodeName, capture := range tf.Captures {
t.Run(nodeName, func(t *testing.T) {
// Check if this node was offline during capture.
// tagged-prod was frequently offline (132 of 188 success tests).
// kakuna (tag:prod) was frequently offline (132 of 188 success tests).
// When offline, packet_filter_rules is null and topology shows
// hostname="unknown" with empty tags.
captureIsNull := len(capture.PacketFilterRules) == 0 ||
string(capture.PacketFilterRules) == "null"
if captureIsNull {
if len(capture.PacketFilterRules) == 0 {
topoNode, exists := tf.Topology.Nodes[nodeName]
if exists && (topoNode.Hostname == "unknown" || topoNode.Hostname == "") {
t.Skipf(
@@ -555,7 +569,7 @@ func testGrantSuccess(
return
}
// Node was online but has null/empty rules — means Tailscale
// Node was online but has empty rules — means Tailscale
// produced no rules. headscale should also produce no rules.
}
@@ -585,21 +599,7 @@ func testGrantSuccess(
gotRules = policyutil.ReduceFilterRules(node.View(), gotRules)
// Unmarshal Tailscale expected rules from JSON capture
var wantRules []tailcfg.FilterRule
if !captureIsNull {
err = json.Unmarshal(
[]byte(capture.PacketFilterRules),
&wantRules,
)
require.NoError(
t,
err,
"%s/%s: failed to unmarshal expected rules from JSON",
tf.TestID,
nodeName,
)
}
wantRules := capture.PacketFilterRules
// Compare headscale output against Tailscale expected output.
// The diff labels show (-tailscale +headscale) to make clear
File diff suppressed because it is too large Load Diff
@@ -1,90 +1,78 @@
// This file is "generated" by Claude.
// It contains a data-driven test that reads SSH-*.json test files captured
// from Tailscale SaaS. Each file contains:
// - The SSH section of the policy
// - The expected SSHPolicy rules for each of 5 test nodes
// This file implements a data-driven test runner for SSH compatibility tests.
// It loads HuJSON golden files from testdata/ssh_results/ssh-*.hujson, captured
// from Tailscale SaaS by tscap, and compares headscale's SSH policy compilation
// against the captured SSH rules.
//
// The test loads each JSON file, constructs a full policy from the SSH section,
// applies it through headscale's SSH policy compilation, and compares the output
// against Tailscale's actual behavior.
// Each file is a testcapture.Capture containing:
// - The full policy that was POSTed to Tailscale SaaS (we use tf.Input.FullPolicy
// directly instead of reconstructing it from a sub-section)
// - The expected SSH rules for each of the 8 test nodes (in tf.Captures[name].SSHRules)
//
// Tests that are known to fail due to unimplemented features or known
// differences are skipped with a TODO comment explaining the root cause.
// As headscale's SSH implementation improves, tests should be removed
// from the skip list.
// Tests known to fail due to unimplemented features or known differences are
// skipped with a TODO comment explaining the root cause.
//
// Test data source: testdata/ssh_results/SSH-*.json
// Captured from: Tailscale SaaS API + tailscale debug localapi
// Test data source: testdata/ssh_results/ssh-*.hujson
// Source format: github.com/juanfont/headscale/hscontrol/types/testcapture
package v2
import (
"encoding/json"
"os"
"path/filepath"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/juanfont/headscale/hscontrol/types"
"github.com/juanfont/headscale/hscontrol/types/testcapture"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tailscale/hujson"
"gorm.io/gorm"
"tailscale.com/tailcfg"
)
// sshTestFile represents the JSON structure of a captured SSH test file.
type sshTestFile struct {
TestID string `json:"test_id"`
PolicyFile string `json:"policy_file"`
SSHSection json.RawMessage `json:"ssh_section"`
Nodes map[string]sshNodeCapture `json:"nodes"`
}
// sshNodeCapture represents the expected SSH rules for a single node.
type sshNodeCapture struct {
Rules json.RawMessage `json:"rules"`
}
// setupSSHDataCompatUsers returns the 3 test users for SSH data-driven
// compatibility tests. The user configuration matches the Tailscale test
// environment with email domains preserved for localpart matching:
// - kratail2tid@example.com (converted from @passkey)
// - kristoffer@dalby.cc (kept as-is — different domain for localpart exclusion)
// - monitorpasskeykradalby@example.com (converted from @passkey)
// compatibility tests. Users get norse-god names; nodes get original-151
// pokémon names — matching the anonymized identifiers tscap writes into
// the capture files (see github.com/kradalby/tscap/anonymize).
//
// odin and freya live on @example.com; thor lives on @example.org so
// that "localpart:*@example.com" resolves to exactly two users
// (matching SaaS output) and the "user on a different email domain"
// case stays covered by scenarios like ssh-d1 that use
// "localpart:*@example.org".
func setupSSHDataCompatUsers() types.Users {
return types.Users{
{
Model: gorm.Model{ID: 1},
Name: "kratail2tid",
Email: "kratail2tid@example.com",
Name: "odin",
Email: "odin@example.com",
},
{
Model: gorm.Model{ID: 2},
Name: "kristoffer",
Email: "kristoffer@dalby.cc",
Name: "thor",
Email: "thor@example.org",
},
{
Model: gorm.Model{ID: 3},
Name: "monitorpasskeykradalby",
Email: "monitorpasskeykradalby@example.com",
Name: "freya",
Email: "freya@example.com",
},
}
}
// setupSSHDataCompatNodes returns the 5 test nodes for SSH data-driven
// compatibility tests. Node GivenNames match the keys in the JSON files:
// - user1 (owned by kratail2tid)
// - user-kris (owned by kristoffer)
// - user-mon (owned by monitorpasskeykradalby)
// - tagged-server (tag:server)
// - tagged-prod (tag:prod)
// setupSSHDataCompatNodes returns the test nodes for SSH data-driven
// compatibility tests. Node GivenNames match the anonymized pokémon names:
// - bulbasaur (owned by odin)
// - ivysaur (owned by thor)
// - venusaur (owned by freya)
// - beedrill (tag:server)
// - kakuna (tag:prod)
func setupSSHDataCompatNodes(users types.Users) types.Nodes {
return types.Nodes{
&types.Node{
ID: 1,
GivenName: "user1",
GivenName: "bulbasaur",
User: &users[0],
UserID: &users[0].ID,
IPv4: ptrAddr("100.90.199.68"),
@@ -93,7 +81,7 @@ func setupSSHDataCompatNodes(users types.Users) types.Nodes {
},
&types.Node{
ID: 2,
GivenName: "user-kris",
GivenName: "ivysaur",
User: &users[1],
UserID: &users[1].ID,
IPv4: ptrAddr("100.110.121.96"),
@@ -102,7 +90,7 @@ func setupSSHDataCompatNodes(users types.Users) types.Nodes {
},
&types.Node{
ID: 3,
GivenName: "user-mon",
GivenName: "venusaur",
User: &users[2],
UserID: &users[2].ID,
IPv4: ptrAddr("100.103.90.82"),
@@ -111,7 +99,7 @@ func setupSSHDataCompatNodes(users types.Users) types.Nodes {
},
&types.Node{
ID: 4,
GivenName: "tagged-server",
GivenName: "beedrill",
IPv4: ptrAddr("100.108.74.26"),
IPv6: ptrAddr("fd7a:115c:a1e0::b901:4a87"),
Tags: []string{"tag:server"},
@@ -119,7 +107,7 @@ func setupSSHDataCompatNodes(users types.Users) types.Nodes {
},
&types.Node{
ID: 5,
GivenName: "tagged-prod",
GivenName: "kakuna",
IPv4: ptrAddr("100.103.8.15"),
IPv6: ptrAddr("fd7a:115c:a1e0::5b37:80f"),
Tags: []string{"tag:prod"},
@@ -128,122 +116,52 @@ func setupSSHDataCompatNodes(users types.Users) types.Nodes {
}
}
// convertSSHPolicyEmails converts Tailscale SaaS email domains to
// headscale-compatible format in the raw policy JSON.
//
// Tailscale uses provider-specific email formats:
// - kratail2tid@passkey (passkey auth)
// - kristoffer@dalby.cc (email auth — kept as-is)
// - monitorpasskeykradalby@passkey (passkey auth)
//
// The @passkey domain is converted to @example.com. The @dalby.cc domain
// is kept as-is to preserve localpart matching semantics (kristoffer should
// NOT match localpart:*@example.com, just as it doesn't match
// localpart:*@passkey in Tailscale SaaS).
func convertSSHPolicyEmails(s string) string {
s = strings.ReplaceAll(s, "@passkey", "@example.com")
return s
}
// constructSSHFullPolicy builds a complete headscale policy from the
// ssh_section captured from Tailscale SaaS.
//
// The base policy includes:
// - groups matching the Tailscale test environment
// - tagOwners for tag:server and tag:prod
// - A permissive ACL allowing all traffic (matches the grants wildcard
// in the original Tailscale policy)
// - The SSH section from the test file
func constructSSHFullPolicy(sshSection json.RawMessage) string {
// Base policy template with groups, tagOwners, and ACLs
// User references match the converted email addresses.
const basePolicyPrefix = `{
"groups": {
"group:admins": ["kratail2tid@example.com"],
"group:developers": ["kristoffer@dalby.cc", "kratail2tid@example.com"],
"group:empty": []
},
"tagOwners": {
"tag:server": ["kratail2tid@example.com"],
"tag:prod": ["kratail2tid@example.com"]
},
"acls": [{"action": "accept", "src": ["*"], "dst": ["*:*"]}]`
// Handle null or empty SSH section
if len(sshSection) == 0 || string(sshSection) == "null" {
// No SSH section at all (like SSH-E4)
return basePolicyPrefix + "\n}"
}
sshStr := string(sshSection)
// Convert Tailscale email domains
sshStr = convertSSHPolicyEmails(sshStr)
return basePolicyPrefix + `,
"ssh": ` + sshStr + "\n}"
}
// loadSSHTestFile loads and parses a single SSH test JSON file.
func loadSSHTestFile(t *testing.T, path string) sshTestFile {
// loadSSHTestFile loads and parses a single SSH capture HuJSON file.
func loadSSHTestFile(t *testing.T, path string) *testcapture.Capture {
t.Helper()
content, err := os.ReadFile(path)
c, err := testcapture.Read(path)
require.NoError(t, err, "failed to read test file %s", path)
ast, err := hujson.Parse(content)
require.NoError(t, err, "failed to parse HuJSON in %s", path)
ast.Standardize()
var tf sshTestFile
err = json.Unmarshal(ast.Pack(), &tf)
require.NoError(t, err, "failed to unmarshal test file %s", path)
return tf
return c
}
// sshSkipReasons documents why each skipped test fails and what needs to be
// fixed. Tests are grouped by root cause to identify high-impact changes.
//
// 37 of 39 tests are expected to pass.
var sshSkipReasons = map[string]string{
// user:*@passkey wildcard pattern not supported in headscale.
// headscale does not support passkey authentication and has no
// equivalent for this wildcard pattern.
"SSH-B5": "user:*@passkey wildcard not supported in headscale",
"SSH-D10": "user:*@passkey wildcard not supported in headscale",
"ssh-b5": "user:*@passkey wildcard not supported in headscale",
"ssh-d10": "user:*@passkey wildcard not supported in headscale",
}
// TestSSHDataCompat is a data-driven test that loads all SSH-*.json test files
// captured from Tailscale SaaS and compares headscale's SSH policy compilation
// against the real Tailscale behavior.
// TestSSHDataCompat is a data-driven test that loads all ssh-*.hujson test
// files captured from Tailscale SaaS and compares headscale's SSH policy
// compilation against the real Tailscale behavior.
//
// Each JSON file contains:
// - The SSH section of the policy
// - Expected SSH rules per node (5 nodes)
// Each capture file contains:
// - The full policy that was POSTed to the SaaS API (Input.FullPolicy)
// - Expected SSH rules per node (Captures[name].SSHRules)
//
// The test constructs a full headscale policy from the SSH section, converts
// Tailscale user email formats to headscale format, and runs the policy
// through unmarshalPolicy and compileSSHPolicy.
// The test converts Tailscale user email formats to headscale format and runs
// the captured policy through unmarshalPolicy and compileSSHPolicy.
func TestSSHDataCompat(t *testing.T) {
t.Parallel()
files, err := filepath.Glob(
filepath.Join("testdata", "ssh_results", "SSH-*.hujson"),
filepath.Join("testdata", "ssh_results", "ssh-*.hujson"),
)
require.NoError(t, err, "failed to glob test files")
require.NotEmpty(
t,
files,
"no SSH-*.hujson test files found in testdata/ssh_results/",
"no ssh-*.hujson test files found in testdata/ssh_results/",
)
t.Logf("Loaded %d SSH test files", len(files))
users := setupSSHDataCompatUsers()
nodes := setupSSHDataCompatNodes(users)
for _, file := range files {
tf := loadSSHTestFile(t, file)
@@ -261,8 +179,20 @@ func TestSSHDataCompat(t *testing.T) {
return
}
// Construct full policy from SSH section
policyJSON := constructSSHFullPolicy(tf.SSHSection)
// Skip captures the SaaS rejected — no expected SSH rules to compare against.
if tf.Error {
t.Skipf("%s: SaaS rejected the policy (api_response_code=%d); no expected SSH rules captured", tf.TestID, tf.Input.APIResponseCode)
return
}
// Build nodes per-scenario from this file's topology.
// tscap uses clean-slate mode, so each scenario has
// different node IPs.
nodes := buildGrantsNodesFromCapture(users, tf)
// Use the captured full policy verbatim. Anonymization in
// tscap already rewrites SaaS emails to @example.com.
policyJSON := tf.Input.FullPolicy
pol, err := unmarshalPolicy([]byte(policyJSON))
require.NoError(
@@ -273,15 +203,13 @@ func TestSSHDataCompat(t *testing.T) {
policyJSON,
)
for nodeName, capture := range tf.Nodes {
for nodeName, capture := range tf.Captures {
t.Run(nodeName, func(t *testing.T) {
node := findNodeByGivenName(nodes, nodeName)
require.NotNilf(
t,
node,
"node %s not found in test setup",
nodeName,
)
if node == nil {
t.Skipf("node %s not in this test's node set", nodeName)
return
}
// Compile headscale SSH policy for this node
gotSSH, err := pol.compileSSHPolicy(
@@ -298,24 +226,10 @@ func TestSSHDataCompat(t *testing.T) {
nodeName,
)
// Parse expected rules from JSON capture
var wantRules []*tailcfg.SSHRule
if len(capture.Rules) > 0 &&
string(capture.Rules) != "null" {
err = json.Unmarshal(capture.Rules, &wantRules)
require.NoError(
t,
err,
"%s/%s: failed to unmarshal expected rules",
tf.TestID,
nodeName,
)
}
// Build expected SSHPolicy from the rules
// Build expected SSHPolicy from the typed rules.
var wantSSH *tailcfg.SSHPolicy
if len(wantRules) > 0 {
wantSSH = &tailcfg.SSHPolicy{Rules: wantRules}
if len(capture.SSHRules) > 0 {
wantSSH = &tailcfg.SSHPolicy{Rules: capture.SSHRules}
}
// Normalize: treat empty-rules SSHPolicy as nil
@@ -327,11 +241,41 @@ func TestSSHDataCompat(t *testing.T) {
// EquateEmpty treats nil and empty slices as equal.
// Sort principals within rules (order doesn't matter).
// Do NOT sort rules — order matters (first-match-wins).
//
// Ignore SSHAction fields that are known to differ
// between headscale and Tailscale SaaS for "check"
// actions:
//
// - SessionDuration: headscale defaults to a
// 12-hour check window; SaaS emits 0s when the
// scenario policy does not specify a checkPeriod.
//
// - AllowAgentForwarding / AllowLocalPortForwarding
// / AllowRemotePortForwarding: headscale hardcodes
// these to true for both accept and check actions
// (filter.go sshAccept / sshCheck); SaaS emits
// false for check actions.
//
// - HoldAndDelegate: headscale uses a URL template
// containing "/from/…?ssh_user=$SSH_USER&local_user=…"
// so its own SSH check handler can identify the
// requested SSH user; SaaS uses "…?local_user=…"
// without the ssh_user query parameter. Comparing
// the literal template would flag every check
// action — we still assert presence via a
// separate check below.
opts := cmp.Options{
cmpopts.SortSlices(func(a, b *tailcfg.SSHPrincipal) bool {
return a.NodeIP < b.NodeIP
}),
cmpopts.EquateEmpty(),
cmpopts.IgnoreFields(tailcfg.SSHAction{},
"SessionDuration",
"AllowAgentForwarding",
"AllowLocalPortForwarding",
"AllowRemotePortForwarding",
"HoldAndDelegate",
),
}
if diff := cmp.Diff(wantSSH, gotSSH, opts...); diff != "" {
t.Errorf(
@@ -341,6 +285,32 @@ func TestSSHDataCompat(t *testing.T) {
diff,
)
}
// Separate presence check: the fields ignored by
// the diff above must still be populated on matching
// rules. This catches regressions where headscale
// would silently drop the HoldAndDelegate URL or
// flip Accept to false while we are not looking.
if wantSSH != nil && gotSSH != nil {
for i, wantRule := range wantSSH.Rules {
if i >= len(gotSSH.Rules) {
break
}
gotRule := gotSSH.Rules[i]
if wantRule.Action == nil || gotRule.Action == nil {
continue
}
wantIsCheck := wantRule.Action.HoldAndDelegate != ""
gotIsCheck := gotRule.Action.HoldAndDelegate != ""
assert.Equalf(t, wantIsCheck, gotIsCheck,
"%s/%s rule %d: HoldAndDelegate presence mismatch",
tf.TestID, nodeName, i,
)
}
}
})
}
})
-258
View File
@@ -1,258 +0,0 @@
// ACL-A01
//
// ACL: accept: src=['autogroup:member'] dst=['*:*']
//
// Expected: Rules on 8 of 8 nodes
{
"test_id": "ACL-A01",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"autogroup:member"
],
"dst": [
"*:*"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.90.82",
"100.110.121.96",
"100.90.199.68",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747",
"fd7a:115c:a1e0::9e37:5a52"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"subnet-router": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.90.82",
"100.110.121.96",
"100.90.199.68",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747",
"fd7a:115c:a1e0::9e37:5a52"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-client": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.90.82",
"100.110.121.96",
"100.90.199.68",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747",
"fd7a:115c:a1e0::9e37:5a52"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-prod": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.90.82",
"100.110.121.96",
"100.90.199.68",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747",
"fd7a:115c:a1e0::9e37:5a52"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.90.82",
"100.110.121.96",
"100.90.199.68",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747",
"fd7a:115c:a1e0::9e37:5a52"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.90.82",
"100.110.121.96",
"100.90.199.68",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747",
"fd7a:115c:a1e0::9e37:5a52"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-mon": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.90.82",
"100.110.121.96",
"100.90.199.68",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747",
"fd7a:115c:a1e0::9e37:5a52"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user1": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.90.82",
"100.110.121.96",
"100.90.199.68",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747",
"fd7a:115c:a1e0::9e37:5a52"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
}
}
}
-290
View File
@@ -1,290 +0,0 @@
// ACL-A02
//
// ACL: accept: src=['autogroup:tagged'] dst=['*:*']
//
// Expected: Rules on 8 of 8 nodes
{
"test_id": "ACL-A02",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"autogroup:tagged"
],
"dst": [
"*:*"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.108.74.26",
"100.83.200.69",
"100.85.66.106",
"100.92.142.61",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"subnet-router": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.108.74.26",
"100.83.200.69",
"100.85.66.106",
"100.92.142.61",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-client": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.108.74.26",
"100.83.200.69",
"100.85.66.106",
"100.92.142.61",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-prod": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.108.74.26",
"100.83.200.69",
"100.85.66.106",
"100.92.142.61",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.108.74.26",
"100.83.200.69",
"100.85.66.106",
"100.92.142.61",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.108.74.26",
"100.83.200.69",
"100.85.66.106",
"100.92.142.61",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-mon": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.108.74.26",
"100.83.200.69",
"100.85.66.106",
"100.92.142.61",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user1": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.108.74.26",
"100.83.200.69",
"100.85.66.106",
"100.92.142.61",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
}
}
}
-128
View File
@@ -1,128 +0,0 @@
// ACL-A03
//
// ACL: accept: src=['autogroup:member', 'tag:client'] dst=['tag:server:22']
//
// Expected: Rules on tagged-server
{
"test_id": "ACL-A03",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"autogroup:member",
"tag:client"
],
"dst": [
"tag:server:22"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.90.82",
"100.110.121.96",
"100.83.200.69",
"100.90.199.68",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747",
"fd7a:115c:a1e0::9e37:5a52",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-167
View File
@@ -1,167 +0,0 @@
// ACL-A04
//
// ACL: accept: src=['*'] dst=['autogroup:self:*']
//
// Expected: Rules on user-kris, user-mon, user1
{
"test_id": "ACL-A04",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"*"
],
"dst": [
"autogroup:self:*"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": null
},
"user-kris": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.110.121.96",
"fd7a:115c:a1e0::1737:7960"
],
"DstPorts": [
{
"IP": "100.110.121.96",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::1737:7960",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-mon": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.90.82",
"fd7a:115c:a1e0::9e37:5a52"
],
"DstPorts": [
{
"IP": "100.103.90.82",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::9e37:5a52",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user1": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.90.199.68",
"fd7a:115c:a1e0::2d01:c747"
],
"DstPorts": [
{
"IP": "100.90.199.68",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::2d01:c747",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
}
}
}
-98
View File
@@ -1,98 +0,0 @@
// ACL-A05
//
// ACL: accept: src=['*'] dst=['autogroup:internet:*']
//
// Expected: No filter rules
{
"test_id": "ACL-A05",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"*"
],
"dst": [
"autogroup:internet:*"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": null
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-173
View File
@@ -1,173 +0,0 @@
// ACL-A06
//
// ACL: accept: src=['*'] dst=['autogroup:member:*']
//
// Expected: Rules on user-kris, user-mon, user1
{
"test_id": "ACL-A06",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"*"
],
"dst": [
"autogroup:member:*"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": null
},
"user-kris": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.110.121.96",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::1737:7960",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-mon": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.103.90.82",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::9e37:5a52",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user1": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.90.199.68",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::2d01:c747",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
}
}
}
-193
View File
@@ -1,193 +0,0 @@
// ACL-A07
//
// ACL: accept: src=['*'] dst=['autogroup:self:*', 'tag:server:22']
//
// Expected: Rules on tagged-server, user-kris, user-mon, user1
{
"test_id": "ACL-A07",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"*"
],
"dst": [
"autogroup:self:*",
"tag:server:22"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.110.121.96",
"fd7a:115c:a1e0::1737:7960"
],
"DstPorts": [
{
"IP": "100.110.121.96",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::1737:7960",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-mon": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.90.82",
"fd7a:115c:a1e0::9e37:5a52"
],
"DstPorts": [
{
"IP": "100.103.90.82",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::9e37:5a52",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user1": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.90.199.68",
"fd7a:115c:a1e0::2d01:c747"
],
"DstPorts": [
{
"IP": "100.90.199.68",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::2d01:c747",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
}
}
}
-223
View File
@@ -1,223 +0,0 @@
// ACL-A08
//
// ACL: accept: src=['*'] dst=['autogroup:tagged:*']
//
// Expected: Rules on exit-node, subnet-router, tagged-client, tagged-prod, tagged-server
{
"test_id": "ACL-A08",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"*"
],
"dst": [
"autogroup:tagged:*"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.85.66.106",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::7c37:426a",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"subnet-router": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.92.142.61",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::3e37:8e3d",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-client": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.83.200.69",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::c537:c845",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-prod": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.103.8.15",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::5b37:80f",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-167
View File
@@ -1,167 +0,0 @@
// ACL-A09
//
// ACL: accept: src=['autogroup:member'] dst=['autogroup:self:*']
//
// Expected: Rules on user-kris, user-mon, user1
{
"test_id": "ACL-A09",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"autogroup:member"
],
"dst": [
"autogroup:self:*"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": null
},
"user-kris": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.110.121.96",
"fd7a:115c:a1e0::1737:7960"
],
"DstPorts": [
{
"IP": "100.110.121.96",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::1737:7960",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-mon": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.90.82",
"fd7a:115c:a1e0::9e37:5a52"
],
"DstPorts": [
{
"IP": "100.103.90.82",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::9e37:5a52",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user1": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.90.199.68",
"fd7a:115c:a1e0::2d01:c747"
],
"DstPorts": [
{
"IP": "100.90.199.68",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::2d01:c747",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
}
}
}
-121
View File
@@ -1,121 +0,0 @@
// ACL-A10
//
// ACL: accept: src=['kratail2tid@passkey'] dst=['autogroup:self:*']
//
// Expected: Rules on user1
{
"test_id": "ACL-A10",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"kratail2tid@passkey"
],
"dst": [
"autogroup:self:*"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": null
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.90.199.68",
"fd7a:115c:a1e0::2d01:c747"
],
"DstPorts": [
{
"IP": "100.90.199.68",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::2d01:c747",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
}
}
}
-121
View File
@@ -1,121 +0,0 @@
// ACL-A11
//
// ACL: accept: src=['group:admins'] dst=['autogroup:self:*']
//
// Expected: Rules on user1
{
"test_id": "ACL-A11",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"group:admins"
],
"dst": [
"autogroup:self:*"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": null
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.90.199.68",
"fd7a:115c:a1e0::2d01:c747"
],
"DstPorts": [
{
"IP": "100.90.199.68",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::2d01:c747",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
}
}
}
-167
View File
@@ -1,167 +0,0 @@
// ACL-A12
//
// ACL: accept: src=['*'] dst=['autogroup:self:22']
//
// Expected: Rules on user-kris, user-mon, user1
{
"test_id": "ACL-A12",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"*"
],
"dst": [
"autogroup:self:22"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": null
},
"user-kris": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.110.121.96",
"fd7a:115c:a1e0::1737:7960"
],
"DstPorts": [
{
"IP": "100.110.121.96",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::1737:7960",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user-mon": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.90.82",
"fd7a:115c:a1e0::9e37:5a52"
],
"DstPorts": [
{
"IP": "100.103.90.82",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::9e37:5a52",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user1": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.90.199.68",
"fd7a:115c:a1e0::2d01:c747"
],
"DstPorts": [
{
"IP": "100.90.199.68",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::2d01:c747",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
}
}
}
-167
View File
@@ -1,167 +0,0 @@
// ACL-A13
//
// ACL: accept: src=['*'] dst=['autogroup:self:80-443']
//
// Expected: Rules on user-kris, user-mon, user1
{
"test_id": "ACL-A13",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"*"
],
"dst": [
"autogroup:self:80-443"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": null
},
"user-kris": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.110.121.96",
"fd7a:115c:a1e0::1737:7960"
],
"DstPorts": [
{
"IP": "100.110.121.96",
"Ports": {
"First": 80,
"Last": 443
}
},
{
"IP": "fd7a:115c:a1e0::1737:7960",
"Ports": {
"First": 80,
"Last": 443
}
}
]
}
]
},
"user-mon": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.90.82",
"fd7a:115c:a1e0::9e37:5a52"
],
"DstPorts": [
{
"IP": "100.103.90.82",
"Ports": {
"First": 80,
"Last": 443
}
},
{
"IP": "fd7a:115c:a1e0::9e37:5a52",
"Ports": {
"First": 80,
"Last": 443
}
}
]
}
]
},
"user1": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.90.199.68",
"fd7a:115c:a1e0::2d01:c747"
],
"DstPorts": [
{
"IP": "100.90.199.68",
"Ports": {
"First": 80,
"Last": 443
}
},
{
"IP": "fd7a:115c:a1e0::2d01:c747",
"Ports": {
"First": 80,
"Last": 443
}
}
]
}
]
}
}
}
-251
View File
@@ -1,251 +0,0 @@
// ACL-A14
//
// ACL: accept: src=['*'] dst=['autogroup:self:22,80,443']
//
// Expected: Rules on user-kris, user-mon, user1
{
"test_id": "ACL-A14",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"*"
],
"dst": [
"autogroup:self:22,80,443"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": null
},
"user-kris": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.110.121.96",
"fd7a:115c:a1e0::1737:7960"
],
"DstPorts": [
{
"IP": "100.110.121.96",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "100.110.121.96",
"Ports": {
"First": 80,
"Last": 80
}
},
{
"IP": "100.110.121.96",
"Ports": {
"First": 443,
"Last": 443
}
},
{
"IP": "fd7a:115c:a1e0::1737:7960",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::1737:7960",
"Ports": {
"First": 80,
"Last": 80
}
},
{
"IP": "fd7a:115c:a1e0::1737:7960",
"Ports": {
"First": 443,
"Last": 443
}
}
]
}
]
},
"user-mon": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.90.82",
"fd7a:115c:a1e0::9e37:5a52"
],
"DstPorts": [
{
"IP": "100.103.90.82",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "100.103.90.82",
"Ports": {
"First": 80,
"Last": 80
}
},
{
"IP": "100.103.90.82",
"Ports": {
"First": 443,
"Last": 443
}
},
{
"IP": "fd7a:115c:a1e0::9e37:5a52",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::9e37:5a52",
"Ports": {
"First": 80,
"Last": 80
}
},
{
"IP": "fd7a:115c:a1e0::9e37:5a52",
"Ports": {
"First": 443,
"Last": 443
}
}
]
}
]
},
"user1": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.90.199.68",
"fd7a:115c:a1e0::2d01:c747"
],
"DstPorts": [
{
"IP": "100.90.199.68",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "100.90.199.68",
"Ports": {
"First": 80,
"Last": 80
}
},
{
"IP": "100.90.199.68",
"Ports": {
"First": 443,
"Last": 443
}
},
{
"IP": "fd7a:115c:a1e0::2d01:c747",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::2d01:c747",
"Ports": {
"First": 80,
"Last": 80
}
},
{
"IP": "fd7a:115c:a1e0::2d01:c747",
"Ports": {
"First": 443,
"Last": 443
}
}
]
}
]
}
}
}
-339
View File
@@ -1,339 +0,0 @@
// ACL-A15
//
// ACL: accept: src=['autogroup:member', 'autogroup:tagged'] dst=['*:*']
//
// Expected: Rules on 8 of 8 nodes
{
"test_id": "ACL-A15",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"autogroup:member",
"autogroup:tagged"
],
"dst": [
"*:*"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.103.90.82",
"100.108.74.26",
"100.110.121.96",
"100.83.200.69",
"100.85.66.106",
"100.90.199.68",
"100.92.142.61",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::9e37:5a52",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"subnet-router": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.103.90.82",
"100.108.74.26",
"100.110.121.96",
"100.83.200.69",
"100.85.66.106",
"100.90.199.68",
"100.92.142.61",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::9e37:5a52",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-client": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.103.90.82",
"100.108.74.26",
"100.110.121.96",
"100.83.200.69",
"100.85.66.106",
"100.90.199.68",
"100.92.142.61",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::9e37:5a52",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-prod": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.103.90.82",
"100.108.74.26",
"100.110.121.96",
"100.83.200.69",
"100.85.66.106",
"100.90.199.68",
"100.92.142.61",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::9e37:5a52",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.103.90.82",
"100.108.74.26",
"100.110.121.96",
"100.83.200.69",
"100.85.66.106",
"100.90.199.68",
"100.92.142.61",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::9e37:5a52",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.103.90.82",
"100.108.74.26",
"100.110.121.96",
"100.83.200.69",
"100.85.66.106",
"100.90.199.68",
"100.92.142.61",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::9e37:5a52",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-mon": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.103.90.82",
"100.108.74.26",
"100.110.121.96",
"100.83.200.69",
"100.85.66.106",
"100.90.199.68",
"100.92.142.61",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::9e37:5a52",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user1": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.103.90.82",
"100.108.74.26",
"100.110.121.96",
"100.83.200.69",
"100.85.66.106",
"100.90.199.68",
"100.92.142.61",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::9e37:5a52",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
}
}
}
-136
View File
@@ -1,136 +0,0 @@
// ACL-A16
//
// ACL: accept: src=['autogroup:member', 'autogroup:tagged'] dst=['tag:server:22']
//
// Expected: Rules on tagged-server
{
"test_id": "ACL-A16",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"autogroup:member",
"autogroup:tagged"
],
"dst": [
"tag:server:22"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.103.90.82",
"100.108.74.26",
"100.110.121.96",
"100.83.200.69",
"100.85.66.106",
"100.90.199.68",
"100.92.142.61",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::9e37:5a52",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-266
View File
@@ -1,266 +0,0 @@
// ACL-A17
//
// ACL: accept: src=['*'] dst=['autogroup:self:*', 'tag:server:22', 'autogroup:member:80']
//
// Expected: Rules on tagged-server, user-kris, user-mon, user1
{
"test_id": "ACL-A17",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"*"
],
"dst": [
"autogroup:self:*",
"tag:server:22",
"autogroup:member:80"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.110.121.96",
"Ports": {
"First": 80,
"Last": 80
}
},
{
"IP": "fd7a:115c:a1e0::1737:7960",
"Ports": {
"First": 80,
"Last": 80
}
}
]
},
{
"SrcIPs": [
"100.110.121.96",
"fd7a:115c:a1e0::1737:7960"
],
"DstPorts": [
{
"IP": "100.110.121.96",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::1737:7960",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-mon": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.103.90.82",
"Ports": {
"First": 80,
"Last": 80
}
},
{
"IP": "fd7a:115c:a1e0::9e37:5a52",
"Ports": {
"First": 80,
"Last": 80
}
}
]
},
{
"SrcIPs": [
"100.103.90.82",
"fd7a:115c:a1e0::9e37:5a52"
],
"DstPorts": [
{
"IP": "100.103.90.82",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::9e37:5a52",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user1": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.90.199.68",
"Ports": {
"First": 80,
"Last": 80
}
},
{
"IP": "fd7a:115c:a1e0::2d01:c747",
"Ports": {
"First": 80,
"Last": 80
}
}
]
},
{
"SrcIPs": [
"100.90.199.68",
"fd7a:115c:a1e0::2d01:c747"
],
"DstPorts": [
{
"IP": "100.90.199.68",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::2d01:c747",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
}
}
}
-227
View File
@@ -1,227 +0,0 @@
// ACL-AH01
//
// ACL: accept: src=['internal', 'subnet24'] dst=['*:*']
//
// Expected: Rules on 8 of 8 nodes
{
"test_id": "ACL-AH01",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"internal",
"subnet24"
],
"dst": [
"*:*"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.0.0.0/8",
"192.168.1.0/24"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"subnet-router": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.0.0.0/8",
"192.168.1.0/24"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-client": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.0.0.0/8",
"192.168.1.0/24"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-prod": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.0.0.0/8",
"192.168.1.0/24"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.0.0.0/8",
"192.168.1.0/24"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.0.0.0/8",
"192.168.1.0/24"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-mon": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.0.0.0/8",
"192.168.1.0/24"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user1": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.0.0.0/8",
"192.168.1.0/24"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
}
}
}
-122
View File
@@ -1,122 +0,0 @@
// ACL-AH02
//
// ACL: accept: src=['internal', '100.108.74.26'] dst=['tag:server:22']
//
// Expected: Rules on tagged-server
{
"test_id": "ACL-AH02",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"internal",
"100.108.74.26"
],
"dst": [
"tag:server:22"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.0.0.0/8",
"100.108.74.26"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-143
View File
@@ -1,143 +0,0 @@
// ACL-AH03
//
// ACL: accept: src=['*'] dst=['internal:22', 'subnet24:80', 'tag:server:443']
//
// Expected: Rules on subnet-router, tagged-server
{
"test_id": "ACL-AH03",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"*"
],
"dst": [
"internal:22",
"subnet24:80",
"tag:server:443"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "10.0.0.0/8",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 443,
"Last": 443
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 443,
"Last": 443
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-121
View File
@@ -1,121 +0,0 @@
// ACL-AH04
//
// ACL: accept: src=['internal', '10.0.0.0/8'] dst=['tag:server:22']
//
// Expected: Rules on tagged-server
{
"test_id": "ACL-AH04",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"internal",
"10.0.0.0/8"
],
"dst": [
"tag:server:22"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.0.0.0/8"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-116
View File
@@ -1,116 +0,0 @@
// ACL-AH05
//
// ACL: accept: src=['*'] dst=['internal:22']
//
// Expected: Rules on subnet-router
{
"test_id": "ACL-AH05",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"*"
],
"dst": [
"internal:22"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "10.0.0.0/8",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": null
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-116
View File
@@ -1,116 +0,0 @@
// ACL-AH06
//
// ACL: accept: src=['*'] dst=['10.0.0.0/8:22']
//
// Expected: Rules on subnet-router
{
"test_id": "ACL-AH06",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"*"
],
"dst": [
"10.0.0.0/8:22"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "10.0.0.0/8",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": null
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-160
View File
@@ -1,160 +0,0 @@
// ACL-AR01
//
// ACLs:
// accept: src=['tag:client'] dst=['tag:server:22']
// accept: src=['tag:client'] dst=['tag:server:80,443']
//
// Expected: Rules on tagged-server
{
"test_id": "ACL-AR01",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"tag:client"
],
"dst": [
"tag:server:22"
]
},
{
"action": "accept",
"src": [
"tag:client"
],
"dst": [
"tag:server:80,443"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.83.200.69",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "100.108.74.26",
"Ports": {
"First": 80,
"Last": 80
}
},
{
"IP": "100.108.74.26",
"Ports": {
"First": 443,
"Last": 443
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 80,
"Last": 80
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 443,
"Last": 443
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-198
View File
@@ -1,198 +0,0 @@
// ACL-AR02
//
// ACLs:
// accept: src=['tag:client'] dst=['tag:server:22']
// accept: src=['tag:client'] dst=['tag:server:80,443']
// accept: src=['*'] dst=['tag:server:53'] proto=udp
//
// Expected: Rules on tagged-server
{
"test_id": "ACL-AR02",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"tag:client"
],
"dst": [
"tag:server:22"
]
},
{
"action": "accept",
"src": [
"tag:client"
],
"dst": [
"tag:server:80,443"
]
},
{
"action": "accept",
"src": [
"*"
],
"proto": "udp",
"dst": [
"tag:server:53"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.83.200.69",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "100.108.74.26",
"Ports": {
"First": 80,
"Last": 80
}
},
{
"IP": "100.108.74.26",
"Ports": {
"First": 443,
"Last": 443
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 80,
"Last": 80
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 443,
"Last": 443
}
}
]
},
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 53,
"Last": 53
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 53,
"Last": 53
}
}
],
"IPProto": [
17
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-170
View File
@@ -1,170 +0,0 @@
// ACL-AR03
//
// ACLs:
// accept: src=['tag:client'] dst=['tag:server:22']
// accept: src=['tag:client'] dst=['tag:server:80']
// accept: src=['tag:client'] dst=['tag:server:443']
//
// Expected: Rules on tagged-server
{
"test_id": "ACL-AR03",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"tag:client"
],
"dst": [
"tag:server:22"
]
},
{
"action": "accept",
"src": [
"tag:client"
],
"dst": [
"tag:server:80"
]
},
{
"action": "accept",
"src": [
"tag:client"
],
"dst": [
"tag:server:443"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.83.200.69",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "100.108.74.26",
"Ports": {
"First": 80,
"Last": 80
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 80,
"Last": 80
}
},
{
"IP": "100.108.74.26",
"Ports": {
"First": 443,
"Last": 443
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 443,
"Last": 443
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-186
View File
@@ -1,186 +0,0 @@
// ACL-AR04
//
// ACLs:
// accept: src=['tag:client'] dst=['tag:server:22']
// accept: src=['tag:prod'] dst=['tag:server:22']
// accept: src=['tag:router'] dst=['tag:server:22']
//
// Expected: Rules on tagged-server
{
"test_id": "ACL-AR04",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"tag:client"
],
"dst": [
"tag:server:22"
]
},
{
"action": "accept",
"src": [
"tag:prod"
],
"dst": [
"tag:server:22"
]
},
{
"action": "accept",
"src": [
"tag:router"
],
"dst": [
"tag:server:22"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.83.200.69",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
}
]
},
{
"SrcIPs": [
"100.103.8.15",
"fd7a:115c:a1e0::5b37:80f"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
}
]
},
{
"SrcIPs": [
"100.92.142.61",
"fd7a:115c:a1e0::3e37:8e3d"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-202
View File
@@ -1,202 +0,0 @@
// ACL-AR05
//
// ACLs:
// accept: src=['tag:client'] dst=['tag:server:22']
// accept: src=['tag:client'] dst=['tag:server:80']
// accept: src=['tag:prod'] dst=['tag:server:22']
// accept: src=['tag:prod'] dst=['tag:server:443']
//
// Expected: Rules on tagged-server
{
"test_id": "ACL-AR05",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"tag:client"
],
"dst": [
"tag:server:22"
]
},
{
"action": "accept",
"src": [
"tag:client"
],
"dst": [
"tag:server:80"
]
},
{
"action": "accept",
"src": [
"tag:prod"
],
"dst": [
"tag:server:22"
]
},
{
"action": "accept",
"src": [
"tag:prod"
],
"dst": [
"tag:server:443"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.83.200.69",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "100.108.74.26",
"Ports": {
"First": 80,
"Last": 80
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 80,
"Last": 80
}
}
]
},
{
"SrcIPs": [
"100.103.8.15",
"fd7a:115c:a1e0::5b37:80f"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "100.108.74.26",
"Ports": {
"First": 443,
"Last": 443
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 443,
"Last": 443
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-156
View File
@@ -1,156 +0,0 @@
// ACL-AR06
//
// ACLs:
// accept: src=['tag:client'] dst=['tag:server:22']
// accept: src=['*'] dst=['tag:server:80']
//
// Expected: Rules on tagged-server
{
"test_id": "ACL-AR06",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"tag:client"
],
"dst": [
"tag:server:22"
]
},
{
"action": "accept",
"src": [
"*"
],
"dst": [
"tag:server:80"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.83.200.69",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
}
]
},
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 80,
"Last": 80
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 80,
"Last": 80
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-294
View File
@@ -1,294 +0,0 @@
// ACL-AT01
//
// ACL: accept: src=['tag:server', 'tag:client', 'tag:prod', 'tag:router', 'tag:exit'] dst=['*:*']
//
// Expected: Rules on 8 of 8 nodes
{
"test_id": "ACL-AT01",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"tag:server",
"tag:client",
"tag:prod",
"tag:router",
"tag:exit"
],
"dst": [
"*:*"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.108.74.26",
"100.83.200.69",
"100.85.66.106",
"100.92.142.61",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"subnet-router": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.108.74.26",
"100.83.200.69",
"100.85.66.106",
"100.92.142.61",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-client": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.108.74.26",
"100.83.200.69",
"100.85.66.106",
"100.92.142.61",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-prod": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.108.74.26",
"100.83.200.69",
"100.85.66.106",
"100.92.142.61",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.108.74.26",
"100.83.200.69",
"100.85.66.106",
"100.92.142.61",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.108.74.26",
"100.83.200.69",
"100.85.66.106",
"100.92.142.61",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-mon": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.108.74.26",
"100.83.200.69",
"100.85.66.106",
"100.92.142.61",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user1": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.108.74.26",
"100.83.200.69",
"100.85.66.106",
"100.92.142.61",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
}
}
}
-227
View File
@@ -1,227 +0,0 @@
// ACL-AT02
//
// ACL: accept: src=['*'] dst=['tag:server:22', 'tag:client:22', 'tag:prod:22', 'tag:router:22', 'tag:exit:22']
//
// Expected: Rules on exit-node, subnet-router, tagged-client, tagged-prod, tagged-server
{
"test_id": "ACL-AT02",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"*"
],
"dst": [
"tag:server:22",
"tag:client:22",
"tag:prod:22",
"tag:router:22",
"tag:exit:22"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.85.66.106",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::7c37:426a",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"subnet-router": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.92.142.61",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::3e37:8e3d",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"tagged-client": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.83.200.69",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::c537:c845",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"tagged-prod": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.103.8.15",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::5b37:80f",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-195
View File
@@ -1,195 +0,0 @@
// ACL-AT03
//
// ACL: accept: src=['tag:server', 'tag:client', 'tag:prod', 'tag:router', 'tag:exit'] dst=['autogroup:member:22']
//
// Expected: Rules on user-kris, user-mon, user1
{
"test_id": "ACL-AT03",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"tag:server",
"tag:client",
"tag:prod",
"tag:router",
"tag:exit"
],
"dst": [
"autogroup:member:22"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": null
},
"user-kris": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.108.74.26",
"100.83.200.69",
"100.85.66.106",
"100.92.142.61",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "100.110.121.96",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::1737:7960",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user-mon": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.108.74.26",
"100.83.200.69",
"100.85.66.106",
"100.92.142.61",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "100.103.90.82",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::9e37:5a52",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user1": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.108.74.26",
"100.83.200.69",
"100.85.66.106",
"100.92.142.61",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "100.90.199.68",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::2d01:c747",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
}
}
}
-166
View File
@@ -1,166 +0,0 @@
// ACL-AT04
//
// ACLs:
// accept: src=['autogroup:tagged'] dst=['tag:server:22']
// accept: src=['autogroup:member'] dst=['tag:server:80']
//
// Expected: Rules on tagged-server
{
"test_id": "ACL-AT04",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"autogroup:tagged"
],
"dst": [
"tag:server:22"
]
},
{
"action": "accept",
"src": [
"autogroup:member"
],
"dst": [
"tag:server:80"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.108.74.26",
"100.83.200.69",
"100.85.66.106",
"100.92.142.61",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
}
]
},
{
"SrcIPs": [
"100.103.90.82",
"100.110.121.96",
"100.90.199.68",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747",
"fd7a:115c:a1e0::9e37:5a52"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 80,
"Last": 80
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 80,
"Last": 80
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-155
View File
@@ -1,155 +0,0 @@
// ACL-AT05
//
// ACLs:
// accept: src=['tag:client'] dst=['tag:server:22']
// accept: src=['tag:server'] dst=['tag:client:22']
//
// Expected: Rules on tagged-client, tagged-server
{
"test_id": "ACL-AT05",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"tag:client"
],
"dst": [
"tag:server:22"
]
},
{
"action": "accept",
"src": [
"tag:server"
],
"dst": [
"tag:client:22"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26",
"fd7a:115c:a1e0::b901:4a87"
],
"DstPorts": [
{
"IP": "100.83.200.69",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::c537:c845",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.83.200.69",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-220
View File
@@ -1,220 +0,0 @@
// ACL-AT06
//
// ACLs:
// accept: src=['tag:client'] dst=['tag:server:22']
// accept: src=['tag:server'] dst=['tag:prod:5432']
// accept: src=['tag:prod'] dst=['tag:client:80']
// accept: src=['tag:client'] dst=['tag:prod:443']
//
// Expected: Rules on tagged-client, tagged-prod, tagged-server
{
"test_id": "ACL-AT06",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"tag:client"
],
"dst": [
"tag:server:22"
]
},
{
"action": "accept",
"src": [
"tag:server"
],
"dst": [
"tag:prod:5432"
]
},
{
"action": "accept",
"src": [
"tag:prod"
],
"dst": [
"tag:client:80"
]
},
{
"action": "accept",
"src": [
"tag:client"
],
"dst": [
"tag:prod:443"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"fd7a:115c:a1e0::5b37:80f"
],
"DstPorts": [
{
"IP": "100.83.200.69",
"Ports": {
"First": 80,
"Last": 80
}
},
{
"IP": "fd7a:115c:a1e0::c537:c845",
"Ports": {
"First": 80,
"Last": 80
}
}
]
}
]
},
"tagged-prod": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.83.200.69",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "100.103.8.15",
"Ports": {
"First": 443,
"Last": 443
}
},
{
"IP": "fd7a:115c:a1e0::5b37:80f",
"Ports": {
"First": 443,
"Last": 443
}
}
]
},
{
"SrcIPs": [
"100.108.74.26",
"fd7a:115c:a1e0::b901:4a87"
],
"DstPorts": [
{
"IP": "100.103.8.15",
"Ports": {
"First": 5432,
"Last": 5432
}
},
{
"IP": "fd7a:115c:a1e0::5b37:80f",
"Ports": {
"First": 5432,
"Last": 5432
}
}
]
}
]
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.83.200.69",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-121
View File
@@ -1,121 +0,0 @@
// ACL-AU01
//
// ACL: accept: src=['kristoffer@dalby.cc'] dst=['tag:server:22']
//
// Expected: Rules on tagged-server
{
"test_id": "ACL-AU01",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"kristoffer@dalby.cc"
],
"dst": [
"tag:server:22"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.110.121.96",
"fd7a:115c:a1e0::1737:7960"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-121
View File
@@ -1,121 +0,0 @@
// ACL-AU02
//
// ACL: accept: src=['monitorpasskeykradalby@passkey'] dst=['tag:prod:5432']
//
// Expected: Rules on tagged-prod
{
"test_id": "ACL-AU02",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"monitorpasskeykradalby@passkey"
],
"dst": [
"tag:prod:5432"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.90.82",
"fd7a:115c:a1e0::9e37:5a52"
],
"DstPorts": [
{
"IP": "100.103.8.15",
"Ports": {
"First": 5432,
"Last": 5432
}
},
{
"IP": "fd7a:115c:a1e0::5b37:80f",
"Ports": {
"First": 5432,
"Last": 5432
}
}
]
}
]
},
"tagged-server": {
"packet_filter_rules": null
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-149
View File
@@ -1,149 +0,0 @@
// ACL-AU03
//
// ACL: accept: src=['group:developers'] dst=['tag:server:22', 'tag:prod:5432']
//
// Expected: Rules on tagged-prod, tagged-server
{
"test_id": "ACL-AU03",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"group:developers"
],
"dst": [
"tag:server:22",
"tag:prod:5432"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.110.121.96",
"100.90.199.68",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747"
],
"DstPorts": [
{
"IP": "100.103.8.15",
"Ports": {
"First": 5432,
"Last": 5432
}
},
{
"IP": "fd7a:115c:a1e0::5b37:80f",
"Ports": {
"First": 5432,
"Last": 5432
}
}
]
}
]
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.110.121.96",
"100.90.199.68",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-148
View File
@@ -1,148 +0,0 @@
// ACL-AU04
//
// ACL: accept: src=['*'] dst=['group:developers:22']
//
// Expected: Rules on user-kris, user1
{
"test_id": "ACL-AU04",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"*"
],
"dst": [
"group:developers:22"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": null
},
"user-kris": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.110.121.96",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::1737:7960",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.90.199.68",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::2d01:c747",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
}
}
}
-123
View File
@@ -1,123 +0,0 @@
// ACL-AU05
//
// ACL: accept: src=['*'] dst=['group:monitors:*']
//
// Expected: Rules on user-mon
{
"test_id": "ACL-AU05",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"*"
],
"dst": [
"group:monitors:*"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": null
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.103.90.82",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::9e37:5a52",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user1": {
"packet_filter_rules": null
}
}
}
-127
View File
@@ -1,127 +0,0 @@
// ACL-AU06
//
// ACL: accept: src=['group:admins', 'group:developers', 'group:monitors'] dst=['tag:server:22']
//
// Expected: Rules on tagged-server
{
"test_id": "ACL-AU06",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"group:admins",
"group:developers",
"group:monitors"
],
"dst": [
"tag:server:22"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.90.82",
"100.110.121.96",
"100.90.199.68",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747",
"fd7a:115c:a1e0::9e37:5a52"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-193
View File
@@ -1,193 +0,0 @@
// ACL-C01
//
// ACLs:
// accept: src=['tag:client'] dst=['tag:server:22']
// accept: src=['autogroup:member'] dst=['tag:server:80']
// accept: src=['*'] dst=['tag:prod:5432']
//
// Expected: Rules on tagged-prod, tagged-server
{
"test_id": "ACL-C01",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"tag:client"
],
"dst": [
"tag:server:22"
]
},
{
"action": "accept",
"src": [
"autogroup:member"
],
"dst": [
"tag:server:80"
]
},
{
"action": "accept",
"src": [
"*"
],
"dst": [
"tag:prod:5432"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.103.8.15",
"Ports": {
"First": 5432,
"Last": 5432
}
},
{
"IP": "fd7a:115c:a1e0::5b37:80f",
"Ports": {
"First": 5432,
"Last": 5432
}
}
]
}
]
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.83.200.69",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
}
]
},
{
"SrcIPs": [
"100.103.90.82",
"100.110.121.96",
"100.90.199.68",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747",
"fd7a:115c:a1e0::9e37:5a52"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 80,
"Last": 80
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 80,
"Last": 80
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-194
View File
@@ -1,194 +0,0 @@
// ACL-C02
//
// ACLs:
// accept: src=['tag:client', 'autogroup:member'] dst=['tag:server:22']
// accept: src=['tag:prod'] dst=['tag:server:80']
// accept: src=['group:admins'] dst=['tag:prod:5432']
//
// Expected: Rules on tagged-prod, tagged-server
{
"test_id": "ACL-C02",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"tag:client",
"autogroup:member"
],
"dst": [
"tag:server:22"
]
},
{
"action": "accept",
"src": [
"tag:prod"
],
"dst": [
"tag:server:80"
]
},
{
"action": "accept",
"src": [
"group:admins"
],
"dst": [
"tag:prod:5432"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.90.199.68",
"fd7a:115c:a1e0::2d01:c747"
],
"DstPorts": [
{
"IP": "100.103.8.15",
"Ports": {
"First": 5432,
"Last": 5432
}
},
{
"IP": "fd7a:115c:a1e0::5b37:80f",
"Ports": {
"First": 5432,
"Last": 5432
}
}
]
}
]
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.90.82",
"100.110.121.96",
"100.83.200.69",
"100.90.199.68",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747",
"fd7a:115c:a1e0::9e37:5a52",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
}
]
},
{
"SrcIPs": [
"100.103.8.15",
"fd7a:115c:a1e0::5b37:80f"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 80,
"Last": 80
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 80,
"Last": 80
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-233
View File
@@ -1,233 +0,0 @@
// ACL-C03
//
// ACLs:
// accept: src=['tag:client'] dst=['tag:server:22', 'tag:prod:5432', 'webserver:80']
// accept: src=['autogroup:member'] dst=['autogroup:self:*']
//
// Expected: Rules on tagged-prod, tagged-server, user-kris, user-mon, user1
{
"test_id": "ACL-C03",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"tag:client"
],
"dst": [
"tag:server:22",
"tag:prod:5432",
"webserver:80"
]
},
{
"action": "accept",
"src": [
"autogroup:member"
],
"dst": [
"autogroup:self:*"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.83.200.69",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "100.103.8.15",
"Ports": {
"First": 5432,
"Last": 5432
}
},
{
"IP": "fd7a:115c:a1e0::5b37:80f",
"Ports": {
"First": 5432,
"Last": 5432
}
}
]
}
]
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.83.200.69",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 80,
"Last": 80
}
},
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.110.121.96",
"fd7a:115c:a1e0::1737:7960"
],
"DstPorts": [
{
"IP": "100.110.121.96",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::1737:7960",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-mon": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.90.82",
"fd7a:115c:a1e0::9e37:5a52"
],
"DstPorts": [
{
"IP": "100.103.90.82",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::9e37:5a52",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user1": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.90.199.68",
"fd7a:115c:a1e0::2d01:c747"
],
"DstPorts": [
{
"IP": "100.90.199.68",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::2d01:c747",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
}
}
}
-244
View File
@@ -1,244 +0,0 @@
// ACL-C04
//
// ACLs:
// accept: src=['tag:client'] dst=['tag:server:22']
// accept: src=['tag:server'] dst=['tag:prod:5432']
// accept: src=['autogroup:member'] dst=['autogroup:self:*']
// accept: src=['*'] dst=['autogroup:internet:*']
//
// Expected: Rules on tagged-prod, tagged-server, user-kris, user-mon, user1
{
"test_id": "ACL-C04",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"tag:client"
],
"dst": [
"tag:server:22"
]
},
{
"action": "accept",
"src": [
"tag:server"
],
"dst": [
"tag:prod:5432"
]
},
{
"action": "accept",
"src": [
"autogroup:member"
],
"dst": [
"autogroup:self:*"
]
},
{
"action": "accept",
"src": [
"*"
],
"dst": [
"autogroup:internet:*"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26",
"fd7a:115c:a1e0::b901:4a87"
],
"DstPorts": [
{
"IP": "100.103.8.15",
"Ports": {
"First": 5432,
"Last": 5432
}
},
{
"IP": "fd7a:115c:a1e0::5b37:80f",
"Ports": {
"First": 5432,
"Last": 5432
}
}
]
}
]
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.83.200.69",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.110.121.96",
"fd7a:115c:a1e0::1737:7960"
],
"DstPorts": [
{
"IP": "100.110.121.96",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::1737:7960",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-mon": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.90.82",
"fd7a:115c:a1e0::9e37:5a52"
],
"DstPorts": [
{
"IP": "100.103.90.82",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::9e37:5a52",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user1": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.90.199.68",
"fd7a:115c:a1e0::2d01:c747"
],
"DstPorts": [
{
"IP": "100.90.199.68",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::2d01:c747",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
}
}
}
-370
View File
@@ -1,370 +0,0 @@
// ACL-C05
//
// ACL: accept: src=['*'] dst=['tag:server:22', 'tag:prod:5432', 'tag:client:80', 'tag:router:*', 'tag:exit:*', 'autogroup:member:443', 'autogroup:self:*']
//
// Expected: Rules on 8 of 8 nodes
{
"test_id": "ACL-C05",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"*"
],
"dst": [
"tag:server:22",
"tag:prod:5432",
"tag:client:80",
"tag:router:*",
"tag:exit:*",
"autogroup:member:443",
"autogroup:self:*"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.85.66.106",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::7c37:426a",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"subnet-router": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.92.142.61",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::3e37:8e3d",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-client": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.83.200.69",
"Ports": {
"First": 80,
"Last": 80
}
},
{
"IP": "fd7a:115c:a1e0::c537:c845",
"Ports": {
"First": 80,
"Last": 80
}
}
]
}
]
},
"tagged-prod": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.103.8.15",
"Ports": {
"First": 5432,
"Last": 5432
}
},
{
"IP": "fd7a:115c:a1e0::5b37:80f",
"Ports": {
"First": 5432,
"Last": 5432
}
}
]
}
]
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.110.121.96",
"Ports": {
"First": 443,
"Last": 443
}
},
{
"IP": "fd7a:115c:a1e0::1737:7960",
"Ports": {
"First": 443,
"Last": 443
}
}
]
},
{
"SrcIPs": [
"100.110.121.96",
"fd7a:115c:a1e0::1737:7960"
],
"DstPorts": [
{
"IP": "100.110.121.96",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::1737:7960",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-mon": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.103.90.82",
"Ports": {
"First": 443,
"Last": 443
}
},
{
"IP": "fd7a:115c:a1e0::9e37:5a52",
"Ports": {
"First": 443,
"Last": 443
}
}
]
},
{
"SrcIPs": [
"100.103.90.82",
"fd7a:115c:a1e0::9e37:5a52"
],
"DstPorts": [
{
"IP": "100.103.90.82",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::9e37:5a52",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user1": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.90.199.68",
"Ports": {
"First": 443,
"Last": 443
}
},
{
"IP": "fd7a:115c:a1e0::2d01:c747",
"Ports": {
"First": 443,
"Last": 443
}
}
]
},
{
"SrcIPs": [
"100.90.199.68",
"fd7a:115c:a1e0::2d01:c747"
],
"DstPorts": [
{
"IP": "100.90.199.68",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::2d01:c747",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
}
}
}
-135
View File
@@ -1,135 +0,0 @@
// ACL-C06
//
// ACL: accept: src=['tag:client', 'tag:prod', 'tag:server', 'autogroup:member', 'group:admins'] dst=['tag:server:22']
//
// Expected: Rules on tagged-server
{
"test_id": "ACL-C06",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"tag:client",
"tag:prod",
"tag:server",
"autogroup:member",
"group:admins"
],
"dst": [
"tag:server:22"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.103.90.82",
"100.108.74.26",
"100.110.121.96",
"100.83.200.69",
"100.90.199.68",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::9e37:5a52",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-194
View File
@@ -1,194 +0,0 @@
// ACL-C07
//
// ACLs:
// accept: src=['tag:client'] dst=['tag:server:22']
// accept: src=['tag:client'] dst=['tag:server:80']
// accept: src=['tag:client'] dst=['tag:server:443']
// accept: src=['tag:client'] dst=['tag:server:8080']
//
// Expected: Rules on tagged-server
{
"test_id": "ACL-C07",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"tag:client"
],
"dst": [
"tag:server:22"
]
},
{
"action": "accept",
"src": [
"tag:client"
],
"dst": [
"tag:server:80"
]
},
{
"action": "accept",
"src": [
"tag:client"
],
"dst": [
"tag:server:443"
]
},
{
"action": "accept",
"src": [
"tag:client"
],
"dst": [
"tag:server:8080"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.83.200.69",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "100.108.74.26",
"Ports": {
"First": 80,
"Last": 80
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 80,
"Last": 80
}
},
{
"IP": "100.108.74.26",
"Ports": {
"First": 443,
"Last": 443
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 443,
"Last": 443
}
},
{
"IP": "100.108.74.26",
"Ports": {
"First": 8080,
"Last": 8080
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 8080,
"Last": 8080
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-227
View File
@@ -1,227 +0,0 @@
// ACL-C08
//
// ACL: accept: src=['*'] dst=['tag:server:22', 'tag:prod:22', 'tag:client:22', 'tag:router:22', 'tag:exit:22']
//
// Expected: Rules on exit-node, subnet-router, tagged-client, tagged-prod, tagged-server
{
"test_id": "ACL-C08",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"*"
],
"dst": [
"tag:server:22",
"tag:prod:22",
"tag:client:22",
"tag:router:22",
"tag:exit:22"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.85.66.106",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::7c37:426a",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"subnet-router": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.92.142.61",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::3e37:8e3d",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"tagged-client": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.83.200.69",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::c537:c845",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"tagged-prod": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.103.8.15",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::5b37:80f",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-309
View File
@@ -1,309 +0,0 @@
// ACL-C09
//
// ACLs:
// accept: src=['tag:client'] dst=['tag:server:22']
// accept: src=['tag:client'] dst=['tag:prod:22']
// accept: src=['tag:server'] dst=['tag:prod:5432']
// ... (6 rules total)
//
// Expected: Rules on subnet-router, tagged-prod, tagged-server, user-kris, user-mon, user1
{
"test_id": "ACL-C09",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"tag:client"
],
"dst": [
"tag:server:22"
]
},
{
"action": "accept",
"src": [
"tag:client"
],
"dst": [
"tag:prod:22"
]
},
{
"action": "accept",
"src": [
"tag:server"
],
"dst": [
"tag:prod:5432"
]
},
{
"action": "accept",
"src": [
"autogroup:member"
],
"dst": [
"autogroup:self:*"
]
},
{
"action": "accept",
"src": [
"group:developers"
],
"dst": [
"tag:router:*"
]
},
{
"action": "accept",
"src": [
"*"
],
"dst": [
"autogroup:internet:*"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.110.121.96",
"100.90.199.68",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747"
],
"DstPorts": [
{
"IP": "100.92.142.61",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::3e37:8e3d",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.83.200.69",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "100.103.8.15",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::5b37:80f",
"Ports": {
"First": 22,
"Last": 22
}
}
]
},
{
"SrcIPs": [
"100.108.74.26",
"fd7a:115c:a1e0::b901:4a87"
],
"DstPorts": [
{
"IP": "100.103.8.15",
"Ports": {
"First": 5432,
"Last": 5432
}
},
{
"IP": "fd7a:115c:a1e0::5b37:80f",
"Ports": {
"First": 5432,
"Last": 5432
}
}
]
}
]
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.83.200.69",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.110.121.96",
"fd7a:115c:a1e0::1737:7960"
],
"DstPorts": [
{
"IP": "100.110.121.96",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::1737:7960",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-mon": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.90.82",
"fd7a:115c:a1e0::9e37:5a52"
],
"DstPorts": [
{
"IP": "100.103.90.82",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::9e37:5a52",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user1": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.90.199.68",
"fd7a:115c:a1e0::2d01:c747"
],
"DstPorts": [
{
"IP": "100.90.199.68",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::2d01:c747",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
}
}
}
-396
View File
@@ -1,396 +0,0 @@
// ACL-C10
//
// ACLs:
// accept: src=['autogroup:member'] dst=['autogroup:self:*']
// accept: src=['autogroup:member'] dst=['tag:server:22', 'tag:prod:5432']
// accept: src=['autogroup:tagged'] dst=['autogroup:tagged:*']
//
// Expected: Rules on 8 of 8 nodes
{
"test_id": "ACL-C10",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"autogroup:member"
],
"dst": [
"autogroup:self:*"
]
},
{
"action": "accept",
"src": [
"autogroup:member"
],
"dst": [
"tag:server:22",
"tag:prod:5432"
]
},
{
"action": "accept",
"src": [
"autogroup:tagged"
],
"dst": [
"autogroup:tagged:*"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.108.74.26",
"100.83.200.69",
"100.85.66.106",
"100.92.142.61",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "100.85.66.106",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::7c37:426a",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"subnet-router": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.108.74.26",
"100.83.200.69",
"100.85.66.106",
"100.92.142.61",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "100.92.142.61",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::3e37:8e3d",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-client": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.108.74.26",
"100.83.200.69",
"100.85.66.106",
"100.92.142.61",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "100.83.200.69",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::c537:c845",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-prod": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.90.82",
"100.110.121.96",
"100.90.199.68",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747",
"fd7a:115c:a1e0::9e37:5a52"
],
"DstPorts": [
{
"IP": "100.103.8.15",
"Ports": {
"First": 5432,
"Last": 5432
}
},
{
"IP": "fd7a:115c:a1e0::5b37:80f",
"Ports": {
"First": 5432,
"Last": 5432
}
}
]
},
{
"SrcIPs": [
"100.103.8.15",
"100.108.74.26",
"100.83.200.69",
"100.85.66.106",
"100.92.142.61",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "100.103.8.15",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::5b37:80f",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.90.82",
"100.110.121.96",
"100.90.199.68",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747",
"fd7a:115c:a1e0::9e37:5a52"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
}
]
},
{
"SrcIPs": [
"100.103.8.15",
"100.108.74.26",
"100.83.200.69",
"100.85.66.106",
"100.92.142.61",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.110.121.96",
"fd7a:115c:a1e0::1737:7960"
],
"DstPorts": [
{
"IP": "100.110.121.96",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::1737:7960",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-mon": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.90.82",
"fd7a:115c:a1e0::9e37:5a52"
],
"DstPorts": [
{
"IP": "100.103.90.82",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::9e37:5a52",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user1": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.90.199.68",
"fd7a:115c:a1e0::2d01:c747"
],
"DstPorts": [
{
"IP": "100.90.199.68",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::2d01:c747",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
}
}
}
-156
View File
@@ -1,156 +0,0 @@
// ACL-D01
//
// ACLs:
// accept: src=['tag:client'] dst=['tag:server:22']
// accept: src=['*'] dst=['tag:server:22']
//
// Expected: Rules on tagged-server
{
"test_id": "ACL-D01",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"tag:client"
],
"dst": [
"tag:server:22"
]
},
{
"action": "accept",
"src": [
"*"
],
"dst": [
"tag:server:22"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.83.200.69",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
}
]
},
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-129
View File
@@ -1,129 +0,0 @@
// ACL-D02
//
// ACL: accept: src=['tag:client'] dst=['tag:server:22', 'webserver:22']
//
// Expected: Rules on tagged-server
{
"test_id": "ACL-D02",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"tag:client"
],
"dst": [
"tag:server:22",
"webserver:22"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.83.200.69",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-227
View File
@@ -1,227 +0,0 @@
// ACL-D03
//
// ACL: accept: src=['100.108.74.26', 'tag:server'] dst=['*:*']
//
// Expected: Rules on 8 of 8 nodes
{
"test_id": "ACL-D03",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"100.108.74.26",
"tag:server"
],
"dst": [
"*:*"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26",
"fd7a:115c:a1e0::b901:4a87"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"subnet-router": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26",
"fd7a:115c:a1e0::b901:4a87"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-client": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26",
"fd7a:115c:a1e0::b901:4a87"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-prod": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26",
"fd7a:115c:a1e0::b901:4a87"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26",
"fd7a:115c:a1e0::b901:4a87"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26",
"fd7a:115c:a1e0::b901:4a87"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-mon": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26",
"fd7a:115c:a1e0::b901:4a87"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user1": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26",
"fd7a:115c:a1e0::b901:4a87"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
}
}
}
-219
View File
@@ -1,219 +0,0 @@
// ACL-D04
//
// ACL: accept: src=['100.108.74.26', 'webserver'] dst=['*:*']
//
// Expected: Rules on 8 of 8 nodes
{
"test_id": "ACL-D04",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"100.108.74.26",
"webserver"
],
"dst": [
"*:*"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"subnet-router": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-client": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-prod": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-mon": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user1": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
}
}
}
-131
View File
@@ -1,131 +0,0 @@
// ACL-D05
//
// ACL: accept: src=['*'] dst=['100.108.74.26:22', 'tag:server:22']
//
// Expected: Rules on tagged-server
{
"test_id": "ACL-D05",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"*"
],
"dst": [
"100.108.74.26:22",
"tag:server:22"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-124
View File
@@ -1,124 +0,0 @@
// ACL-D06
//
// ACL: accept: src=['*'] dst=['100.108.74.26:22', 'webserver:22']
//
// Expected: Rules on tagged-server
{
"test_id": "ACL-D06",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"*"
],
"dst": [
"100.108.74.26:22",
"webserver:22"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-339
View File
@@ -1,339 +0,0 @@
// ACL-D07
//
// ACL: accept: src=['autogroup:member', 'autogroup:tagged'] dst=['*:*']
//
// Expected: Rules on 8 of 8 nodes
{
"test_id": "ACL-D07",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"autogroup:member",
"autogroup:tagged"
],
"dst": [
"*:*"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.103.90.82",
"100.108.74.26",
"100.110.121.96",
"100.83.200.69",
"100.85.66.106",
"100.90.199.68",
"100.92.142.61",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::9e37:5a52",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"subnet-router": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.103.90.82",
"100.108.74.26",
"100.110.121.96",
"100.83.200.69",
"100.85.66.106",
"100.90.199.68",
"100.92.142.61",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::9e37:5a52",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-client": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.103.90.82",
"100.108.74.26",
"100.110.121.96",
"100.83.200.69",
"100.85.66.106",
"100.90.199.68",
"100.92.142.61",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::9e37:5a52",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-prod": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.103.90.82",
"100.108.74.26",
"100.110.121.96",
"100.83.200.69",
"100.85.66.106",
"100.90.199.68",
"100.92.142.61",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::9e37:5a52",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.103.90.82",
"100.108.74.26",
"100.110.121.96",
"100.83.200.69",
"100.85.66.106",
"100.90.199.68",
"100.92.142.61",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::9e37:5a52",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.103.90.82",
"100.108.74.26",
"100.110.121.96",
"100.83.200.69",
"100.85.66.106",
"100.90.199.68",
"100.92.142.61",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::9e37:5a52",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-mon": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.103.90.82",
"100.108.74.26",
"100.110.121.96",
"100.83.200.69",
"100.85.66.106",
"100.90.199.68",
"100.92.142.61",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::9e37:5a52",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user1": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.8.15",
"100.103.90.82",
"100.108.74.26",
"100.110.121.96",
"100.83.200.69",
"100.85.66.106",
"100.90.199.68",
"100.92.142.61",
"fd7a:115c:a1e0::1737:7960",
"fd7a:115c:a1e0::2d01:c747",
"fd7a:115c:a1e0::3e37:8e3d",
"fd7a:115c:a1e0::5b37:80f",
"fd7a:115c:a1e0::7c37:426a",
"fd7a:115c:a1e0::9e37:5a52",
"fd7a:115c:a1e0::b901:4a87",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
}
}
}
-192
View File
@@ -1,192 +0,0 @@
// ACL-D08
//
// ACLs:
// accept: src=['*'] dst=['autogroup:self:*']
// accept: src=['kratail2tid@passkey'] dst=['kratail2tid@passkey:*']
//
// Expected: Rules on user-kris, user-mon, user1
{
"test_id": "ACL-D08",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"*"
],
"dst": [
"autogroup:self:*"
]
},
{
"action": "accept",
"src": [
"kratail2tid@passkey"
],
"dst": [
"kratail2tid@passkey:*"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": null
},
"user-kris": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.110.121.96",
"fd7a:115c:a1e0::1737:7960"
],
"DstPorts": [
{
"IP": "100.110.121.96",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::1737:7960",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-mon": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.103.90.82",
"fd7a:115c:a1e0::9e37:5a52"
],
"DstPorts": [
{
"IP": "100.103.90.82",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::9e37:5a52",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user1": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.90.199.68",
"fd7a:115c:a1e0::2d01:c747"
],
"DstPorts": [
{
"IP": "100.90.199.68",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::2d01:c747",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "100.90.199.68",
"Ports": {
"First": 0,
"Last": 65535
}
},
{
"IP": "fd7a:115c:a1e0::2d01:c747",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
}
}
}
-218
View File
@@ -1,218 +0,0 @@
// ACL-E01
//
// ACL: accept: src=['100.108.74.26'] dst=['*:*']
//
// Expected: Rules on 8 of 8 nodes
{
"test_id": "ACL-E01",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"100.108.74.26"
],
"dst": [
"*:*"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"subnet-router": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-client": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-prod": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-mon": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user1": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
}
}
}
-226
View File
@@ -1,226 +0,0 @@
// ACL-E02
//
// ACL: accept: src=['tag:server'] dst=['*:*']
//
// Expected: Rules on 8 of 8 nodes
{
"test_id": "ACL-E02",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"tag:server"
],
"dst": [
"*:*"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26",
"fd7a:115c:a1e0::b901:4a87"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"subnet-router": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26",
"fd7a:115c:a1e0::b901:4a87"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-client": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26",
"fd7a:115c:a1e0::b901:4a87"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-prod": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26",
"fd7a:115c:a1e0::b901:4a87"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26",
"fd7a:115c:a1e0::b901:4a87"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26",
"fd7a:115c:a1e0::b901:4a87"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-mon": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26",
"fd7a:115c:a1e0::b901:4a87"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user1": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26",
"fd7a:115c:a1e0::b901:4a87"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
}
}
}
-218
View File
@@ -1,218 +0,0 @@
// ACL-E03
//
// ACL: accept: src=['webserver'] dst=['*:*']
//
// Expected: Rules on 8 of 8 nodes
{
"test_id": "ACL-E03",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"webserver"
],
"dst": [
"*:*"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"subnet-router": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-client": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-prod": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-mon": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user1": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
}
}
}
-116
View File
@@ -1,116 +0,0 @@
// ACL-E04
//
// ACL: accept: src=['*'] dst=['100.108.74.26:22']
//
// Expected: Rules on tagged-server
{
"test_id": "ACL-E04",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"*"
],
"dst": [
"100.108.74.26:22"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-123
View File
@@ -1,123 +0,0 @@
// ACL-E05
//
// ACL: accept: src=['*'] dst=['tag:server:22']
//
// Expected: Rules on tagged-server
{
"test_id": "ACL-E05",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"*"
],
"dst": [
"tag:server:22"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-116
View File
@@ -1,116 +0,0 @@
// ACL-E06
//
// ACL: accept: src=['*'] dst=['webserver:22']
//
// Expected: Rules on tagged-server
{
"test_id": "ACL-E06",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"*"
],
"dst": [
"webserver:22"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-121
View File
@@ -1,121 +0,0 @@
// ACL-E07
//
// ACL: accept: src=['kratail2tid@passkey'] dst=['tag:server:22']
//
// Expected: Rules on tagged-server
{
"test_id": "ACL-E07",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"kratail2tid@passkey"
],
"dst": [
"tag:server:22"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.90.199.68",
"fd7a:115c:a1e0::2d01:c747"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-121
View File
@@ -1,121 +0,0 @@
// ACL-E08
//
// ACL: accept: src=['group:admins'] dst=['tag:server:22']
//
// Expected: Rules on tagged-server
{
"test_id": "ACL-E08",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"group:admins"
],
"dst": [
"tag:server:22"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.90.199.68",
"fd7a:115c:a1e0::2d01:c747"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-122
View File
@@ -1,122 +0,0 @@
// ACL-E09
//
// ACL: accept: src=['kratail2tid@passkey', 'group:admins'] dst=['tag:server:22']
//
// Expected: Rules on tagged-server
{
"test_id": "ACL-E09",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"kratail2tid@passkey",
"group:admins"
],
"dst": [
"tag:server:22"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.90.199.68",
"fd7a:115c:a1e0::2d01:c747"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
@@ -1,76 +0,0 @@
// ACL-ERR01
//
// ACL: accept: src=['tag:nonexistent'] dst=['tag:server:22']
//
// Expected: Error — src=tag not found: "tag:nonexistent"
{
"test_id": "ACL-ERR01",
"error": true,
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"tag:nonexistent"
],
"dst": [
"tag:server:22"
]
}
]
},
"api_response_body": {
"message": "src=tag not found: \"tag:nonexistent\""
}
}
}
@@ -1,76 +0,0 @@
// ACL-ERR02
//
// ACL: accept: src=['autogroup:self'] dst=['tag:server:22']
//
// Expected: Error — "autogroup:self" not valid on the src side of a rule
{
"test_id": "ACL-ERR02",
"error": true,
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"autogroup:self"
],
"dst": [
"tag:server:22"
]
}
]
},
"api_response_body": {
"message": "\"autogroup:self\" not valid on the src side of a rule"
}
}
}
@@ -1,76 +0,0 @@
// ACL-ERR03
//
// ACL: accept: src=['*'] dst=['autogroup:self']
//
// Expected: Error — dst="autogroup:self": port range "self": invalid first integer
{
"test_id": "ACL-ERR03",
"error": true,
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"*"
],
"dst": [
"autogroup:self"
]
}
]
},
"api_response_body": {
"message": "dst=\"autogroup:self\": port range \"self\": invalid first integer"
}
}
}
@@ -1,76 +0,0 @@
// ACL-ERR04
//
// ACL: accept: src=['tag:nonexistent'] dst=['*:*']
//
// Expected: Error — src=tag not found: "tag:nonexistent"
{
"test_id": "ACL-ERR04",
"error": true,
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"tag:nonexistent"
],
"dst": [
"*:*"
]
}
]
},
"api_response_body": {
"message": "src=tag not found: \"tag:nonexistent\""
}
}
}
@@ -1,76 +0,0 @@
// ACL-ERR05
//
// ACL: accept: src=['*'] dst=['tag:nonexistent:22']
//
// Expected: Error — dst="tag:nonexistent": tag not found: "tag:nonexistent"
{
"test_id": "ACL-ERR05",
"error": true,
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"*"
],
"dst": [
"tag:nonexistent:22"
]
}
]
},
"api_response_body": {
"message": "dst=\"tag:nonexistent\": tag not found: \"tag:nonexistent\""
}
}
}
@@ -1,76 +0,0 @@
// ACL-ERR06
//
// ACL: deny: src=['tag:client'] dst=['tag:server:22']
//
// Expected: Error — action="deny" is not supported
{
"test_id": "ACL-ERR06",
"error": true,
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "deny",
"src": [
"tag:client"
],
"dst": [
"tag:server:22"
]
}
]
},
"api_response_body": {
"message": "action=\"deny\" is not supported"
}
}
}
@@ -1,76 +0,0 @@
// ACL-ERR07
//
// ACL: accept: src=['*'] dst=['tag:server:ssh']
//
// Expected: Error — dst="tag:server:ssh": port range "ssh": invalid first integer
{
"test_id": "ACL-ERR07",
"error": true,
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"*"
],
"dst": [
"tag:server:ssh"
]
}
]
},
"api_response_body": {
"message": "dst=\"tag:server:ssh\": port range \"ssh\": invalid first integer"
}
}
}
@@ -1,87 +0,0 @@
// ACL-ERR08
//
// ACLs:
// accept: src=['*'] dst=['autogroup:self:*']
// accept: src=['tag:client'] dst=['autogroup:self:22']
//
// Expected: Error — autogroup:self can only be used with users, groups, or supported autogroups
{
"test_id": "ACL-ERR08",
"error": true,
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"*"
],
"dst": [
"autogroup:self:*"
]
},
{
"action": "accept",
"src": [
"tag:client"
],
"dst": [
"autogroup:self:22"
]
}
]
},
"api_response_body": {
"message": "autogroup:self can only be used with users, groups, or supported autogroups"
}
}
}
@@ -1,87 +0,0 @@
// ACL-ERR09
//
// ACLs:
// accept: src=['*'] dst=['autogroup:self:*']
// accept: src=['autogroup:tagged'] dst=['autogroup:self:22']
//
// Expected: Error — autogroup:self can only be used with users, groups, or supported autogroups
{
"test_id": "ACL-ERR09",
"error": true,
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"*"
],
"dst": [
"autogroup:self:*"
]
},
{
"action": "accept",
"src": [
"autogroup:tagged"
],
"dst": [
"autogroup:self:22"
]
}
]
},
"api_response_body": {
"message": "autogroup:self can only be used with users, groups, or supported autogroups"
}
}
}
-116
View File
@@ -1,116 +0,0 @@
// ACL-H01
//
// ACL: accept: src=['*'] dst=['webserver:80']
//
// Expected: Rules on tagged-server
{
"test_id": "ACL-H01",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"*"
],
"dst": [
"webserver:80"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 80,
"Last": 80
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-218
View File
@@ -1,218 +0,0 @@
// ACL-H02
//
// ACL: accept: src=['webserver'] dst=['*:*']
//
// Expected: Rules on 8 of 8 nodes
{
"test_id": "ACL-H02",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"webserver"
],
"dst": [
"*:*"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"subnet-router": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-client": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-prod": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user-mon": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
},
"user1": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26"
],
"DstPorts": [
{
"IP": "*",
"Ports": {
"First": 0,
"Last": 65535
}
}
]
}
]
}
}
}
-120
View File
@@ -1,120 +0,0 @@
// ACL-H03
//
// ACL: accept: src=['internal'] dst=['tag:server:22']
//
// Expected: Rules on tagged-server
{
"test_id": "ACL-H03",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"internal"
],
"dst": [
"tag:server:22"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.0.0.0/8"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-116
View File
@@ -1,116 +0,0 @@
// ACL-H04
//
// ACL: accept: src=['*'] dst=['internal:22']
//
// Expected: Rules on subnet-router
{
"test_id": "ACL-H04",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"*"
],
"dst": [
"internal:22"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "10.0.0.0/8",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": null
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-135
View File
@@ -1,135 +0,0 @@
// ACL-H05
//
// ACL: accept: src=['*'] dst=['webserver:22', 'prodbox:5432']
//
// Expected: Rules on tagged-prod, tagged-server
{
"test_id": "ACL-H05",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"*"
],
"dst": [
"webserver:22",
"prodbox:5432"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.103.8.15",
"Ports": {
"First": 5432,
"Last": 5432
}
}
]
}
]
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"10.33.0.0/16",
"100.115.94.0-100.127.255.255",
"100.64.0.0-100.115.91.255",
"fd7a:115c:a1e0::/48"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}
-123
View File
@@ -1,123 +0,0 @@
// ACL-H06
//
// ACL: accept: src=['webserver', 'tag:client'] dst=['tag:server:22']
//
// Expected: Rules on tagged-server
{
"test_id": "ACL-H06",
"input": {
"full_policy": {
"groups": {
"group:admins": [
"kratail2tid@passkey"
],
"group:developers": [
"kristoffer@dalby.cc",
"kratail2tid@passkey"
],
"group:monitors": [
"monitorpasskeykradalby@passkey"
],
"group:empty": []
},
"tagOwners": {
"tag:server": [
"kratail2tid@passkey"
],
"tag:prod": [
"kratail2tid@passkey"
],
"tag:client": [
"kratail2tid@passkey"
],
"tag:router": [
"kratail2tid@passkey"
],
"tag:exit": [
"kratail2tid@passkey"
]
},
"hosts": {
"webserver": "100.108.74.26",
"prodbox": "100.103.8.15",
"internal": "10.0.0.0/8",
"subnet24": "192.168.1.0/24"
},
"autoApprovers": {
"routes": {
"10.33.0.0/16": [
"tag:router"
],
"0.0.0.0/0": [
"tag:exit"
],
"::/0": [
"tag:exit"
]
}
},
"acls": [
{
"action": "accept",
"src": [
"webserver",
"tag:client"
],
"dst": [
"tag:server:22"
]
}
]
}
},
"captures": {
"exit-node": {
"packet_filter_rules": null
},
"subnet-router": {
"packet_filter_rules": null
},
"tagged-client": {
"packet_filter_rules": null
},
"tagged-prod": {
"packet_filter_rules": null
},
"tagged-server": {
"packet_filter_rules": [
{
"SrcIPs": [
"100.108.74.26",
"100.83.200.69",
"fd7a:115c:a1e0::c537:c845"
],
"DstPorts": [
{
"IP": "100.108.74.26",
"Ports": {
"First": 22,
"Last": 22
}
},
{
"IP": "fd7a:115c:a1e0::b901:4a87",
"Ports": {
"First": 22,
"Last": 22
}
}
]
}
]
},
"user-kris": {
"packet_filter_rules": null
},
"user-mon": {
"packet_filter_rules": null
},
"user1": {
"packet_filter_rules": null
}
}
}

Some files were not shown because too many files have changed in this diff Show More