Help us shape the future of Go! Take the 2026 Go Developer Survey

server

package
v0.40.0 Latest Latest
Warning

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

Go to latest
Published: Oct 26, 2026 License: Apache-2.0 Imports: 50 Imported by: 0

Documentation

Index

Constants

View Source
const (
	DefaultSessionTTL    = 30 * time.Minute       // Default TTL for session data in Consul
	DefaultConsulTimeout = 5 * time.Second        // Default timeout for Consul operations
	DefaultWatchTimeout  = 10 * time.Minute       // Default timeout for Consul watch operations (long-polling)
	DefaultMaxRetries    = 3                      // Default number of retries for Consul operations
	DefaultRetryDelay    = 100 * time.Millisecond // Default delay between retries
	DefaultKeyPrefix     = "uptermd"              // Default key prefix for Consul storage
	UnusedNodeAddress    = "localhost"            // Placeholder address for node registration (not used but required by Consul)
)
View Source
const DefaultHandshakeTimeout = 60 * time.Second

Variables

View Source
var (
	// ErrSuperseded refuses a registration that doesn't supersede the one the
	// store holds for its ID.
	ErrSuperseded = errors.New("superseded by a newer registration")
	// ErrLeaseLost is the definite answer that a registration no longer holds
	// its entry, as opposed to a renewal that merely failed.
	ErrLeaseLost = errors.New("session lease lost")
)
View Source
var ErrListnerClosed = errors.New("routing: listener closed")
View Source
var File_server_proto protoreflect.FileDescriptor

Functions

func Start

func Start(ctx context.Context, opt Opt, logger *slog.Logger) error

Types

type AuthRequest

type AuthRequest struct {
	ClientVersion string `protobuf:"bytes,1,opt,name=client_version,json=clientVersion,proto3" json:"client_version,omitempty"`
	RemoteAddr    string `protobuf:"bytes,2,opt,name=remote_addr,json=remoteAddr,proto3" json:"remote_addr,omitempty"`
	AuthorizedKey []byte `protobuf:"bytes,3,opt,name=authorized_key,json=authorizedKey,proto3" json:"authorized_key,omitempty"`
	// The relay's own end of the guest's connection, as remote_addr is the
	// guest's: the server half of the SSH_CONNECTION a guest's forced command
	// sees. Empty from a relay that predates it.
	LocalAddr string `protobuf:"bytes,4,opt,name=local_addr,json=localAddr,proto3" json:"local_addr,omitempty"`
	// contains filtered or unexported fields
}

func (*AuthRequest) Descriptor deprecated

func (*AuthRequest) Descriptor() ([]byte, []int)

Deprecated: Use AuthRequest.ProtoReflect.Descriptor instead.

func (*AuthRequest) GetAuthorizedKey

func (x *AuthRequest) GetAuthorizedKey() []byte

func (*AuthRequest) GetClientVersion

func (x *AuthRequest) GetClientVersion() string

func (*AuthRequest) GetLocalAddr added in v0.37.0

func (x *AuthRequest) GetLocalAddr() string

func (*AuthRequest) GetRemoteAddr

func (x *AuthRequest) GetRemoteAddr() string

func (*AuthRequest) ProtoMessage

func (*AuthRequest) ProtoMessage()

func (*AuthRequest) ProtoReflect added in v0.5.0

func (x *AuthRequest) ProtoReflect() protoreflect.Message

func (*AuthRequest) Reset

func (x *AuthRequest) Reset()

func (*AuthRequest) String

func (x *AuthRequest) String() string

type CreateSessionRequest

