headscale

package module
v0.0.14 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 2, 2023 License: BSD-3-Clause Imports: 81 Imported by: 0

README

headscale logo

ci

An open source, self-hosted implementation of the Tailscale control server.

Join our Discord server for a chat.

Note: Always select the same GitHub tag as the released version you use to ensure you have the correct example configuration and documentation. The main branch might contain unreleased changes.

What is Tailscale

Tailscale is a modern VPN built on top of Wireguard. It works like an overlay network between the computers of your networks - using NAT traversal.

Everything in Tailscale is Open Source, except the GUI clients for proprietary OS (Windows and macOS/iOS), and the control server.

The control server works as an exchange point of Wireguard public keys for the nodes in the Tailscale network. It assigns the IP addresses of the clients, creates the boundaries between each user, enables sharing machines between users, and exposes the advertised routes of your nodes.

A Tailscale network (tailnet) is private network which Tailscale assigns to a user in terms of private users or an organisation.

Design goal

headscale aims to implement a self-hosted, open source alternative to the Tailscale control server. headscale has a narrower scope and an instance of headscale implements a single Tailnet, which is typically what a single organisation, or home/personal setup would use.

headscale uses terms that maps to Tailscale's control server, consult the glossary for explainations.

Support

If you like headscale and find it useful, there is a sponsorship and donation buttons available in the repo.

If you would like to sponsor features, bugs or prioritisation, reach out to one of the maintainers.

Features

  • Full "base" support of Tailscale's features
  • Configurable DNS
  • Node registration
    • Single-Sign-On (via Open ID Connect)
    • Pre authenticated key
  • Taildrop (File Sharing)
  • Access control lists
  • MagicDNS
  • Support for multiple IP ranges in the tailnet
  • Dual stack (IPv4 and IPv6)
  • Routing advertising (including exit nodes)
  • Ephemeral nodes
  • Embedded DERP server

Client OS support

OS Supports headscale
Linux Yes
OpenBSD Yes
FreeBSD Yes
macOS Yes (see /apple on your headscale for more information)
Windows Yes docs
Android Yes docs
iOS Yes docs

Running headscale

Please have a look at the documentation under docs/.

Graphical Control Panels

Headscale provides an API for complete management of your Tailnet. These are community projects not directly affiliated with the Headscale project.

Name Repository Link Description Status
headscale-webui Github A simple Headscale web UI for small-scale deployments. Alpha

Talks

Disclaimer

  1. We have nothing to do with Tailscale, or Tailscale Inc.
  2. The purpose of Headscale is maintaining a working, self-hosted Tailscale control panel.

Contributing

To contribute to headscale you would need the lastest version of Go and Buf(Protobuf generator).

We recommend using Nix to setup a development environment. This can be done with nix develop, which will install the tools and give you a shell. This guarantees that you will have the same dev env as headscale maintainers.

PRs and suggestions are welcome.

Code style

To ensure we have some consistency with a growing number of contributions, this project has adopted linting and style/formatting rules:

The Go code is linted with golangci-lint and formatted with golines (width 88) and gofumpt. Please configure your editor to run the tools while developing and make sure to run make lint and make fmt before committing any code.

The Proto code is linted with buf and formatted with clang-format.

The rest (Markdown, YAML, etc) is formatted with prettier.

Check out the .golangci.yaml and Makefile to see the specific configuration.

Install development tools

  • Go
  • Buf
  • Protobuf tools

Install and activate:

nix develop

Testing and building

Some parts of the project require the generation of Go code from Protobuf (if changes are made in proto/) and it must be (re-)generated with:

make generate

Note: Please check in changes from gen/ in a separate commit to make it easier to review.

To run the tests:

make test

To build the program:

nix build

or

make build

Contributors

