Documentation
¶
Overview ¶
Package config loads tailkeeper's gate configuration (spec §15).
In M1 the configuration holds contexts (tailnet ID plus read credential), local CLI settings, the MCP profile and audit settings. Unknown keys are rejected: a typo must never be silently ignored.
Index ¶
- Constants
- func CheckOwnership(path string, allowOwners ...int) error
- func CheckSecretFile(path string) error
- func OwnedBy(owners ...int) func(path string, opened os.FileInfo) error
- func ReadSecretFile(path string) ([]byte, error)
- type ACL
- type Audit
- type Checker
- type Config
- type Context
- type Credentials
- type Dirs
- type Loaded
- type Local
- type MCP
- type Provider
- type Source
Constants ¶
const ( PersonalDataMask = "mask" PersonalDataShow = "show" )
Values of Config.PersonalData.
const ( DefaultValidatePerMinute = 30 MinValidatePerMinute = 1 MaxValidatePerMinute = 120 )
The bounds of ACL.ValidatePerMinute.
const FileName = "config.hujson"
FileName is the configuration file inside a configuration directory.
const StrictModeEnforced = true
StrictModeEnforced reports whether CheckOwnership and CheckSecretFile verify ownership and permissions on this platform.
Variables ¶
This section is empty.
Functions ¶
func CheckOwnership ¶
CheckOwnership is the default Checker: path must be a regular file (not a symlink) and path and its directory must be owned by one of allowOwners and writable by neither group nor others.
func CheckSecretFile ¶
CheckSecretFile is stricter: owner-only permissions (no group or other access at all).
func OwnedBy ¶ added in v0.6.0
OwnedBy returns the check for safefile.Options.Verify that holds a file to the rule CheckOwnership applies, on the file that was opened: fi is the open file's Stat, so what is judged is the file that is read, not whatever the path names a moment before or after. The file must be regular, and it and its directory must be owned by one of owners and writable by neither group nor others. Windows reads no owner; there it refuses a file that is not a regular one and nothing else.
func ReadSecretFile ¶
ReadSecretFile is CheckSecretFile and the read in one step: the bytes come from the file that was checked. A file that is not there is the system's own error, with no code, so that the caller can name what to create and give it the code that fits (credential_unavailable, privacy_key_unavailable); a file that is there and cannot be inspected is config_unsafe.
Types ¶
type ACL ¶ added in v0.6.0
type ACL struct {
// InvariantsFile is the absolute path of the invariants file: tests every
// validation must also pass (a HuJSON object with optional "tests" and
// "sshTests"). Unset means no invariants. A set path that is missing or
// unreadable fails every call that uses it; it is never taken for none.
InvariantsFile string `json:"invariantsFile,omitempty"`
// ValidatePerMinute is the process's own limit on the policy validation requests
// tailkeeper decides to send, 1 to 120; a retry of a request takes no token. Unset
// means DefaultValidatePerMinute.
ValidatePerMinute *int `json:"validatePerMinute,omitempty"`
}
ACL configures the policy checks (acl validate, acl diff). The keys are read by 0.6.0 and later: a 0.5.0 binary refuses them as unknown (config_invalid), so they belong in a context only 0.6.0 uses.
func (ACL) ValidateRate ¶ added in v0.6.0
ValidateRate is the validation requests per minute this process decides to send.
type Audit ¶
type Audit struct {
Reads string `json:"reads,omitempty"` // "metadata" (default) or "none"
}
Audit configures tailkeeper's own audit log.
type Config ¶
type Config struct {
Contexts map[string]Context `json:"contexts"`
DefaultContext string `json:"defaultContext,omitempty"`
Local Local `json:"local,omitzero"`
MCP MCP `json:"mcp,omitzero"`
Audit Audit `json:"audit,omitzero"`
ACL ACL `json:"acl,omitzero"`
// PersonalData is "mask" (the default) or "show": whether tool results carry
// login names, display names, email addresses and public IP addresses whole
// (spec Appendix C).
PersonalData string `json:"personalData,omitempty"`
}
Config is the decoded config.hujson.
type Context ¶
type Context struct {
TailnetID string `json:"tailnetId"`
Credentials Credentials `json:"credentials"`
}
Context binds one tailnet to its credentials. It never carries gate settings.
type Credentials ¶
type Credentials struct {
Read Provider `json:"read"`
}
Credentials per class. M1 implements the read class only.
type Dirs ¶
type Dirs struct {
System string // root-owned gate configuration (wins outright when it has a config)
User string // personal-mode configuration
State string // plans and other state (later milestones)
Logs string // audit log
}
Dirs are the directories tailkeeper reads and writes.
func DefaultDirs ¶
DefaultDirs returns the platform directories of spec §15.
type Loaded ¶
type Loaded struct {
Config Config
Source Source
Path string
Dirs Dirs
IgnoredUserConfig bool // a user config exists but the system config won (spec §15: no merging)
}
Loaded is a configuration together with where it came from.
type Local ¶
type Local struct {
TailscaleBinary string `json:"tailscaleBinary,omitempty"`
Socket string `json:"socket,omitempty"`
DNSQueryAllowlist []string `json:"dnsQueryAllowlist,omitempty"`
}
Local configures the local tailscale CLI tools.
type MCP ¶
type MCP struct {
Profile string `json:"profile,omitempty"` // "reads" (default), "core", "full"
EnableAlpha bool `json:"enableAlpha,omitempty"`
}
MCP configures the stdio MCP server.
type Provider ¶
type Provider struct {
Provider string `json:"provider"` // "env", "file", "exec" or "oidc"
Command []string `json:"command,omitempty"` // exec: absolute wrapper argv, e.g. ["/path/to/wrapper","--env-file=/etc/tailkeeper/read.env","--"]
Path string `json:"path,omitempty"` // file: absolute path to a 0600 NAME=value file
ClientID string `json:"clientId,omitempty"` // oidc: federated identity client ID (not a secret)
Audience string `json:"audience,omitempty"` // oidc: defaults to api.tailscale.com/<clientId>
TokenFile string `json:"tokenFile,omitempty"` // oidc: file holding a platform identity token
}
Provider says where a credential comes from (spec §7.3).