diff --git a/integration/acl_test.go b/integration/acl_test.go index 87b016d1..75f739c0 100644 --- a/integration/acl_test.go +++ b/integration/acl_test.go @@ -58,6 +58,7 @@ var veryLargeDestination = []policyv2.AliasWithPorts{ func aclScenario( t *testing.T, policy *policyv2.Policy, + testName string, clientsPerUser int, ) *Scenario { t.Helper() @@ -81,9 +82,7 @@ func aclScenario( tsic.WithDockerWorkdir("/"), }, hsic.WithACLPolicy(policy), - hsic.WithTestName("acl"), - hsic.WithEmbeddedDERPServerOnly(), - hsic.WithTLS(), + hsic.WithTestName(testName), ) require.NoError(t, err) @@ -305,6 +304,7 @@ func TestACLHostsInNetMapTable(t *testing.T) { err = scenario.CreateHeadscaleEnv( []tsic.Option{}, + hsic.WithTestName("aclnetmap"), hsic.WithACLPolicy(&testCase.policy), ) @@ -351,6 +351,7 @@ func TestACLAllowUser80Dst(t *testing.T) { }, }, }, + "acl-allowuser80", 1, ) defer scenario.ShutdownAssertNoPanics(t) @@ -414,6 +415,7 @@ func TestACLDenyAllPort80(t *testing.T) { }, }, }, + "acl-denyport80", 4, ) defer scenario.ShutdownAssertNoPanics(t) @@ -462,6 +464,7 @@ func TestACLAllowUserDst(t *testing.T) { }, }, }, + "acl-allowuserdst", 2, ) defer scenario.ShutdownAssertNoPanics(t) @@ -524,6 +527,7 @@ func TestACLAllowStarDst(t *testing.T) { }, }, }, + "acl-allowstar", 2, ) defer scenario.ShutdownAssertNoPanics(t) @@ -591,6 +595,7 @@ func TestACLNamedHostsCanReachBySubnet(t *testing.T) { }, }, }, + "acl-namedsubnet", 3, ) defer scenario.ShutdownAssertNoPanics(t) @@ -743,6 +748,7 @@ func TestACLNamedHostsCanReach(t *testing.T) { t.Run(name, func(t *testing.T) { scenario := aclScenario(t, &testCase.policy, + "acl-namedreach", 2, ) defer scenario.ShutdownAssertNoPanics(t) @@ -1044,7 +1050,7 @@ func TestACLDevice1CanAccessDevice2(t *testing.T) { for name, testCase := range tests { t.Run(name, func(t *testing.T) { - scenario := aclScenario(t, &testCase.policy, 1) + scenario := aclScenario(t, &testCase.policy, "acl-dev1dev2", 1) defer scenario.ShutdownAssertNoPanics(t) test1ip := netip.MustParseAddr("100.64.0.1") @@ -1159,7 +1165,7 @@ func TestPolicyUpdateWhileRunningWithCLIInDatabase(t *testing.T) { tsic.WithDockerWorkdir("/"), }, hsic.WithTestName("policyreload"), - hsic.WithPolicyMode(types.PolicyModeDB), + hsic.WithPolicyMode(types.PolicyModeDB), // test updates policy at runtime via CLI ) require.NoError(t, err) @@ -1290,6 +1296,7 @@ func TestACLAutogroupMember(t *testing.T) { }, }, }, + "acl-agmember", 2, ) defer scenario.ShutdownAssertNoPanics(t) @@ -1383,8 +1390,6 @@ func TestACLAutogroupTagged(t *testing.T) { headscale, err := scenario.Headscale( hsic.WithACLPolicy(policy), hsic.WithTestName("acl-autogroup-tagged"), - hsic.WithEmbeddedDERPServerOnly(), - hsic.WithTLS(), ) require.NoError(t, err) @@ -1430,7 +1435,10 @@ func TestACLAutogroupTagged(t *testing.T) { network = networks[0] } - // Create the tailscale node with appropriate options + // Create the tailscale node with appropriate options. + // CACert and HeadscaleName are passed explicitly because + // nodes created via CreateTailscaleNode are not part of + // the standard CreateHeadscaleEnv flow. opts := []tsic.Option{ tsic.WithCACert(headscale.GetCert()), tsic.WithHeadscaleName(headscale.GetHostname()), @@ -1698,8 +1706,6 @@ func TestACLAutogroupSelf(t *testing.T) { }, hsic.WithACLPolicy(policy), hsic.WithTestName("acl-autogroup-self"), - hsic.WithEmbeddedDERPServerOnly(), - hsic.WithTLS(), ) require.NoError(t, err) @@ -1721,7 +1727,10 @@ func TestACLAutogroupSelf(t *testing.T) { authKey, err := scenario.CreatePreAuthKeyWithTags(routerUser.GetId(), true, false, []string{"tag:router-node"}) require.NoError(t, err) - // Create router node (tags come from the PreAuthKey) + // Create router node (tags come from the PreAuthKey). + // CACert and HeadscaleName are passed explicitly because + // nodes created via tsic.New are not part of the standard + // CreateHeadscaleEnv flow. routerClient, err := tsic.New( scenario.Pool(), "unstable", @@ -1917,9 +1926,7 @@ func TestACLPolicyPropagationOverTime(t *testing.T) { tsic.WithDockerWorkdir("/"), }, hsic.WithTestName("aclpropagation"), - hsic.WithPolicyMode(types.PolicyModeDB), - hsic.WithEmbeddedDERPServerOnly(), - hsic.WithTLS(), + hsic.WithPolicyMode(types.PolicyModeDB), // test updates policy at runtime via CLI ) require.NoError(t, err) @@ -2738,8 +2745,6 @@ func TestACLTagPropagation(t *testing.T) { }, hsic.WithACLPolicy(tt.policy), hsic.WithTestName("acl-tag-"+tt.name), - hsic.WithEmbeddedDERPServerOnly(), - hsic.WithTLS(), ) require.NoError(t, err) @@ -2926,8 +2931,6 @@ func TestACLTagPropagationPortSpecific(t *testing.T) { }, hsic.WithACLPolicy(policy), hsic.WithTestName("acl-tag-port-specific"), - hsic.WithEmbeddedDERPServerOnly(), - hsic.WithTLS(), ) require.NoError(t, err) @@ -3090,8 +3093,6 @@ func TestACLGroupWithUnknownUser(t *testing.T) { }, hsic.WithACLPolicy(policy), hsic.WithTestName("acl-unknown-user"), - hsic.WithEmbeddedDERPServerOnly(), - hsic.WithTLS(), ) require.NoError(t, err) @@ -3192,8 +3193,6 @@ func TestACLGroupAfterUserDeletion(t *testing.T) { }, hsic.WithACLPolicy(policy), hsic.WithTestName("acl-deleted-user"), - hsic.WithEmbeddedDERPServerOnly(), - hsic.WithTLS(), hsic.WithPolicyMode(types.PolicyModeDB), // Use DB mode so policy persists after user deletion ) require.NoError(t, err) @@ -3386,9 +3385,7 @@ func TestACLGroupDeletionExactReproduction(t *testing.T) { }, hsic.WithACLPolicy(initialPolicy), hsic.WithTestName("acl-exact-repro"), - hsic.WithEmbeddedDERPServerOnly(), - hsic.WithTLS(), - hsic.WithPolicyMode(types.PolicyModeDB), + hsic.WithPolicyMode(types.PolicyModeDB), // test updates policy at runtime via CLI ) require.NoError(t, err) @@ -3565,9 +3562,7 @@ func TestACLDynamicUnknownUserAddition(t *testing.T) { }, hsic.WithACLPolicy(validPolicy), hsic.WithTestName("acl-dynamic-unknown"), - hsic.WithEmbeddedDERPServerOnly(), - hsic.WithTLS(), - hsic.WithPolicyMode(types.PolicyModeDB), + hsic.WithPolicyMode(types.PolicyModeDB), // test updates policy at runtime via CLI ) require.NoError(t, err) @@ -3723,9 +3718,7 @@ func TestACLDynamicUnknownUserRemoval(t *testing.T) { }, hsic.WithACLPolicy(policyWithUnknown), hsic.WithTestName("acl-unknown-removal"), - hsic.WithEmbeddedDERPServerOnly(), - hsic.WithTLS(), - hsic.WithPolicyMode(types.PolicyModeDB), + hsic.WithPolicyMode(types.PolicyModeDB), // test updates policy at runtime via CLI ) require.NoError(t, err) diff --git a/integration/api_auth_test.go b/integration/api_auth_test.go index 2b5e1726..f074196d 100644 --- a/integration/api_auth_test.go +++ b/integration/api_auth_test.go @@ -435,7 +435,6 @@ func TestGRPCAuthenticationBypass(t *testing.T) { err = scenario.CreateHeadscaleEnv( []tsic.Option{}, hsic.WithTestName("grpcauthtest"), - hsic.WithTLS(), hsic.WithConfigEnv(map[string]string{ // Enable gRPC on the standard port "HEADSCALE_GRPC_LISTEN_ADDR": "0.0.0.0:50443", @@ -560,7 +559,6 @@ func TestCLIWithConfigAuthenticationBypass(t *testing.T) { err = scenario.CreateHeadscaleEnv( []tsic.Option{}, hsic.WithTestName("cliconfigauth"), - hsic.WithTLS(), hsic.WithConfigEnv(map[string]string{ "HEADSCALE_GRPC_LISTEN_ADDR": "0.0.0.0:50443", }), diff --git a/integration/auth_key_test.go b/integration/auth_key_test.go index 74482e19..21166907 100644 --- a/integration/auth_key_test.go +++ b/integration/auth_key_test.go @@ -35,14 +35,7 @@ func TestAuthKeyLogoutAndReloginSameUser(t *testing.T) { defer scenario.ShutdownAssertNoPanics(t) opts := []hsic.Option{ - hsic.WithTestName("pingallbyip"), - hsic.WithEmbeddedDERPServerOnly(), - hsic.WithDERPAsIP(), - } - if https { - opts = append(opts, []hsic.Option{ - hsic.WithTLS(), - }...) + hsic.WithTestName("authkey-relogsame"), } err = scenario.CreateHeadscaleEnv([]tsic.Option{}, opts...) @@ -241,8 +234,6 @@ func TestAuthKeyLogoutAndReloginNewUser(t *testing.T) { err = scenario.CreateHeadscaleEnv([]tsic.Option{}, hsic.WithTestName("keyrelognewuser"), - hsic.WithTLS(), - hsic.WithDERPAsIP(), ) requireNoErrHeadscaleEnv(t, err) @@ -375,13 +366,7 @@ func TestAuthKeyLogoutAndReloginSameUserExpiredKey(t *testing.T) { defer scenario.ShutdownAssertNoPanics(t) opts := []hsic.Option{ - hsic.WithTestName("pingallbyip"), - hsic.WithDERPAsIP(), - } - if https { - opts = append(opts, []hsic.Option{ - hsic.WithTLS(), - }...) + hsic.WithTestName("authkey-rlogexpired"), } err = scenario.CreateHeadscaleEnv([]tsic.Option{}, opts...) @@ -503,7 +488,7 @@ func TestAuthKeyDeleteKey(t *testing.T) { require.NoError(t, err) defer scenario.ShutdownAssertNoPanics(t) - err = scenario.CreateHeadscaleEnv([]tsic.Option{}, hsic.WithTestName("delkey"), hsic.WithTLS(), hsic.WithDERPAsIP()) + err = scenario.CreateHeadscaleEnv([]tsic.Option{}, hsic.WithTestName("delkey")) requireNoErrHeadscaleEnv(t, err) headscale, err := scenario.Headscale() @@ -621,7 +606,6 @@ func TestAuthKeyLogoutAndReloginRoutesPreserved(t *testing.T) { tsic.WithExtraLoginArgs([]string{"--advertise-routes=" + advertiseRoute}), }, hsic.WithTestName("routelogout"), - hsic.WithTLS(), hsic.WithACLPolicy( &policyv2.Policy{ ACLs: []policyv2.ACL{ diff --git a/integration/auth_oidc_test.go b/integration/auth_oidc_test.go index dadaa9a4..7681f0d8 100644 --- a/integration/auth_oidc_test.go +++ b/integration/auth_oidc_test.go @@ -51,11 +51,13 @@ func TestOIDCAuthenticationPingAll(t *testing.T) { "HEADSCALE_OIDC_CLIENT_SECRET_PATH": "${CREDENTIALS_DIRECTORY_TEST}/hs_client_oidc_secret", } + // OIDC tests configure the mock OIDC provider via environment + // variables and inject the client secret as a file. This + // pattern is shared by all OIDC integration tests. err = scenario.CreateHeadscaleEnvWithLoginURL( nil, hsic.WithTestName("oidcauthping"), hsic.WithConfigEnv(oidcMap), - hsic.WithTLS(), hsic.WithFileInContainer("/tmp/hs_client_oidc_secret", []byte(scenario.mockOIDC.ClientSecret())), ) requireNoErrHeadscaleEnv(t, err) @@ -374,7 +376,6 @@ func TestOIDC024UserCreation(t *testing.T) { nil, hsic.WithTestName("oidcmigration"), hsic.WithConfigEnv(oidcMap), - hsic.WithTLS(), hsic.WithFileInContainer("/tmp/hs_client_oidc_secret", []byte(scenario.mockOIDC.ClientSecret())), ) requireNoErrHeadscaleEnv(t, err) @@ -432,7 +433,6 @@ func TestOIDCAuthenticationWithPKCE(t *testing.T) { nil, hsic.WithTestName("oidcauthpkce"), hsic.WithConfigEnv(oidcMap), - hsic.WithTLS(), hsic.WithFileInContainer("/tmp/hs_client_oidc_secret", []byte(scenario.mockOIDC.ClientSecret())), ) requireNoErrHeadscaleEnv(t, err) @@ -487,12 +487,9 @@ func TestOIDCReloginSameNodeNewUser(t *testing.T) { err = scenario.CreateHeadscaleEnvWithLoginURL( nil, - hsic.WithTestName("oidcauthrelog"), + hsic.WithTestName("oidc-authrelog"), hsic.WithConfigEnv(oidcMap), - hsic.WithTLS(), hsic.WithFileInContainer("/tmp/hs_client_oidc_secret", []byte(scenario.mockOIDC.ClientSecret())), - hsic.WithEmbeddedDERPServerOnly(), - hsic.WithDERPAsIP(), ) requireNoErrHeadscaleEnv(t, err) @@ -899,11 +896,9 @@ func TestOIDCFollowUpUrl(t *testing.T) { err = scenario.CreateHeadscaleEnvWithLoginURL( nil, - hsic.WithTestName("oidcauthrelog"), + hsic.WithTestName("oidc-followup"), hsic.WithConfigEnv(oidcMap), - hsic.WithTLS(), hsic.WithFileInContainer("/tmp/hs_client_oidc_secret", []byte(scenario.mockOIDC.ClientSecret())), - hsic.WithEmbeddedDERPServerOnly(), ) require.NoError(t, err) @@ -1011,9 +1006,7 @@ func TestOIDCMultipleOpenedLoginUrls(t *testing.T) { nil, hsic.WithTestName("oidcauthrelog"), hsic.WithConfigEnv(oidcMap), - hsic.WithTLS(), hsic.WithFileInContainer("/tmp/hs_client_oidc_secret", []byte(scenario.mockOIDC.ClientSecret())), - hsic.WithEmbeddedDERPServerOnly(), ) require.NoError(t, err) @@ -1145,10 +1138,7 @@ func TestOIDCReloginSameNodeSameUser(t *testing.T) { nil, hsic.WithTestName("oidcsameuser"), hsic.WithConfigEnv(oidcMap), - hsic.WithTLS(), hsic.WithFileInContainer("/tmp/hs_client_oidc_secret", []byte(scenario.mockOIDC.ClientSecret())), - hsic.WithEmbeddedDERPServerOnly(), - hsic.WithDERPAsIP(), ) requireNoErrHeadscaleEnv(t, err) @@ -1373,10 +1363,7 @@ func TestOIDCExpiryAfterRestart(t *testing.T) { nil, hsic.WithTestName("oidcexpiry"), hsic.WithConfigEnv(oidcMap), - hsic.WithTLS(), hsic.WithFileInContainer("/tmp/hs_client_oidc_secret", []byte(scenario.mockOIDC.ClientSecret())), - hsic.WithEmbeddedDERPServerOnly(), - hsic.WithDERPAsIP(), ) requireNoErrHeadscaleEnv(t, err) @@ -1524,7 +1511,6 @@ func TestOIDCACLPolicyOnJoin(t *testing.T) { }, hsic.WithTestName("oidcaclpolicy"), hsic.WithConfigEnv(oidcMap), - hsic.WithTLS(), hsic.WithFileInContainer("/tmp/hs_client_oidc_secret", []byte(scenario.mockOIDC.ClientSecret())), hsic.WithACLPolicy( &policyv2.Policy{ @@ -1801,10 +1787,7 @@ func TestOIDCReloginSameUserRoutesPreserved(t *testing.T) { }, hsic.WithTestName("oidcrouterelogin"), hsic.WithConfigEnv(oidcMap), - hsic.WithTLS(), hsic.WithFileInContainer("/tmp/hs_client_oidc_secret", []byte(scenario.mockOIDC.ClientSecret())), - hsic.WithEmbeddedDERPServerOnly(), - hsic.WithDERPAsIP(), hsic.WithACLPolicy( &policyv2.Policy{ ACLs: []policyv2.ACL{ diff --git a/integration/auth_web_flow_test.go b/integration/auth_web_flow_test.go index d00c5fdd..06d7ca96 100644 --- a/integration/auth_web_flow_test.go +++ b/integration/auth_web_flow_test.go @@ -32,9 +32,6 @@ func TestAuthWebFlowAuthenticationPingAll(t *testing.T) { err = scenario.CreateHeadscaleEnvWithLoginURL( nil, hsic.WithTestName("webauthping"), - hsic.WithEmbeddedDERPServerOnly(), - hsic.WithDERPAsIP(), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -73,8 +70,6 @@ func TestAuthWebFlowLogoutAndReloginSameUser(t *testing.T) { err = scenario.CreateHeadscaleEnvWithLoginURL( nil, hsic.WithTestName("weblogout"), - hsic.WithDERPAsIP(), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -239,8 +234,6 @@ func TestAuthWebFlowLogoutAndReloginNewUser(t *testing.T) { err = scenario.CreateHeadscaleEnvWithLoginURL( nil, hsic.WithTestName("webflowrelnewuser"), - hsic.WithDERPAsIP(), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) diff --git a/integration/cli_test.go b/integration/cli_test.go index a7696bb4..1ceeb3ae 100644 --- a/integration/cli_test.go +++ b/integration/cli_test.go @@ -58,7 +58,7 @@ func TestUserCommand(t *testing.T) { require.NoError(t, err) defer scenario.ShutdownAssertNoPanics(t) - err = scenario.CreateHeadscaleEnv([]tsic.Option{}, hsic.WithTestName("clins")) + err = scenario.CreateHeadscaleEnv([]tsic.Option{}, hsic.WithTestName("cli-user")) require.NoError(t, err) headscale, err := scenario.Headscale() @@ -588,9 +588,7 @@ func TestPreAuthKeyCorrectUserLoggedInCommand(t *testing.T) { err = scenario.CreateHeadscaleEnv( []tsic.Option{}, - hsic.WithTestName("clipak"), - hsic.WithEmbeddedDERPServerOnly(), - hsic.WithTLS(), + hsic.WithTestName("cli-paklogin"), ) require.NoError(t, err) @@ -699,8 +697,6 @@ func TestTaggedNodesCLIOutput(t *testing.T) { err = scenario.CreateHeadscaleEnv( []tsic.Option{}, hsic.WithTestName("tagcli"), - hsic.WithEmbeddedDERPServerOnly(), - hsic.WithTLS(), ) require.NoError(t, err) @@ -811,7 +807,7 @@ func TestApiKeyCommand(t *testing.T) { require.NoError(t, err) defer scenario.ShutdownAssertNoPanics(t) - err = scenario.CreateHeadscaleEnv([]tsic.Option{}, hsic.WithTestName("clins")) + err = scenario.CreateHeadscaleEnv([]tsic.Option{}, hsic.WithTestName("cli-apikey")) require.NoError(t, err) headscale, err := scenario.Headscale() @@ -1058,7 +1054,7 @@ func TestNodeCommand(t *testing.T) { require.NoError(t, err) defer scenario.ShutdownAssertNoPanics(t) - err = scenario.CreateHeadscaleEnv([]tsic.Option{}, hsic.WithTestName("clins")) + err = scenario.CreateHeadscaleEnv([]tsic.Option{}, hsic.WithTestName("cli-node")) require.NoError(t, err) headscale, err := scenario.Headscale() @@ -1319,7 +1315,7 @@ func TestNodeExpireCommand(t *testing.T) { require.NoError(t, err) defer scenario.ShutdownAssertNoPanics(t) - err = scenario.CreateHeadscaleEnv([]tsic.Option{}, hsic.WithTestName("clins")) + err = scenario.CreateHeadscaleEnv([]tsic.Option{}, hsic.WithTestName("cli-nodeexpire")) require.NoError(t, err) headscale, err := scenario.Headscale() @@ -1454,7 +1450,7 @@ func TestNodeRenameCommand(t *testing.T) { require.NoError(t, err) defer scenario.ShutdownAssertNoPanics(t) - err = scenario.CreateHeadscaleEnv([]tsic.Option{}, hsic.WithTestName("clins")) + err = scenario.CreateHeadscaleEnv([]tsic.Option{}, hsic.WithTestName("cli-noderename")) require.NoError(t, err) headscale, err := scenario.Headscale() @@ -1634,9 +1630,9 @@ func TestPolicyCommand(t *testing.T) { err = scenario.CreateHeadscaleEnv( []tsic.Option{}, - hsic.WithTestName("clins"), + hsic.WithTestName("cli-policy"), hsic.WithConfigEnv(map[string]string{ - "HEADSCALE_POLICY_MODE": "database", + "HEADSCALE_POLICY_MODE": "database", // test sets/gets policy via CLI }), ) require.NoError(t, err) @@ -1719,9 +1715,9 @@ func TestPolicyBrokenConfigCommand(t *testing.T) { err = scenario.CreateHeadscaleEnv( []tsic.Option{}, - hsic.WithTestName("clins"), + hsic.WithTestName("cli-policybad"), hsic.WithConfigEnv(map[string]string{ - "HEADSCALE_POLICY_MODE": "database", + "HEADSCALE_POLICY_MODE": "database", // test sets invalid policy via CLI }), ) require.NoError(t, err) diff --git a/integration/derp_verify_endpoint_test.go b/integration/derp_verify_endpoint_test.go index 1cc87de3..4abf6bec 100644 --- a/integration/derp_verify_endpoint_test.go +++ b/integration/derp_verify_endpoint_test.go @@ -32,7 +32,7 @@ func TestDERPVerifyEndpoint(t *testing.T) { headscalePort := 8080 // Create cert for headscale - certHeadscale, keyHeadscale, err := integrationutil.CreateCertificate(hostname) + caHeadscale, certHeadscale, keyHeadscale, err := integrationutil.CreateCertificate(hostname) require.NoError(t, err) spec := ScenarioSpec{ @@ -46,7 +46,7 @@ func TestDERPVerifyEndpoint(t *testing.T) { defer scenario.ShutdownAssertNoPanics(t) derper, err := scenario.CreateDERPServer("head", - dsic.WithCACert(certHeadscale), + dsic.WithCACert(caHeadscale), dsic.WithVerifyClientURL(fmt.Sprintf("https://%s/verify", net.JoinHostPort(hostname, strconv.Itoa(headscalePort)))), ) require.NoError(t, err) @@ -72,10 +72,18 @@ func TestDERPVerifyEndpoint(t *testing.T) { }, } + // WithHostname is used instead of WithTestName because the hostname + // must match the pre-generated TLS certificate created above. + // The test name "derpverify" is embedded in the hostname variable. + // + // WithCACert passes the external DERP server's certificate so + // tailscale clients trust it. WithCustomTLS and WithDERPConfig + // configure headscale to use the external DERP server created + // above instead of the default embedded one. err = scenario.CreateHeadscaleEnv([]tsic.Option{tsic.WithCACert(derper.GetCert())}, hsic.WithHostname(hostname), hsic.WithPort(headscalePort), - hsic.WithCustomTLS(certHeadscale, keyHeadscale), + hsic.WithCustomTLS(caHeadscale, certHeadscale, keyHeadscale), hsic.WithDERPConfig(derpMap)) requireNoErrHeadscaleEnv(t, err) diff --git a/integration/dns_test.go b/integration/dns_test.go index 648f2049..a0accc35 100644 --- a/integration/dns_test.go +++ b/integration/dns_test.go @@ -104,8 +104,6 @@ func TestResolveMagicDNSExtraRecordsPath(t *testing.T) { "HEADSCALE_DNS_EXTRA_RECORDS_PATH": erPath, }), hsic.WithFileInContainer(erPath, b), - hsic.WithEmbeddedDERPServerOnly(), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) diff --git a/integration/dsic/dsic.go b/integration/dsic/dsic.go index e25e2bc4..c442e655 100644 --- a/integration/dsic/dsic.go +++ b/integration/dsic/dsic.go @@ -40,6 +40,7 @@ type DERPServerInContainer struct { stunPort int derpPort int caCerts [][]byte + tlsCACert []byte tlsCert []byte tlsKey []byte withExtraHosts []string @@ -160,22 +161,27 @@ func New( hostname = fmt.Sprintf("derp-%s-%s", strings.ReplaceAll(version, ".", "-"), hash) } - tlsCert, tlsKey, err := integrationutil.CreateCertificate(hostname) + tlsCACert, tlsCert, tlsKey, err := integrationutil.CreateCertificate(hostname) if err != nil { - return nil, fmt.Errorf("creating certificates for headscale test: %w", err) + return nil, fmt.Errorf("creating certificates for derp test: %w", err) } dsic := &DERPServerInContainer{ - version: version, - hostname: hostname, - pool: pool, - networks: networks, - tlsCert: tlsCert, - tlsKey: tlsKey, - stunPort: 3478, //nolint - derpPort: 443, //nolint + version: version, + hostname: hostname, + pool: pool, + networks: networks, + tlsCACert: tlsCACert, + tlsCert: tlsCert, + tlsKey: tlsKey, + stunPort: 3478, //nolint + derpPort: 443, //nolint } + // Install the CA cert so the DERP server trusts its own certificate + // and any headscale CA certs passed via WithCACert. + dsic.caCerts = append(dsic.caCerts, tlsCACert) + for _, opt := range opts { opt(dsic) } @@ -297,9 +303,10 @@ func (t *DERPServerInContainer) Shutdown() error { return t.pool.Purge(t.container) } -// GetCert returns the TLS certificate of the DERPer instance. +// GetCert returns the CA certificate that clients should trust to +// verify this DERP server's TLS certificate. func (t *DERPServerInContainer) GetCert() []byte { - return t.tlsCert + return t.tlsCACert } // Hostname returns the hostname of the DERPer instance. diff --git a/integration/embedded_derp_test.go b/integration/embedded_derp_test.go index 89154f63..97c68e49 100644 --- a/integration/embedded_derp_test.go +++ b/integration/embedded_derp_test.go @@ -28,7 +28,7 @@ func TestDERPServerScenario(t *testing.T) { }, } - derpServerScenario(t, spec, false, func(scenario *Scenario) { + derpServerScenario(t, spec, "derp-tcp", false, func(scenario *Scenario) { allClients, err := scenario.ListTailscaleClients() requireNoErrListClients(t, err) t.Logf("checking %d clients for websocket connections", len(allClients)) @@ -78,7 +78,7 @@ func TestDERPServerWebsocketScenario(t *testing.T) { }, } - derpServerScenario(t, spec, true, func(scenario *Scenario) { + derpServerScenario(t, spec, "derp-ws", true, func(scenario *Scenario) { allClients, err := scenario.ListTailscaleClients() requireNoErrListClients(t, err) t.Logf("checking %d clients for websocket connections", len(allClients)) @@ -103,6 +103,7 @@ func TestDERPServerWebsocketScenario(t *testing.T) { func derpServerScenario( t *testing.T, spec ScenarioSpec, + testName string, websocket bool, furtherAssertions ...func(*Scenario), ) { @@ -117,11 +118,11 @@ func derpServerScenario( []tsic.Option{ tsic.WithWebsocketDERP(websocket), }, - hsic.WithTestName("derpserver"), + hsic.WithTestName(testName), + // Expose STUN port for DERP NAT traversal. hsic.WithExtraPorts([]string{"3478/udp"}), - hsic.WithEmbeddedDERPServerOnly(), + // DERP clients expect the server on the standard HTTPS port. hsic.WithPort(443), - hsic.WithTLS(), hsic.WithConfigEnv(map[string]string{ "HEADSCALE_DERP_AUTO_UPDATE_ENABLED": "true", "HEADSCALE_DERP_UPDATE_FREQUENCY": "10s", diff --git a/integration/general_test.go b/integration/general_test.go index 42ba58bf..d3c03b0d 100644 --- a/integration/general_test.go +++ b/integration/general_test.go @@ -41,8 +41,9 @@ func TestPingAllByIP(t *testing.T) { err = scenario.CreateHeadscaleEnv( []tsic.Option{}, hsic.WithTestName("pingallbyip"), - hsic.WithEmbeddedDERPServerOnly(), - hsic.WithTLS(), + // All other tests use the default sequential allocation. + // This test uses random allocation to ensure it does not + // break basic connectivity. hsic.WithIPAllocationStrategy(types.IPAllocationStrategyRandom), ) requireNoErrHeadscaleEnv(t, err) @@ -102,6 +103,12 @@ func TestPingAllByIPPublicDERP(t *testing.T) { err = scenario.CreateHeadscaleEnv( []tsic.Option{}, hsic.WithTestName("pingallbyippubderp"), + // Explicitly use public DERP relays instead of the embedded + // DERP server to verify connectivity through Tailscale's + // infrastructure. TLS is disabled because the headscale + // server does not need to terminate TLS for this test. + hsic.WithPublicDERP(), + hsic.WithoutTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -128,6 +135,8 @@ func TestEphemeral(t *testing.T) { testEphemeralWithOptions(t, hsic.WithTestName("ephemeral")) } +// TestEphemeralInAlternateTimezone verifies that ephemeral node +// expiry works correctly when the server runs in a non-UTC timezone. func TestEphemeralInAlternateTimezone(t *testing.T) { testEphemeralWithOptions( t, @@ -387,8 +396,6 @@ func TestTaildrop(t *testing.T) { err = scenario.CreateHeadscaleEnv([]tsic.Option{}, hsic.WithTestName("taildrop"), - hsic.WithEmbeddedDERPServerOnly(), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -1403,9 +1410,6 @@ func TestPingAllByIPManyUpDown(t *testing.T) { err = scenario.CreateHeadscaleEnv( []tsic.Option{}, hsic.WithTestName("pingallbyipmany"), - hsic.WithEmbeddedDERPServerOnly(), - hsic.WithDERPAsIP(), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -1512,8 +1516,6 @@ func Test2118DeletingOnlineNodePanics(t *testing.T) { err = scenario.CreateHeadscaleEnv( []tsic.Option{}, hsic.WithTestName("deletenocrash"), - hsic.WithEmbeddedDERPServerOnly(), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) diff --git a/integration/hsic/config.go b/integration/hsic/config.go index 8ceca90f..961c92f1 100644 --- a/integration/hsic/config.go +++ b/integration/hsic/config.go @@ -28,11 +28,24 @@ func DefaultConfigEnv() map[string]string { "HEADSCALE_PRIVATE_KEY_PATH": "/tmp/private.key", "HEADSCALE_NOISE_PRIVATE_KEY_PATH": "/tmp/noise_private.key", "HEADSCALE_METRICS_LISTEN_ADDR": "0.0.0.0:9090", - "HEADSCALE_DERP_URLS": "https://controlplane.tailscale.com/derpmap/default", - "HEADSCALE_DERP_AUTO_UPDATE_ENABLED": "false", - "HEADSCALE_DERP_UPDATE_FREQUENCY": "1m", "HEADSCALE_DEBUG_PORT": "40000", + // Embedded DERP is the default for test isolation. + // Tests should not depend on external DERP infrastructure. + // Use WithPublicDERP() to opt out for tests that explicitly + // need public DERP relays. + "HEADSCALE_DERP_URLS": "", + "HEADSCALE_DERP_AUTO_UPDATE_ENABLED": "false", + "HEADSCALE_DERP_UPDATE_FREQUENCY": "1m", + "HEADSCALE_DERP_SERVER_ENABLED": "true", + "HEADSCALE_DERP_SERVER_REGION_ID": "999", + "HEADSCALE_DERP_SERVER_REGION_CODE": "headscale", + "HEADSCALE_DERP_SERVER_REGION_NAME": "Headscale Embedded DERP", + "HEADSCALE_DERP_SERVER_STUN_LISTEN_ADDR": "0.0.0.0:3478", + "HEADSCALE_DERP_SERVER_PRIVATE_KEY_PATH": "/tmp/derp.key", + "DERP_DEBUG_LOGS": "true", + "DERP_PROBER_DEBUG_LOGS": "true", + // a bunch of tests (ACL/Policy) rely on predictable IP alloc, // so ensure the sequential alloc is used by default. "HEADSCALE_PREFIXES_ALLOCATION": string(types.IPAllocationStrategySequential), diff --git a/integration/hsic/hsic.go b/integration/hsic/hsic.go index cd60c20d..1323927e 100644 --- a/integration/hsic/hsic.go +++ b/integration/hsic/hsic.go @@ -82,8 +82,10 @@ type HeadscaleInContainer struct { hostPortBindings map[string][]string aclPolicy *policyv2.Policy env map[string]string + tlsCACert []byte tlsCert []byte tlsKey []byte + noTLS bool filesInContainer []fileInContainer postgres bool policyMode types.PolicyMode @@ -115,24 +117,24 @@ func WithCACert(cert []byte) Option { } } -// WithTLS creates certificates and enables HTTPS. -func WithTLS() Option { +// WithoutTLS disables the default TLS configuration. +// Most tests should not need this. Use only for tests that +// explicitly need to test non-TLS behavior. +func WithoutTLS() Option { return func(hsic *HeadscaleInContainer) { - cert, key, err := integrationutil.CreateCertificate(hsic.hostname) - if err != nil { - log.Fatalf("creating certificates for headscale test: %s", err) - } - - hsic.tlsCert = cert - hsic.tlsKey = key + hsic.noTLS = true } } // WithCustomTLS uses the given certificates for the Headscale instance. -func WithCustomTLS(cert, key []byte) Option { +// The caCert is installed into the container's trust store and returned +// by GetCert() so that clients can trust this server. +func WithCustomTLS(caCert, cert, key []byte) Option { return func(hsic *HeadscaleInContainer) { + hsic.tlsCACert = caCert hsic.tlsCert = cert hsic.tlsKey = key + hsic.caCerts = append(hsic.caCerts, caCert) } } @@ -216,25 +218,20 @@ func WithIPAllocationStrategy(strategy types.IPAllocationStrategy) Option { } } -// WithEmbeddedDERPServerOnly configures Headscale to start -// and only use the embedded DERP server. -// It requires WithTLS and WithHostnameAsServerURL to be -// set. -// -//nolint:goconst // env var values like "true" and "headscale" are clearer inline -func WithEmbeddedDERPServerOnly() Option { +// WithPublicDERP disables the embedded DERP server and restores +// the default public DERP relay configuration. Use this for tests +// that explicitly need to test public DERP behavior. +func WithPublicDERP() Option { return func(hsic *HeadscaleInContainer) { - hsic.env["HEADSCALE_DERP_URLS"] = "" - hsic.env["HEADSCALE_DERP_SERVER_ENABLED"] = "true" - hsic.env["HEADSCALE_DERP_SERVER_REGION_ID"] = "999" - hsic.env["HEADSCALE_DERP_SERVER_REGION_CODE"] = "headscale" - hsic.env["HEADSCALE_DERP_SERVER_REGION_NAME"] = "Headscale Embedded DERP" - hsic.env["HEADSCALE_DERP_SERVER_STUN_LISTEN_ADDR"] = "0.0.0.0:3478" - hsic.env["HEADSCALE_DERP_SERVER_PRIVATE_KEY_PATH"] = "/tmp/derp.key" - - // Envknob for enabling DERP debug logs - hsic.env["DERP_DEBUG_LOGS"] = "true" - hsic.env["DERP_PROBER_DEBUG_LOGS"] = "true" + hsic.env["HEADSCALE_DERP_URLS"] = "https://controlplane.tailscale.com/derpmap/default" + hsic.env["HEADSCALE_DERP_SERVER_ENABLED"] = "false" + delete(hsic.env, "HEADSCALE_DERP_SERVER_REGION_ID") + delete(hsic.env, "HEADSCALE_DERP_SERVER_REGION_CODE") + delete(hsic.env, "HEADSCALE_DERP_SERVER_REGION_NAME") + delete(hsic.env, "HEADSCALE_DERP_SERVER_STUN_LISTEN_ADDR") + delete(hsic.env, "HEADSCALE_DERP_SERVER_PRIVATE_KEY_PATH") + delete(hsic.env, "DERP_DEBUG_LOGS") + delete(hsic.env, "DERP_PROBER_DEBUG_LOGS") } } @@ -282,14 +279,6 @@ func WithTimezone(timezone string) Option { } } -// WithDERPAsIP enables using IP address instead of hostname for DERP server. -// This is useful for integration tests where DNS resolution may be unreliable. -func WithDERPAsIP() Option { - return func(hsic *HeadscaleInContainer) { - hsic.env["HEADSCALE_DEBUG_DERP_USE_IP"] = "1" - } -} - // buildEntrypoint builds the container entrypoint command based on configuration. // It constructs proper wait conditions instead of fixed sleeps: // 1. Wait for network to be ready @@ -367,6 +356,26 @@ func New( opt(hsic) } + // TLS is enabled by default for all integration tests. + // Generate a self-signed certificate if TLS was not explicitly + // disabled via WithoutTLS() and no custom cert was provided + // via WithCustomTLS(). + if !hsic.noTLS && len(hsic.tlsCert) == 0 { + caCert, cert, key, err := integrationutil.CreateCertificate(hsic.hostname) + if err != nil { + return nil, fmt.Errorf("creating default TLS certificates: %w", err) + } + + hsic.tlsCACert = caCert + hsic.tlsCert = cert + hsic.tlsKey = key + + // Install the CA cert into the headscale container's trust + // store so that tools like curl trust the server's own + // certificate. + hsic.caCerts = append(hsic.caCerts, caCert) + } + log.Println("NAME: ", hsic.hostname) portProto := fmt.Sprintf("%d/tcp", hsic.port) @@ -1030,9 +1039,10 @@ func (t *HeadscaleInContainer) getEndpoint(useIP bool) string { return "http://" + hostEndpoint } -// GetCert returns the public certificate of the HeadscaleInContainer. +// GetCert returns the CA certificate that clients should trust to +// verify this server's TLS certificate. func (t *HeadscaleInContainer) GetCert() []byte { - return t.tlsCert + return t.tlsCACert } // GetHostname returns the hostname of the HeadscaleInContainer. diff --git a/integration/integrationutil/util.go b/integration/integrationutil/util.go index 2a155619..6ae72eac 100644 --- a/integration/integrationutil/util.go +++ b/integration/integrationutil/util.go @@ -120,7 +120,11 @@ func FetchPathFromContainer( } // nolint -func CreateCertificate(hostname string) ([]byte, []byte, error) { +// CreateCertificate generates a CA certificate and a server certificate +// signed by that CA for the given hostname. It returns the CA certificate +// PEM (for trust stores), server certificate PEM, and server private key +// PEM. +func CreateCertificate(hostname string) (caCertPEM, certPEM, keyPEM []byte, err error) { // From: // https://shaneutt.com/blog/golang-ca-and-signed-cert-go/ @@ -144,7 +148,27 @@ func CreateCertificate(hostname string) ([]byte, []byte, error) { caPrivKey, err := rsa.GenerateKey(rand.Reader, 4096) if err != nil { - return nil, nil, err + return nil, nil, nil, err + } + + caBytes, err := x509.CreateCertificate( + rand.Reader, + ca, + ca, + &caPrivKey.PublicKey, + caPrivKey, + ) + if err != nil { + return nil, nil, nil, err + } + + caPEM := new(bytes.Buffer) + err = pem.Encode(caPEM, &pem.Block{ + Type: "CERTIFICATE", + Bytes: caBytes, + }) + if err != nil { + return nil, nil, nil, err } cert := &x509.Certificate{ @@ -165,7 +189,7 @@ func CreateCertificate(hostname string) ([]byte, []byte, error) { certPrivKey, err := rsa.GenerateKey(rand.Reader, 4096) if err != nil { - return nil, nil, err + return nil, nil, nil, err } certBytes, err := x509.CreateCertificate( @@ -176,30 +200,28 @@ func CreateCertificate(hostname string) ([]byte, []byte, error) { caPrivKey, ) if err != nil { - return nil, nil, err + return nil, nil, nil, err } - certPEM := new(bytes.Buffer) - - err = pem.Encode(certPEM, &pem.Block{ + serverCertPEM := new(bytes.Buffer) + err = pem.Encode(serverCertPEM, &pem.Block{ Type: "CERTIFICATE", Bytes: certBytes, }) if err != nil { - return nil, nil, err + return nil, nil, nil, err } certPrivKeyPEM := new(bytes.Buffer) - err = pem.Encode(certPrivKeyPEM, &pem.Block{ Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(certPrivKey), }) if err != nil { - return nil, nil, err + return nil, nil, nil, err } - return certPEM.Bytes(), certPrivKeyPEM.Bytes(), nil + return caPEM.Bytes(), serverCertPEM.Bytes(), certPrivKeyPEM.Bytes(), nil } func BuildExpectedOnlineMap(all map[types.NodeID][]tailcfg.MapResponse) map[types.NodeID]map[types.NodeID]bool { diff --git a/integration/route_test.go b/integration/route_test.go index 1b35a224..6ce91057 100644 --- a/integration/route_test.go +++ b/integration/route_test.go @@ -55,7 +55,7 @@ func TestEnablingRoutes(t *testing.T) { err = scenario.CreateHeadscaleEnv( []tsic.Option{tsic.WithAcceptRoutes()}, - hsic.WithTestName("clienableroute")) + hsic.WithTestName("rt-enable")) requireNoErrHeadscaleEnv(t, err) allClients, err := scenario.ListTailscaleClients() @@ -261,9 +261,7 @@ func TestHASubnetRouterFailover(t *testing.T) { err = scenario.CreateHeadscaleEnv( []tsic.Option{tsic.WithAcceptRoutes()}, - hsic.WithTestName("clienableroute"), - hsic.WithEmbeddedDERPServerOnly(), - hsic.WithTLS(), + hsic.WithTestName("rt-hafailover"), ) requireNoErrHeadscaleEnv(t, err) @@ -1363,7 +1361,7 @@ func TestSubnetRouteACL(t *testing.T) { err = scenario.CreateHeadscaleEnv([]tsic.Option{ tsic.WithAcceptRoutes(), - }, hsic.WithTestName("clienableroute"), hsic.WithACLPolicy( + }, hsic.WithTestName("rt-subnetacl"), hsic.WithACLPolicy( &policyv2.Policy{ Groups: policyv2.Groups{ policyv2.Group("group:admins"): []policyv2.Username{policyv2.Username(user + "@")}, @@ -1616,7 +1614,7 @@ func TestEnablingExitRoutes(t *testing.T) { err = scenario.CreateHeadscaleEnv([]tsic.Option{ tsic.WithExtraLoginArgs([]string{"--advertise-exit-node"}), - }, hsic.WithTestName("clienableroute")) + }, hsic.WithTestName("rt-exitroute")) requireNoErrHeadscaleEnv(t, err) allClients, err := scenario.ListTailscaleClients() @@ -1729,9 +1727,7 @@ func TestSubnetRouterMultiNetwork(t *testing.T) { defer scenario.ShutdownAssertNoPanics(t) err = scenario.CreateHeadscaleEnv([]tsic.Option{tsic.WithAcceptRoutes()}, - hsic.WithTestName("clienableroute"), - hsic.WithEmbeddedDERPServerOnly(), - hsic.WithTLS(), + hsic.WithTestName("rt-multinet"), ) requireNoErrHeadscaleEnv(t, err) @@ -1884,9 +1880,7 @@ func TestSubnetRouterMultiNetworkExitNode(t *testing.T) { defer scenario.ShutdownAssertNoPanics(t) err = scenario.CreateHeadscaleEnv([]tsic.Option{}, - hsic.WithTestName("clienableroute"), - hsic.WithEmbeddedDERPServerOnly(), - hsic.WithTLS(), + hsic.WithTestName("rt-multinetexit"), ) requireNoErrHeadscaleEnv(t, err) @@ -2306,10 +2300,8 @@ func TestAutoApproveMultiNetwork(t *testing.T) { opts := []hsic.Option{ hsic.WithTestName("autoapprovemulti"), - hsic.WithEmbeddedDERPServerOnly(), - hsic.WithTLS(), hsic.WithACLPolicy(pol), - hsic.WithPolicyMode(polMode), + hsic.WithPolicyMode(polMode), // test iterates over file and DB policy modes } tsOpts := []tsic.Option{ @@ -3026,7 +3018,7 @@ func TestSubnetRouteACLFiltering(t *testing.T) { tsic.WithAcceptRoutes(), }, hsic.WithTestName("routeaclfilter"), hsic.WithACLPolicy(aclPolicy), - hsic.WithPolicyMode(types.PolicyModeDB), + hsic.WithPolicyMode(types.PolicyModeDB), // test updates policy at runtime via CLI ) requireNoErrHeadscaleEnv(t, err) diff --git a/integration/scenario_test.go b/integration/scenario_test.go index 71998fca..ae264221 100644 --- a/integration/scenario_test.go +++ b/integration/scenario_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/juanfont/headscale/integration/dockertestutil" + "github.com/juanfont/headscale/integration/hsic" "github.com/juanfont/headscale/integration/tsic" "github.com/stretchr/testify/require" ) @@ -40,7 +41,7 @@ func TestHeadscale(t *testing.T) { defer scenario.ShutdownAssertNoPanics(t) t.Run("start-headscale", func(t *testing.T) { - headscale, err := scenario.Headscale() + headscale, err := scenario.Headscale(hsic.WithTestName("scenariohs")) if err != nil { t.Fatalf("failed to create start headcale: %s", err) } @@ -89,7 +90,7 @@ func TestTailscaleNodesJoiningHeadcale(t *testing.T) { defer scenario.ShutdownAssertNoPanics(t) t.Run("start-headscale", func(t *testing.T) { - headscale, err := scenario.Headscale() + headscale, err := scenario.Headscale(hsic.WithTestName("scenariojoin")) if err != nil { t.Fatalf("failed to create start headcale: %s", err) } diff --git a/integration/ssh_test.go b/integration/ssh_test.go index 73918b9b..909a5ee4 100644 --- a/integration/ssh_test.go +++ b/integration/ssh_test.go @@ -27,7 +27,7 @@ func isSSHNoAccessStdError(stderr string) bool { strings.Contains(stderr, "tailnet policy does not permit you to SSH") } -func sshScenario(t *testing.T, policy *policyv2.Policy, clientsPerUser int) *Scenario { +func sshScenario(t *testing.T, policy *policyv2.Policy, testName string, clientsPerUser int) *Scenario { t.Helper() spec := ScenarioSpec{ @@ -50,7 +50,7 @@ func sshScenario(t *testing.T, policy *policyv2.Policy, clientsPerUser int) *Sce tsic.WithDockerWorkdir("/"), }, hsic.WithACLPolicy(policy), - hsic.WithTestName("ssh"), + hsic.WithTestName(testName), ) require.NoError(t, err) @@ -95,6 +95,7 @@ func TestSSHOneUserToAll(t *testing.T) { }, }, }, + "ssh-onetoall", len(MustTestVersions), ) defer scenario.ShutdownAssertNoPanics(t) @@ -168,6 +169,7 @@ func TestSSHMultipleUsersAllToAll(t *testing.T) { }, }, }, + "ssh-multiall", len(MustTestVersions), ) defer scenario.ShutdownAssertNoPanics(t) @@ -242,6 +244,7 @@ func TestSSHNoSSHConfigured(t *testing.T) { }, SSHs: []policyv2.SSH{}, }, + "ssh-nosshcfg", len(MustTestVersions), ) defer scenario.ShutdownAssertNoPanics(t) @@ -293,6 +296,7 @@ func TestSSHIsBlockedInACL(t *testing.T) { }, }, }, + "ssh-blocked", len(MustTestVersions), ) defer scenario.ShutdownAssertNoPanics(t) @@ -354,6 +358,7 @@ func TestSSHUserOnlyIsolation(t *testing.T) { }, }, }, + "ssh-isolation", len(MustTestVersions), ) defer scenario.ShutdownAssertNoPanics(t) @@ -571,6 +576,7 @@ func TestSSHAutogroupSelf(t *testing.T) { }, }, }, + "ssh-agself", 2, // 2 clients per user ) defer scenario.ShutdownAssertNoPanics(t) @@ -811,7 +817,7 @@ func findNewSSHCheckAuthID( func TestSSHOneUserToOneCheckModeCLI(t *testing.T) { IntegrationSkip(t) - scenario := sshScenario(t, sshCheckPolicy(), 1) + scenario := sshScenario(t, sshCheckPolicy(), "ssh-checkcli", 1) // defer scenario.ShutdownAssertNoPanics(t) allClients, err := scenario.ListTailscaleClients() @@ -920,7 +926,6 @@ func TestSSHOneUserToOneCheckModeOIDC(t *testing.T) { hsic.WithACLPolicy(sshCheckPolicy()), hsic.WithTestName("sshcheckoidc"), hsic.WithConfigEnv(oidcMap), - hsic.WithTLS(), hsic.WithFileInContainer( "/tmp/hs_client_oidc_secret", []byte(scenario.mockOIDC.ClientSecret()), @@ -1087,7 +1092,7 @@ func TestSSHCheckModeCheckPeriodCLI(t *testing.T) { IntegrationSkip(t) // 1 minute is the documented minimum checkPeriod - scenario := sshScenario(t, sshCheckPolicyWithPeriod(time.Minute), 1) + scenario := sshScenario(t, sshCheckPolicyWithPeriod(time.Minute), "ssh-checkperiod", 1) defer scenario.ShutdownAssertNoPanics(t) allClients, err := scenario.ListTailscaleClients() @@ -1182,7 +1187,7 @@ func TestSSHCheckModeAutoApprove(t *testing.T) { IntegrationSkip(t) // 5 minute checkPeriod — long enough not to expire during test - scenario := sshScenario(t, sshCheckPolicyWithPeriod(5*time.Minute), 1) + scenario := sshScenario(t, sshCheckPolicyWithPeriod(5*time.Minute), "ssh-autoapprove", 1) defer scenario.ShutdownAssertNoPanics(t) allClients, err := scenario.ListTailscaleClients() @@ -1247,7 +1252,7 @@ func TestSSHCheckModeAutoApprove(t *testing.T) { func TestSSHCheckModeNegativeCLI(t *testing.T) { IntegrationSkip(t) - scenario := sshScenario(t, sshCheckPolicy(), 1) + scenario := sshScenario(t, sshCheckPolicy(), "ssh-negcli", 1) defer scenario.ShutdownAssertNoPanics(t) allClients, err := scenario.ListTailscaleClients() @@ -1509,7 +1514,6 @@ func TestSSHLocalpart(t *testing.T) { hsic.WithTestName("sshlocalpart"), hsic.WithACLPolicy(tt.policy), hsic.WithConfigEnv(oidcMap), - hsic.WithTLS(), hsic.WithFileInContainer("/tmp/hs_client_oidc_secret", []byte(scenario.mockOIDC.ClientSecret())), ) requireNoErrHeadscaleEnv(t, err) diff --git a/integration/tags_test.go b/integration/tags_test.go index 399ba7cf..265d7602 100644 --- a/integration/tags_test.go +++ b/integration/tags_test.go @@ -138,7 +138,6 @@ func TestTagsAuthKeyWithTagRequestDifferentTag(t *testing.T) { []tsic.Option{}, hsic.WithACLPolicy(policy), hsic.WithTestName("tags-authkey-diff"), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -213,7 +212,6 @@ func TestTagsAuthKeyWithTagNoAdvertiseFlag(t *testing.T) { []tsic.Option{}, hsic.WithACLPolicy(policy), hsic.WithTestName("tags-authkey-inherit"), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -286,7 +284,6 @@ func TestTagsAuthKeyWithTagCannotAddViaCLI(t *testing.T) { []tsic.Option{}, hsic.WithACLPolicy(policy), hsic.WithTestName("tags-authkey-noadd"), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -387,7 +384,6 @@ func TestTagsAuthKeyWithTagCannotChangeViaCLI(t *testing.T) { []tsic.Option{}, hsic.WithACLPolicy(policy), hsic.WithTestName("tags-authkey-nochange"), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -484,7 +480,6 @@ func TestTagsAuthKeyWithTagAdminOverrideReauthPreserves(t *testing.T) { []tsic.Option{}, hsic.WithACLPolicy(policy), hsic.WithTestName("tags-authkey-admin"), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -612,7 +607,6 @@ func TestTagsAuthKeyWithTagCLICannotModifyAdminTags(t *testing.T) { []tsic.Option{}, hsic.WithACLPolicy(policy), hsic.WithTestName("tags-authkey-noadmin"), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -735,7 +729,6 @@ func TestTagsAuthKeyWithoutTagCannotRequestTags(t *testing.T) { []tsic.Option{}, hsic.WithACLPolicy(policy), hsic.WithTestName("tags-nokey-req"), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -807,7 +800,6 @@ func TestTagsAuthKeyWithoutTagRegisterNoTags(t *testing.T) { []tsic.Option{}, hsic.WithACLPolicy(policy), hsic.WithTestName("tags-nokey-noreg"), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -877,7 +869,6 @@ func TestTagsAuthKeyWithoutTagCannotAddViaCLI(t *testing.T) { []tsic.Option{}, hsic.WithACLPolicy(policy), hsic.WithTestName("tags-nokey-noadd"), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -977,7 +968,6 @@ func TestTagsAuthKeyWithoutTagCLINoOpAfterAdminWithReset(t *testing.T) { []tsic.Option{}, hsic.WithACLPolicy(policy), hsic.WithTestName("tags-nokey-reset"), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -1098,7 +1088,6 @@ func TestTagsAuthKeyWithoutTagCLINoOpAfterAdminWithEmptyAdvertise(t *testing.T) []tsic.Option{}, hsic.WithACLPolicy(policy), hsic.WithTestName("tags-nokey-empty"), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -1218,7 +1207,6 @@ func TestTagsAuthKeyWithoutTagCLICannotReduceAdminMultiTag(t *testing.T) { []tsic.Option{}, hsic.WithACLPolicy(policy), hsic.WithTestName("tags-nokey-reduce"), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -1340,7 +1328,6 @@ func TestTagsUserLoginOwnedTagAtRegistration(t *testing.T) { }, hsic.WithACLPolicy(policy), hsic.WithTestName("tags-webauth-owned"), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -1411,7 +1398,6 @@ func TestTagsUserLoginNonExistentTagAtRegistration(t *testing.T) { []tsic.Option{}, hsic.WithACLPolicy(policy), hsic.WithTestName("tags-webauth-nonexist"), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -1484,7 +1470,6 @@ func TestTagsUserLoginUnownedTagAtRegistration(t *testing.T) { []tsic.Option{}, hsic.WithACLPolicy(policy), hsic.WithTestName("tags-webauth-unowned"), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -1554,7 +1539,6 @@ func TestTagsUserLoginAddTagViaCLIReauth(t *testing.T) { []tsic.Option{}, hsic.WithACLPolicy(policy), hsic.WithTestName("tags-webauth-addtag"), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -1646,7 +1630,6 @@ func TestTagsUserLoginRemoveTagViaCLIReauth(t *testing.T) { []tsic.Option{}, hsic.WithACLPolicy(policy), hsic.WithTestName("tags-webauth-rmtag"), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -1738,7 +1721,6 @@ func TestTagsUserLoginCLINoOpAfterAdminAssignment(t *testing.T) { []tsic.Option{}, hsic.WithACLPolicy(policy), hsic.WithTestName("tags-webauth-adminwin"), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -1856,7 +1838,6 @@ func TestTagsUserLoginCLICannotRemoveAdminTags(t *testing.T) { []tsic.Option{}, hsic.WithACLPolicy(policy), hsic.WithTestName("tags-webauth-norem"), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -1974,7 +1955,6 @@ func TestTagsAuthKeyWithTagRequestNonExistentTag(t *testing.T) { []tsic.Option{}, hsic.WithACLPolicy(policy), hsic.WithTestName("tags-authkey-nonexist"), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -2045,7 +2025,6 @@ func TestTagsAuthKeyWithTagRequestUnownedTag(t *testing.T) { []tsic.Option{}, hsic.WithACLPolicy(policy), hsic.WithTestName("tags-authkey-unowned"), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -2120,7 +2099,6 @@ func TestTagsAuthKeyWithoutTagRequestNonExistentTag(t *testing.T) { []tsic.Option{}, hsic.WithACLPolicy(policy), hsic.WithTestName("tags-nokey-nonexist"), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -2191,7 +2169,6 @@ func TestTagsAuthKeyWithoutTagRequestUnownedTag(t *testing.T) { []tsic.Option{}, hsic.WithACLPolicy(policy), hsic.WithTestName("tags-nokey-unowned"), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -2266,7 +2243,6 @@ func TestTagsAdminAPICannotSetNonExistentTag(t *testing.T) { []tsic.Option{}, hsic.WithACLPolicy(policy), hsic.WithTestName("tags-admin-nonexist"), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -2339,7 +2315,6 @@ func TestTagsAdminAPICanSetUnownedTag(t *testing.T) { []tsic.Option{}, hsic.WithACLPolicy(policy), hsic.WithTestName("tags-admin-unowned"), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -2428,7 +2403,6 @@ func TestTagsAdminAPICannotRemoveAllTags(t *testing.T) { []tsic.Option{}, hsic.WithACLPolicy(policy), hsic.WithTestName("tags-admin-empty"), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -2546,7 +2520,6 @@ func TestTagsIssue2978ReproTagReplacement(t *testing.T) { }, hsic.WithACLPolicy(policy), hsic.WithTestName("tags-issue-2978"), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -2752,7 +2725,6 @@ func TestTagsAdminAPICannotSetInvalidFormat(t *testing.T) { []tsic.Option{}, hsic.WithACLPolicy(policy), hsic.WithTestName("tags-admin-invalid"), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -2853,7 +2825,6 @@ func TestTagsUserLoginReauthWithEmptyTagsRemovesAllTags(t *testing.T) { []tsic.Option{}, hsic.WithACLPolicy(policy), hsic.WithTestName("tags-reauth-untag-2979-"+tc.testName), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -3008,7 +2979,6 @@ func TestTagsAuthKeyWithoutUserInheritsTags(t *testing.T) { []tsic.Option{}, hsic.WithACLPolicy(policy), hsic.WithTestName("tags-authkey-no-user-inherit"), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -3080,7 +3050,6 @@ func TestTagsAuthKeyWithoutUserRejectsAdvertisedTags(t *testing.T) { []tsic.Option{}, hsic.WithACLPolicy(policy), hsic.WithTestName("tags-authkey-no-user-reject-advertise"), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err) @@ -3147,7 +3116,6 @@ func TestTagsAuthKeyConvertToUserViaCLIRegister(t *testing.T) { []tsic.Option{}, hsic.WithACLPolicy(policy), hsic.WithTestName("tags-authkey-to-user-cli-3038"), - hsic.WithTLS(), ) requireNoErrHeadscaleEnv(t, err)