cedar

package
v0.1.3 Latest Latest
Warning

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

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

Documentation

Overview

Package cedar is the cedar-go authorization driver (ADR-0074) behind the auth.Authorizer port (ADR-0018): it answers per-object, fine-grained data-plane decisions (KV first) that the coarse RBAC driver cannot express. It is DEFAULT-DENY — with no permitting Policy a kv::read is denied; the built-in forbid(kv::write) unless principal == resource.owner makes writes single-writer. The compiled PolicySet is cached and recompiled on a Policy change; per call only the request-relevant entities (principal Function + resource KVTable + its parent KVStore) are resolved from the metastore, never a full-store rebuild. It is a leaf under internal/auth, like the rbac driver.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CompileEgressPolicy

func CompileEgressPolicy(ns v1.NamespaceName, ep *v1.EgressPolicy, funcs []v1.ObjectName) ([]v1.Policy, error)

CompileEgressPolicy compiles one namespace's EgressPolicy into SYNTHETIC v1.Policy objects (Spec.Cedar), listed by the policy source alongside user KindPolicy and compiled by the existing compile()/ NewPolicyListFromBytes path — NOT a pre-built PolicySet (ADR-0117, M1). ONE permit per RULE (the namespace-attribute collapse): a domain/wildcard matches via resource.domains.contains, a CIDR via resource.ip.isInRange(ip("…")), ports as a set. The principal scope is the entity's existing `namespace` attribute (`principal.namespace == "<ns>"`) for a whole-namespace policy, or a bounded disjunction over the explicit spec.appliesTo list (`principal == Function::"<ns>/<fn>"`) — O(rules), independent of the namespace Function count, using NO Cedar group entity and NO edit to the registry assembly. funcs is the namespace Function-set (drives the cache revision; the compiled set does not depend on it). A nil ep or no rules ⇒ no policies (default-deny holds).

Each permit is assembled as a Cedar JSON EST document and parsed with cedar.Policy.UnmarshalJSON (injection-safe: every domain/CIDR is a JSON value node, never interpolated syntax; a malformed CIDR is a compile error, never templated). MarshalCedar renders each permit back to canonical Cedar text to preserve the M1 PolicySource→compile() contract.

func CompileRolesAssignment

func CompileRolesAssignment(ctx context.Context, ra *v1.RolesAssignment, roles RoleResolver) ([]v1.Policy, error)

CompileRolesAssignment compiles a RolesAssignment's READ/query/invoke grants into synthetic v1.Policy Cedar permits (ADR-0136; the injection-safe EST path, mirroring CompileEgressPolicy). WRITE grants are NOT permits (a Cedar forbid overrides a permit) — they are surfaced via WriterGrants for the resource materializer's `writers` set. A missing role / empty grant ⇒ no policy (default-deny holds).

func KnownAction

func KnownAction(action string) bool

KnownAction reports whether action is in the assembled schema vocabulary (ADR-0116).

func KnownEntityType

func KnownEntityType(entityType string) bool

KnownEntityType reports whether entityType is in the assembled schema vocabulary (ADR-0116).

func New

func New(d Deps) (auth.Authorizer, error)

New builds the cedar driver behind the auth.Authorizer port (ADR-0074). Entities + Policies are required.

func ValidateCedar

func ValidateCedar(text string) error

ValidateCedar checks that text PARSES as Cedar and that every statement references only the curated actions + entity types (ADR-0074 policy-validity). It returns fault.Invalid on a parse error or an off-schema action/entity-type — the policy-validity admission surfaces it. cedar-go's own schema validator is experimental, so this is the curated, fixed-schema check the driver owns.

Types

type Capability