Kristoffer
Kristoffer Dalby
Juan
Juan Font
Ward
Ward Vandewege
Jiang
Jiang Zhu
Benjamin
Benjamin Roberts
Nico/
Nico
Even
Even Holthe
e-zk/
e-zk
Justin
Justin Angel
Alessandro
Alessandro (Ale) Segala
unreality/
unreality
Moritz
Moritz Poldrack
ohdearaugustin/
ohdearaugustin
Andriy
Andriy Kushnir
Adrien
Adrien Raffin-Caboisse
GrigoriyMikhalkin/
GrigoriyMikhalkin
Christian
Christian Heusel
Mike
Mike Lloyd
Anton
Anton Schubert
Niek
Niek van der Maas
Eugen
Eugen Biegler
Azz/
Azz
Aaron
Aaron Bieber
Igor
Igor Perepilitsyn
Laurent
Laurent Marchaud
Stefan
Stefan Majer
Fernando
Fernando De Lucchi
Orville
Orville Q. Song
hdhoang/
hdhoang
bravechamp/
bravechamp
Deon
Deon Thomas
Jamie
Jamie Greeff
ChibangLW/
ChibangLW
Mevan
Mevan Samaratunga
Michael
Michael G.
Paul
Paul Tötterman
Samuel
Samuel Lock
Gonçalo
Gonçalo Rodrigues
kevinlin/
kevinlin
Snack/
Snack
Artem
Artem Klevtsov
Casey
Casey Marshall
dbevacqua/
dbevacqua
Josh
Josh Taylor
LiuHanCheng/
LiuHanCheng
Motiejus
Motiejus Jakštys
Pavlos
Pavlos Vinieratos
Silver
Silver Bullet
Steven
Steven Honson
Victor
Victor Freire
thomas/
thomas
Sean
Sean Reifschneider
Abraham
Abraham Ingersoll
Albert
Albert Copeland
Andrei
Andrei Pechkurov
Anoop
Anoop Sundaresh
Antoine
Antoine POPINEAU
Antonio
Antonio Fernandez
Aofei
Aofei Sheng
Arnar/
Arnar
Arthur
Arthur Woimbée
Avirut
Avirut Mehta
Bryan
Bryan Stenson
Carson
Carson Yang
Darrell
Darrell Kundel
fatih-acar/
fatih-acar
Felix
Felix Kronlage-Dammers
Felix
Felix Yan
Gabe
Gabe Cook
JJGadgets/
JJGadgets
hrtkpf/
hrtkpf
Jim
Jim Tittsler
Johan
Johan Siebens
John
John Axel Eriksson
Jonathan
Jonathan de Jong
Julien
Julien Zweverink
Kurnia
Kurnia D Win
Marc/
Marc
Maxim
Maxim Gajdaj
Michael
Michael Savage
Pierre
Pierre Carru
Pontus
Pontus N
Rasmus
Rasmus Moorats
rcursaru/
rcursaru
Mend
Mend Renovate
Ryan
Ryan Fowler
Shaanan
Shaanan Cohney
Stefan
Stefan VanBuren
sophware/
sophware
Tanner/
Tanner
Teteros/
Teteros
The
The Gitter Badger
Tianon
Tianon Gravi
Till
Till Hoffmann
Tjerk
Tjerk Woudsma
Yang
Yang Bin
Yujie
Yujie Xia
Zachary
Zachary Newell
Zakhar
Zakhar Bessarab
Zhiyuan
Zhiyuan Zheng
Ziyuan
Ziyuan Han
caelansar/
caelansar
derelm/
derelm
dnaq/
dnaq
henning
henning mueller
ignoramous/
ignoramous
jimyag/
jimyag
suhelen/
suhelen
sharkonet/
sharkonet
ma6174/
ma6174
manju-rn/
manju-rn
nicholas-yap/
nicholas-yap
Tommi
Tommi Pernila
phpmalik/
phpmalik
Wakeful-Cloud/
Wakeful-Cloud
zy/
zy
Àlex
Àlex Torregrosa

Documentation

Overview

nolint

Index

Constants

View Source
const (
	Base8     = 8
	Base10    = 10
	BitSize16 = 16
	BitSize32 = 32
	BitSize64 = 64
)
View Source
const (
	RegisterMethodAuthKey                    = "authkey"
	RegisterMethodOIDC                       = "oidc"
	RegisterMethodCLI                        = "cli"
	ErrRegisterMethodCLIDoesNotSupportExpire = Error(
		"machines registered with CLI does not support expire",
	)
)
View Source
const (
	AuthPrefix = "Bearer "
	Postgres   = "postgres"
	Sqlite     = "sqlite3"

	HTTPReadTimeout     = 30 * time.Second
	HTTPShutdownTimeout = 3 * time.Second

	DisabledClientAuth = "disabled"
	RelaxedClientAuth  = "relaxed"
	EnforcedClientAuth = "enforced"
)
View Source
const (
	JSONLogFormat = "json"
	TextLogFormat = "text"
)
View Source
const (
	ErrMachineNotFound                  = Error("machine not found")
	ErrMachineRouteIsNotAvailable       = Error("route is not available on machine")
	ErrMachineAddressesInvalid          = Error("failed to parse machine addresses")
	ErrMachineNotFoundRegistrationCache = Error(
		"machine not found in registration cache",
	)
	ErrCouldNotConvertMachineInterface = Error("failed to convert machine interface")
	ErrHostnameTooLong                 = Error("Hostname too long")
	ErrDifferentRegisteredUser         = Error(
		"machine was previously registered with a different user",
	)
	MachineGivenNameHashLength = 8
	MachineGivenNameTrimSize   = 2
)
View Source
const (
	ErrPreAuthKeyNotFound          = Error("AuthKey not found")
	ErrPreAuthKeyExpired           = Error("AuthKey expired")
	ErrSingleUseAuthKeyHasBeenUsed = Error("AuthKey has already been used")
	ErrUserMismatch                = Error("user mismatch")
	ErrPreAuthKeyACLTagInvalid     = Error("AuthKey tag is invalid")
)
View Source
const (
	ErrUserExists        = Error("User already exists")
	ErrUserNotFound      = Error("User not found")
	ErrUserStillHasNodes = Error("User not empty: node(s) found")
	ErrInvalidUserName   = Error("Invalid user name")
)
View Source
const (
	ErrCannotDecryptResponse = Error("cannot decrypt response")
	ErrCouldNotAllocateIP    = Error("could not find any suitable IP")

	PermissionFallback = 0o700

	ZstdCompression = "zstd"
)
View Source
const (
	ByteSize = 8
)
View Source
const (
	ErrAPIKeyFailedToParse = Error("Failed to parse ApiKey")
)
View Source
const (
	ErrCannotParsePrefix = Error("cannot parse prefix")
)
View Source
const (
	ErrRouteIsNotAvailable = Error("route is not available")
)
View Source
const (
	// The CapabilityVersion is used by Tailscale clients to indicate
	// their codebase version. Tailscale clients can communicate over TS2021
	// from CapabilityVersion 28, but we only have good support for it
	// since https://github.com/tailscale/tailscale/pull/4323 (Noise in any HTTPS port).
	//
	// Related to this change, there is https://github.com/tailscale/tailscale/pull/5379,
	// where CapabilityVersion 39 is introduced to indicate #4323 was merged.
	//
	// See also https://github.com/tailscale/tailscale/blob/main/tailcfg/tailcfg.go
	NoiseCapabilityVersion = 39
)
View Source
const (
	ProtocolFC = 133 // Fibre Channel
)