type CreateSessionRequest struct {
	HostUser             string   `protobuf:"bytes,1,opt,name=hostUser,proto3" json:"hostUser,omitempty"`
	HostPublicKeys       [][]byte `protobuf:"bytes,2,rep,name=hostPublicKeys,proto3" json:"hostPublicKeys,omitempty"`
	ClientAuthorizedKeys [][]byte `protobuf:"bytes,3,rep,name=clientAuthorizedKeys,proto3" json:"clientAuthorizedKeys,omitempty"`
	// The next three fields claim a session ID derived from the host's key. The
	// relay honours them only with a proof; a request without one gets a random
	// ID.
	//
	// The per-run secret the ID derives from, together with the single host key
	// in hostPublicKeys.
	SessionSecret []byte `protobuf:"bytes,4,opt,name=sessionSecret,proto3" json:"sessionSecret,omitempty"`
	// Orders registrations of the same ID; at least 1.
	Generation uint64 `protobuf:"varint,5,opt,name=generation,proto3" json:"generation,omitempty"`
	// The host key's signature over this connection's SSH session ID, the
	// secret and the generation.
	HostKeyProof []byte `protobuf:"bytes,6,opt,name=hostKeyProof,proto3" json:"hostKeyProof,omitempty"`
	// contains filtered or unexported fields
}

func (*CreateSessionRequest) Descriptor deprecated

func (*CreateSessionRequest) Descriptor() ([]byte, []int)

Deprecated: Use CreateSessionRequest.ProtoReflect.Descriptor instead.

func (*CreateSessionRequest) GetClientAuthorizedKeys

func (x *CreateSessionRequest) GetClientAuthorizedKeys() [][]byte

func (*CreateSessionRequest) GetGeneration added in v0.34.0

func (x *CreateSessionRequest) GetGeneration() uint64

func (*CreateSessionRequest) GetHostKeyProof added in v0.34.0

func (x *CreateSessionRequest) GetHostKeyProof() []byte

func (*CreateSessionRequest) GetHostPublicKeys

func (x *CreateSessionRequest) GetHostPublicKeys() [][]byte

func (*CreateSessionRequest) GetHostUser

func (x *CreateSessionRequest) GetHostUser() string

func (*CreateSessionRequest) GetSessionSecret added in v0.34.0

func (x *CreateSessionRequest) GetSessionSecret() []byte

func (*CreateSessionRequest) ProtoMessage

func (*CreateSessionRequest) ProtoMessage()

func (*CreateSessionRequest) ProtoReflect added in v0.5.0

func (x *CreateSessionRequest) ProtoReflect() protoreflect.Message

func (*CreateSessionRequest) Reset

func (x *CreateSessionRequest) Reset()

func (*CreateSessionRequest) String

func (x *CreateSessionRequest) String() string

type CreateSessionResponse

type CreateSessionResponse struct {
	SessionID string `protobuf:"bytes,1,opt,name=sessionID,proto3" json:"sessionID,omitempty"`
	NodeAddr  string `protobuf:"bytes,2,opt,name=nodeAddr,proto3" json:"nodeAddr,omitempty"`
	SshUser   string `protobuf:"bytes,3,opt,name=ssh_user,json=sshUser,proto3" json:"ssh_user,omitempty"` // SSH username for client connections
	// True when this relay admits any host key (no --authorized-keys), so a
	// host can authenticate a redial with its session key alone.
	SessionKeyRedial bool `protobuf:"varint,4,opt,name=sessionKeyRedial,proto3" json:"sessionKeyRedial,omitempty"`
	// contains filtered or unexported fields
}

func (*CreateSessionResponse) Descriptor deprecated

func (*CreateSessionResponse) Descriptor() ([]byte, []int)

Deprecated: Use CreateSessionResponse.ProtoReflect.Descriptor instead.

func (*CreateSessionResponse) GetNodeAddr

func (x *CreateSessionResponse) GetNodeAddr() string

func (*CreateSessionResponse) GetSessionID

func (x *CreateSessionResponse) GetSessionID() string

func (*CreateSessionResponse) GetSessionKeyRedial added in v0.34.0

func (x *CreateSessionResponse) GetSessionKeyRedial() bool

func (*CreateSessionResponse) GetSshUser added in v0.15.0

