Documentation
¶
Overview ¶
Package overlaykey fetches a fresh single-use overlay (Tailscale/ Headscale) pre-auth key from cloudbox when this host's tailnet registration is no longer valid.
Why this exists: overlay credentials used to arrive only at pairing and during reattach, and reattach runs at daemon BOOT only. So anything that invalidated the registration — most commonly a cloudbox deploy, which resets the embedded Headscale — left the node unable to rejoin until a human restarted the daemon. The credentials were always re-issuable; the node simply had no way to ask.
The key we ask with is the cloudbox access token. It is signed with cloudbox's JWT secret and has nothing to do with the tailnet, so it keeps working across exactly the failures that break overlay auth. Every fetch is a fresh SINGLE-USE key: nothing replayable is stored on disk, and the alternative (a long-lived reusable key held forever) would be a standing credential to join the tailnet, which is what reaches the pod network.
Index ¶
Constants ¶
const DefaultInterval = 60 * time.Second
DefaultInterval is how often the refresher checks overlay health.
The failure it repairs is rare (a cloudbox deploy) but leaves the node unusable for cluster networking until fixed, so a minute of extra downtime is worse than a cheap poll. The check itself is one exec into a container when healthy.
Variables ¶
var ErrOverlayDisabled = fmt.Errorf("overlaykey: overlay not enabled on cloudbox")
ErrOverlayDisabled means cloudbox is not running the overlay at all.
Distinct from a transient failure on purpose: a caller that cannot tell "the feature is off" from "the mint failed" will retry forever against something that is never going to answer.
var ErrThrottled = fmt.Errorf("overlaykey: throttled by cloudbox")
ErrThrottled means cloudbox refused because we asked too recently.
Functions ¶
This section is empty.
Types ¶
type Client ¶
type Client struct {
// BaseURL is the cloudbox base (e.g. https://ai.dhnt.io).
BaseURL string
// AccessToken is this host's cloudbox bearer token.
AccessToken string
// AgentName is this host's registered name.
AgentName string
// HTTP is optional; a 30s-timeout client is used when nil.
HTTP *http.Client
}
Client fetches overlay credentials for one paired host.
type Credentials ¶
type Credentials struct {
LoginServer string `json:"overlay_login_server"`
AuthKey string `json:"overlay_auth_key"`
PodCIDR string `json:"overlay_pod_cidr"`
ExpiresInSeconds int `json:"expires_in_seconds"`
}
Credentials is one issuance from cloudbox.
type Refresher ¶
type Refresher struct {
Client *Client
Exec ExecFunc
PodCIDR string
Interval time.Duration
Log *slog.Logger
}
Refresher keeps this host registered on the overlay.
It exists because overlay credentials used to be a boot-time-only affair: pairing and reattach handed them over, and reattach runs when the daemon starts. Anything that invalidated the tailnet registration afterwards — a cloudbox deploy resetting Headscale being the common case — left the node off the pod network until a human restarted the daemon. Nothing was broken that could not be re-issued; the node simply never asked.
func (*Refresher) Healthy ¶
Healthy reports whether tailscaled considers itself logged in and running.
A failure to ASK is deliberately not "unhealthy": the container may be gone, tailscale may not be installed, or the overlay may simply be off on this host. Treating "could not determine" as "broken" would have the refresher mint keys and run `tailscale up` against hosts that never wanted an overlay — acting on the absence of evidence.