cmd/k8s-operator,k8s-operator: Kubernetes Peer Relays (#20495)
This commit contains the Kubernetes implementation of peer relays via the new `PeerRelay` CRD. It's a mega branch consisting of the commits of other PRs gone into this work: 1. https://github.com/tailscale/tailscale/pull/20211 2. https://github.com/tailscale/tailscale/pull/20329 3. https://github.com/tailscale/tailscale/pull/20423 4. https://github.com/tailscale/tailscale/pull/20503 An instance of the `PeerRelay` CRD deploys a `StatefulSet` of containerboot instances configured to advertise themselves as peer relays using the IP addresses configured via `LoadBalancer` services on each cloud provider (with some AWS specifics as it's less automatic than its competing cloud providers). Per replica, a `LoadBalancer` type `Service` resource is provisioned and its IP address is used to configure the respective relay. This has been tested with success in AWS, GCP & Azure and provides additional modification to `Service` resources via the CRD for any other kinds of deployment environments. It also contains some work that may appear to be duplication of what already exists within `cmd/k8s-operator` so we can start building an appropriate migration path for `Connector`, `ProxyGroup` etc into respective `k8s-operator/reconciler/*` packages. Closes https://github.com/tailscale/corp/issues/34524
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
// Copyright (c) Tailscale Inc & contributors
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build !plan9
|
||||
|
||||
package tailscaled
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
|
||||
tailscaleclient "tailscale.com/client/tailscale/v2"
|
||||
|
||||
"tailscale.com/ipn"
|
||||
"tailscale.com/k8s-operator/tsclient"
|
||||
)
|
||||
|
||||
// ClientProvider returns a Tailscale API client for the given tailnet name. A blank name should return the
|
||||
// operator's default client.
|
||||
type ClientProvider interface {
|
||||
For(tailnet string) (tsclient.Client, error)
|
||||
}
|
||||
|
||||
// NewAuthKey mints a single-use, preauthorized tailnet auth key with the given tags. The key is intended for one
|
||||
// tailscaled pod to consume on first startup; callers should not persist or share it.
|
||||
func NewAuthKey(ctx context.Context, client tsclient.Client, tags []string) (string, error) {
|
||||
var caps tailscaleclient.KeyCapabilities
|
||||
caps.Devices.Create.Reusable = false
|
||||
caps.Devices.Create.Preauthorized = true
|
||||
caps.Devices.Create.Tags = tags
|
||||
|
||||
key, err := client.Keys().CreateAuthKey(ctx, tailscaleclient.CreateKeyRequest{Capabilities: caps})
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create auth key: %w", err)
|
||||
}
|
||||
return key.Key, nil
|
||||
}
|
||||
|
||||
// AuthKeyFromConfigSecret returns the auth key embedded in the tailscaled config file stored in secret, or nil if
|
||||
// none is set. secret is expected to be a Secret produced by NewConfigSecret. The Data map may contain multiple
|
||||
// versioned config files (cap-<n>.hujson); the first one to parse successfully and yield a non-empty AuthKey wins.
|
||||
func AuthKeyFromConfigSecret(secret *corev1.Secret) *string {
|
||||
for _, body := range secret.Data {
|
||||
var conf ipn.ConfigVAlpha
|
||||
if err := json.Unmarshal(body, &conf); err != nil {
|
||||
continue
|
||||
}
|
||||
if conf.AuthKey != nil && *conf.AuthKey != "" {
|
||||
return conf.AuthKey
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user