func (x *CreateSessionResponse) GetSshUser() string

func (*CreateSessionResponse) ProtoMessage

func (*CreateSessionResponse) ProtoMessage()

func (*CreateSessionResponse) ProtoReflect added in v0.5.0

func (x *CreateSessionResponse) ProtoReflect() protoreflect.Message

func (*CreateSessionResponse) Reset

func (x *CreateSessionResponse) Reset()

func (*CreateSessionResponse) String

func (x *CreateSessionResponse) String() string

type ErrSessionNotFound added in v0.15.1

type ErrSessionNotFound struct {
	SessionID string
}

ErrSessionNotFound represents a non-retryable session not found error

func (*ErrSessionNotFound) Error added in v0.15.1

func (e *ErrSessionNotFound) Error() string

type HostCertSigner added in v0.5.0

type HostCertSigner struct {
	Hostnames []string
}

func (*HostCertSigner) SignCert added in v0.5.0

func (s *HostCertSigner) SignCert(signer ssh.Signer) (ssh.Signer, error)

type MemoryProvider

type MemoryProvider struct {
	SocketPath string
	// contains filtered or unexported fields
}

func (*MemoryProvider) Name

func (p *MemoryProvider) Name() string

func (*MemoryProvider) Opts

func (p *MemoryProvider) Opts() string

func (*MemoryProvider) SSHD

func (p *MemoryProvider) SSHD() SSHDDialListener

func (*MemoryProvider) Session

func (p *MemoryProvider) Session() SessionDialListener

func (*MemoryProvider) SetOpts

func (p *MemoryProvider) SetOpts(opts NetworkOptions) error

type NetworkOptions

type NetworkOptions map[string]string

type NetworkProvider

type NetworkProvider interface {
	SetOpts(opts NetworkOptions) error
	Session() SessionDialListener
	SSHD() SSHDDialListener
	Name() string
	Opts() string
}

type Opt

type Opt struct {
	HandshakeTimeout    time.Duration `mapstructure:"handshake-timeout"`
	SSHAddr             string        `mapstructure:"ssh-addr"`
	SSHProxyProtocol    bool          `mapstructure:"ssh-proxy-protocol"`
	WSAddr              string        `mapstructure:"ws-addr"`
	NodeAddr            string        `mapstructure:"node-addr"`
	AuthorizedKeysFiles []string      `mapstructure:"authorized-keys"`
	PrivateKeys         []string      `mapstructure:"private-key"`
	Hostnames           []string      `mapstructure:"hostname"`
	Network             string        `mapstructure:"network"`
	NetworkOpts         []string      `mapstructure:"network-opt"`
	MetricAddr          string        `mapstructure:"metric-addr"`
	Debug               bool          `mapstructure:"debug"`
	Routing             routing.Mode  `mapstructure:"routing"`
	ConsulURL           string        `mapstructure:"consul-url"`
	ConsulSessionTTL    string        `mapstructure:"consul-session-ttl"`
	SentryDSN           string        `mapstructure:"sentry-dsn"`
}

func (*Opt) ResolvedRouting added in v0.25.0

func (opt *Opt) ResolvedRouting() routing.Mode

ResolvedRouting returns the effective routing mode. It resolves ModeAuto against whether a Consul URL was configured, and supplies the ModeEmbedded default for a zero value.

func (*Opt) Validate added in v0.15.0

func (opt *Opt) Validate() error

Validate validates the server configuration

type Registration added in v0.34.0

type Registration struct {
	Session *Session
	// ConfirmedAt is the send time of the lock-session creation this
	// registration's lease came from (memory: taken before the write). The
	// expiry budget counts from it, and the lease's TTL clock can't have
	// started earlier, so the budget can only end early.
	ConfirmedAt time.Time
	// contains filtered or unexported fields
}

Registration is one stored claim to a session ID. Whatever later renews, releases or rebuilds the entry acts through the handle, so it can only touch its own claim, never a successor's.

