Documentation
¶
Overview ¶
Package egress is a forward proxy that lets a plugin reach only the hosts it declared, and never an internal address.
Index ¶
- Constants
- func EncodePolicy(p Policy) ([]byte, error)
- func HexHash(h SecretHash) string
- func ListenPolicySocket(path string) (net.Listener, error)
- func ProxyURL(plugin, secret, hostport string) string
- func PushPolicy(ctx context.Context, socketPath string, p Policy) error
- type Allowlist
- type Config
- type Counters
- type CredentialStore
- type DenialCount
- type DenyFunc
- type HashedCredentials
- type Options
- type PluginPolicy
- type Policy
- type PolicyServer
- type PolicyStore
- type Proxy
- type Resolver
- type SecretHash
- type StaticAllowlist
Constants ¶
const ( EnvConnectTimeout = "APP_PLUGIN_EGRESS_CONNECT_TIMEOUT" EnvIdleTimeout = "APP_PLUGIN_EGRESS_IDLE_TIMEOUT" EnvMaxTunnels = "APP_PLUGIN_EGRESS_MAX_TUNNELS" EnvBytesPerMinute = "APP_PLUGIN_EGRESS_BYTES_PER_MINUTE" EnvAllowPrivate = "APP_PLUGIN_EGRESS_ALLOW_PRIVATE" )
Environment variable names read by ConfigFromEnv.
const ( EnvPolicySocket = "APP_PLUGIN_EGRESS_POLICY_SOCKET" EnvPolicyCache = "APP_PLUGIN_EGRESS_POLICY_CACHE" EnvListen = "APP_PLUGIN_EGRESS_LISTEN" )
Environment variable names for the sidecar policy channel.
const ( ReasonUnknownCaller = "unknown_caller" ReasonHostNotListed = "host_not_allowed" ReasonBlockedAddr = "blocked_address" ReasonResolveFailed = "resolve_failed" ReasonDialFailed = "dial_failed" ReasonTunnelCap = "too_many_tunnels" ReasonRateLimit = "rate_limited" ReasonBadRequest = "bad_request" )
Denial reasons passed to the deny callback.
Variables ¶
This section is empty.
Functions ¶
func EncodePolicy ¶
EncodePolicy validates and serializes a policy.
func ListenPolicySocket ¶
ListenPolicySocket creates the socket directory (0700) and the socket (0600).
Types ¶
type Config ¶
type Config struct {
ConnectTimeout time.Duration
IdleTimeout time.Duration
// MaxTunnels caps simultaneous connections per plugin.
MaxTunnels int
// BytesPerMinute caps traffic per plugin in both directions combined.
BytesPerMinute int64
// AllowPrivate lets targets that resolve to internal addresses through.
// The caller decides it, usually from EnvAllowPrivate.
AllowPrivate bool
}
Config holds the proxy limits. Zero values mean "use the default".
type Counters ¶
type Counters struct {
// contains filtered or unexported fields
}
Counters tallies denials per plugin and reason. It holds no hosts or payload, so its size is bounded by plugins times reasons.
func (*Counters) Record ¶
Record adds one denial. An unknown caller is filed under an empty plugin name.
func (*Counters) Snapshot ¶
func (c *Counters) Snapshot() []DenialCount
Snapshot returns the tally sorted by plugin then reason.
type CredentialStore ¶
CredentialStore verifies a plugin's proxy credential.
type DenialCount ¶
type DenialCount struct {
Plugin string `json:"plugin"`
Reason string `json:"reason"`
Count int64 `json:"count"`
// LastDenied is the UTC time of the latest refusal (RFC 3339).
LastDenied string `json:"last_denied,omitempty"`
}
DenialCount is how often one plugin was refused for one reason.
func FetchDenials ¶
func FetchDenials(ctx context.Context, socketPath string, timeout time.Duration) ([]DenialCount, error)
FetchDenials reads the denial tally from a sidecar's policy socket. It is read-only.
type HashedCredentials ¶
type HashedCredentials struct {
// contains filtered or unexported fields
}
HashedCredentials is a CredentialStore over plugin to secret hash.
func NewHashedCredentials ¶
func NewHashedCredentials(hashes map[string]SecretHash) *HashedCredentials
NewHashedCredentials copies the map so later edits cannot change it.
func (*HashedCredentials) Verify ¶
func (h *HashedCredentials) Verify(plugin, secret string) bool
Verify compares in constant time and does the same work for an unknown plugin, so timing does not reveal which names exist.
type Options ¶
type Options struct {
Credentials CredentialStore
Allowlist Allowlist
// Resolver defaults to net.DefaultResolver.
Resolver Resolver
OnDeny DenyFunc
Config Config
}
Options wires the proxy. Credentials and Allowlist are required.
type PluginPolicy ¶
type PluginPolicy struct {
Name string `json:"name"`
SecretHash string `json:"secret_hash"`
Hosts []string `json:"hosts"`
}
PluginPolicy is one plugin's credential hash (hex SHA-256) and allowed hosts. Hosts are "host" (port 443) or "host:port", as StaticAllowlist expects.
type Policy ¶
type Policy struct {
Version int64 `json:"version"`
Plugins []PluginPolicy `json:"plugins"`
}
Policy is the full egress policy the control plane pushes to the sidecar.
func DecodePolicy ¶
DecodePolicy parses strictly (unknown fields and trailing data are errors) and validates.
type PolicyServer ¶
type PolicyServer struct {
// contains filtered or unexported fields
}
PolicyServer applies pushed policies to a store and caches the last good one.
func NewPolicyServer ¶
func NewPolicyServer(store *PolicyStore, cachePath string) *PolicyServer
NewPolicyServer returns a server. An empty cachePath disables the cache.
func (*PolicyServer) Handler ¶
func (s *PolicyServer) Handler() http.Handler
Handler serves PUT /policy and GET /healthz.
func (*PolicyServer) LoadCache ¶
func (s *PolicyServer) LoadCache() error
LoadCache installs the cached policy when the store has none yet. A missing cache is not an error; a corrupt one is, and leaves the store denying all.
func (*PolicyServer) WithCounters ¶
func (s *PolicyServer) WithCounters(c *Counters) *PolicyServer
WithCounters serves the denial tally at GET /denials.
type PolicyStore ¶
type PolicyStore struct {
// contains filtered or unexported fields
}
PolicyStore holds the active policy and swaps it atomically. With no policy it denies everything. It implements CredentialStore and Allowlist.
func NewPolicyStore ¶
func NewPolicyStore() *PolicyStore
NewPolicyStore returns a store with no policy (deny all).
func (*PolicyStore) Allowed ¶
func (s *PolicyStore) Allowed(plugin, host string, port int) bool
Allowed implements Allowlist.
func (*PolicyStore) Ready ¶
func (s *PolicyStore) Ready() bool
Ready reports whether a policy has been installed.
func (*PolicyStore) Set ¶
func (s *PolicyStore) Set(p Policy) error
Set validates and installs a policy in one atomic swap.
func (*PolicyStore) Verify ¶
func (s *PolicyStore) Verify(plugin, secret string) bool
Verify implements CredentialStore.
func (*PolicyStore) Version ¶
func (s *PolicyStore) Version() int64
Version returns the installed policy version, or -1 with none.
type Proxy ¶
type Proxy struct {
// contains filtered or unexported fields
}
Proxy is an http.Handler serving CONNECT and absolute-form requests.
type Resolver ¶
type Resolver interface {
LookupNetIP(ctx context.Context, network, host string) ([]netip.Addr, error)
}
Resolver looks up the addresses of a host.
type SecretHash ¶
SecretHash is the SHA-256 of a plugin credential. Only hashes are stored.
func HashSecret ¶
func HashSecret(secret string) SecretHash
HashSecret returns the stored form of a secret.
func NewCredential ¶
func NewCredential() (secret string, hash SecretHash, err error)
NewCredential returns a random secret and the hash to store for it.
type StaticAllowlist ¶
StaticAllowlist is a simple Allowlist. Entries are "host" (port 443 only) or "host:port" (that port only); hosts match exactly, ignoring case.