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
- func NewWorkloadSVID(t *testing.T, id string) *workload.X509SVID
- func UnservedSocket(t *testing.T) string
- type BrokerEntry
- type CA
- func (c *CA) BrokerSVID(t *testing.T, id string, version int) *brokerpb.X509SVID
- func (c *CA) Bundle(td spiffeid.TrustDomain) *x509bundle.Bundle
- func (c *CA) BundleDER() []byte
- func (c *CA) Identity(t *testing.T, id string, extra ...*x509bundle.Bundle) *Identity
- func (c *CA) SVID(t *testing.T, id string) *x509svid.SVID
- type FakeBroker
- func (f *FakeBroker) BadHeaders() int64
- func (f *FakeBroker) LastReference() *brokerpb.KubernetesObjectReference
- func (f *FakeBroker) Rotate(namespace, name string, entry *BrokerEntry) int
- func (f *FakeBroker) SetCloseAfterFirst(namespace, name string, close bool)
- func (f *FakeBroker) SetEntry(namespace, name string, entry *BrokerEntry)
- func (f *FakeBroker) SetNotFoundFor(namespace, name string, n int)
- func (f *FakeBroker) SetPermissionDeniedFor(namespace, name string, denied bool)
- func (f *FakeBroker) SubscribeToX509SVID(req *brokerpb.SubscribeToX509SVIDRequest, ...) error
- func (f *FakeBroker) Subscribes() int64
- type FakeWorkloadAPI
- type Identity
Constants ¶
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.
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.
const TrustDomain = "example.org"
TrustDomain is the trust domain of every SVID this package mints.
Variables ¶
This section is empty.
Functions ¶
func NewWorkloadSVID ¶
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 ¶
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 (*CA) BrokerSVID ¶
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 ¶
BundleDER returns this CA's certificate as the concatenated ASN.1 DER the Broker API carries in its bundle fields.
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 ¶
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 ¶
func (f *FakeBroker) SubscribeToX509SVID(req *brokerpb.SubscribeToX509SVIDRequest, stream grpc.ServerStreamingServer[brokerpb.SubscribeToX509SVIDResponse]) error
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 ¶
func (f *FakeWorkloadAPI) FetchX509SVID(_ *workload.X509SVIDRequest, stream grpc.ServerStreamingServer[workload.X509SVIDResponse]) error
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 ¶
GetX509SVID implements x509svid.Source.