func (*Registration) Capable added in v0.34.0

func (r *Registration) Capable() bool

Capable reports whether the host proved its key, and so can reconnect. A legacy registration keeps today's behaviour.

func (*Registration) Generation added in v0.34.0

func (r *Registration) Generation() uint64

func (*Registration) ID added in v0.34.0

func (r *Registration) ID() string

func (*Registration) Same added in v0.34.0

func (r *Registration) Same(o *Registration) bool

Same reports whether r and o are the same registration. A rebuild stores the same registration again under a new lease, and its handle stands in for the one it replaced, so this compares identity rather than handles.

type Route added in v0.34.0

type Route struct {
	NodeAddr   string
	Generation uint64
}

Route is where a guest's upstream was sent: the node, and the registration that was current when it was resolved.

type SSHDDialListener

type SSHDDialListener interface {
	Listen() (net.Listener, error)
	Dial() (net.Conn, error)
	DialContext(ctx context.Context) (net.Conn, error)
}

type SSHRouting

type SSHRouting struct {
	HandshakeTimeout time.Duration
	HostSigners      []ssh.Signer
	Auth             *proxyAuth
	Logger           *slog.Logger
	MetricsProvider  provider.Provider
	// contains filtered or unexported fields
}

func (*SSHRouting) Serve

func (p *SSHRouting) Serve(ln net.Listener) error

func (*SSHRouting) Shutdown

func (p *SSHRouting) Shutdown() error

type Server

type Server struct {
	HandshakeTimeout    time.Duration
	NodeAddr            string
	AuthorizedKeysFiles []string
	HostSigners         []ssh.Signer
	Signers             []ssh.Signer
	NetworkProvider     NetworkProvider
	MetricsProvider     provider.Provider
	SessionManager      *SessionManager
	Logger              *slog.Logger
	// contains filtered or unexported fields
}

func (*Server) ServeWithContext

func (s *Server) ServeWithContext(ctx context.Context, sshln net.Listener, wsln net.Listener) error

func (*Server) Shutdown

func (s *Server) Shutdown() error

Shutdown cancels serving and waits for it to finish. It deliberately does not close sshln or wsln: each is owned by the component serving it, which closes it from its own run.Group interrupt as the context unwinds. Closing them here as well made every listener close twice with no ordering between the two, and the loser of that race reported "use of closed network connection" from whichever side it landed on.

type ServerInfo

type ServerInfo struct {
	NodeAddr string
}

type Session added in v0.15.0

type Session struct {
	ID       string
	NodeAddr string
	// Generation orders registrations of the same ID. 0 is a legacy
	// registration: a random ID with no proof behind it.
	Generation           uint64
	HostUser             string
	HostPublicKeys       []ssh.PublicKey
	ClientAuthorizedKeys []ssh.PublicKey
}

Session represents the complete session information

func NewSession added in v0.15.0

func NewSession(sessionID, nodeAddr, hostUser string, hostPublicKeys, clientAuthorizedKeys [][]byte) *Session

NewSession creates Session from session parameters

func (*Session) IsClientKeyAllowed added in v0.15.0

func (s *Session) IsClientKeyAllowed(key ssh.PublicKey) bool

IsClientKeyAllowed checks if a client key is authorized for this session

func (*Session) MarshalJSON added in v0.15.0

func (s *Session) MarshalJSON() ([]byte, error)

MarshalJSON implements custom JSON marshaling for Session

func (*Session) UnmarshalJSON added in v0.15.0

func (s *Session) UnmarshalJSON(data []byte) error

UnmarshalJSON implements custom JSON unmarshaling for Session

type SessionDialListener

type SessionDialListener interface {
	Listen(sesisonID string) (net.Listener, error)
	Dial(sessionID string) (net.Conn, error)
	DialContext(ctx context.Context, sessionID string) (net.Conn, error)
}

