Documentation
¶
Index ¶
- func BaseMethod(method string) string
- func FetchTokenFromSocket(ctx context.Context, socketPath string) (string, error)
- func IsExpired(err error) bool
- func ReadTokenEnv() string
- func ReadTokenFile(path string) (string, error)
- func ResolveToken(tokenFilePath string) string
- func SealTokenAtRest(method string) bool
- func WriteTokenFile(path string, token string, seal bool) error
- type LifecycleManager
- func (lm *LifecycleManager) NeedsReauth() bool
- func (lm *LifecycleManager) Reload()
- func (lm *LifecycleManager) SetOnReauth(fn func())
- func (lm *LifecycleManager) SetTokenFilePath(p string)
- func (lm *LifecycleManager) SetTokenSocket(p string)
- func (lm *LifecycleManager) Start(ctx context.Context) <-chan error
- type LoginStatus
- type LoginTracker
- type MTLSParams
- type Manager
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func BaseMethod ¶ added in v0.23.0
BaseMethod strips the "+tpm" sealing modifier, returning the underlying auth flow: "oidc", "ldap", "token", or "mtls". The login dispatch switches on this so a "+tpm" variant routes to the same flow as its base.
func FetchTokenFromSocket ¶ added in v0.24.0
FetchTokenFromSocket retrieves a Vault token from a peer dotvault daemon's web API exposed over a Unix-domain socket — the programmatic equivalent of
curl --unix-socket <socketPath> http://localhost/api/v1/token
It backs dotvault-to-dotvault token sharing: a remote-forwarded socket (e.g. ~/.ssh/dotvault.sock created by an SSH RemoteForward from a machine running the dotvault web UI) lets a host with no interactive login facility borrow the live token from a peer that has one.
It is best-effort and never fatal. An empty path, an unexpandable ~, a missing socket file, a stale socket (file present but no listener), a non-200 response (the peer holds no token), or a malformed body all resolve to ("", nil) so the caller simply carries on with its normal auth flow. The returned token is deliberately NOT validated here — callers run LookupSelf before adopting it, exactly as they do for the token file and DOTVAULT_TOKEN.
func IsExpired ¶
IsExpired reports whether err is the token-expired sentinel. The Start loop uses this to route expired tokens through the same recovery path as a 403 response.
func ReadTokenEnv ¶
func ReadTokenEnv() string
ReadTokenEnv reads the Vault token from the DOTVAULT_TOKEN environment variable. VAULT_TOKEN is deliberately ignored — it belongs to the `vault` CLI, and honouring it would let an unrelated shell session's token leak into the daemon (the Vault SDK's own VAULT_TOKEN pickup is likewise neutralised in internal/vault.NewClient).
An env-var token is necessarily plaintext: there is no way to TPM-seal an environment value. The "+tpm" sealing applies only to the token file.
func ReadTokenFile ¶
ReadTokenFile reads a Vault token from a file, trimming whitespace. Returns empty string (not error) if the file doesn't exist.
A file written by WriteTokenFile with sealing on carries sealedTokenPrefix; this transparently unseals it via the TPM. A plaintext file is returned verbatim, so existing token files keep working and migration is free.
func ResolveToken ¶
ResolveToken returns a Vault token, checking the DOTVAULT_TOKEN env var first, then the token file. Returns empty string if neither is set. A sealed token file that cannot be unsealed resolves to "" (the warning is logged in ReadTokenFile), which the auth flow treats as "no usable token, re-authenticate" — never a silent plaintext fallback.
func SealTokenAtRest ¶ added in v0.23.0
SealTokenAtRest reports whether the auth method requests TPM-sealing of the token file — the "+tpm" suffix. When true, WriteTokenFile seals the token under the TPM and writes a self-describing sealed envelope, which ReadTokenFile transparently unseals on read (so the daemon, the CLI, and the public client/ facade all consume it without knowing the method).
func WriteTokenFile ¶
WriteTokenFile writes a Vault token to a file with 0600 permissions. When seal is true the token is sealed under the TPM (machine-bound) and written as a self-describing sealed envelope that ReadTokenFile transparently unseals. Sealing requires a working TPM (Linux/Windows); seal=true on a host with no hardware backend returns an error rather than silently writing plaintext — the same no-silent-fallback contract as mtls+tpm key sealing.
Types ¶
type LifecycleManager ¶
type LifecycleManager struct {
// contains filtered or unexported fields
}
LifecycleManager manages token TTL checks and renewal.
func NewLifecycleManager ¶
func NewLifecycleManager(client *vault.Client, checkInterval time.Duration, disableRenewal bool) *LifecycleManager
NewLifecycleManager creates a new token lifecycle manager. When disableRenewal is true the manager still monitors TTL and signals re-auth when the token expires, but never calls RenewSelf.
func (*LifecycleManager) NeedsReauth ¶
func (lm *LifecycleManager) NeedsReauth() bool
NeedsReauth returns true if the token is expired or needs re-authentication.
func (*LifecycleManager) Reload ¶
func (lm *LifecycleManager) Reload()
Reload signals the lifecycle goroutine to perform an immediate tryReload on the next scheduling pass — used by the SIGHUP handler and by the in-process token-file watcher (internal/tokenwatch) so a freshly-written token file (the configured tokenFilePath, by default ~/.dotvault-token) is picked up without waiting for the 5-minute lifecycle tick. Coalescing: concurrent or back-to-back calls collapse into a single reload. Safe to call before or after Start; calls made before Start are buffered and consumed by the goroutine on its first select.
func (*LifecycleManager) SetOnReauth ¶
func (lm *LifecycleManager) SetOnReauth(fn func())
SetOnReauth registers a callback fired when the manager transitions into the needs-reauth state. The callback runs synchronously on the lifecycle goroutine — keep it short. In web mode this is used to clear the in-memory Vault token so the SPA's status check reflects "logged out".
func (*LifecycleManager) SetTokenFilePath ¶
func (lm *LifecycleManager) SetTokenFilePath(p string)
SetTokenFilePath wires a token file path so that on detection of an invalid/expired token the manager will attempt to reload (and re-validate) the token from disk or DOTVAULT_TOKEN before declaring re-auth necessary. This lets an external facility (e.g. a tty session running `dotvault login`) recover a running daemon without a restart.
func (*LifecycleManager) SetTokenSocket ¶ added in v0.24.0
func (lm *LifecycleManager) SetTokenSocket(p string)
SetTokenSocket wires the path to a peer dotvault's web-API Unix socket so the recovery path can borrow the peer's live token (dotvault-to-dotvault sharing) before declaring re-auth necessary. Empty disables it. See FetchTokenFromSocket.
type LoginStatus ¶
type LoginStatus struct {
State string `json:"state"`
Token string `json:"-"`
Error string `json:"error,omitempty"`
MFAMethods []vault.MFAMethod `json:"mfa_methods,omitempty"`
}
LoginStatus represents the current state of an async login attempt.
type LoginTracker ¶
type LoginTracker struct {
// contains filtered or unexported fields
}
LoginTracker manages async login attempts keyed by session ID.
func NewLoginTracker ¶
func NewLoginTracker(vc *vault.Client) *LoginTracker
NewLoginTracker creates a new LoginTracker.
func (*LoginTracker) Clear ¶
func (lt *LoginTracker) Clear(sessionID string)
Clear removes a completed login session.
func (*LoginTracker) Close ¶
func (lt *LoginTracker) Close()
Close stops the background GC goroutine.
func (*LoginTracker) GetStatus ¶
func (lt *LoginTracker) GetStatus(sessionID string) *LoginStatus
GetStatus returns the current login status for a session. Returns nil if the session does not exist.
func (*LoginTracker) StartLogin ¶
func (lt *LoginTracker) StartLogin(sessionID, mount, username, password string)
StartLogin begins an async LDAP login attempt. The login runs in a background goroutine with a 5-minute timeout. Poll GetStatus to check progress.
func (*LoginTracker) SubmitTOTP ¶
func (lt *LoginTracker) SubmitTOTP(sessionID, passcode string)
SubmitTOTP submits a TOTP passcode for an in-progress MFA login.
type MTLSParams ¶ added in v0.23.0
type MTLSParams struct {
// Connectivity for building a cert-presenting login client.
VaultAddress string
CACert string
TLSSkipVerify bool
Method string // "mtls" | "mtls+tpm"
BootstrapMethod string
BootstrapMount string
CertMount string
CertRole string
PKIMount string
PKIRole string
KeyType string
CommonName string // template over {{.user}}
TTL string
ReissueBefore time.Duration
SealToPCRs bool
StorageDir string
BYOCert string
BYOKey string
}
MTLSParams carries everything the cert-auth flow needs. It is populated by the daemon (cmd/dotvault) from the validated vault.mtls config and attached to a Manager whose AuthMethod is "mtls" or "mtls+tpm".
type Manager ¶
type Manager struct {
VaultClient *vault.Client
TokenFilePath string
// AuthMethod is the configured method: "oidc", "ldap", "token", "mtls", or
// "mtls+tpm". A "+tpm" suffix on any base method (e.g. "oidc+tpm") also
// requests TPM-sealing of the cached token file at rest; for "mtls+tpm"
// that is in addition to the cert key the cert flow already seals.
AuthMethod string
AuthMount string // auth mount path
AuthRole string // optional role
Username string
// TokenSocket is an optional path to a peer dotvault's web-API Unix
// socket. When set, Login first tries to borrow a live token from the
// peer (dotvault-to-dotvault sharing) before running the configured
// interactive flow. A missing or stale socket is ignored. See
// FetchTokenFromSocket.
TokenSocket string
// MTLS is required when the base auth method is "mtls".
MTLS *MTLSParams
}
Manager orchestrates Vault authentication.
func (*Manager) Authenticate ¶
Authenticate attempts to authenticate with Vault. It first tries to reuse an existing token, then falls back to the configured method.
func (*Manager) Login ¶
Login runs the configured fresh-auth flow unconditionally, without attempting to reuse an existing token. Used by `dotvault login` and as the fallback path inside Authenticate.
func (*Manager) ReissueIfDue ¶ added in v0.23.0
ReissueIfDue rotates the certificate when it is inside the re-issue window, using the current operational Vault token (no human). It is a no-op for non-cert methods, when no credential exists, or when the cert is not yet due for rotation. The daemon calls this periodically so a long-running process whose token keeps renewing still rotates its certificate before expiry — without this, a warm daemon never re-enters the cert flow and the cert could expire unrotated. Safe to call repeatedly: after one successful rotation the fresh NotAfter moves out of the window and subsequent calls return nil.