Documentation
¶
Overview ¶
Package mereach is the homelab side of kombify Me's reach API (Gateway services/me/docs/API.md "Homelab reach: tunnel mode and DNS-01"): the homelab's own Me registration enables tunnel mode for its base, receives the connector token sealed to its local custody, and publishes DNS-01 values and the LAN name's private address for the LAN-name certificate (homelab identity target §5, §8, §14 decisions 3 and 4). It holds the Me registration key in Owner custody and never prints, logs or returns it.
Index ¶
- Constants
- Variables
- func BaseOf(domain string) (string, bool)
- func RemoveRegistration(workspace string) error
- func SaveRegistration(workspace string, registration Registration) error
- type APIError
- type Client
- func (c Client) DeliverToken(ctx context.Context, now func() time.Time) (TunnelView, []byte, error)
- func (c Client) DisableTunnel(ctx context.Context) (TunnelView, error)
- func (c Client) EnableTunnel(ctx context.Context) (TunnelView, error)
- func (c Client) LANName() string
- func (c Client) RemoveChallenge(ctx context.Context, identifier, value string) error
- func (c Client) RemoveLANAddress(ctx context.Context) error
- func (c Client) SetChallenge(ctx context.Context, identifier, value string) error
- func (c Client) SetLANAddress(ctx context.Context, name string, address netip.Addr) error
- func (c Client) Tunnel(ctx context.Context) (TunnelView, error)
- type DNSRecord
- type LANAddressRecord
- type Registration
- type TunnelView
Constants ¶
const ( // Zone is the shared parent of every homelab base. Zone = "kombify.me" // DefaultAPI is Me's public API root. DefaultAPI = "https://kombify.me/_kombify/api/v1" // RemoteListenerIngress is the only ingress tunnel mode may carry: the // Access Gate's remote entrypoint on the connector network. RemoteListenerIngress = "http://stackkit-remote-listener.internal:8000" )
Variables ¶
var ErrLANAddressReadBack = errors.New("mereach: kombify Me's read-back of the LAN address record differs from what was sent")
ErrLANAddressReadBack reports a Me answer that does not read back the LAN address record as it was sent.
var ( // ErrNoRegistration reports a homelab without a Me registration in custody. ErrNoRegistration = errors.New("mereach: no Me registration in custody; run 'sudo stackkit reach registration set'") )
Functions ¶
func RemoveRegistration ¶
RemoveRegistration deletes the registration from custody.
func SaveRegistration ¶
func SaveRegistration(workspace string, registration Registration) error
SaveRegistration stores the registration 0600 in Owner custody.
Types ¶
type APIError ¶
type APIError struct {
Status int
Code string `json:"error_code"`
Message string `json:"error"`
Retryable bool `json:"retryable"`
}
APIError is Me's error answer.
type Client ¶
type Client struct {
Registration Registration
HTTP *http.Client
}
Client calls Me with the homelab's own registration key.
func (Client) DeliverToken ¶
DeliverToken rotates the tunnel secret and receives the new connector token sealed to a fresh key of this node's local custody, which opens it. The caller owns and clears the token.
func (Client) DisableTunnel ¶
func (c Client) DisableTunnel(ctx context.Context) (TunnelView, error)
DisableTunnel removes the base's tunnel and its DNS record; Me reads both back absent before it answers.
func (Client) EnableTunnel ¶
func (c Client) EnableTunnel(ctx context.Context) (TunnelView, error)
EnableTunnel enables or repairs tunnel mode for the base. It answers no token. The node refuses a tunnel whose ingress is not the remote listener.
func (Client) RemoveChallenge ¶
RemoveChallenge removes one DNS-01 value; Me proves it absent.
func (Client) RemoveLANAddress ¶
RemoveLANAddress removes the base's LAN address record; Me proves it absent.
func (Client) SetChallenge ¶
SetChallenge publishes one DNS-01 value for a name under the base.
func (Client) SetLANAddress ¶
SetLANAddress publishes the node's private address as the one DNS-only A or AAAA record of name, which must be this base's LAN name, and checks Me's read-back: the same name, DNS-only and the same address. A Me refusal is an *APIError naming Me's answer code; Me itself admits only private addresses and only for the caller's own base.
type DNSRecord ¶
type DNSRecord struct {
Name string `json:"name"`
Type string `json:"type,omitempty"`
Content string `json:"content,omitempty"`
Proxied bool `json:"proxied,omitempty"`
State string `json:"state,omitempty"`
}
DNSRecord is one record of the tunnel view.
type LANAddressRecord ¶
type LANAddressRecord struct {
Name string `json:"name"`
Type string `json:"type"`
Address string `json:"address"`
Proxied *bool `json:"proxied"`
TTL int `json:"ttl"`
Created bool `json:"created"`
}
LANAddressRecord is Me's Cloudflare read-back of the base's LAN address record lan.<base>.kombify.me. Proxied is a pointer so that an answer without it never reads as DNS-only.
type Registration ¶
type Registration struct {
APIVersion string `json:"apiVersion"`
Base string `json:"base"`
API string `json:"api"`
APIKey string `json:"apiKey"`
}
Registration is the homelab's own Me registration: its base and the registration key Me answered once.
func LoadRegistration ¶
func LoadRegistration(workspace string) (Registration, error)
LoadRegistration reads the registration from Owner custody.
type TunnelView ¶
type TunnelView struct {
Base string `json:"base"`
Enabled bool `json:"enabled"`
TunnelID string `json:"tunnel_id"`
TunnelName string `json:"tunnel_name"`
TunnelStatus string `json:"tunnel_status"`
Hostnames []string `json:"hostnames"`
IngressService string `json:"ingress_service"`
IngressCurrent bool `json:"ingress_current"`
DNSRecords []DNSRecord `json:"dns_records"`
Custody string `json:"custody,omitempty"`
Tunnel string `json:"tunnel,omitempty"`
}
TunnelView is Me's Cloudflare read-back of a base's tunnel mode. It never carries a token.