DialContext is part of these interfaces rather than an optional capability discovered by type assertion: the SSH front door bounds upstream establishment with it, so a provider that offered only Dial would compile, serve every Dial-based path, and then fail every SSH connection after downstream authentication had already succeeded.

type SessionManager added in v0.15.0

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

SessionManager provides a high-level interface for session management, combining session storage with connection ID encoding based on routing mode

func NewSessionManager added in v0.15.0

func NewSessionManager(mode routing.Mode, opts ...SessionManagerOption) (*SessionManager, error)

NewSessionManager creates a new SessionManager with the specified routing mode and options

Examples:

// Embedded mode (simple, with default logger)
sm, err := NewSessionManager(routing.ModeEmbedded)

// Embedded mode with custom logger
sm, err := NewSessionManager(routing.ModeEmbedded, WithSessionManagerLogger(logger))

// Consul mode with minimal configuration
sm, err := NewSessionManager(routing.ModeConsul, WithSessionManagerConsulURL("http://localhost:8500"))

// Consul mode with full configuration
sm, err := NewSessionManager(routing.ModeConsul,
    WithSessionManagerLogger(logger),
    WithSessionManagerConsulURL("http://consul.example.com:8500"),
    WithSessionManagerConsulTTL(1*time.Hour))

func (*SessionManager) CreateSession added in v0.15.0

func (sm *SessionManager) CreateSession(session *Session) (string, error)

CreateSession stores the session and returns the encoded SSH user identifier

func (*SessionManager) DeleteSession added in v0.15.0

func (sm *SessionManager) DeleteSession(sessionID string) error

DeleteSession removes a session by ID

func (*SessionManager) GetEncodeDecoder added in v0.15.0

func (sm *SessionManager) GetEncodeDecoder() routing.EncodeDecoder

GetEncodeDecoder returns the EncodeDecoder used by this session manager

func (*SessionManager) GetEntry added in v0.36.0

func (sm *SessionManager) GetEntry(sessionID string) (StoreEntry, error)

GetEntry is GetSession, with the lock session that holds the entry.

func (*SessionManager) GetRoutingMode added in v0.15.0

func (sm *SessionManager) GetRoutingMode() routing.Mode

GetRoutingMode returns the routing mode of this session manager

func (*SessionManager) GetSession added in v0.15.0

func (sm *SessionManager) GetSession(sessionID string) (*Session, error)

GetSession retrieves a session by ID

func (*SessionManager) GetStore added in v0.15.0

func (sm *SessionManager) GetStore() SessionStore

GetStore returns the underlying SessionStore for compatibility

func (*SessionManager) LeaseTTL added in v0.34.0

func (sm *SessionManager) LeaseTTL() time.Duration

LeaseTTL is how long an unrenewed registration lasts; 0 if it doesn't expire.

func (*SessionManager) Observe added in v0.34.0

func (sm *SessionManager) Observe(fn func(epoch, index uint64, entries map[string]StoreEntry))

Observe has fn called with each view of every entry the store's watch delivers: entries maps each session ID to its stored session and the lock session holding it, as of index in epoch. Indexes order only within an epoch, which advances when the watch's index goes backwards; a Registration records both. fn runs on the watch's goroutine and holds up the next delivery, so it must not make store calls; entries is shared with the other observers, and is theirs only to read. A store no other writer shares never calls fn.

func (*SessionManager) RefreshRoute added in v0.34.0

func (sm *SessionManager) RefreshRoute(ctx context.Context, sshUser string, attempted Route) (fresh *Session, moved bool, err error)

RefreshRoute reads sshUser's session from the store itself, skipping any cache, and reports whether it has moved from attempted to another node or another registration. It compares with the route an attempt was actually sent on, never with the cache: the watch may have updated that while the attempt was failing, and would then hide the move.

func (*SessionManager) Register added in v0.34.0

func (sm *SessionManager) Register(ctx context.Context, s *Session) (*Registration, string, error)

