Documentation
¶
Overview ¶
Package gate is lockhttp's data plane: the HTTP(S) proxy every request of the agents goes through. It decides each request with the policy the console approved (it never reads a policy file), holds what needs a human, asks the console, and audits what it lets through or refuses.
Index ¶
- Constants
- Variables
- func BodyFingerprint(contentType string, body []byte) string
- func Preview(contentType string, body []byte) string
- func PushRefs(body []byte) []string
- func RequestFingerprint(container, method, url string, h http.Header, bodyFP string) string
- type AuditLog
- type CertSource
- type Config
- type Console
- type Credentials
- type Gate
- type Grants
- func (g *Grants) Connect(container, hostport string) bool
- func (g *Grants) GrantConnect(container, hostport string, d time.Duration)
- func (g *Grants) GrantOnce(fp string)
- func (g *Grants) GrantRedirect(container, url string)
- func (g *Grants) Sweep()
- func (g *Grants) UseOnce(fp string) bool
- func (g *Grants) UseRedirect(container, url string) bool
- type Hub
- type LockkitConsole
- type Outcome
- type Queue
- type Refusal
- type Sources
- type Status
- type Withdrawn
Constants ¶
const AuditRetention = 30 * 24 * time.Hour
AuditRetention is how long the gate keeps its daily audit files.
const ContractVersion = 1
ContractVersion is the version of the files lea writes for the gate.
const RedirectTTL = 60 * time.Second
RedirectTTL is how long a listed CDN redirect target stays open.
const SingleUseTTL = 10 * time.Minute
SingleUseTTL is how long a single-use authorisation waits for its request.
const StandaloneReason = "the gate was restarted without its hub (standalone)"
StandaloneReason is why a standalone start withdraws the plans of the gate's hub mode, as the plans store and then the hub record it.
Variables ¶
var ErrNoConsole = errors.New("no lockhttp console is running")
ErrNoConsole means no console answers.
Functions ¶
func BodyFingerprint ¶
BodyFingerprint is the normalised fingerprint of a body: multipart parts without their boundary, canonical JSON without volatile fields, else the raw bytes.
func Preview ¶
Preview is the masked start of a body for the approval screen (decision D-body): textual bodies only, personal data and secrets masked, at most wire.MaxPreview bytes.
Types ¶
type AuditLog ¶
type AuditLog struct {
// contains filtered or unexported fields
}
AuditLog is the gate's JSONL audit of every decision it applies: FREE, DENY, and the outcome of each ask (the console audits the human's side): one file per UTC day, gate-YYYY-MM-DD.jsonl, kept 30 days. With no directory it writes to w (stderr) or nowhere.
func NewAuditLog ¶
NewAuditLog opens dir (created 0700) or, when dir is "", writes to w.
type CertSource ¶
type CertSource interface {
Certificate(ctx context.Context, host string) (*tls.Certificate, error)
}
CertSource issues the leaf certificate presented to a client for host (MITM). The CA key stays with the signer.
type Config ¶
type Config struct {
Profile string
// Upstream is the proxy the gate sends through (squid on loopback);
// nil dials the target itself, refusing private addresses.
Upstream *url.URL
Sources *Sources
Creds *Credentials
Console Console
Audit *AuditLog
// StatusFile is rewritten when the console state or the pending
// counts change ("" for none).
StatusFile string
// Certs enables MITM; nil decides CONNECTs at the domain.
Certs CertSource
// UpstreamTLS verifies the targets (nil: the system roots). The gate
// never skips verification.
UpstreamTLS *tls.Config
// Dial replaces the network dialer (tests).
Dial func(ctx context.Context, network, addr string) (net.Conn, error)
// Resolve replaces the resolver of direct mode (tests).
Resolve func(ctx context.Context, host string) ([]netip.Addr, error)
// Hub, when set, sends the asks to lockhub (hub mode); the console
// still serves the policy.
Hub *Hub
// Withdrawn, in standalone mode, are the hub tickets the gate's last
// hub mode left pending and this start withdrew (WithdrawStandalone):
// the request of one is refused once, explicitly (E_WITHDRAWN).
Withdrawn *Withdrawn
// PolicyPoll is how often the policy is fetched (2 s by default).
PolicyPoll time.Duration
Now func() time.Time
// Log receives operational lines (not the audit).
Log io.Writer
}
Config configures a gate.
type Console ¶
type Console interface {
Policy(ctx context.Context) (wire.PolicyResult, error)
// Approve returns nil when approved; a *Refusal when the human (or the
// timeout) refused; ErrNoConsole when no console answers.
Approve(ctx context.Context, p wire.ApproveParams) (wire.ApproveResult, error)
}
Console is the gate's view of the console: the approved policy and the human's answers.
type Credentials ¶
type Credentials struct {
// contains filtered or unexported fields
}
Credentials implements decide.Credentials from credentials.json; with no file the check is off. An unreadable file fails closed: every credential is unknown.
func NewCredentials ¶
func NewCredentials(path string) *Credentials
NewCredentials loads path ("" for none).
func (*Credentials) Known ¶
func (c *Credentials) Known(container, via, sum string) (bool, bool)
Known implements decide.Credentials.
func (*Credentials) Reload ¶
func (c *Credentials) Reload()
Reload reads the file again when it changed.
type Gate ¶
type Gate struct {
// contains filtered or unexported fields
}
Gate is a running data plane.
func (*Gate) Policy ¶
Policy returns the policy in force (nil: none received yet) and its fingerprint.
func (*Gate) Run ¶
Run polls the policy, runs the ask queue and reloads the source files until ctx ends.
type Grants ¶
type Grants struct {
// contains filtered or unexported fields
}
Grants holds what approvals open: connect grants (container × host × port, for the policy's connect_grant), single-use authorisations (request fingerprint, 10 min) and redirect exemptions (container × exact URL, 60 s, GET only).
func (*Grants) GrantConnect ¶
GrantConnect opens container × host:port for d.
func (*Grants) GrantRedirect ¶
GrantRedirect opens the exact URL for container's next GET.
func (*Grants) UseRedirect ¶
UseRedirect consumes a redirect exemption.
type Hub ¶ added in v0.3.0
type Hub struct {
Client *hubclient.Client
Plans *plans.Store
// Hosts are the names of the hub on its network and Nets its
// addresses: the gate refuses them as targets, whatever internal_hosts
// allows, so that an agent never reaches the hub through the gate.
Hosts []string
Nets []netip.Prefix
// Poll is how often a held ask looks for its decision (1 s by
// default); the decisions arrive by the client's long poll.
Poll time.Duration
// contains filtered or unexported fields
}
Hub sends the gate's asks to lockhub instead of the console: each held request becomes a plan and a signed ticket, and a decision that verifies under the pinned hub key grants the same single-use pass (or connect grant) a console approval does. The console still serves the policy.
type LockkitConsole ¶
type LockkitConsole struct {
Profile string
// Cwd is where the client looks for a project (none: "/").
Cwd string
// contains filtered or unexported fields
}
LockkitConsole dials the console with lockkit's client: one connection for the policy poll, one for approvals (the console is serial: a poll queued behind an approval simply waits).
func (*LockkitConsole) Approve ¶
func (c *LockkitConsole) Approve(ctx context.Context, p wire.ApproveParams) (wire.ApproveResult, error)
Approve implements Console.
func (*LockkitConsole) Policy ¶
func (c *LockkitConsole) Policy(ctx context.Context) (wire.PolicyResult, error)
Policy implements Console.
type Outcome ¶
type Outcome struct {
Approved bool
Auto bool
Code string
Reason string
// Ticket is the hub ticket an E_PENDING ask waits on (hub mode).
Ticket string
}
Outcome is the answer to an ask.
type Queue ¶
type Queue struct {
// contains filtered or unexported fields
}
Queue holds the asks and sends them to the console one at a time (lockkit's console is serial, decision D7). A human decision is shared only by requests of identical fingerprint; requests under the same key with another fingerprint are separate items.
func (*Queue) Submit ¶
func (q *Queue) Submit(fp, key string, p wire.ApproveParams, onApprove func(clientGone bool)) (<-chan Outcome, func())
Submit adds a waiter for the request of fingerprint fp. It returns the channel the outcome arrives on and a cancel func the waiter calls when it stops waiting (the item stays queued).
type Refusal ¶
type Refusal struct {
Code string
Reason string
// Ticket is the hub ticket the refusal is about (hub mode), "" for
// none.
Ticket string
}
Refusal is a console's refusal of an approval.
type Sources ¶
type Sources struct {
// contains filtered or unexported fields
}
Sources resolves who sent a connection. With no file it runs in standalone mode: every connection is container "local".
func NewSources ¶
NewSources loads path ("" for standalone mode).
func (*Sources) Reload ¶
func (s *Sources) Reload()
Reload reads the file again when it changed. A file that cannot be read or parsed fails closed: every lookup is refused until it is fixed.
type Status ¶
type Status struct {
Version int `json:"version"`
Console string `json:"console"`
Pending int `json:"pending"`
PendingByContainer map[string]int `json:"pending_by_container"`
PolicyFP string `json:"policy_fp,omitempty"`
Updated string `json:"updated"`
}
Status is the status file lea reads (docs/lea.md §5).
type Withdrawn ¶ added in v0.5.0
type Withdrawn struct {
// contains filtered or unexported fields
}
Withdrawn are the hub tickets a standalone start withdrew, by the fingerprint of their request: the gate refuses that request once, explicitly, rather than ask the console about a request the agent believes waits on the hub.
func WithdrawStandalone ¶ added in v0.5.0
WithdrawStandalone is the rollback of hub mode (decision D.5), for a gate started without its hub flags: the plans every hub instance under hubDir (hubclient.KeyDir of the gate's home) left pending end Withdrawn, marked for the hub to hear of at the next start in hub mode (hubclient.Client.Sync). An instance whose plans another gate holds open (plans.ErrLocked: it runs in hub mode now) is left alone. It returns the withdrawn tickets by request, for Config.Withdrawn.