ecluse:ecluse-core
Safe HaskellNone
LanguageGHC2021

Ecluse.Core.Security.Host

Description

Outbound-request guards for the data plane: where the proxy is allowed to fetch.

An outbound target comes from the client's request path or an upstream's dist.tarball, and must pass both halves of the SSRF gate: isAllowedUpstreamHost restricts a fetch to the configured upstream host:port pairs, and isBlockedTarget rejects internal address literals. They compare different projections on purpose. Authorisation compares the full authority, because the fetch dials the port too, while the block classifies the bare host, because an address is internal at any port.

Synopsis

Outbound host:port allowlist

data AllowedHostPorts Source #

The host:port pairs the host guards authorise, canonicalised by allowedHostPorts, its only constructor. An entry authorises exactly its own pair, port 443 when none was written.

allowedHostPorts :: Set HostPort -> AllowedHostPorts Source #

Normalise configured upstream authorities to the key form the guards match on. Equivalent spellings of one IP literal collapse, so an operator's 0:0:0:0:0:0:0:1 matches an incoming ::1.

isAllowedUpstreamHost :: AllowedHostPorts -> HostPort -> Bool Source #

The allowlist half of the SSRF gate. Matching the pair is load-bearing: an allowlisted host on an attacker-chosen port (registry.npmjs.org:9443) is an unauthorised target.

Internal-range block

isBlockedTarget :: [IPRange] -> Text -> Bool Source #

Whether host is an internal-address literal the proxy must not fetch. A DNS name is not blocked here: the allowlist and the validating-TLS manager close that class.

isBlockedIP :: [IPRange] -> IP -> Bool Source #

Whether an IP falls in a blocked internal range. An IPv6 address embedding an IPv4 one decodes first (see decodeEmbeddedV4), so an embedding literal cannot slip the IPv4 ranges.

parseBlockedRange :: Text -> Maybe IPRange Source #

Parse one operator-configured CIDR entry ("203.0.113.0/24") into an IPRange. It goes through iproute's total Read, not its partial IsString, so a malformed entry fails closed.

Artifact-host gate

data Origin Source #

The trust of the origin a dist.tarball comes from. It governs the literal internal-range block alone, since a private registry may live on an internal address.

Constructors

TrustedOrigin

The operator-configured private upstream: exempt from the literal internal-range block.

UntrustedOrigin

The public upstream, and any attacker-influenceable target: subject to the literal internal-range block.

Instances

Instances details
Show Origin Source # 
Instance details

Defined in Ecluse.Core.Security.Host

Eq Origin Source # 
Instance details

Defined in Ecluse.Core.Security.Host

Methods

(==) :: Origin -> Origin -> Bool #

(/=) :: Origin -> Origin -> Bool #

tarballHostAllowed Source #

Arguments

:: AllowedHostPorts

The ecosystem's canonical artifact authorities, same-host-equivalent.

-> Origin 
-> AllowedHostPorts

The host:port allowlist (the same one every outbound fetch is gated by).

-> [IPRange]

The operator-configured ranges extending the fixed internal-range block (untrusted origin).

-> Maybe HostPort

The authority that served the packument, when one could be extracted.

-> Maybe HostPort

The authority of the candidate dist.tarball, when one could be extracted.

-> Bool 

Whether a dist.tarball authority may be fetched. An upstream's dist.tarball is server-chosen data, so the target must equal the packument authority, ecosystemHosts aside.

artifactAuthorityHonoured :: AllowedHostPorts -> Maybe HostPort -> Maybe HostPort -> Bool Source #

Whether an artifact's authority is honoured for a document the given authority served: the same dial target, or one the ecosystem serves artifact bytes from by design.

ecosystemArtifactAuthorities :: [Text] -> AllowedHostPorts Source #

The authority set of an ecosystem's declared artifact hosts, which the gate and each adapter's projection both derive artifactAuthorityHonoured's first argument through.

data TarballHostGate Source #

The mount-constant inputs to the per-request tarballHostAllowed gate. The gate runs on the hot artifact path, so only the dynamic public dist.tarball authority is parsed per request.

Constructors

TarballHostGate 

Fields

tarballHostGate :: [Text] -> Maybe Text -> Text -> Maybe Text -> TarballHostGate Source #

Build the gate from the ecosystem's artifact hosts and a mount's private, public, and mirror-target URLs. A URL no authority extracts from authorises nothing (fail closed).