opsclient

package
v0.18.5 Latest Latest
Warning

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

Go to latest
Published: Aug 29, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Overview

Package opsclient is the SSRF-safe outbound HTTP client for the App Ops Interface (plan §4.1, §15 §6.3). It is the load-bearing control for attacker class C (a compromised monitored app answering Mooring's polls).

Invariants enforced here:

  • The destination host is PINNED to the operator-configured base URL. A compromised app's descriptor can only supply a RELATIVE path; it can never move the outbound host (the "descriptor cannot move the outbound host" abuse test).
  • DNS-rebind-safe: the dialer re-resolves on EVERY connection (keep-alives disabled) and dials the validated IP directly, refusing loopback / link-local / metadata (169.254.169.254) / multicast / unspecified — which covers cloud metadata and every loopback-bound control-plane service (admin UI, socket-proxy, Caddy admin). Private container ranges are allowed (that is where apps live); the systemd egress firewall (§15) is the physical backstop.
  • No redirect-follow; http/https scheme only; responses size-capped.
  • The shared secret travels only in an operator-named header, server-side, never to the browser, never logged (secret.Redacted).

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrBlockedTarget means the pinned host resolved to a forbidden address.
	ErrBlockedTarget = errors.New("opsclient: target resolves to a blocked address")
	// ErrBadRelPath means the relative path failed the §4.1 grammar.
	ErrBadRelPath = errors.New("opsclient: invalid relative path")
	// ErrBadBase means the operator-configured base URL is not a usable origin.
	ErrBadBase = errors.New("opsclient: base URL must be http(s)://host[:port]")
	// ErrBadHeader means the secret header name is not a valid token.
	ErrBadHeader = errors.New("opsclient: invalid secret header name")
)

Functions

func IsBlockedAddr

func IsBlockedAddr(ip netip.Addr) bool

IsBlockedAddr reports whether an address is one the SSRF-safe client refuses to dial. Exported so config-time validation can reuse the exact same predicate as the request-time dialer (no drift; review #3).

func ValidHeaderName

func ValidHeaderName(s string) bool

ValidHeaderName reports whether s is a valid secret-header name (review #8).

func ValidateRelPath

func ValidateRelPath(p string) bool

ValidateRelPath reports whether p is a safe relative ops path (plan §4.1). It also rejects `//` (protocol-relative authority) and any `..` traversal segment.

Types

type Client

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

Client performs pinned, rebind-safe requests.

func New

func New() *Client

New returns a production Client (blocks loopback/link-local/metadata).

func (*Client) Get

func (c *Client) Get(ctx context.Context, base, relPath, secretHeader string, sec secret.Redacted) (*Response, error)

Get fetches base+relPath with the secret header.

func (*Client) Post

func (c *Client) Post(ctx context.Context, base, relPath, secretHeader string, sec secret.Redacted, body []byte) (*Response, error)

Post sends a body to base+relPath with the secret header.

type Response

type Response struct {
	Status int
	Body   []byte
}

Response is a size-capped ops response.

Jump to

Keyboard shortcuts

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