type Capability struct {
	// Name is the capability's short id (e.g. "kv", "invoke", "s3", "egress") — for diagnostics/dedup.
	// Unique across the registry.
	Name string
	// Actions are the Cedar actions this capability authorizes (e.g. auth.ActionKVRead, ActionKVWrite).
	// Unique across the registry (no two capabilities share an action).
	Actions []auth.Action
	// EmitsEntityType is the primary Cedar entity type this capability materializes as a resource (e.g.
	// entityTypeKVTable). Used ONLY for schema-vocabulary assembly (KnownEntityType) — NOT a dispatch key
	// (an EntityRef.Type v1.Kind never equals the Cedar entity type: KindKVStore→KVTable, KindBucket→
	// BlobPrefix). Resource dispatch is by the Resource func's ok, below.
	EmitsEntityType cedartypes.EntityType
	// SupportingEntityTypes are the additional Cedar entity types this capability contributes to the
	// schema vocabulary beyond its primary EmitsEntityType — the resource's parent (KVStore for kv,
	// Bucket for s3) and any alternate principal type it admits (S3Identity for s3). A Policy may scope
	// on these (`resource in KVStore::"…"`, `principal == S3Identity::"…"`), so KnownEntityType must
	// accept them; they are assembled from the registry exactly like EmitsEntityType (never hand-listed).
	SupportingEntityTypes []cedartypes.EntityType
	// Resource materializes the resource entity (UID + parents + owner attr) for a request whose resource
	// this capability owns. ok==false ⇒ not ours (try the next capability) — this ok is the SOLE resource-
	// dispatch mechanism. A dangling resource still returns ok==true with bare entities (evaluable,
	// default-deny). nil ⇒ the capability owns no resource shape (Policy-only over an existing entity).
	Resource func(ctx context.Context, r MetaReader, resource auth.EntityRef) (em cedartypes.EntityMap, ok bool, err error)
	// PrincipalBinding declares this capability's binding-as-grant attribute on the principal: Attr is the
	// principal attribute name (e.g. "kvBindings"); Bind materializes its members from a resolved
	// principal object (see PrincipalSource). The provider sets Attr whenever Bind returns a non-nil slice
	// (possibly empty), matching today's EntitiesFor (a Function always carries links/kvBindings/blobBindings;
	// the built-ins also `has`-guard, so empty ≡ absent). A Bind that returns nil for a source type
	// contributes nothing (attr absent) — e.g. kv/invoke for a CatalogService. Zero value ⇒ no binding.
	PrincipalBinding PrincipalBinding
	// Builtin is this capability's built-in permit policy text (the .cedar granting the capability when
	// principal.<attr>.contains(resource)); "" ⇒ no built-in (Policy-only).
	Builtin string
}

Capability declares one authorization capability (kv, invoke, s3, egress, …) so the schema vocabulary, the EntityProvider, and the built-in permits are ASSEMBLED from the registered set — registering a new capability adds no branch to shared code (ADR-0116). All funcs are typed (no any).

Two orthogonal axes are kept separate (judge B1): a Capability is an {action + resource + built-in} on a PRINCIPAL; *where a principal's binding attributes come from* is a PrincipalSource (below), so the ADR-0088 provider fallback (Function-first, else CatalogService) is NOT a fourth capability — s3 is one capability with two principal sources.

func CatalogCapability

func CatalogCapability() Capability

CatalogCapability is the catalog::query capability (ADR-0137): spec.catalogs → the `catalogBindings` Set of CatalogService entity-refs (binding-as-query-grant); the resource is the CatalogService the query targets. It is READ-SHAPED — like invoke it owns no writable resource, so there is NO WriterLister and NO write action; the built-in permit reads principal.catalogBindings, not the resource's attrs, so default-deny holds even if the target is missing. External Identities are granted via a Catalog-scoped RolesAssignment (compiled to a permit), not this built-in.

func EgressCapability

func EgressCapability() Capability

EgressCapability registers egress on the ADR-0116 registry (ADR-0117, F81): Action egress::connect; resource entity NetDestination materialized from the request EntityRef's Path (no MetaReader read — the destination is ephemeral); NO PrincipalBinding (governed by EgressPolicy, not a spec.<field> grant) and NO Builtin (default-deny — grants come only from a compiled EgressPolicy). Its Resource emits the UID + attributes {ip, port, domains}; the driver's resourceUID gains a matching KindNetDestination case (entities.go).

func InvokeCapability

func InvokeCapability() Capability