For some reason golang.org/x/net/internal/iana is an internal package.

Variables

View Source
var (
	ExitRouteV4 = netip.MustParsePrefix("0.0.0.0/0")
	ExitRouteV6 = netip.MustParsePrefix("::/0")
)
View Source
var NodePublicKeyRegex = regexp.MustCompile("nodekey:[a-fA-F0-9]+")

Functions

func AbsolutePathFromConfigPath

func AbsolutePathFromConfigPath(path string) string

func CheckForFQDNRules

func CheckForFQDNRules(name string) error

func DiscoPublicKeyEnsurePrefix

func DiscoPublicKeyEnsurePrefix(discoKey string) string

func DiscoPublicKeyStripPrefix

func DiscoPublicKeyStripPrefix(discoKey key.DiscoPublic) string

func GenerateRandomBytes

func GenerateRandomBytes(n int) ([]byte, error)

GenerateRandomBytes returns securely generated random bytes. It will return an error if the system's secure random number generator fails to function correctly, in which case the caller should not continue.

func GenerateRandomStringDNSSafe

func GenerateRandomStringDNSSafe(size int) (string, error)

GenerateRandomStringDNSSafe returns a DNS-safe securely generated random string. It will return an error if the system's secure random number generator fails to function correctly, in which case the caller should not continue.

func GenerateRandomStringURLSafe

func GenerateRandomStringURLSafe(n int) (string, error)

GenerateRandomStringURLSafe returns a URL-safe, base64 encoded securely generated random string. It will return an error if the system's secure random number generator fails to function correctly, in which case the caller should not continue.

func GetDERPMap

func GetDERPMap(cfg DERPConfig) *tailcfg.DERPMap

func GetDNSConfig

func GetDNSConfig() (*tailcfg.DNSConfig, string)

func GetFileMode

func GetFileMode(key string) fs.FileMode

func GetIPPrefixEndpoints

func GetIPPrefixEndpoints(na netip.Prefix) (netip.Addr, netip.Addr)

func GrpcSocketDialer

func GrpcSocketDialer(ctx context.Context, addr string) (net.Conn, error)

func IsCLIConfigured

func IsCLIConfigured() bool

func IsStringInSlice

func IsStringInSlice(slice []string, str string) bool

func LoadConfig

func LoadConfig(path string, isFile bool) error

func MachinePublicKeyEnsurePrefix

func MachinePublicKeyEnsurePrefix(machineKey string) string

func MachinePublicKeyStripPrefix

func MachinePublicKeyStripPrefix(machineKey key.MachinePublic) string

func NodePublicKeyEnsurePrefix

func NodePublicKeyEnsurePrefix(nodeKey string) string

func NodePublicKeyStripPrefix

func NodePublicKeyStripPrefix(nodeKey key.NodePublic) string

func NormalizeToFQDNRules

func NormalizeToFQDNRules(name string, stripEmailDomain bool) (string, error)

NormalizeToFQDNRules will replace forbidden chars in user it can also return an error if the user doesn't respect RFC 952 and 1123.

func PrivateKeyEnsurePrefix

func PrivateKeyEnsurePrefix(privateKey string) string

func SwaggerAPIv1

func SwaggerAPIv1(
	writer http.ResponseWriter,
	req *http.Request,
)

func SwaggerUI

func SwaggerUI(
	writer http.ResponseWriter,
	req *http.Request,
)

Types

type ACL

type ACL struct {
	Action       string   `json:"action" yaml:"action"`
	Protocol     string   `json:"proto"  yaml:"proto"`
	Sources      []string `json:"src"    yaml:"src"`
	Destinations []string `json:"dst"    yaml:"dst"`
}

ACL is a basic rule for the ACL Policy.

type ACLConfig

type ACLConfig struct {
	PolicyPath string
}

func GetACLConfig

func GetACLConfig() ACLConfig

type ACLPolicy

type ACLPolicy struct {
	Groups        Groups        `json:"groups"        yaml:"groups"`
	Hosts         Hosts         `json:"hosts"         yaml:"hosts"`
	TagOwners     TagOwners     `json:"tagOwners"     yaml:"tagOwners"`
	ACLs          []ACL         `json:"acls"          yaml:"acls"`
	Tests         []ACLTest     `json:"tests"         yaml:"tests"`
	AutoApprovers AutoApprovers `json:"autoApprovers" yaml:"autoApprovers"`
	SSHs          []SSH         `json:"ssh"           yaml:"ssh"`
}

