spiretest

package
v0.0.0-...-8fb1331 Latest Latest
Warning

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

Go to latest
Published: Sep 22, 2026 License: Apache-2.0 Imports: 30 Imported by: 0

Documentation

Overview

Package spiretest provides a fake SPIRE Workload API server for tests.

It exists so every binary that waits for an SVID (issue #740) can prove the same two things hermetically, without a container or a real SPIRE agent: that startup returns immediately while the Workload API is refusing to attest, and that identity is folded in the moment it starts serving. The refusal is a switch (StartServing) rather than a delay, because the window being reproduced is exactly "the agent socket is there, but no identity has been issued yet".

Index

Constants

View Source
const (
	BrokerSecurityHeader      = "broker.spiffe.io"
	BrokerSecurityHeaderValue = "true"
)

BrokerSecurityHeader is the static gRPC metadata the SPIFFE Broker Endpoint specification requires on every request (SPIFFE_Broker_Endpoint.md §3). The fake rejects a call without it, exactly as a real SPIRE agent does, so a client that forgets the interceptor fails its very first test.

View Source
const DefaultBrokerServerID = "spiffe://" + TrustDomain + "/spire/agent/k8s_psat/demo/node-a"

DefaultBrokerServerID is the SPIFFE ID the fake broker presents by default: a SPIRE agent identity, which is what a client is expected to authorize.

View Source
const TrustDomain = "example.org"

TrustDomain is the trust domain of every SVID this package mints.

Variables

This section is empty.

Functions

func NewWorkloadSVID

func NewWorkloadSVID(t *testing.T, id string) *workload.X509SVID

NewWorkloadSVID mints a CA plus a leaf carrying the SPIFFE ID as its URI SAN and marshals them the way the Workload API returns them (DER chain, PKCS#8 key, DER bundle), so go-spiffe's own parser accepts them.

func UnservedSocket

func UnservedSocket(t *testing.T) string

UnservedSocket returns a path inside a temporary directory that nothing is listening on: the "SPIRE is not there at all" half of the #740 matrix.

Types

type BrokerEntry

type BrokerEntry struct {
	// SVIDs are the X.509-SVIDs the referenced pod is entitled to.
	SVIDs []*brokerpb.X509SVID
	// FederatedBundles are the foreign trust bundles carried alongside them,
	// keyed by the foreign trust domain's SPIFFE URI (as SPIRE keys them).
	FederatedBundles map[string][]byte
}

BrokerEntry is what the fake broker returns for one resolved reference.

type CA

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

CA mints X.509 SVIDs for tests. Unlike NewWorkloadSVID it keeps the signing key, so both ends of a mutually-authenticated connection can be issued identities that chain to the same bundle.

func NewCA

func NewCA(t *testing.T) *CA

NewCA returns a self-signed test CA.

func (*CA) BrokerSVID

func (c *CA) BrokerSVID(t *testing.T, id string, version int) *brokerpb.X509SVID

BrokerSVID mints a Broker API X509SVID for the given SPIFFE ID: the wire shape, with the chain and the bundle as concatenated DER and the key as PKCS#8 DER. version distinguishes one generation of an SVID from the next in tests that assert ordering; it is encoded in the certificate serial number.

func (*CA) Bundle

func (c *CA) Bundle(td spiffeid.TrustDomain) *x509bundle.Bundle

Bundle returns the trust bundle for td containing this CA.

func (*CA) BundleDER

func (c *CA) BundleDER() []byte

BundleDER returns this CA's certificate as the concatenated ASN.1 DER the Broker API carries in its bundle fields.

func (*CA) Identity

func (c *CA) Identity(t *testing.T, id string, extra ...*x509bundle.Bundle) *Identity

Identity mints an identity for id backed by this CA, trusting this CA's bundle plus any extra bundles (used to test that a peer in another trust domain is rejected by the authorizer rather than by chain verification).

func (*CA) SVID

func (c *CA) SVID(t *testing.T, id string) *x509svid.SVID

SVID mints a leaf SVID for the given SPIFFE ID, signed by this CA.

type FakeBroker

type FakeBroker struct {
	brokerpb.UnimplementedAPIServer
	// contains filtered or unexported fields
}

FakeBroker is a SPIFFE Broker Endpoint that resolves KubernetesObjectReferences from a table. It enforces the parts of the specification a client can get wrong: mutual TLS, and the mandatory security header.

func NewFakeBroker

func NewFakeBroker() *FakeBroker

NewFakeBroker returns an empty fake with its tables initialised.

func StartBroker

func StartBroker(t *testing.T, ca *CA, serverID string) (*FakeBroker, string)

StartBroker serves a FakeBroker over mutual TLS on a temporary UDS and returns it with the socket path. The server presents serverID (a SPIRE agent identity by default) and accepts any client in ca's trust domain; the client is expected to authorize the server itself.

os.MkdirTemp("") keeps the path inside the ~108-byte AF_UNIX budget, which a Bazel sandbox path would blow.

func (*FakeBroker) BadHeaders

func (f *FakeBroker) BadHeaders() int64

BadHeaders counts calls that arrived without the broker security header. A real SPIRE agent rejects those with InvalidArgument, so a non-zero count means the client is missing its interceptor.

func (*FakeBroker) LastReference

func (f *FakeBroker) LastReference() *brokerpb.KubernetesObjectReference

LastReference returns a copy of the most recent reference the fake decoded, so a test can assert the UID was sent alongside the key.

func (*FakeBroker) Rotate

func (f *FakeBroker) Rotate(namespace, name string, entry *BrokerEntry) int

Rotate pushes a new response onto every live stream for a pod reference and makes it the entry future subscribes resolve to. It reports how many live streams received it.

func (*FakeBroker) SetCloseAfterFirst

func (f *FakeBroker) SetCloseAfterFirst(namespace, name string, close bool)

SetCloseAfterFirst makes the FIRST stream for a pod reference end after one response, so a client's re-subscribe path can be exercised.

func (*FakeBroker) SetEntry

func (f *FakeBroker) SetEntry(namespace, name string, entry *BrokerEntry)

SetEntry registers (or replaces) the response for a pod reference.

func (*FakeBroker) SetNotFoundFor

func (f *FakeBroker) SetNotFoundFor(namespace, name string, n int)

SetNotFoundFor makes the next n subscribes for a pod reference fail with NotFound before it resolves.

func (*FakeBroker) SetPermissionDeniedFor

func (f *FakeBroker) SetPermissionDeniedFor(namespace, name string, denied bool)

SetPermissionDeniedFor makes every subscribe for a pod reference fail with PermissionDenied.

func (*FakeBroker) SubscribeToX509SVID

SubscribeToX509SVID implements the Broker API's X.509-SVID profile.

func (*FakeBroker) Subscribes

func (f *FakeBroker) Subscribes() int64

Subscribes counts the SubscribeToX509SVID calls received so far, including the ones that were rejected.

type FakeWorkloadAPI

type FakeWorkloadAPI struct {
	workload.UnimplementedSpiffeWorkloadAPIServer
	// contains filtered or unexported fields
}

FakeWorkloadAPI is a SPIRE Workload API server whose FetchX509SVID refuses to serve — exactly as a SPIRE agent that is up but cannot attest the workload yet — until StartServing is called.

func Start

func Start(t *testing.T, spiffeID string) (*FakeWorkloadAPI, string)

Start serves a FakeWorkloadAPI carrying spiffeID on a temporary UDS and returns it with the socket path. It is not serving yet: call StartServing to release the SVID.

os.MkdirTemp("") keeps the path inside the ~108-byte AF_UNIX budget, which a Bazel sandbox path would blow (same reason as agent/internal/spire's fake SPIRE agent).

func (*FakeWorkloadAPI) BadHeaders

func (f *FakeWorkloadAPI) BadHeaders() int64

BadHeaders counts calls that arrived without the Workload API security header. A real SPIRE agent rejects those, so a non-zero count means the client is misconfigured.

func (*FakeWorkloadAPI) FetchX509SVID

FetchX509SVID implements the Workload API.

func (*FakeWorkloadAPI) Fetches

func (f *FakeWorkloadAPI) Fetches() int64

Fetches counts the FetchX509SVID calls received so far.

func (*FakeWorkloadAPI) SpiffeID

func (f *FakeWorkloadAPI) SpiffeID() string

SpiffeID is the SPIFFE ID of the SVID this fake serves.

func (*FakeWorkloadAPI) StartServing

func (f *FakeWorkloadAPI) StartServing()

StartServing makes the fake issue its SVID to every subsequent fetch.

type Identity

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

Identity is a static x509svid.Source + x509bundle.Source, the shape common/spire.WaitingSource has once SPIRE has issued an SVID. It also announces updates, so a bridge that wakes on Updated() can be driven.

func NewPendingIdentity

func NewPendingIdentity() *Identity

NewPendingIdentity returns an Identity that has NOTHING yet: every accessor fails, which is the state common/spire.WaitingSource is in while SPIRE is still coming up (issue #740). Call Arrive to publish one.

func (*Identity) Arrive

func (i *Identity) Arrive(svid *x509svid.SVID, bundles ...*x509bundle.Bundle)

Arrive publishes an identity and wakes whoever is watching, as go-spiffe does on the first Workload API update.

func (*Identity) GetX509BundleForTrustDomain

func (i *Identity) GetX509BundleForTrustDomain(td spiffeid.TrustDomain) (*x509bundle.Bundle, error)

GetX509BundleForTrustDomain implements x509bundle.Source.

func (*Identity) GetX509SVID

func (i *Identity) GetX509SVID() (*x509svid.SVID, error)

GetX509SVID implements x509svid.Source.

func (*Identity) Updated

func (i *Identity) Updated() <-chan struct{}

Updated implements the update announcement a WaitingSource makes.

Jump to

Keyboard shortcuts

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