Skip to content

Commit 8eadc5a

Browse files
committed
Add integration tests for ACLs related to 699
Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
1 parent 51b32dd commit 8eadc5a

4 files changed

+333
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
2+
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
3+
4+
name: Integration Test v2 - TestACLAllowStarDst
5+
6+
on: [pull_request]
7+
8+
concurrency:
9+
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
10+
cancel-in-progress: true
11+
12+
jobs:
13+
test:
14+
runs-on: ubuntu-latest
15+
16+
steps:
17+
- uses: actions/checkout@v3
18+
with:
19+
fetch-depth: 2
20+
21+
- name: Get changed files
22+
id: changed-files
23+
uses: tj-actions/changed-files@v34
24+
with:
25+
files: |
26+
*.nix
27+
go.*
28+
**/*.go
29+
integration_test/
30+
config-example.yaml
31+
32+
- uses: cachix/install-nix-action@v18
33+
if: ${{ env.ACT }} || steps.changed-files.outputs.any_changed == 'true'
34+
35+
- name: Run general integration tests
36+
if: steps.changed-files.outputs.any_changed == 'true'
37+
run: |
38+
nix develop --command -- docker run \
39+
--tty --rm \
40+
--volume ~/.cache/hs-integration-go:/go \
41+
--name headscale-test-suite \
42+
--volume $PWD:$PWD -w $PWD/integration \
43+
--volume /var/run/docker.sock:/var/run/docker.sock \
44+
--volume $PWD/control_logs:/tmp/control \
45+
golang:1 \
46+
go test ./... \
47+
-tags ts2019 \
48+
-failfast \
49+
-timeout 120m \
50+
-parallel 1 \
51+
-run "^TestACLAllowStarDst$"
52+
53+
- uses: actions/upload-artifact@v3
54+
if: always() && steps.changed-files.outputs.any_changed == 'true'
55+
with:
56+
name: logs
57+
path: "control_logs/*.log"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
2+
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
3+
4+
name: Integration Test v2 - TestACLAllowUserDst
5+
6+
on: [pull_request]
7+
8+
concurrency:
9+
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
10+
cancel-in-progress: true
11+
12+
jobs:
13+
test:
14+
runs-on: ubuntu-latest
15+
16+
steps:
17+
- uses: actions/checkout@v3
18+
with:
19+
fetch-depth: 2
20+
21+
- name: Get changed files
22+
id: changed-files
23+
uses: tj-actions/changed-files@v34
24+
with:
25+
files: |
26+
*.nix
27+
go.*
28+
**/*.go
29+
integration_test/
30+
config-example.yaml
31+
32+
- uses: cachix/install-nix-action@v18
33+
if: ${{ env.ACT }} || steps.changed-files.outputs.any_changed == 'true'
34+
35+
- name: Run general integration tests
36+
if: steps.changed-files.outputs.any_changed == 'true'
37+
run: |
38+
nix develop --command -- docker run \
39+
--tty --rm \
40+
--volume ~/.cache/hs-integration-go:/go \
41+
--name headscale-test-suite \
42+
--volume $PWD:$PWD -w $PWD/integration \
43+
--volume /var/run/docker.sock:/var/run/docker.sock \
44+
--volume $PWD/control_logs:/tmp/control \
45+
golang:1 \
46+
go test ./... \
47+
-tags ts2019 \
48+
-failfast \
49+
-timeout 120m \
50+
-parallel 1 \
51+
-run "^TestACLAllowUserDst$"
52+
53+
- uses: actions/upload-artifact@v3
54+
if: always() && steps.changed-files.outputs.any_changed == 'true'
55+
with:
56+
name: logs
57+
path: "control_logs/*.log"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
2+
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
3+
4+
name: Integration Test v2 - TestACLDenyAllPort80
5+
6+
on: [pull_request]
7+
8+
concurrency:
9+
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
10+
cancel-in-progress: true
11+
12+
jobs:
13+
test:
14+
runs-on: ubuntu-latest
15+
16+
steps:
17+
- uses: actions/checkout@v3
18+
with:
19+
fetch-depth: 2
20+
21+
- name: Get changed files
22+
id: changed-files
23+
uses: tj-actions/changed-files@v34
24+
with:
25+
files: |
26+
*.nix
27+
go.*
28+
**/*.go
29+
integration_test/
30+
config-example.yaml
31+
32+
- uses: cachix/install-nix-action@v18
33+
if: ${{ env.ACT }} || steps.changed-files.outputs.any_changed == 'true'
34+
35+
- name: Run general integration tests
36+
if: steps.changed-files.outputs.any_changed == 'true'
37+
run: |
38+
nix develop --command -- docker run \
39+
--tty --rm \
40+
--volume ~/.cache/hs-integration-go:/go \
41+
--name headscale-test-suite \
42+
--volume $PWD:$PWD -w $PWD/integration \
43+
--volume /var/run/docker.sock:/var/run/docker.sock \
44+
--volume $PWD/control_logs:/tmp/control \
45+
golang:1 \
46+
go test ./... \
47+
-tags ts2019 \
48+
-failfast \
49+
-timeout 120m \
50+
-parallel 1 \
51+
-run "^TestACLDenyAllPort80$"
52+
53+
- uses: actions/upload-artifact@v3
54+
if: always() && steps.changed-files.outputs.any_changed == 'true'
55+
with:
56+
name: logs
57+
path: "control_logs/*.log"

integration/acl_test.go

+162-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package integration
22

33
import (
44
"fmt"
5+
"strings"
56
"testing"
67

78
"github.com/juanfont/headscale"
@@ -32,7 +33,7 @@ func aclScenario(t *testing.T, policy headscale.ACLPolicy) *Scenario {
3233
tsic.WithDockerWorkdir("/"),
3334
},
3435
hsic.WithACLPolicy(&policy),
35-
hsic.WithTestName("acldenyallping"),
36+
hsic.WithTestName("acl"),
3637
)
3738
assert.NoError(t, err)
3839

@@ -278,3 +279,163 @@ func TestACLAllowUser80Dst(t *testing.T) {
278279
err = scenario.Shutdown()
279280
assert.NoError(t, err)
280281
}
282+
283+
func TestACLDenyAllPort80(t *testing.T) {
284+
IntegrationSkip(t)
285+
286+
scenario := aclScenario(t,
287+
headscale.ACLPolicy{
288+
Groups: map[string][]string{
289+
"group:integration-acl-test": {"user1", "user2"},
290+
},
291+
ACLs: []headscale.ACL{
292+
{
293+
Action: "accept",
294+
Sources: []string{"group:integration-acl-test"},
295+
Destinations: []string{"*:22"},
296+
},
297+
},
298+
},
299+
)
300+
301+
allClients, err := scenario.ListTailscaleClients()
302+
assert.NoError(t, err)
303+
304+
allHostnames, err := scenario.ListTailscaleClientsFQDNs()
305+
assert.NoError(t, err)
306+
307+
for _, client := range allClients {
308+
for _, hostname := range allHostnames {
309+
// We will always be allowed to check _self_ so shortcircuit
310+
// the test here.
311+
if strings.Contains(hostname, client.Hostname()) {
312+
continue
313+
}
314+
315+
url := fmt.Sprintf("http://%s/etc/hostname", hostname)
316+
t.Logf("url from %s to %s", client.Hostname(), url)
317+
318+
result, err := client.Curl(url)
319+
assert.Empty(t, result)
320+
assert.Error(t, err)
321+
}
322+
}
323+
324+
err = scenario.Shutdown()
325+
assert.NoError(t, err)
326+
}
327+
328+
// Test to confirm that we can use user:* from one user.
329+
// This ACL will not allow user1 access its own machines.
330+
// Reported: https://github.com/juanfont/headscale/issues/699
331+
func TestACLAllowUserDst(t *testing.T) {
332+
IntegrationSkip(t)
333+
334+
scenario := aclScenario(t,
335+
headscale.ACLPolicy{
336+
ACLs: []headscale.ACL{
337+
{
338+
Action: "accept",
339+
Sources: []string{"user1"},
340+
Destinations: []string{"user2:*"},
341+
},
342+
},
343+
},
344+
)
345+
346+
user1Clients, err := scenario.ListTailscaleClients("user1")
347+
assert.NoError(t, err)
348+
349+
user2Clients, err := scenario.ListTailscaleClients("user2")
350+
assert.NoError(t, err)
351+
352+
// Test that user1 can visit all user2
353+
for _, client := range user1Clients {
354+
for _, peer := range user2Clients {
355+
fqdn, err := peer.FQDN()
356+
assert.NoError(t, err)
357+
358+
url := fmt.Sprintf("http://%s/etc/hostname", fqdn)
359+
t.Logf("url from %s to %s", client.Hostname(), url)
360+
361+
result, err := client.Curl(url)
362+
assert.Len(t, result, 13)
363+
assert.NoError(t, err)
364+
}
365+
}
366+
367+
// Test that user2 _cannot_ visit user1
368+
for _, client := range user2Clients {
369+
for _, peer := range user1Clients {
370+
fqdn, err := peer.FQDN()
371+
assert.NoError(t, err)
372+
373+
url := fmt.Sprintf("http://%s/etc/hostname", fqdn)
374+
t.Logf("url from %s to %s", client.Hostname(), url)
375+
376+
result, err := client.Curl(url)
377+
assert.Empty(t, result)
378+
assert.Error(t, err)
379+
}
380+
}
381+
382+
err = scenario.Shutdown()
383+
assert.NoError(t, err)
384+
}
385+
386+
// Test to confirm that we can use *:* from one user
387+
// Reported: https://github.com/juanfont/headscale/issues/699
388+
func TestACLAllowStarDst(t *testing.T) {
389+
IntegrationSkip(t)
390+
391+
scenario := aclScenario(t,
392+
headscale.ACLPolicy{
393+
ACLs: []headscale.ACL{
394+
{
395+
Action: "accept",
396+
Sources: []string{"user1"},
397+
Destinations: []string{"*:*"},
398+
},
399+
},
400+
},
401+
)
402+
403+
user1Clients, err := scenario.ListTailscaleClients("user1")
404+
assert.NoError(t, err)
405+
406+
user2Clients, err := scenario.ListTailscaleClients("user2")
407+
assert.NoError(t, err)
408+
409+
// Test that user1 can visit all user2
410+
for _, client := range user1Clients {
411+
for _, peer := range user2Clients {
412+
fqdn, err := peer.FQDN()
413+
assert.NoError(t, err)
414+
415+
url := fmt.Sprintf("http://%s/etc/hostname", fqdn)
416+
t.Logf("url from %s to %s", client.Hostname(), url)
417+
418+
result, err := client.Curl(url)
419+
assert.Len(t, result, 13)
420+
assert.NoError(t, err)
421+
}
422+
}
423+
424+
// Test that user2 _cannot_ visit user1
425+
for _, client := range user2Clients {
426+
for _, peer := range user1Clients {
427+
fqdn, err := peer.FQDN()
428+
assert.NoError(t, err)
429+
430+
url := fmt.Sprintf("http://%s/etc/hostname", fqdn)
431+
t.Logf("url from %s to %s", client.Hostname(), url)
432+
433+
result, err := client.Curl(url)
434+
assert.Empty(t, result)
435+
assert.Error(t, err)
436+
}
437+
}
438+
439+
err = scenario.Shutdown()
440+
assert.NoError(t, err)
441+
}

0 commit comments

Comments
 (0)