ACLPolicy represents a Tailscale ACL Policy.

func (ACLPolicy) IsZero

func (policy ACLPolicy) IsZero() bool

IsZero is perhaps a bit naive here.

func (ACLPolicy) ToProto added in v0.0.9

func (policy ACLPolicy) ToProto() *v1.ACLPolicy

type ACLTest

type ACLTest struct {
	Source string   `json:"src"            yaml:"src"`
	Accept []string `json:"accept"         yaml:"accept"`
	Deny   []string `json:"deny,omitempty" yaml:"deny,omitempty"`
}

ACLTest is not implemented, but should be use to check if a certain rule is allowed.

type APIKey

type APIKey struct {
	ID     uint64 `gorm:"primary_key"`
	Prefix string `gorm:"uniqueIndex"`
	Hash   []byte

	CreatedAt  *time.Time
	Expiration *time.Time
	LastSeen   *time.Time
}

APIKey describes the datamodel for API keys used to remotely authenticate with headscale.

type AppleMobileConfig

type AppleMobileConfig struct {
	UUID    uuid.UUID
	URL     string
	Payload string
}

type AppleMobilePlatformConfig

type AppleMobilePlatformConfig struct {
	UUID uuid.UUID
	URL  string
}

type AutoApprovers

type AutoApprovers struct {
	Routes   map[string][]string `json:"routes"   yaml:"routes"`
	ExitNode []string            `json:"exitNode" yaml:"exitNode"`
}

AutoApprovers specify which users (users?), groups or tags have their advertised routes or exit node status automatically enabled.

func (*AutoApprovers) GetRouteApprovers

func (autoApprovers *AutoApprovers) GetRouteApprovers(
	prefix netip.Prefix,
) ([]string, error)

Returns the list of autoApproving users, groups or tags for a given IPPrefix.

type CLIConfig

type CLIConfig struct {
	Address  string
	APIKey   string
	Timeout  time.Duration
	Insecure bool
}

type Config

type Config struct {
	ServerURL                      string
	Addr                           string
	MetricsAddr                    string
	GRPCAddr                       string
	GRPCAllowInsecure              bool
	EphemeralNodeInactivityTimeout time.Duration
	NodeUpdateCheckInterval        time.Duration
	IPPrefixes                     []netip.Prefix
	PrivateKeyPath                 string
	NoisePrivateKeyPath            string
	BaseDomain                     string
	Log                            LogConfig
	DisableUpdateCheck             bool

	DERP DERPConfig

	DBtype string
	DBpath string
	DBhost string
	DBport int
	DBname string
	DBuser string
	DBpass string
	DBssl  string

	TLS TLSConfig

	ACMEURL   string
	ACMEEmail string

	DNSConfig *tailcfg.DNSConfig

	UnixSocket           string
	UnixSocketPermission fs.FileMode

	OIDC OIDCConfig

	LogTail             LogTailConfig
	RandomizeClientPort bool

	CLI CLIConfig

	ACL ACLConfig
}

Config contains the initial Headscale configuration.

func GetHeadscaleConfig

func GetHeadscaleConfig() (*Config, error)

type DERPConfig

type DERPConfig struct {
	ServerEnabled    bool
	ServerRegionID   int
	ServerRegionCode string
	ServerRegionName string
	STUNAddr         string
	URLs             []url.URL
	Paths            []string
	AutoUpdate       bool
	UpdateFrequency  time.Duration
}

func GetDERPConfig

func GetDERPConfig() DERPConfig

type DERPServer

type DERPServer struct {
	// contains filtered or unexported fields
}

type Error

type Error string

Error is used to compare errors as per https://dave.cheney.net/2016/04/07/constant-errors

func (Error) Error

func (e Error) Error() string

type Groups

type Groups map[string][]string

Groups references a series of alias in the ACL rules.

type Headscale

type Headscale struct {
	DERPMap    *tailcfg.DERPMap
	DERPServer *DERPServer
	// contains filtered or unexported fields
}

Headscale represents the base app of the service.

func NewHeadscale

func NewHeadscale(cfg *Config) (*Headscale, error)

func (*Headscale) AppleConfigMessage

func (h *Headscale) AppleConfigMessage(
	writer http.ResponseWriter,
	req *http.Request,
)

AppleConfigMessage shows a simple message in the browser to point the user to the iOS/MacOS profile and instructions for how to install it.

func (*Headscale) ApplePlatformConfig

func (h *Headscale) ApplePlatformConfig(
	writer http.ResponseWriter,
	req *http.Request,
)

func (*Headscale) CreateAPIKey

func (h *Headscale) CreateAPIKey(
	expiration *time.Time,
) (string, *APIKey, error)

CreateAPIKey creates a new ApiKey in a user, and returns it.

func (*Headscale) CreateOrUpdateUserACLPolicy added in v0.0.13

func (h *Headscale) CreateOrUpdateUserACLPolicy(
	userID uint,
	policy ACLPolicy,
) (*UserACLPolicy, error)

CreateOrUpdateUserACLPolicy creates an acl policy for the given user.