Register stores s as a fresh registration, which needs its ID absent or a higher generation than the stored one, and returns its handle and the encoded SSH user identifier. A Register that fails may outlast ctx by up to DefaultConsulTimeout, while the store destroys a lease it created.

func (*SessionManager) Release added in v0.34.0

func (sm *SessionManager) Release(ctx context.Context, reg *Registration) error

Release removes reg's entry if reg still holds it.

func (*SessionManager) Renew added in v0.34.0

func (sm *SessionManager) Renew(ctx context.Context, reg *Registration) error

Renew keeps reg's entry alive; see SessionStore.Renew for its errors.

func (*SessionManager) Reregister added in v0.34.0

func (sm *SessionManager) Reregister(ctx context.Context, reg *Registration) (*Registration, error)

Reregister rebuilds reg after a known loss: the same registration, stored again with a lease of its own. Unlike Register it may replace an entry of reg's own identity; only reg's lease keeper calls it. The handle it returns is Same as reg. Release reg afterwards only if its lease is non-empty and differs from the new handle's: a store without leases keeps one entry for both handles, and releasing reg there would delete the entry just rebuilt.

func (*SessionManager) ResolveSSHUser added in v0.15.0

func (sm *SessionManager) ResolveSSHUser(sshUser string) (sessionID, nodeAddr string, err error)

ResolveSSHUser resolves an SSH username by decoding it and conditionally validating session existence In embedded mode: only decodes (session may be on another node) In consul mode: decodes and validates (shared store across all nodes)

func (*SessionManager) Shutdown added in v0.15.0

func (sm *SessionManager) Shutdown(ctx context.Context, nodeAddr string) (err error)

Shutdown deletes this node's sessions and finalizes the store once per call. Consul cleanup finishes before Close. A legacy call cannot be interrupted; cancellation instead lets this caller reach Close while that worker unwinds.

type SessionManagerConfig added in v0.15.0

type SessionManagerConfig struct {
	Mode      routing.Mode
	Logger    *slog.Logger
	ConsulURL *url.URL
	ConsulTTL time.Duration
}

SessionManagerConfig holds configuration for creating a SessionManager

type SessionManagerOption added in v0.15.0

type SessionManagerOption func(*SessionManagerConfig)

SessionManagerOption is a functional option for configuring SessionManager

func WithSessionManagerConsulTTL added in v0.15.0

func WithSessionManagerConsulTTL(ttl time.Duration) SessionManagerOption

WithSessionManagerConsulTTL sets the session TTL for consul mode

func WithSessionManagerConsulURL added in v0.15.1

func WithSessionManagerConsulURL(consulURL *url.URL) SessionManagerOption

WithSessionManagerConsulURL sets the Consul URL for consul mode

func WithSessionManagerLogger added in v0.15.0

func WithSessionManagerLogger(logger *slog.Logger) SessionManagerOption

WithSessionManagerLogger sets the logger for the session manager

type SessionStore added in v0.15.0

