diff --git a/Dockerfile.tailscale b/Dockerfile.tailscale deleted file mode 100644 index adf37ed039..0000000000 --- a/Dockerfile.tailscale +++ /dev/null @@ -1,16 +0,0 @@ -FROM ubuntu:22.04 - -ARG TAILSCALE_VERSION=* -ARG TAILSCALE_CHANNEL=stable - -RUN apt-get update \ - && apt-get install -y gnupg curl ssh dnsutils ca-certificates \ - && adduser --shell=/bin/bash ssh-it-user - -# Tailscale is deliberately split into a second stage so we can cash utils as a seperate layer. -RUN curl -fsSL https://pkgs.tailscale.com/${TAILSCALE_CHANNEL}/ubuntu/focal.gpg | apt-key add - \ - && curl -fsSL https://pkgs.tailscale.com/${TAILSCALE_CHANNEL}/ubuntu/focal.list | tee /etc/apt/sources.list.d/tailscale.list \ - && apt-get update \ - && apt-get install -y tailscale=${TAILSCALE_VERSION} \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* diff --git a/integration/acl_test.go b/integration/acl_test.go index 654f557dde..ebaf812938 100644 --- a/integration/acl_test.go +++ b/integration/acl_test.go @@ -58,9 +58,9 @@ func aclScenario(t *testing.T, policy *policy.ACLPolicy, clientsPerUser int) *Sc err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{ tsic.WithDockerEntrypoint([]string{ - "/bin/bash", + "/bin/sh", "-c", - "/bin/sleep 3 ; update-ca-certificates ; python3 -m http.server --bind :: 80 & tailscaled --tun=tsdev", + "/bin/sleep 3 ; apk add python3 curl ; update-ca-certificates ; python3 -m http.server --bind :: 80 & tailscaled --tun=tsdev", }), tsic.WithDockerWorkdir("/"), }, diff --git a/integration/scenario.go b/integration/scenario.go index 2d3f28368a..1c54ef0536 100644 --- a/integration/scenario.go +++ b/integration/scenario.go @@ -34,33 +34,34 @@ var ( tailscaleVersions2021 = []string{ "head", "unstable", - "1.46.1", - "1.44.2", - "1.42.0", - "1.40.0", - "1.38.4", - "1.36.2", - "1.34.2", - "1.32.3", - "1.30.2", + "1.48", + "1.46", + "1.44", + "1.42", + "1.40", + "1.38", + "1.36", + "1.34", + "1.32", + "1.30", } tailscaleVersions2019 = []string{ - "1.28.0", - "1.26.2", - "1.24.2", - "1.22.2", - "1.20.4", + "1.28", + "1.26", + "1.24", + "1.22", + "1.20", + "1.18", + "1.16", } // tailscaleVersionsUnavailable = []string{ // // These versions seem to fail when fetching from apt. - // "1.18.2", - // "1.16.2", - // "1.14.6", - // "1.12.4", - // "1.10.2", - // "1.8.7", + // "1.14.6", + // "1.12.4", + // "1.10.2", + // "1.8.7", // }. // TailscaleVersions represents a list of Tailscale versions the suite diff --git a/integration/ssh_test.go b/integration/ssh_test.go index c8963b1991..ce5ecc651e 100644 --- a/integration/ssh_test.go +++ b/integration/ssh_test.go @@ -41,50 +41,69 @@ var retry = func(times int, sleepInterval time.Duration, return result, stderr, err } -func TestSSHOneUserAllToAll(t *testing.T) { - IntegrationSkip(t) - t.Parallel() - +func sshScenario(t *testing.T, policy *policy.ACLPolicy, clientsPerUser int) *Scenario { + t.Helper() scenario, err := NewScenario() - if err != nil { - t.Errorf("failed to create scenario: %s", err) - } + assert.NoError(t, err) spec := map[string]int{ - "user1": len(TailscaleVersions) - 5, + "user1": clientsPerUser, + "user2": clientsPerUser, } err = scenario.CreateHeadscaleEnv(spec, - []tsic.Option{tsic.WithSSH()}, - hsic.WithACLPolicy( - &policy.ACLPolicy{ - Groups: map[string][]string{ - "group:integration-test": {"user1"}, - }, - ACLs: []policy.ACL{ - { - Action: "accept", - Sources: []string{"*"}, - Destinations: []string{"*:*"}, - }, - }, - SSHs: []policy.SSH{ - { - Action: "accept", - Sources: []string{"group:integration-test"}, - Destinations: []string{"group:integration-test"}, - Users: []string{"ssh-it-user"}, - }, - }, - }, - ), + []tsic.Option{ + tsic.WithDockerEntrypoint([]string{ + "/bin/sh", + "-c", + "/bin/sleep 3 ; apk add ssh ; update-ca-certificates ; tailscaled --tun=tsdev", + }), + tsic.WithDockerWorkdir("/"), + }, + hsic.WithACLPolicy(policy), + hsic.WithTestName("ssh"), hsic.WithConfigEnv(map[string]string{ "HEADSCALE_EXPERIMENTAL_FEATURE_SSH": "1", }), ) - if err != nil { - t.Errorf("failed to create headscale environment: %s", err) - } + assert.NoError(t, err) + + err = scenario.WaitForTailscaleSync() + assert.NoError(t, err) + + _, err = scenario.ListTailscaleClientsFQDNs() + assert.NoError(t, err) + + return scenario +} + +func TestSSHOneUserAllToAll(t *testing.T) { + IntegrationSkip(t) + t.Parallel() + + scenario := sshScenario(t, + &policy.ACLPolicy{ + Groups: map[string][]string{ + "group:integration-test": {"user1"}, + }, + ACLs: []policy.ACL{ + { + Action: "accept", + Sources: []string{"*"}, + Destinations: []string{"*:*"}, + }, + }, + SSHs: []policy.SSH{ + { + Action: "accept", + Sources: []string{"group:integration-test"}, + Destinations: []string{"group:integration-test"}, + Users: []string{"ssh-it-user"}, + }, + }, + }, + len(TailscaleVersions)-5, + ) allClients, err := scenario.ListTailscaleClients() if err != nil { @@ -121,47 +140,29 @@ func TestSSHMultipleUsersAllToAll(t *testing.T) { IntegrationSkip(t) t.Parallel() - scenario, err := NewScenario() - if err != nil { - t.Errorf("failed to create scenario: %s", err) - } - - spec := map[string]int{ - "user1": len(TailscaleVersions) - 5, - "user2": len(TailscaleVersions) - 5, - } - - err = scenario.CreateHeadscaleEnv(spec, - []tsic.Option{tsic.WithSSH()}, - hsic.WithACLPolicy( - &policy.ACLPolicy{ - Groups: map[string][]string{ - "group:integration-test": {"user1", "user2"}, - }, - ACLs: []policy.ACL{ - { - Action: "accept", - Sources: []string{"*"}, - Destinations: []string{"*:*"}, - }, + scenario := sshScenario(t, + &policy.ACLPolicy{ + Groups: map[string][]string{ + "group:integration-test": {"user1", "user2"}, + }, + ACLs: []policy.ACL{ + { + Action: "accept", + Sources: []string{"*"}, + Destinations: []string{"*:*"}, }, - SSHs: []policy.SSH{ - { - Action: "accept", - Sources: []string{"group:integration-test"}, - Destinations: []string{"group:integration-test"}, - Users: []string{"ssh-it-user"}, - }, + }, + SSHs: []policy.SSH{ + { + Action: "accept", + Sources: []string{"group:integration-test"}, + Destinations: []string{"group:integration-test"}, + Users: []string{"ssh-it-user"}, }, }, - ), - hsic.WithConfigEnv(map[string]string{ - "HEADSCALE_EXPERIMENTAL_FEATURE_SSH": "1", - }), + }, + len(TailscaleVersions)-5, ) - if err != nil { - t.Errorf("failed to create headscale environment: %s", err) - } nsOneClients, err := scenario.ListTailscaleClients("user1") if err != nil { @@ -204,40 +205,22 @@ func TestSSHNoSSHConfigured(t *testing.T) { IntegrationSkip(t) t.Parallel() - scenario, err := NewScenario() - if err != nil { - t.Errorf("failed to create scenario: %s", err) - } - - spec := map[string]int{ - "user1": len(TailscaleVersions) - 5, - } - - err = scenario.CreateHeadscaleEnv(spec, - []tsic.Option{tsic.WithSSH()}, - hsic.WithACLPolicy( - &policy.ACLPolicy{ - Groups: map[string][]string{ - "group:integration-test": {"user1"}, - }, - ACLs: []policy.ACL{ - { - Action: "accept", - Sources: []string{"*"}, - Destinations: []string{"*:*"}, - }, + scenario := sshScenario(t, + &policy.ACLPolicy{ + Groups: map[string][]string{ + "group:integration-test": {"user1"}, + }, + ACLs: []policy.ACL{ + { + Action: "accept", + Sources: []string{"*"}, + Destinations: []string{"*:*"}, }, - SSHs: []policy.SSH{}, }, - ), - hsic.WithTestName("sshnoneconfigured"), - hsic.WithConfigEnv(map[string]string{ - "HEADSCALE_EXPERIMENTAL_FEATURE_SSH": "1", - }), + SSHs: []policy.SSH{}, + }, + len(TailscaleVersions)-5, ) - if err != nil { - t.Errorf("failed to create headscale environment: %s", err) - } allClients, err := scenario.ListTailscaleClients() if err != nil { @@ -274,47 +257,29 @@ func TestSSHIsBlockedInACL(t *testing.T) { IntegrationSkip(t) t.Parallel() - scenario, err := NewScenario() - if err != nil { - t.Errorf("failed to create scenario: %s", err) - } - - spec := map[string]int{ - "user1": len(TailscaleVersions) - 5, - } - - err = scenario.CreateHeadscaleEnv(spec, - []tsic.Option{tsic.WithSSH()}, - hsic.WithACLPolicy( - &policy.ACLPolicy{ - Groups: map[string][]string{ - "group:integration-test": {"user1"}, - }, - ACLs: []policy.ACL{ - { - Action: "accept", - Sources: []string{"*"}, - Destinations: []string{"*:80"}, - }, + scenario := sshScenario(t, + &policy.ACLPolicy{ + Groups: map[string][]string{ + "group:integration-test": {"user1"}, + }, + ACLs: []policy.ACL{ + { + Action: "accept", + Sources: []string{"*"}, + Destinations: []string{"*:80"}, }, - SSHs: []policy.SSH{ - { - Action: "accept", - Sources: []string{"group:integration-test"}, - Destinations: []string{"group:integration-test"}, - Users: []string{"ssh-it-user"}, - }, + }, + SSHs: []policy.SSH{ + { + Action: "accept", + Sources: []string{"group:integration-test"}, + Destinations: []string{"group:integration-test"}, + Users: []string{"ssh-it-user"}, }, }, - ), - hsic.WithTestName("sshisblockedinacl"), - hsic.WithConfigEnv(map[string]string{ - "HEADSCALE_EXPERIMENTAL_FEATURE_SSH": "1", - }), + }, + len(TailscaleVersions)-5, ) - if err != nil { - t.Errorf("failed to create headscale environment: %s", err) - } allClients, err := scenario.ListTailscaleClients() if err != nil { @@ -351,55 +316,36 @@ func TestSSUserOnlyIsolation(t *testing.T) { IntegrationSkip(t) t.Parallel() - scenario, err := NewScenario() - if err != nil { - t.Errorf("failed to create scenario: %s", err) - } - - spec := map[string]int{ - "useracl1": len(TailscaleVersions) - 5, - "useracl2": len(TailscaleVersions) - 5, - } - - err = scenario.CreateHeadscaleEnv(spec, - []tsic.Option{tsic.WithSSH()}, - hsic.WithACLPolicy( - &policy.ACLPolicy{ - Groups: map[string][]string{ - "group:ssh1": {"useracl1"}, - "group:ssh2": {"useracl2"}, + scenario := sshScenario(t, + &policy.ACLPolicy{ + Groups: map[string][]string{ + "group:ssh1": {"user1"}, + "group:ssh2": {"user2"}, + }, + ACLs: []policy.ACL{ + { + Action: "accept", + Sources: []string{"*"}, + Destinations: []string{"*:*"}, }, - ACLs: []policy.ACL{ - { - Action: "accept", - Sources: []string{"*"}, - Destinations: []string{"*:*"}, - }, + }, + SSHs: []policy.SSH{ + { + Action: "accept", + Sources: []string{"group:ssh1"}, + Destinations: []string{"group:ssh1"}, + Users: []string{"ssh-it-user"}, }, - SSHs: []policy.SSH{ - { - Action: "accept", - Sources: []string{"group:ssh1"}, - Destinations: []string{"group:ssh1"}, - Users: []string{"ssh-it-user"}, - }, - { - Action: "accept", - Sources: []string{"group:ssh2"}, - Destinations: []string{"group:ssh2"}, - Users: []string{"ssh-it-user"}, - }, + { + Action: "accept", + Sources: []string{"group:ssh2"}, + Destinations: []string{"group:ssh2"}, + Users: []string{"ssh-it-user"}, }, }, - ), - hsic.WithTestName("sshtwouseraclblock"), - hsic.WithConfigEnv(map[string]string{ - "HEADSCALE_EXPERIMENTAL_FEATURE_SSH": "1", - }), + }, + len(TailscaleVersions)-5, ) - if err != nil { - t.Errorf("failed to create headscale environment: %s", err) - } ssh1Clients, err := scenario.ListTailscaleClients("useracl1") if err != nil { diff --git a/integration/tsic/tsic.go b/integration/tsic/tsic.go index ecf293bd6f..41b445515b 100644 --- a/integration/tsic/tsic.go +++ b/integration/tsic/tsic.go @@ -165,7 +165,7 @@ func New( network: network, withEntrypoint: []string{ - "/bin/bash", + "/bin/sh", "-c", "/bin/sleep 3 ; update-ca-certificates ; tailscaled --tun=tsdev", }, @@ -204,13 +204,44 @@ func New( return nil, err } - container, err := pool.BuildAndRunWithBuildOptions( - createTailscaleBuildOptions(version), - tailscaleOptions, - dockertestutil.DockerRestartPolicy, - dockertestutil.DockerAllowLocalIPv6, - dockertestutil.DockerAllowNetworkAdministration, - ) + var container *dockertest.Resource + switch version { + case "head": + buildOptions := &dockertest.BuildOptions{ + Dockerfile: "Dockerfile.tailscale-HEAD", + ContextDir: dockerContextPath, + BuildArgs: []docker.BuildArg{}, + } + + container, err = pool.BuildAndRunWithBuildOptions( + buildOptions, + tailscaleOptions, + dockertestutil.DockerRestartPolicy, + dockertestutil.DockerAllowLocalIPv6, + dockertestutil.DockerAllowNetworkAdministration, + ) + case "unstable": + tailscaleOptions.Repository = "tailscale/tailscale" + tailscaleOptions.Tag = version + + container, err = pool.RunWithOptions( + tailscaleOptions, + dockertestutil.DockerRestartPolicy, + dockertestutil.DockerAllowLocalIPv6, + dockertestutil.DockerAllowNetworkAdministration, + ) + default: + tailscaleOptions.Repository = "tailscale/tailscale" + tailscaleOptions.Tag = "v" + version + + container, err = pool.RunWithOptions( + tailscaleOptions, + dockertestutil.DockerRestartPolicy, + dockertestutil.DockerAllowLocalIPv6, + dockertestutil.DockerAllowNetworkAdministration, + ) + } + if err != nil { return nil, fmt.Errorf( "could not start tailscale container (version: %s): %w", @@ -704,47 +735,3 @@ func (t *TailscaleInContainer) Curl(url string, opts ...CurlOption) (string, err func (t *TailscaleInContainer) WriteFile(path string, data []byte) error { return integrationutil.WriteFileToContainer(t.pool, t.container, path, data) } - -func createTailscaleBuildOptions(version string) *dockertest.BuildOptions { - var tailscaleBuildOptions *dockertest.BuildOptions - switch version { - case "head": - tailscaleBuildOptions = &dockertest.BuildOptions{ - Dockerfile: "Dockerfile.tailscale-HEAD", - ContextDir: dockerContextPath, - BuildArgs: []docker.BuildArg{}, - } - case "unstable": - tailscaleBuildOptions = &dockertest.BuildOptions{ - Dockerfile: "Dockerfile.tailscale", - ContextDir: dockerContextPath, - BuildArgs: []docker.BuildArg{ - { - Name: "TAILSCALE_VERSION", - Value: "*", // Installs the latest version https://askubuntu.com/a/824926 - }, - { - Name: "TAILSCALE_CHANNEL", - Value: "unstable", - }, - }, - } - default: - tailscaleBuildOptions = &dockertest.BuildOptions{ - Dockerfile: "Dockerfile.tailscale", - ContextDir: dockerContextPath, - BuildArgs: []docker.BuildArg{ - { - Name: "TAILSCALE_VERSION", - Value: version, - }, - { - Name: "TAILSCALE_CHANNEL", - Value: "stable", - }, - }, - } - } - - return tailscaleBuildOptions -}