func (*Headscale) CreatePreAuthKey

func (h *Headscale) CreatePreAuthKey(
	userName string,
	reusable bool,
	ephemeral bool,
	expiration *time.Time,
	aclTags []string,
) (*PreAuthKey, error)

CreatePreAuthKey creates a new PreAuthKey in a user, and returns it.

func (*Headscale) CreateUser

func (h *Headscale) CreateUser(name string) (*User, error)

CreateUser creates a new User. Returns error if could not be created or another user already exists.

func (*Headscale) DERPBootstrapDNSHandler

func (h *Headscale) DERPBootstrapDNSHandler(
	writer http.ResponseWriter,
	req *http.Request,
)

DERPBootstrapDNSHandler implements the /bootsrap-dns endpoint Described in https://github.com/tailscale/tailscale/issues/1405, this endpoint provides a way to help a client when it fails to start up because its DNS are broken. The initial implementation is here https://github.com/tailscale/tailscale/pull/1406 They have a cache, but not clear if that is really necessary at Headscale, uh, scale. An example implementation is found here https://derp.tailscale.com/bootstrap-dns

func (*Headscale) DERPHandler

func (h *Headscale) DERPHandler(
	writer http.ResponseWriter,
	req *http.Request,
)

func (*Headscale) DERPProbeHandler

func (h *Headscale) DERPProbeHandler(
	writer http.ResponseWriter,
	req *http.Request,
)

DERPProbeHandler is the endpoint that js/wasm clients hit to measure DERP latency, since they can't do UDP STUN queries.

func (*Headscale) DeleteMachine

func (h *Headscale) DeleteMachine(machine *Machine) error

DeleteMachine softs deletes a Machine from the database.

func (*Headscale) DeleteMachineRoutes

func (h *Headscale) DeleteMachineRoutes(m *Machine) error

func (*Headscale) DeleteRoute

func (h *Headscale) DeleteRoute(id uint64) error

func (*Headscale) DestroyAPIKey

func (h *Headscale) DestroyAPIKey(key APIKey) error

DestroyAPIKey destroys a ApiKey. Returns error if the ApiKey does not exist.

func (*Headscale) DestroyPreAuthKey

func (h *Headscale) DestroyPreAuthKey(pak PreAuthKey) error

DestroyPreAuthKey destroys a preauthkey. Returns error if the PreAuthKey does not exist.

func (*Headscale) DestroyUser

func (h *Headscale) DestroyUser(name string) error

DestroyUser destroys a User. Returns error if the User does not exist or if there are machines associated with it.

func (*Headscale) DestroyUserACLPolicy added in v0.0.10

func (h *Headscale) DestroyUserACLPolicy(userID uint) error

DestroyUserACLPolicy destroys a acl policy for a given user if it exists.

func (*Headscale) DisableRoute

func (h *Headscale) DisableRoute(id uint64) error

func (*Headscale) EnableAutoApprovedRoutes

func (h *Headscale) EnableAutoApprovedRoutes(machine *Machine) error

EnableAutoApprovedRoutes enables any routes advertised by a machine that match the ACL autoApprovers policy.

func (*Headscale) EnableRoute

func (h *Headscale) EnableRoute(id uint64) error

func (*Headscale) ExpireAPIKey

func (h *Headscale) ExpireAPIKey(key *APIKey) error

ExpireAPIKey marks a ApiKey as expired.

func (*Headscale) ExpireMachine

func (h *Headscale) ExpireMachine(machine *Machine) error

ExpireMachine takes a Machine struct and sets the expire field to now.

func (*Headscale) ExpirePreAuthKey

func (h *Headscale) ExpirePreAuthKey(k *PreAuthKey) error

MarkExpirePreAuthKey marks a PreAuthKey as expired.

func (*Headscale) GenerateGivenName

func (h *Headscale) GenerateGivenName(
	machineKey string,
	suppliedName string,
) (string, error)

func (*Headscale) GetAPIKey

func (h *Headscale) GetAPIKey(prefix string) (*APIKey, error)

GetAPIKey returns a ApiKey for a given key.

func (*Headscale) GetAPIKeyByID

func (h *Headscale) GetAPIKeyByID(id uint64) (*APIKey, error)

GetAPIKeyByID returns a ApiKey for a given id.

func (*Headscale) GetAdvertisedRoutes

func (h *Headscale) GetAdvertisedRoutes(machine *Machine) ([]netip.Prefix, error)

GetAdvertisedRoutes returns the routes that are be advertised by the given machine.

func (*Headscale) GetEnabledRoutes

func (h *Headscale) GetEnabledRoutes(machine *Machine) ([]netip.Prefix, error)

GetEnabledRoutes returns the routes that are enabled for the machine.

func (*Headscale) GetMachine

func (h *Headscale) GetMachine(user string, name string) (*Machine, error)

GetMachine finds a Machine by name and user and returns the Machine struct.

func (*Headscale) GetMachineByAnyKey

func (h *Headscale) GetMachineByAnyKey(
	machineKey key.MachinePublic, nodeKey key.NodePublic, oldNodeKey key.NodePublic,
) (*Machine, error)

GetMachineByAnyNodeKey finds a Machine by its MachineKey, its current NodeKey or the old one, and returns the Machine struct.

