Documentation
¶
Overview ¶
Package vault provides age-encrypted credential management.
Package vault provides age-encrypted credential management.
The vault stores credentials (username/password pairs) encrypted with age, organized into contexts that map to SSH config include files. It supports multiple security backends via the agent package.
Storage Structure ¶
Credentials are stored in an age-encrypted JSON file:
$XDG_CONFIG_HOME/nssh/credentials.age
The encryption key is either:
- Software mode: passphrase-protected age identity (age.key.enc)
- PIV mode: YubiKey hardware-backed key (piv.json)
Credential Resolution ¶
The Manager.ResolveCredential method finds credentials for a host using a priority-based lookup:
- Host-specific credential (exact hostname match)
- Context default credential (from the SSH include file)
- Domain-based credential (matching domain suffix)
Contexts ¶
Contexts group related hosts and credentials, typically corresponding to SSH config include files (e.g., "work.conf", "home.conf"). Each context can have a default credential and host-specific overrides.
Session Integration ¶
The vault requires an active agent session for decryption. Use Manager.NeedsUnlock to check if unlock is required, and coordinate with the session package for agent communication.
Index ¶
- Variables
- func DetectSecurityMode(configDir string) (string, error)
- func HasMultipleKeystores(configDir string) bool
- func IsInitialized(configDir string) bool
- type Context
- type ContextEntry
- type Credential
- type DecryptFunc
- type HostCredentials
- type LockFunc
- type Manager
- func (m *Manager) AddContextCredential(name, username string, password *secret.Secret, overwrite bool) error
- func (m *Manager) AddHostCredential(host, username string, password *secret.Secret) error
- func (m *Manager) AuditLogger() *logging.AuditLogger
- func (m *Manager) ConfigDir() string
- func (m *Manager) CreateBackup() (string, error)
- func (m *Manager) CreateContext(name, gitIncludeFile, domain string, cred *Credential) error
- func (m *Manager) CredentialPath() string
- func (m *Manager) DeleteContext(name string) (bool, error)
- func (m *Manager) DeleteHostCredentials(host string) (bool, error)
- func (m *Manager) GetContext(name string) (*ContextEntry, error)
- func (m *Manager) GetContextByIncludeFile(includeFile string) (*ContextEntry, error)
- func (m *Manager) GetHostCredentials(host string) ([]Credential, error)
- func (m *Manager) GetHostDefaultCredential(host string) (string, error)
- func (m *Manager) GetIdentity() (age.Identity, error)
- func (m *Manager) GetRecipient() (age.Recipient, error)
- func (m *Manager) ListContexts() ([]ContextEntry, error)
- func (m *Manager) ListHostsWithCredentials() (map[string]bool, error)
- func (m *Manager) Lock() error
- func (m *Manager) ModeString() string
- func (m *Manager) NeedsUnlock() bool
- func (m *Manager) ReEncryptVault(newRecipient age.Recipient) error
- func (m *Manager) ReEncryptVaultWithVerify(newRecipient age.Recipient, verifyFn func(tempPath string) error) (backupPath string, err error)
- func (m *Manager) RemoveContextCredential(name string) error
- func (m *Manager) RemoveHostCredential(host, username string) (bool, error)
- func (m *Manager) ResolveCredential(host, gitIncludeFile, username string) (*ResolvedCredential, error)
- func (m *Manager) ResolveCredentialWithDomain(host, username string) (*ResolvedCredential, error)
- func (m *Manager) SetHostDefaultCredential(host, username string) error
- func (m *Manager) SoftwareStore() software.Store
- func (m *Manager) UpdateContextDomain(name, domain string) error
- func (m *Manager) UpdateContextIncludeFile(name, gitIncludeFile string) error
- func (m *Manager) UpdateHostCredential(host, username string, password *secret.Secret) (bool, error)
- func (m *Manager) WithLock(fn func() error) error
- type Mode
- type Option
- type ResolvedCredential
- type SessionAvailableFunc
- type SessionDeps
- type VaultData
Constants ¶
This section is empty.
Variables ¶
var ErrAmbiguousMode = errors.New("ambiguous state: both software and hardware keystores found")
ErrAmbiguousMode is returned when both software and hardware keystores exist.
var ErrNotInitialized = errors.New("not initialized: no keystore found")
ErrNotInitialized is returned when no keystore is found.
ErrSessionUnavailable indicates no decrypt session is available.
Functions ¶
func DetectSecurityMode ¶
DetectSecurityMode returns the current security mode based on filesystem state. It checks for the presence of keystore files rather than reading config.
Returns:
- agent.ModeSoftware if age.key.enc exists (and piv.json doesn't)
- agent.ModePIV if piv.json exists (and age.key.enc doesn't)
- ErrAmbiguousMode if both keystores exist
- ErrNotInitialized if neither keystore exists
func HasMultipleKeystores ¶
HasMultipleKeystores returns true if both software and hardware keystores exist. This indicates an ambiguous or partial state, typically from a failed mode switch.
func IsInitialized ¶
IsInitialized returns true if at least one keystore exists.
Types ¶
type Context ¶
type Context struct {
GitIncludeFile string `json:"git_include_file"`
Credential *Credential `json:"credential"`
Domain string `json:"domain"`
}
Context represents a credential context with associated metadata.
type ContextEntry ¶
type ContextEntry struct {
Name string `json:"name"`
GitIncludeFile string `json:"git_include_file"`
Domain string `json:"domain"`
Credential *Credential `json:"credential"`
CredentialCount int `json:"credential_count"`
}
ContextEntry is returned by ListContexts with computed fields.
type Credential ¶
type Credential struct {
Username string `json:"username"`
Password string `json:"password"`
Default bool `json:"default,omitempty"`
}
Credential represents a username/password pair.
type DecryptFunc ¶
DecryptFunc decrypts vault ciphertext via an external session (typically agent). Implementations should respect ctx (deadlines/cancel) where possible.
type HostCredentials ¶
type HostCredentials struct {
Credentials []Credential `json:"credentials"`
}
HostCredentials represents host-specific credentials.
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager handles age-encrypted credential storage.
func NewManager ¶
NewManager creates a vault manager with the specified mode. Options are for orthogonal concerns (logging, paths) only.
func (*Manager) AddContextCredential ¶
func (m *Manager) AddContextCredential(name, username string, password *secret.Secret, overwrite bool) error
AddContextCredential adds or updates a context's credential.
func (*Manager) AddHostCredential ¶
AddHostCredential adds a credential to a host.
Parameters:
- host: The SSH Host identifier (unique within a context/include file)
- username: The username for the credential
- password: The password for the credential
func (*Manager) AuditLogger ¶
func (m *Manager) AuditLogger() *logging.AuditLogger
AuditLogger exposes the underlying audit logger (nil if auditing disabled).
func (*Manager) CreateBackup ¶
CreateBackup creates a timestamped backup of the current vault. Returns the backup path on success, empty string if no vault exists.
func (*Manager) CreateContext ¶
func (m *Manager) CreateContext(name, gitIncludeFile, domain string, cred *Credential) error
CreateContext creates a new context.
func (*Manager) CredentialPath ¶
CredentialPath returns the path to the credential file.
func (*Manager) DeleteContext ¶
DeleteContext removes a context.
func (*Manager) DeleteHostCredentials ¶
DeleteHostCredentials removes all credentials for a host.
Parameters:
- host: The SSH Host identifier (unique within a context/include file)
func (*Manager) GetContext ¶
func (m *Manager) GetContext(name string) (*ContextEntry, error)
GetContext returns a context by name.
func (*Manager) GetContextByIncludeFile ¶
func (m *Manager) GetContextByIncludeFile(includeFile string) (*ContextEntry, error)
GetContextByIncludeFile returns a context matching the SSH include file. Accepts either a filename or full path - extracts basename for matching.
func (*Manager) GetHostCredentials ¶
func (m *Manager) GetHostCredentials(host string) ([]Credential, error)
GetHostCredentials returns credentials for a specific host.
Parameters:
- host: The SSH Host identifier (unique within a context/include file)
func (*Manager) GetHostDefaultCredential ¶
GetHostDefaultCredential returns the default credential username for a host.
Parameters:
- host: The SSH Host identifier (unique within a context/include file)
func (*Manager) GetIdentity ¶
GetIdentity returns the current age identity for decryption. Requires the vault to be unlocked.
func (*Manager) GetRecipient ¶
GetRecipient returns the age recipient for encryption. Does NOT require unlock - reads from cached value, store, or age.pub file.
func (*Manager) ListContexts ¶
func (m *Manager) ListContexts() ([]ContextEntry, error)
ListContexts returns all contexts sorted by name.
func (*Manager) ListHostsWithCredentials ¶
ListHostsWithCredentials returns a set of Host identifiers that have custom credentials.
func (*Manager) ModeString ¶
ModeString returns the mode as a string for logging/IPC.
func (*Manager) NeedsUnlock ¶
NeedsUnlock returns true if the vault requires unlock before use. Returns false if a session is already available or identities are pre-loaded.
func (*Manager) ReEncryptVault ¶
ReEncryptVault re-encrypts the vault with a new recipient. For safer migration with verification, use ReEncryptVaultWithVerify.
func (*Manager) ReEncryptVaultWithVerify ¶
func (m *Manager) ReEncryptVaultWithVerify(newRecipient age.Recipient, verifyFn func(tempPath string) error) (backupPath string, err error)
ReEncryptVaultWithVerify re-encrypts the vault with a new recipient. If verifyFn is provided, it's called with the temp file path before committing. The original file is only replaced if verification succeeds. Returns the backup path (for recovery if needed) and any error.
func (*Manager) RemoveContextCredential ¶
RemoveContextCredential removes a context's credential.
func (*Manager) RemoveHostCredential ¶
RemoveHostCredential removes a specific credential by username from a host. Returns true if a credential was removed, false if not found.
Parameters:
- host: The SSH Host identifier (unique within a context/include file)
- username: The username to remove
func (*Manager) ResolveCredential ¶
func (m *Manager) ResolveCredential(host, gitIncludeFile, username string) (*ResolvedCredential, error)
ResolveCredential resolves credentials for a host using the resolution algorithm.
Parameters:
- host: The SSH Host identifier (unique within a context/include file)
- gitIncludeFile: The SSH config include file basename (for context lookup)
- username: Optional username filter (empty = use default)
Algorithm: If username specified:
- Search hosts[host].credentials for username match
- Search context.credential for username match (if context exists)
- Return nil if not found
If username not specified:
- If a host credential has default=true, use that credential
- Otherwise fall back to context.credential
- Return nil
func (*Manager) ResolveCredentialWithDomain ¶
func (m *Manager) ResolveCredentialWithDomain(host, username string) (*ResolvedCredential, error)
ResolveCredentialWithDomain resolves credentials using domain-based context matching. This is used when the host identifier matches a context's domain pattern.
Parameters:
- host: The SSH Host identifier (unique within a context/include file)
- username: Optional username filter (empty = use default)
func (*Manager) SetHostDefaultCredential ¶
SetHostDefaultCredential sets the default credential username for a host. Pass empty username to clear the default.
Parameters:
- host: The SSH Host identifier (unique within a context/include file)
- username: The username to set as default (empty to clear)
func (*Manager) SoftwareStore ¶
SoftwareStore returns the software store for CLI unlock operations. Returns nil for hardware modes.
func (*Manager) UpdateContextDomain ¶
UpdateContextDomain updates a context's domain.
func (*Manager) UpdateContextIncludeFile ¶
UpdateContextIncludeFile updates a context's SSH config include file.
func (*Manager) UpdateHostCredential ¶
func (m *Manager) UpdateHostCredential(host, username string, password *secret.Secret) (bool, error)
UpdateHostCredential updates the password for an existing host credential. Returns true if updated, false if not found.
Parameters:
- host: The SSH Host identifier (unique within a context/include file)
- username: The username to update
- password: The new password
type Mode ¶
type Mode interface {
// contains filtered or unexported methods
}
Mode is a sealed interface for manager initialization modes. The unexported mode() method ensures only types in this package can implement Mode.
func Auto ¶
func Auto() Mode
Auto returns a mode that detects configuration from existing files. This is the only mode with a valid zero-value (no parameters needed).
func Hardware ¶
Hardware returns a mode using a key stored on a hardware device. The agent mediates access to the hardware token. Panics if kind is empty (programming error). Unknown kinds return errors from NewManager, not panics, since they may come from config.
func Provided ¶
func Provided(identity *age.X25519Identity) Mode
Provided returns a mode using an already-decrypted identity. Used for rekey/enrollment operations where the identity is obtained externally. Panics if identity is nil (programming error).
type Option ¶
type Option func(*managerConfig)
Option configures orthogonal concerns that apply across all modes.
func WithAuditLogger ¶
func WithAuditLogger(logger *logging.AuditLogger) Option
WithAuditLogger sets the audit logger for security events.
func WithMaxBackups ¶
WithMaxBackups sets the maximum number of credential backups to retain.
func WithSessionDeps ¶
func WithSessionDeps(deps SessionDeps) Option
WithSessionDeps injects optional locked-mode session behavior. The zero-value (all fields nil) means "no session available".
type ResolvedCredential ¶
type ResolvedCredential struct {
Username string
Password *secret.Secret
Source string // "host", "context", or "default"
}
ResolvedCredential represents a resolved username/password pair.
type SessionAvailableFunc ¶
SessionAvailableFunc reports whether a decrypt session is available.
type SessionDeps ¶
type SessionDeps struct {
BaseContext context.Context
Available SessionAvailableFunc
Decrypt DecryptFunc
Lock LockFunc
}
SessionDeps holds optional agent-backed session behavior. Zero-value (all fields nil) means "no session available".
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package hardware provides types for hardware security device integration.
|
Package hardware provides types for hardware security device integration. |
|
Package piv provides PIV keystore persistence and ECIES crypto helpers.
|
Package piv provides PIV keystore persistence and ECIES crypto helpers. |
|
Package software provides host-backed age identity storage.
|
Package software provides host-backed age identity storage. |