cloudmeta

package
v0.0.5 Latest Latest
Warning

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

Go to latest
Published: Oct 12, 2026 License: MIT Imports: 4 Imported by: 0

Documentation

Overview

Package cloudmeta is the one table of cloud metadata services, and the one rule for an allow list that contains one (Task 20397).

A metadata service is an address on which a cloud hands whatever runs on a machine that machine's identity: instance credentials, user data, extension settings, a pod's role. A sandbox that reaches one holds the host's cloud account for as long as those credentials last, which is why every egress control in cloop drops these addresses unless an allow list names them.

Why one table

Three enforcement points decide whether a sandbox reaches a metadata service: pkg/netfilter compiles allow lists into nftables rules and Kubernetes NetworkPolicies, pkg/egressbroker refuses connections at its proxy, and every surface that accepts an allow list — the hub's configuration, the dashboard's device, virtual-executor and project firewalls, egress grants — validates what it is given. Until this package each kept its own idea of what a metadata service is, and that idea was one address, 169.254.169.254. AWS's IPv6 endpoint is in ULA space and Alibaba Cloud's in CGNAT space, so an edge host allowed fc00::/7 for hardware work opened a metadata service while every surface called the range "private". And the rule for a prefix that merely contains one differed: the broker refused it, the packet filter compiled it ahead of the drop that was meant to keep the address closed.

The rule

An allow-list entry that strictly contains a metadata address — contains it, and is not that address's own /32 or /128 — opens the service without naming it. Check reports every such entry unless the same list also names the address, or a deny list keeps it closed. Every surface refuses what Check reports when it is written, and every compiler keeps the address closed when it meets one anyway (a rule stored before the rule existed): Carved names the addresses to drop ahead of the allows that contain them.

The package depends on nothing but the standard library, so every one of the enforcement points can import it without importing each other.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Canonical

func Canonical(p netip.Prefix) (netip.Prefix, bool)

Canonical returns p the way every allow list compares prefixes: masked, and an IPv4-mapped prefix as the IPv4 prefix it spells — ::ffff:169.254.0.0/112 is 169.254.0.0/16, and treating it as anything else would let a spelling decide whether the rule applies. ok is false for an invalid prefix and for a mapped one shorter than /96, which mixes mapped and native space.

Types

type Finding

type Finding struct {
	// Allow is the entry, canonical.
	Allow netip.Prefix
	// Services are the services it contains and nothing names or closes,
	// sorted like Services.
	Services []Service
}

Finding is one allow-list entry and every metadata service it opens without naming.

func Check

func Check(allow, closed []netip.Prefix) []Finding

Check applies the rule to an allow list: one Finding per entry that strictly contains a metadata service the list does not also name by its own host prefix. closed holds prefixes that keep an address unreachable whatever the allows say — a deny list — and a service inside one of them is not reported: an operator who denied it has said what they meant as clearly as one who allowed it.

Entries that do not parse are skipped: syntax is each surface's own check, and this one has to be callable on a list that has not passed it yet.

func (Finding) Explain

func (f Finding) Explain(allowIn, denyIn string) string

Explain is the whole refusal: the finding and its remedy as one sentence.

func (Finding) Hosts

func (f Finding) Hosts() string

Hosts lists the host prefixes that would name the finding's services: "169.254.169.254/32", or "169.254.0.23/32, 169.254.42.42/32".

func (Finding) Remedy

func (f Finding) Remedy(allowIn, denyIn string) string

Remedy is the explicit alternative, in the words of the surface the list was written on. allowIn names where an allow goes ("the allowlist", "allow_cidrs"); denyIn names a deny list, or is empty where the surface has none, and then the alternative is a narrower range.

func (Finding) Sentence

func (f Finding) Sentence() string

Sentence states the finding, without a remedy: "169.254.0.0/16 contains the cloud metadata service at 169.254.169.254 (…) without naming it".

type Service

type Service struct {
	// Addr is the address the service answers on.
	Addr netip.Addr
	// Name says whose service it is, short enough to list several in one
	// sentence: "Alibaba Cloud", "Amazon EKS Pod Identity".
	Name string
}

Service is one metadata endpoint.

func Carved

func Carved(allow, closed []netip.Prefix) []Service

Carved returns the services Check reports for an allow list, once each: the addresses a compiled filter drops ahead of the allows that contain them, so that an entry stored before the rule existed fails closed rather than open.

func Lookup

func Lookup(addr netip.Addr) (Service, bool)

Lookup reports the service at addr, seen through an IPv4-mapped spelling.

func Services

func Services() []Service

Services returns the table. The slice is a copy, so a caller that sorts or filters it cannot reach into what every filter is compiled against.

func Within

func Within(p netip.Prefix) []Service

Within returns the services strictly inside p: inside it, and p is not the service's own host prefix. Sorted like Services.

func (Service) Describe

func (s Service) Describe() string

Describe names the service in a sentence: "169.254.0.23 (Tencent Cloud)".

func (Service) Prefix

func (s Service) Prefix() netip.Prefix

Prefix is the service's own host prefix: the /32 or /128 an allow list names it by.

func (Service) Reason

func (s Service) Reason() string

Reason is the sentence a drop for the service carries: in an nft comment, in the proxy's refusal, in the audit trail. It names the address rather than the cloud, because one address serves most clouds and the address is what an operator reading a ruleset can act on.

Jump to

Keyboard shortcuts

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