func (*Headscale) GetMachineByGivenName

func (h *Headscale) GetMachineByGivenName(
	user string,
	givenName string,
) (*Machine, error)

GetMachineByGivenName finds a Machine by given name and user and returns the Machine struct.

func (*Headscale) GetMachineByID

func (h *Headscale) GetMachineByID(id uint64) (*Machine, error)

GetMachineByID finds a Machine by ID and returns the Machine struct.

func (*Headscale) GetMachineByMachineKey

func (h *Headscale) GetMachineByMachineKey(
	machineKey key.MachinePublic,
) (*Machine, error)

GetMachineByMachineKey finds a Machine by its MachineKey and returns the Machine struct.

func (*Headscale) GetMachineByNodeKey

func (h *Headscale) GetMachineByNodeKey(
	nodeKey key.NodePublic,
) (*Machine, error)

GetMachineByNodeKey finds a Machine by its current NodeKey.

func (*Headscale) GetMachineRoutes

func (h *Headscale) GetMachineRoutes(m *Machine) ([]Route, error)

func (*Headscale) GetPreAuthKey

func (h *Headscale) GetPreAuthKey(user string, key string) (*PreAuthKey, error)

GetPreAuthKey returns a PreAuthKey for a given key.

func (*Headscale) GetRoute

func (h *Headscale) GetRoute(id uint64) (*Route, error)

func (*Headscale) GetRoutes

func (h *Headscale) GetRoutes() ([]Route, error)

func (*Headscale) GetUser

func (h *Headscale) GetUser(name string) (*User, error)

GetUser fetches a user by name.

func (*Headscale) HardDeleteMachine

func (h *Headscale) HardDeleteMachine(machine *Machine) error

HardDeleteMachine hard deletes a Machine from the database.

func (*Headscale) HealthHandler

func (h *Headscale) HealthHandler(
	writer http.ResponseWriter,
	req *http.Request,
)

func (*Headscale) IsRoutesEnabled

func (h *Headscale) IsRoutesEnabled(machine *Machine, routeStr string) bool

func (*Headscale) KeyHandler

func (h *Headscale) KeyHandler(
	writer http.ResponseWriter,
	req *http.Request,
)

KeyHandler provides the Headscale pub key Listens in /key.

func (*Headscale) ListAPIKeys

func (h *Headscale) ListAPIKeys() ([]APIKey, error)

ListAPIKeys returns the list of ApiKeys for a user.

func (*Headscale) ListMachines

func (h *Headscale) ListMachines() ([]Machine, error)

func (*Headscale) ListMachinesByGivenName

func (h *Headscale) ListMachinesByGivenName(givenName string) ([]Machine, error)

func (*Headscale) ListMachinesByUser

func (h *Headscale) ListMachinesByUser(name string) ([]Machine, error)

ListMachinesByUser gets all the nodes in a given user.

func (*Headscale) ListMachinesByUserID added in v0.0.9

func (h *Headscale) ListMachinesByUserID(userID uint) ([]Machine, error)

func (*Headscale) ListPeers

func (h *Headscale) ListPeers(machine *Machine) (Machines, error)

func (*Headscale) ListPreAuthKeys

func (h *Headscale) ListPreAuthKeys(userName string) ([]PreAuthKey, error)

ListPreAuthKeys returns the list of PreAuthKeys for a user.

func (*Headscale) ListUsers

func (h *Headscale) ListUsers() ([]User, error)

ListUsers gets all the existing users.

func (*Headscale) NewDERPServer

func (h *Headscale) NewDERPServer() (*DERPServer, error)

func (*Headscale) NoiseUpgradeHandler

func (h *Headscale) NoiseUpgradeHandler(
	writer http.ResponseWriter,
	req *http.Request,
)

NoiseUpgradeHandler is to upgrade the connection and hijack the net.Conn in order to use the Noise-based TS2021 protocol. Listens in /ts2021.

func (*Headscale) OIDCCallback

func (h *Headscale) OIDCCallback(
	writer http.ResponseWriter,
	req *http.Request,
)

OIDCCallback handles the callback from the OIDC endpoint Retrieves the nkey from the state cache and adds the machine to the users email user TODO: A confirmation page for new machines should be added to avoid phishing vulnerabilities TODO: Add groups information from OIDC tokens into machine HostInfo Listens in /oidc/callback.

func (*Headscale) RefreshMachine

func (h *Headscale) RefreshMachine(machine *Machine, expiry time.Time) error

RefreshMachine takes a Machine struct and sets the expire field to now.

func (*Headscale) RegisterMachine

func (h *Headscale) RegisterMachine(machine Machine,
) (*Machine, error)

RegisterMachine is executed from the CLI to register a new Machine using its MachineKey.

func (*Headscale) RegisterMachineFromAuthCallback

func (h *Headscale) RegisterMachineFromAuthCallback(
	nodeKeyStr string,
	userName string,
	machineExpiry *time.Time,
	registrationMethod string,
) (*Machine, error)

func (*Headscale) RegisterOIDC

func (h *Headscale) RegisterOIDC(
	writer http.ResponseWriter,
	req *http.Request,
)