type SessionStore interface {
	// Register stores s when its ID is absent or s has a higher generation
	// than the stored entry. Otherwise it returns an error wrapping
	// ErrSuperseded and writes nothing. A Register that fails may outlast ctx
	// by up to DefaultConsulTimeout, while it destroys a lease it created.
	Register(ctx context.Context, s *Session) (*Registration, error)
	// Reregister is the owner's rebuild of reg after a known loss: it stores
	// reg's session again under a new lease, as Register does, and may also
	// replace an entry of reg's own identity, which Register refuses. A store
	// with leases also replaces a value reg's own lease holds, whatever was
	// written into it. It orders, retries and cleans up as Register does.
	Reregister(ctx context.Context, reg *Registration) (*Registration, error)
	// Release removes reg's entry if reg still holds it.
	Release(ctx context.Context, reg *Registration) error
	// Renew keeps reg's entry alive. An error wrapping ErrLeaseLost means reg
	// no longer holds it; any other error leaves that unknown.
	Renew(ctx context.Context, reg *Registration) error
	// LeaseTTL is how long an unrenewed entry lasts; 0 if it doesn't expire.
	LeaseTTL() time.Duration
	// Get complete session data
	Get(sessionID string) (*Session, error)
	// Entry is Get with the lock session that holds the entry, "" in a store
	// without leases.
	Entry(sessionID string) (StoreEntry, error)
	// GetFresh reads sessionID from the store itself, skipping any cache, and
	// updates the cache with what it finds, the entry or its absence, as Get's
	// read-through does. It gives up once ctx is done.
	GetFresh(ctx context.Context, sessionID string) (*Session, error)
	// Delete session data, only for an entry this instance holds
	Delete(sessionID string) error
	// BatchDelete multiple sessions efficiently, likewise
	BatchDelete(sessionIDs []string) error
	// List all sessions (for cleanup and management)
	List() ([]*Session, error)
	// Observe has fn called with each view of every entry the store's watch
	// delivers; see SessionManager.Observe. A store no other writer shares
	// has nothing to watch, and never calls fn.
	Observe(fn func(epoch, index uint64, entries map[string]StoreEntry))
	// Close cleans up resources and stops background processes
	Close() error
}

SessionStore defines the interface for session storage.

Registrations are ordered: a stored entry is replaced only by a higher generation, or by its owner rebuilding it, and a handle's Release and Renew act only on its own entry.

type StoreEntry added in v0.36.0

type StoreEntry struct {
	Session *Session
	Lease   string
}

StoreEntry is one session as the store's watch delivered it: the value stored for its ID, and the lock session that holds its key, "" if none does.

type UnixProvider

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

func (*UnixProvider) Name

func (p *UnixProvider) Name() string

func (*UnixProvider) Opts

func (p *UnixProvider) Opts() string

func (*UnixProvider) SSHD

func (p *UnixProvider) SSHD() SSHDDialListener

func (*UnixProvider) Session

func (p *UnixProvider) Session() SessionDialListener

func (*UnixProvider) SetOpts

func (p *UnixProvider) SetOpts(opts NetworkOptions) error

type UserCertChecker added in v0.5.0

type UserCertChecker struct {
	// IsUserAuthority reports whether a key may vouch for a certificate's
	// AuthRequest. Nil trusts nothing, so a call site that names no authority
	// gets no certificate identities: the safe direction to fail in, and the
	// one a future call site that forgets this field lands in.
	//
	// The relay names its own signing keys, because it is the only party that
	// mints upterm certificates. A host names the single relay key its host
	// key callback accepted.
	//
	// A relay offers one certificate per signing key, and x/crypto counts a
	// rejected public-key query against MaxAuthTries -- 6 by default, which
	// charm.land/ssh does not change. So a host pinning one key survives five
	// rejected offers and is disconnected on the sixth: the pinned key must be
	// among the first six a relay offers. One key, or two through a rotation,
	// is always fine. Raising the guest door's MaxAuthTries through a
	// ServerConfigCallback is the escape hatch if that ever binds.
	IsUserAuthority func(auth ssh.PublicKey) bool

	UserKeyFallback func(user string, key ssh.PublicKey) (ssh.PublicKey, error)
}

func (*UserCertChecker) Authenticate added in v0.5.0

func (c *UserCertChecker) Authenticate(user string, key ssh.PublicKey) (*AuthRequest, ssh.PublicKey, error)

Authenticate tries to pass auth request and public key from a cert. If the public key is not a cert, it calls the UserKeyFallback func. Otherwise it returns an error.

type UserCertSigner added in v0.5.0

type UserCertSigner struct {
	SessionID   string
	User        string
	AuthRequest *AuthRequest
}

func (*UserCertSigner) SignCert added in v0.5.0

func (g *UserCertSigner) SignCert(signer ssh.Signer) (ssh.Signer, error)

Jump to

Keyboard shortcuts

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