mirror of
https://github.com/tailscale/tailscale.git
synced 2026-04-04 06:36:01 -04:00
* cmd/k8s-operator/e2e: add L7 HA ingress test Change-Id: Ic017e4a7e3affbc3e2a87b9b6b9c38afd65f32ed Signed-off-by: Tom Proctor <tomhjp@users.noreply.github.com> * cmd/k8s-operator: add further E2E tests for Ingress (#34833) This change adds E2E tests for L3 HA Ingress and L7 Ingress (Standalone and HA). Updates the existing L3 Ingress test to use the Service's Magic DNS name to test connectivity. Also refactors test setup to set TS_DEBUG_ACME_DIRECTORY_URL only for tests running against devcontrol, and updates the Kind node image from v1.30.0 to v1.35.0. Fixes tailscale/corp#34833 Signed-off-by: Becky Pauley <becky@tailscale.com> --------- Signed-off-by: Tom Proctor <tomhjp@users.noreply.github.com> Signed-off-by: Becky Pauley <becky@tailscale.com> Co-authored-by: Tom Proctor <tomhjp@users.noreply.github.com>
108 lines
2.8 KiB
Go
108 lines
2.8 KiB
Go
// Copyright (c) Tailscale Inc & contributors
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
package e2e
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
|
|
corev1 "k8s.io/api/core/v1"
|
|
rbacv1 "k8s.io/api/rbac/v1"
|
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
|
"k8s.io/client-go/rest"
|
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
|
|
"tailscale.com/ipn"
|
|
"tailscale.com/tstest"
|
|
)
|
|
|
|
// See [TestMain] for test requirements.
|
|
func TestProxy(t *testing.T) {
|
|
if tnClient == nil {
|
|
t.Skip("TestProxy requires a working tailnet client")
|
|
}
|
|
|
|
// Create role and role binding to allow a group we'll impersonate to do stuff.
|
|
createAndCleanup(t, kubeClient, &rbacv1.Role{
|
|
ObjectMeta: objectMeta("tailscale", "read-secrets"),
|
|
Rules: []rbacv1.PolicyRule{{
|
|
APIGroups: []string{""},
|
|
Verbs: []string{"get"},
|
|
Resources: []string{"secrets"},
|
|
}},
|
|
})
|
|
createAndCleanup(t, kubeClient, &rbacv1.RoleBinding{
|
|
ObjectMeta: objectMeta("tailscale", "read-secrets"),
|
|
Subjects: []rbacv1.Subject{{
|
|
Kind: "Group",
|
|
Name: "ts:e2e-test-proxy",
|
|
}},
|
|
RoleRef: rbacv1.RoleRef{
|
|
Kind: "Role",
|
|
Name: "read-secrets",
|
|
},
|
|
})
|
|
|
|
// Get operator host name from kube secret.
|
|
operatorSecret := corev1.Secret{
|
|
ObjectMeta: objectMeta("tailscale", "operator"),
|
|
}
|
|
if err := get(t.Context(), kubeClient, &operatorSecret); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Join tailnet as a client of the API server proxy.
|
|
proxyCfg := &rest.Config{
|
|
Host: fmt.Sprintf("https://%s:443", hostNameFromOperatorSecret(t, operatorSecret)),
|
|
}
|
|
proxyCl, err := client.New(proxyCfg, client.Options{
|
|
HTTPClient: newHTTPClient(tnClient),
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Expect success.
|
|
allowedSecret := corev1.Secret{
|
|
ObjectMeta: objectMeta("tailscale", "operator"),
|
|
}
|
|
// Wait for up to a minute the first time we use the proxy, to give it time
|
|
// to provision the TLS certs.
|
|
if err := tstest.WaitFor(time.Minute, func() error {
|
|
err := get(t.Context(), proxyCl, &allowedSecret)
|
|
t.Logf("get Secret via proxy: %v", err)
|
|
return err
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Expect forbidden.
|
|
forbiddenSecret := corev1.Secret{
|
|
ObjectMeta: objectMeta("default", "operator"),
|
|
}
|
|
if err := get(t.Context(), proxyCl, &forbiddenSecret); err == nil || !apierrors.IsForbidden(err) {
|
|
t.Fatalf("expected forbidden error fetching secret from default namespace: %s", err)
|
|
}
|
|
}
|
|
|
|
func hostNameFromOperatorSecret(t *testing.T, s corev1.Secret) string {
|
|
t.Helper()
|
|
prefsBytes, ok := s.Data[string(s.Data["_current-profile"])]
|
|
if !ok {
|
|
t.Fatalf("no state in operator Secret data: %#v", s.Data)
|
|
}
|
|
|
|
prefs := ipn.Prefs{}
|
|
if err := json.Unmarshal(prefsBytes, &prefs); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if prefs.Persist == nil {
|
|
t.Fatalf("no hostname in operator Secret data: %#v", s.Data)
|
|
}
|
|
return prefs.Persist.UserProfile.LoginName
|
|
}
|