RegisterOIDC redirects to the OIDC provider for authentication Puts NodeKey in cache so the callback can retrieve it using the oidc state param Listens in /oidc/register/:nKey.

func (*Headscale) RegisterWebAPI

func (h *Headscale) RegisterWebAPI(
	writer http.ResponseWriter,
	req *http.Request,
)

RegisterWebAPI shows a simple message in the browser to point to the CLI Listens in /register/:nkey.

This is not part of the Tailscale control API, as we could send whatever URL in the RegisterResponse.AuthURL field.

func (*Headscale) RenameMachine

func (h *Headscale) RenameMachine(machine *Machine, newName string) error

RenameMachine takes a Machine struct and a new GivenName for the machines and renames it.

func (*Headscale) RenameUser

func (h *Headscale) RenameUser(oldName, newName string) error

RenameUser renames a User. Returns error if the User does not exist or if another User exists with the new name.

func (*Headscale) Serve

func (h *Headscale) Serve() error

Serve launches a GIN server with the Headscale API.

func (*Headscale) ServeSTUN

func (h *Headscale) ServeSTUN()

ServeSTUN starts a STUN server on the configured addr.

func (*Headscale) SetMachineUser

func (h *Headscale) SetMachineUser(machine *Machine, username string) error

SetMachineUser assigns a Machine to a user.

func (*Headscale) SetTags

func (h *Headscale) SetTags(machine *Machine, tags []string) error

SetTags takes a Machine struct pointer and update the forced tags.

func (*Headscale) TouchMachine

func (h *Headscale) TouchMachine(machine *Machine) error

func (*Headscale) UpdateMachineFromDatabase

func (h *Headscale) UpdateMachineFromDatabase(machine *Machine) error