InvokeCapability is the link::invoke capability (ADR-0075): spec.links → the `links` Set of target Function entities (link-as-grant); the resource is the target Function (a bare entity — the built-in permit reads principal.links, not the target's attrs, so default-deny holds even if the target is missing). It owns no principal-owned resource beyond the target Function.

func KVCapability

func KVCapability() Capability

KVCapability is the kv::read/kv::write capability (ADR-0074/0076): spec.kv → the `kvBindings` Set of KVTable entity-refs (read binding-as-grant); the resource is the KVTable + its parent KVStore + the table owner (a Function entity-REFERENCE, so `principal == resource.owner` compares entities). It owns both built-ins: the write single-writer rule and the read binding-grant.

func KVCapabilityWithWriters

func KVCapabilityWithWriters(w WriterLister) Capability

KVCapabilityWithWriters is KVCapability with a WriterLister so a writer-role RolesAssignment (ADR-0136) contributes to a table's `writers` set. KVCapability() (nil lister) is owner-only (back-compat).

func S3Capability

func S3Capability() Capability

S3Capability is the s3::read/s3::write capability (ADR-0080): spec.blob → the `blobBindings` Set of BlobPrefix entity-refs (read binding-as-grant); the resource is the BlobPrefix + its parent Bucket + the prefix owner (a Function entity-REFERENCE). Its Bind handles BOTH a *v1.Function and a *v1.CatalogService (ADR-0088 — both carry spec.blob). It admits the external S3Identity principal type.

func S3CapabilityWithWriters

func S3CapabilityWithWriters(w WriterLister) Capability

S3CapabilityWithWriters is S3Capability with a WriterLister so a writer-role RolesAssignment (ADR-0136) contributes to a prefix's `writers` set (the generalized single-writer forbid). The compose root uses this; S3Capability() (nil lister) is owner-only (back-compat).

type Deps

type Deps struct {
	// Entities resolves the request-relevant Cedar entities per call (principal + resource + parents).
	Entities EntityProvider
	// Policies supplies the user Policy resources (compiled + cached with the built-ins).
	Policies PolicySource
	// Builtins is the always-on built-in Cedar policy text (a Registry's Builtins()) compiled into the
	// PolicySet with the user Policies. Empty ⇒ the default registry's built-ins — so the compose root can
	// supply a variant built-in set (e.g. funcdctl dev's relaxed S3 writes) without a package global.
	Builtins string
	// Logger is the driver's logger; nil ⇒ slog.Default().
	Logger *slog.Logger
}

Deps configures the cedar driver (ADR-0074).

type EntityProvider

type EntityProvider interface {
	EntitiesFor(ctx context.Context, principal, resource auth.EntityRef) (cedartypes.EntityMap, error)
}

EntityProvider resolves ONLY the request-relevant Cedar entities (the principal + the resource + its parents) for one Authorize call (ADR-0074) — never a full-store rebuild. Entities are materialized from the metastore's existing resources (no duplicate state); the registry (ADR-0116) composes it from the registered capabilities' resource materializers + principal-binding Sets.

func NewEntityProvider

func NewEntityProvider(r MetaReader) (EntityProvider, error)

NewEntityProvider builds the default metastore-backed EntityProvider (ADR-0074): the composite provider assembled from the default capability registry (kv, invoke, s3 + the Function/CatalogService sources). r is required. Consumers that register additional capabilities build their own Registry and call (*Registry).EntityProvider directly (ADR-0116).

type MetaReader

type MetaReader interface {
	Get(ctx context.Context, gvk v1.GroupVersionKind, ns v1.NamespaceName, name v1.ObjectName) (v1.Object, error)
}

MetaReader is the read-only metastore view the EntityProvider needs (ADR-0074): it reads the caller Function (for the principal entity) and the target resource (for the owner/parent). Declared here so the cedar package stays a near-leaf; the wiring adapts store.Store.

type PolicySource

type PolicySource interface {
	// Policies returns all Policy resources and an opaque revision; the driver recompiles only when
	// the revision changes (cheap cache invalidation without diffing policy text).
	Policies(ctx context.Context) (policies []v1.Policy, revision string, err error)
}

PolicySource supplies the user Policy resources the driver compiles (ADR-0074). The driver compiles the built-in rules + every user Policy into one cached PolicySet, recompiled when the source's revision changes.

type PrincipalBinding

type PrincipalBinding struct {
	// Attr is the Cedar principal attribute (e.g. "kvBindings", "links", "blobBindings").
	Attr string
	// Bind materializes the attribute's Set members from a resolved principal object. src is whatever a
	// PrincipalSource resolved (a *v1.Function or a *v1.CatalogService); a capability that doesn't apply to
	// that source type returns nil (e.g. kv/invoke return nil for a CatalogService — providers have no
	// links/kv). ns is the principal namespace (for building same-namespace resource UIDs).
	Bind func(ns v1.NamespaceName, src PrincipalObject) []cedartypes.EntityUID
}

PrincipalBinding is one binding-as-grant attribute a capability contributes to a principal.

type PrincipalObject

type PrincipalObject = v1.PrincipalObject

PrincipalObject is a resolved principal-backing object (a *v1.Function or *v1.CatalogService); a closed interface (only api/types implements it, via an unexported marker) so PrincipalBinding.Bind type-switches without any. It aliases v1.PrincipalObject: the marker method must live in the same package as the implementing types, so the sealed interface is declared in api/types/v1alpha1 and re-exported here under the cedar name.

type PrincipalSource

type PrincipalSource func(ctx context.Context, r MetaReader, p auth.EntityRef) (obj PrincipalObject, ok bool, err error)

PrincipalSource resolves the principal's backing object for a principal EntityRef, in order. The default sources are Function-first then CatalogService-fallback (ADR-0088) — the provider case, now a principal SOURCE, not a capability. A source returns ok==false to defer to the next.

func CatalogServicePrincipalSource

func CatalogServicePrincipalSource() PrincipalSource

CatalogServicePrincipalSource is the ADR-0088 fallback: resolve a *v1.CatalogService when no Function of this name exists (Function-first). A provider is a first-class S3 principal — its spec.blob are its blobBindings; it has no links/kv.

func FunctionPrincipalSource

func FunctionPrincipalSource() PrincipalSource

FunctionPrincipalSource resolves the principal's backing *v1.Function (the primary source, ADR-0074).

type Registry

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

Registry is a deduped set of capabilities + an ordered principal-source list. It assembles the shared cedar artifacts (the composite EntityProvider, the KnownAction/KnownEntityType vocabulary, and the built-in PolicySet) from the registered set (ADR-0116).

func NewRegistry

func NewRegistry(caps []Capability, sources []PrincipalSource) (*Registry, error)

NewRegistry validates (unique Name, unique Action across capabilities; ≥1 source) and returns the registry. A duplicate Name/Action or an empty source list is a fault.Invalid wiring error.

func (*Registry) Builtins

func (reg *Registry) Builtins() string

Builtins returns the concatenated built-in permit policy text (the union of the capabilities' Builtin, in registry order so the compiled PolicySet is deterministic).

func (*Registry) EntityProvider

func (reg *Registry) EntityProvider(r MetaReader) (EntityProvider, error)

EntityProvider returns the composite provider over r (ADR-0116). r is required.

func (*Registry) KnownAction

func (reg *Registry) KnownAction(a auth.Action) bool

KnownAction reports whether a is one of the registered capabilities' actions (the assembled schema vocabulary — replaces the hand-listed curatedActions map).

func (*Registry) KnownEntityType

func (reg *Registry) KnownEntityType(t string) bool

KnownEntityType reports whether t is one of the registered capabilities' entity types (primary EmitsEntityType ∪ SupportingEntityTypes — the assembled schema vocabulary, replacing the hand-listed curatedEntityTypes map).

type RoleResolver

type RoleResolver interface {
	Actions(ctx context.Context, ref v1.RoleRef, ns v1.NamespaceName) ([]string, bool)
}

RoleResolver resolves a RoleRef (a built-in name or a custom Role resource) to its action set.

func NewRoleResolver

func NewRoleResolver(r MetaReader) RoleResolver

NewRoleResolver builds the production role resolver over a MetaReader.

type WriterGrant

type WriterGrant struct {
	Principal cedartypes.EntityUID
	Scope     v1.ScopeRef
}

WriterGrant is one principal authorized to WRITE a scope (a s3::write / kv::write grant).

func WriterGrants

func WriterGrants(ctx context.Context, ra *v1.RolesAssignment, roles RoleResolver) []WriterGrant

WriterGrants returns the write-authorizing (principal, scope) grants of a RolesAssignment — consumed by the s3/kv resource materializer to build a resource's `writers` set (the generalized single-writer forbid). Excludes the legacy owner (added separately by the materializer).

type WriterLister

type WriterLister interface {
	BlobWriters(ctx context.Context, ns v1.NamespaceName, bucket, prefix string) []cedartypes.EntityUID
	KVWriters(ctx context.Context, ns v1.NamespaceName, store, table string) []cedartypes.EntityUID
}

WriterLister returns the writer principal UIDs (beyond the legacy owner) authorized to WRITE a blob prefix / kv table, from writer-role RolesAssignments (ADR-0136). It backs the generalized single-writer forbid's `writers` set. A nil WriterLister ⇒ owner-only writers (back-compat, no role grants).

Jump to

Keyboard shortcuts

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