UpdateMachineFromDatabase takes a Machine struct pointer (typically already loaded from database and updates it with the latest data from the database.

func (*Headscale) UsePreAuthKey

func (h *Headscale) UsePreAuthKey(k *PreAuthKey) error

UsePreAuthKey marks a PreAuthKey as used.

func (*Headscale) ValidateAPIKey

func (h *Headscale) ValidateAPIKey(keyStr string) (bool, error)

func (*Headscale) WindowsConfigMessage

func (h *Headscale) WindowsConfigMessage(
	writer http.ResponseWriter,
	req *http.Request,
)

WindowsConfigMessage shows a simple message in the browser for how to configure the Windows Tailscale client.

func (*Headscale) WindowsRegConfig

func (h *Headscale) WindowsRegConfig(
	writer http.ResponseWriter,
	req *http.Request,
)

WindowsRegConfig generates and serves a .reg file configured with the Headscale server address.

type HostInfo

type HostInfo tailcfg.Hostinfo

This is a "wrapper" type around tailscales Hostinfo to allow us to add database "serialization" methods. This allows us to use a typed values throughout the code and not have to marshal/unmarshal and error check all over the code.

func (*HostInfo) Scan

func (hi *HostInfo) Scan(destination interface{}) error

func (HostInfo) Value

func (hi HostInfo) Value() (driver.Value, error)

Value return json value, implement driver.Valuer interface.

type Hosts

type Hosts map[string]netip.Prefix

Hosts are alias for IP addresses or subnets.

func (*Hosts) UnmarshalJSON

func (hosts *Hosts) UnmarshalJSON(data []byte) error

UnmarshalJSON allows to parse the Hosts directly into netip objects.

func (*Hosts) UnmarshalYAML

func (hosts *Hosts) UnmarshalYAML(data []byte) error

UnmarshalYAML allows to parse the Hosts directly into netip objects.

type IDTokenClaims

type IDTokenClaims struct {
	Name     string   `json:"name,omitempty"`
	Groups   []string `json:"groups,omitempty"`
	Email    string   `json:"email"`
	Username string   `json:"preferred_username,omitempty"`
}

type IPPrefix

type IPPrefix netip.Prefix

func (*IPPrefix) Scan

func (i *IPPrefix) Scan(destination interface{}) error

func (IPPrefix) Value

func (i IPPrefix) Value() (driver.Value, error)

Value return json value, implement driver.Valuer interface.

type IPPrefixes

type IPPrefixes []netip.Prefix

func (*IPPrefixes) Scan

func (i *IPPrefixes) Scan(destination interface{}) error

func (IPPrefixes) Value

func (i IPPrefixes) Value() (driver.Value, error)

Value return json value, implement driver.Valuer interface.

type KV

type KV struct {
	Key   string
	Value string
}

KV is a key-value store in a psql table. For future use...

type LetsEncryptConfig

type LetsEncryptConfig struct {
	Listen        string
	Hostname      string
	CacheDir      string
	ChallengeType string
}

type LogConfig

type LogConfig struct {
	Format string
	Level  zerolog.Level
}

func GetLogConfig

func GetLogConfig() LogConfig

type LogTailConfig

type LogTailConfig struct {
	Enabled bool
}

func GetLogTailConfig

func GetLogTailConfig() LogTailConfig

type Machine

type Machine struct {
	ID          uint64 `gorm:"primary_key"`
	MachineKey  string `gorm:"type:varchar(64);unique_index"`
	NodeKey     string
	DiscoKey    string
	IPAddresses MachineAddresses

	// Hostname represents the name given by the Tailscale
	// client during registration
	Hostname string

	// Givenname represents either:
	// a DNS normalized version of Hostname
	// a valid name set by the User
	//
	// GivenName is the name used in all DNS related
	// parts of headscale.
	GivenName string `gorm:"type:varchar(256);unique_index"`
	UserID    uint
	User      User `gorm:"foreignKey:UserID"`

	RegisterMethod string

	ForcedTags StringList

	// TODO(kradalby): This seems like irrelevant information?
	AuthKeyID uint
	AuthKey   *PreAuthKey

	LastSeen             *time.Time
	LastSuccessfulUpdate *time.Time
	Expiry               *time.Time

	HostInfo  HostInfo
	Endpoints StringList

	CreatedAt time.Time
	UpdatedAt time.Time
	DeletedAt *time.Time
}

Machine is a Headscale client.

func (*Machine) GetHostInfo

func (machine *Machine) GetHostInfo() tailcfg.Hostinfo

GetHostInfo returns a Hostinfo struct for the machine.

func (Machine) String

func (machine Machine) String() string

type MachineAddresses

type MachineAddresses []netip.Addr

func (*MachineAddresses) Scan

func (ma *MachineAddresses) Scan(destination interface{}) error

func (MachineAddresses) ToStringSlice

func (ma MachineAddresses) ToStringSlice() []string

func (MachineAddresses) Value

func (ma MachineAddresses) Value() (driver.Value, error)

Value return json value, implement driver.Valuer interface.

type Machines

type Machines []Machine

func (Machines) FilterByIP added in v0.0.9

func (machines Machines) FilterByIP(ip netip.Addr) Machines

func (Machines) String

func (machines Machines) String() string

type MachinesP

type MachinesP []*Machine

func (MachinesP) String

func (machines MachinesP) String() string

TODO(kradalby): Remove when we have generics...

type OIDCConfig

type OIDCConfig struct {
	OnlyStartIfOIDCIsAvailable bool
	Issuer                     string
	ClientID                   string
	ClientSecret               string
	Scope                      []string
	ExtraParams                map[string]string
	AllowedDomains             []string
	AllowedUsers               []string
	AllowedGroups              []string
	StripEmaildomain           bool
	Expiry                     time.Duration
	UseExpiryFromToken         bool
}

type PreAuthKey

type PreAuthKey struct {
	ID        uint64 `gorm:"primary_key"`
	Key       string
	UserID    uint
	User      User
	Reusable  bool
	Ephemeral bool `gorm:"default:false"`
	Used      bool `gorm:"default:false"`
	ACLTags   []PreAuthKeyACLTag

	CreatedAt  *time.Time
	Expiration *time.Time
}

PreAuthKey describes a pre-authorization key usable in a particular user.

type PreAuthKeyACLTag

type PreAuthKeyACLTag struct {
	ID           uint64 `gorm:"primary_key"`
	PreAuthKeyID uint64
	Tag          string
}

PreAuthKeyACLTag describes an autmatic tag applied to a node when registered with the associated PreAuthKey.

type Route

type Route struct {
	gorm.Model

	MachineID uint64
	Machine   Machine
	Prefix    IPPrefix

	Advertised bool
	Enabled    bool
	IsPrimary  bool
}

func (*Route) String

func (r *Route) String() string

type Routes

type Routes []Route

type SSH

type SSH struct {
	Action       string   `json:"action"                yaml:"action"`
	Sources      []string `json:"src"                   yaml:"src"`
	Destinations []string `json:"dst"                   yaml:"dst"`
	Users        []string `json:"users"                 yaml:"users"`
	CheckPeriod  string   `json:"checkPeriod,omitempty" yaml:"checkPeriod,omitempty"`
}

SSH controls who can ssh into which machines.

type StringList

type StringList []string

func (*StringList) Scan

func (i *StringList) Scan(destination interface{}) error

func (StringList) Value

func (i StringList) Value() (driver.Value, error)

Value return json value, implement driver.Valuer interface.

type TLSConfig

type TLSConfig struct {
	CertPath string
	KeyPath  string

	LetsEncrypt LetsEncryptConfig
}

func GetTLSConfig

func GetTLSConfig() TLSConfig

type TagOwners

type TagOwners map[string][]string

TagOwners specify what users (users?) are allow to use certain tags.

type User

type User struct {
	gorm.Model
	Name string `gorm:"unique"`
}

User is the way Headscale implements the concept of users in Tailscale

At the end of the day, users in Tailscale are some kind of 'bubbles' or users that contain our machines.

type UserACLPolicy added in v0.0.9

type UserACLPolicy struct {
	ID uint64 `gorm:"primary_key"`

	UserID uint `gorm:"unique"`
	User   User `gorm:"foreignKey:UserID"`

	ACLPolicy ACLPolicy `gorm:"json"`

	CreatedAt time.Time
	UpdatedAt time.Time
}

UserACLPolicy is a group of acl rules to manage access between devices of a single user.

type WindowsRegistryConfig

type WindowsRegistryConfig struct {
	URL string
}

Directories

Path Synopsis
cmd
gen
go/headscale/v1
Package v1 is a reverse proxy.
Package v1 is a reverse proxy.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL