metadata

package
v0.0.1 Latest Latest
Warning

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

Go to latest
Published: Mar 9, 2026 License: MIT Imports: 33 Imported by: 0

README

Metadata persistence

Access manager metadata is expressed as a tree with annotations on the nodes of the tree. Each node has a URL with the scheme am://. The annotations on the nodes can be structural to indicate leaf nodes of the tree. The annotations can also be permission expressions or applied roles that are used by the access manager itself for making decisions about access. It is also possible to have ad hoc annotations that store things such as public keys that are used by identity plugins, URLs for objects in S3 or addresses of data repositories such as databases or file systems. All annotations are versioned to allow safe update semantics.

The nodes of the metadata tree together with all annotations are stored in a table with key and data formats designed to facilitate some operations (such as scanning for the children of a node) without forcing the storage layer to understand anything about the annotations themselves.

Key Structure

This tree of metadata is persisted in etcd in a namespace with prefix /meta. Annotations are stored by a key formed using URL of the node with the am:// scheme removed and a fragment identifier added to distinguish different annotations. This path is prefixed by a fixed length integer indicating the number of components in the path so that range scans on keys traverse the metadata tree in breadth-first order. For all entries representing annotations on nodes, a fragment identifier is appended to the path to indicate the kind of annotation.

The fragment identifier consists of # followed by a tag and an integer with less than 63-bits expressed in hexadecimal form. This convention allows range scans to be used to get all of the annotations on a node or all of the direct children of a node. The unique integer is required on all annotations other than leaf annotations.

We guarantee that all nodes also appear in etcd without any fragment. This means that all of the nodes in the tree can be enumerated with a range scan even if there are no annotations on a node or some child.

Here is an example of the keys used to store a metadata tree that has one user and one role.

00000 /
00001 /data
00001 /data#ace-37af
00001 /role
00001 /role#ace-e392
00001 /user
00001 /user#ace-48a8
00001 /workload
00001 /workload#ace-5982
00002 /role/operator-admin
00002 /role/operator-admin#leaf-48a3
00002 /user/the-operator
00002 /user/the-operator#leaf-518c
00002 /user/the-operator#role-4857

Note how we can find all of the top-level directories and their annotations using a prefix scan on 00001 /. Similarly, we can find all children of the am://user directory by scanning with a prefix of 00002 /user/

Kinds of Annotations

Each node can have multiple annotations with the same tag. Each annotation has a different key distinguished by the fragment of the URL.

The four kinds of annotation include structural markers, applied roles, permissions expressions, and internal data such as cryptographic public keys, external URLs for credential factories and external identities such as Spiffe IDs. There are conventions about where different kinds of metadata can appear, but the storage layer doesn't care about or enforce these conventions.

The values of all metadata annotations are stored as protobuf encoded values wrapped in a header structure. This header contains the start and end times for the annotation. The actual content of the annotation is stored as a raw bytes that are not interpreted by the storage layer.

A table with commonly used annotation tags is shown below

Type Description
ace A single access control expression
role A role applied to a user or workload.
leaf Indicates that this node is a leaf-node in the metadata tree
svid A SPIFFE id for a workload
ssh-key An ssh key to be used to authenticate a user, workload or key
s3-info Information required to access and S3 table such as URL

The leaf type is used to signal that no children should be created below a node. This is used to indicate any object in the tree such as a dataset, user, role or workload. Other kinds of annotations can appear anywhere in the tree, but, by convention, role is only allowed under the am://user, am://workload and am://key top-level directories. No structural or semantic conventions are enforced at the storage layer.

For all annotations, the annotation content is stored in a wrapper type metadata.Annotation that has a header containing meta-metadata that layers above the storage can use to determine how to interpret the annotation data itself.

For all annotations, the unique value is used to allow multiple metadata values with the same type. This isn't useful for leaf annotations, but most other kinds of annotation can have multiple values on the same node.

Setting the version to -1 allows a record to be created or overwritten without regard to the version of any existing data. Setting version to 0 indicates that there should not be a pre-existing value with the same key. All other values of version require that there be a pre-existing record with exactly that version.

Documentation

Index

Constants

View Source
const (
	Read      = Operation_READ  // read from a dataset
	Write     = Operation_WRITE // write to a dataset, create children of a directory
	View      = Operation_VIEW  // is an entity visible (could be a dataset, role, User = Operation_user          // can permissions on an entity be modified?
	Admin     = Operation_ADMIN
	UseRole   = Operation_USEROLE   // can a role be used in an ACL?
	ApplyRole = Operation_APPLYROLE // can a role be added to a principal?
	VouchFor  = Operation_VOUCHFOR  // can a plugin vouch for an identity?
	Invalid   = Operation_INVALID
)

Variables

View Source
var (
	Operation_name = map[int32]string{
		0: "INVALID",
		1: "READ",
		2: "WRITE",
		3: "VIEW",
		4: "ADMIN",
		5: "USEROLE",
		6: "APPLYROLE",
		7: "VOUCHFOR",
	}
	Operation_value = map[string]int32{
		"INVALID":   0,
		"READ":      1,
		"WRITE":     2,
		"VIEW":      3,
		"ADMIN":     4,
		"USEROLE":   5,
		"APPLYROLE": 6,
		"VOUCHFOR":  7,
	}
)

Enum value maps for Operation.

Functions

This section is empty.

Types

type ACE

type ACE struct {
	Op    Operation `protobuf:"varint,1,opt,name=op,proto3,enum=metadata.Operation" json:"op,omitempty"`
	Local bool      `protobuf:"varint,2,opt,name=local,proto3" json:"local,omitempty"` // if true, ACE is not inherited
	Agent bool      `protobuf:"varint,9,opt,name=agent,proto3" json:"agent,omitempty"` // if true, this ACE is for the agent of the op else it is for the target
	Acls  []*ACL    `protobuf:"bytes,3,rep,name=acls,proto3" json:"acls,omitempty"`    // all of these ACLs must be satisfied
	// common fields for all annotations
	Tag         string `protobuf:"bytes,4,opt,name=tag,proto3" json:"tag,omitempty"`                  // "ace" for all kinds of ACEs
	Unique      int64  `protobuf:"varint,5,opt,name=unique,proto3" json:"unique,omitempty"`           // unique-ifier to avoid collisions for annotations on a metadata node
	Version     int64  `protobuf:"varint,6,opt,name=version,proto3" json:"version,omitempty"`         // version for safe updates
	StartMillis int64  `protobuf:"varint,7,opt,name=startMillis,proto3" json:"startMillis,omitempty"` // what clock time does this ACE take effect
	EndMillis   int64  `protobuf:"varint,8,opt,name=endMillis,proto3" json:"endMillis,omitempty"`     // when does this ACE lose effect
	// contains filtered or unexported fields
}

this is the public view of the standard annotations

func (*ACE) AsAnnotation

func (r *ACE) AsAnnotation() (*Annotation, error)

func (*ACE) Descriptor deprecated

func (*ACE) Descriptor() ([]byte, []int)

Deprecated: Use ACE.ProtoReflect.Descriptor instead.

func (*ACE) GetAcls

func (x *ACE) GetAcls() []*ACL

func (*ACE) GetAgent

func (x *ACE) GetAgent() bool

func (*ACE) GetEndMillis

func (x *ACE) GetEndMillis() int64

func (*ACE) GetLocal

func (x *ACE) GetLocal() bool

func (*ACE) GetOp

func (x *ACE) GetOp() Operation

func (*ACE) GetStartMillis

func (x *ACE) GetStartMillis() int64

func (*ACE) GetTag

func (x *ACE) GetTag() string

func (*ACE) GetUnique

func (x *ACE) GetUnique() int64

func (*ACE) GetVersion

func (x *ACE) GetVersion() int64

func (*ACE) ProtoMessage

func (*ACE) ProtoMessage()

func (*ACE) ProtoReflect

func (x *ACE) ProtoReflect() protoreflect.Message

func (*ACE) Reset

func (x *ACE) Reset()

func (*ACE) String

func (x *ACE) String() string

type ACEPersist

type ACEPersist struct {
	Op    Operation     `protobuf:"varint,1,opt,name=op,proto3,enum=metadata.Operation" json:"op,omitempty"` // what operation is controlled
	Local bool          `protobuf:"varint,2,opt,name=local,proto3" json:"local,omitempty"`                   // if true, ACE is not inherited
	Acls  []*ACLPersist `protobuf:"bytes,3,rep,name=acls,proto3" json:"acls,omitempty"`                      // all of these ACLs must be satisfied
	// contains filtered or unexported fields
}

stores permissions for a single operation

func (*ACEPersist) Descriptor deprecated

func (*ACEPersist) Descriptor() ([]byte, []int)

Deprecated: Use ACEPersist.ProtoReflect.Descriptor instead.

func (*ACEPersist) GetAcls

func (x *ACEPersist) GetAcls() []*ACLPersist

func (*ACEPersist) GetLocal

func (x *ACEPersist) GetLocal() bool

func (*ACEPersist) GetOp

func (x *ACEPersist) GetOp() Operation

func (*ACEPersist) ProtoMessage

func (*ACEPersist) ProtoMessage()

func (*ACEPersist) ProtoReflect

func (x *ACEPersist) ProtoReflect() protoreflect.Message

func (*ACEPersist) Reset

func (x *ACEPersist) Reset()

func (*ACEPersist) String

func (x *ACEPersist) String() string

type ACL

type ACL struct {
	Roles []string `protobuf:"bytes,1,rep,name=roles,proto3" json:"roles,omitempty"`
	// contains filtered or unexported fields
}

func (*ACL) Descriptor deprecated

func (*ACL) Descriptor() ([]byte, []int)

Deprecated: Use ACL.ProtoReflect.Descriptor instead.

func (*ACL) GetRoles

func (x *ACL) GetRoles() []string

func (*ACL) ProtoMessage

func (*ACL) ProtoMessage()

func (*ACL) ProtoReflect

func (x *ACL) ProtoReflect() protoreflect.Message

func (*ACL) Reset

func (x *ACL) Reset()

func (*ACL) String

func (x *ACL) String() string

type ACLPersist

type ACLPersist struct {
	Roles []string `protobuf:"bytes,1,rep,name=roles,proto3" json:"roles,omitempty"`
	// contains filtered or unexported fields
}

implements a conventional ACL. User or workload must have at least one of these attributes

func (*ACLPersist) Descriptor deprecated

func (*ACLPersist) Descriptor() ([]byte, []int)

Deprecated: Use ACLPersist.ProtoReflect.Descriptor instead.

func (*ACLPersist) GetRoles

func (x *ACLPersist) GetRoles() []string

func (*ACLPersist) ProtoMessage

func (*ACLPersist) ProtoMessage()

func (*ACLPersist) ProtoReflect

func (x *ACLPersist) ProtoReflect() protoreflect.Message

func (*ACLPersist) Reset

func (x *ACLPersist) Reset()

func (*ACLPersist) String

func (x *ACLPersist) String() string

type Annotation

type Annotation struct {
	Unique      int64         `json:",string"` //  unique-ifier to avoid collisions for annotations on a metadata node
	Version     int64         `json:",string"` // version for safe updates
	Global      int64         `json:",string"` // the global revision number for last modification
	StartMillis int64         `json:",string"` // what clock time did this annotation take effect
	EndMillis   int64         `json:",string"` // when does this annotation lose effect
	Tag         string        // hint for the interpretation of the value
	Raw         *anypb.Any    // any data specific to the annotation goes here in marshalled form
	Value       proto.Message // and here in unmarshalled form
}

Annotation serves as the wrapper for all annotations and contains the common fields. This is a plain Go object so that we can have a cached value for the unmarshalled annotation itself. There is a parallel structure called AnnotationWrapper in the protobuf that is actually used as the format for storing annotations.

func UnMarshalNotable

func UnMarshalNotable(m json.RawMessage, ax proto.Message) (*Annotation, error)

func UnmarshalAnnotation

func UnmarshalAnnotation(m []byte) (*Annotation, bool, error)

func UserAnnotationString

func UserAnnotationString(tag, value string) (*Annotation, error)

func (*Annotation) AsACE

func (ann *Annotation) AsACE() (*ACE, error)

func (*Annotation) AsAnnotation

func (r *Annotation) AsAnnotation() (*Annotation, error)

func (*Annotation) AsAppliedRole

func (ann *Annotation) AsAppliedRole() (*AppliedRole, error)

func (*Annotation) AsUserAnnotation

func (ann *Annotation) AsUserAnnotation() (*UserAnnotation, error)

func (*Annotation) MarshalJSON

func (a *Annotation) MarshalJSON() ([]byte, error)

type AnnotationStore

type AnnotationStore interface {
	// Annotate adds an annotation to an existing node
	Annotate(ctx context.Context, path string, ann Notable) (int64, error)

	// ScanPath walks the metadata tree from root to `path` and calls the checker
	// function at each prefix. If the checker returns the sentinel as the error,
	// the scan will stop. It is expected that the checker will have a side effect
	// that achieves the goal of the scan; the scanner does not do anything but
	// provide a control flow.
	ScanPath(ctx context.Context, path string, includeLast bool, checker func(path string, ace *ACE, abortScan error) error) error

	// PutNode creates a node or updates one
	PutNode(ctx context.Context, path string, version int64) (int64, error)

	// PutTree writes and entire tree or subtree for bootstrapping or testing.
	// An error should be thrown if the data already exists
	PutTree(ctx context.Context, tree *MetaTree) error

	// GetTree serializes the entire metadata state in a form suitable for preserving
	GetTree(ctx context.Context) (*MetaTree, error)

	// Get reads the metadata for a path with an optional filter. Filters are of the form
	// `metaType/subType` or `metaType` and only metadata annotations that matches at
	// least one of the filters will be returned. If no filters are given, then all
	// metadata annotations are returned.
	Get(ctx context.Context, path string, filters ...KeyOption) ([]*Annotation, error)

	// GetChildren returns the list of the names of the children of the current node
	GetChildren(ctx context.Context, path string) ([]string, error)

	// Delete deletes an object along with all children and annotations
	Delete(ctx context.Context, path string) error

	// DeleteAnnotation deletes a single annotation. Version can be -1 to force the deletion, but tag and unique must be valid
	DeleteAnnotation(ctx context.Context, path string, tag string, version int64, unique int64) error

	// IsFolder returns true if a path names a directory, false if it names a leaf
	// node like a role or a user. An error is thrown if nothing exists with that
	// name.
	IsFolder(ctx context.Context, path string) (bool, error)
}

type AnnotationWrapper

type AnnotationWrapper struct {
	Unique      int64      `protobuf:"varint,1,opt,name=Unique,proto3" json:"Unique,omitempty"`           // unique-ifier to avoid collisions for annotations on a metadata node
	Version     int64      `protobuf:"varint,2,opt,name=Version,proto3" json:"Version,omitempty"`         // version for safe updates
	Global      int64      `protobuf:"varint,3,opt,name=Global,proto3" json:"Global,omitempty"`           // the global revision number for last modification
	StartMillis int64      `protobuf:"varint,4,opt,name=StartMillis,proto3" json:"StartMillis,omitempty"` // what clock time did this annotation take effect
	EndMillis   int64      `protobuf:"varint,5,opt,name=EndMillis,proto3" json:"EndMillis,omitempty"`     // when does this annotation lose effect
	Tag         string     `protobuf:"bytes,6,opt,name=Tag,proto3" json:"Tag,omitempty"`                  // hint for the interpretation of the value such as "role", "ace", or "ssh-key"
	Raw         *anypb.Any `protobuf:"bytes,7,opt,name=Raw,proto3" json:"Raw,omitempty"`                  // any data specific to the annotation goes here in marshalled form
	// contains filtered or unexported fields
}

And these are the forms that are used for persistence the difference is that things like the unique ID, version and duration are factored out for use by the storage system. Underneath, the annotation-type-specific fields are stored in their stripped form.

func (*AnnotationWrapper) Descriptor deprecated

func (*AnnotationWrapper) Descriptor() ([]byte, []int)

Deprecated: Use AnnotationWrapper.ProtoReflect.Descriptor instead.

func (*AnnotationWrapper) GetEndMillis

func (x *AnnotationWrapper) GetEndMillis() int64

func (*AnnotationWrapper) GetGlobal

func (x *AnnotationWrapper) GetGlobal() int64

func (*AnnotationWrapper) GetRaw

func (x *AnnotationWrapper) GetRaw() *anypb.Any

func (*AnnotationWrapper) GetStartMillis

func (x *AnnotationWrapper) GetStartMillis() int64

func (*AnnotationWrapper) GetTag

func (x *AnnotationWrapper) GetTag() string

func (*AnnotationWrapper) GetUnique

func (x *AnnotationWrapper) GetUnique() int64

func (*AnnotationWrapper) GetVersion

func (x *AnnotationWrapper) GetVersion() int64

func (*AnnotationWrapper) ProtoMessage

func (*AnnotationWrapper) ProtoMessage()

func (*AnnotationWrapper) ProtoReflect

func (x *AnnotationWrapper) ProtoReflect() protoreflect.Message

func (*AnnotationWrapper) Reset

func (x *AnnotationWrapper) Reset()

func (*AnnotationWrapper) String

func (x *AnnotationWrapper) String() string

type AppliedRole

type AppliedRole struct {
	Role        string `protobuf:"bytes,1,opt,name=role,proto3" json:"role,omitempty"`
	Tag         string `protobuf:"bytes,2,opt,name=tag,proto3" json:"tag,omitempty"`
	Unique      int64  `protobuf:"varint,3,opt,name=unique,proto3" json:"unique,omitempty"`
	Version     int64  `protobuf:"varint,4,opt,name=version,proto3" json:"version,omitempty"`
	StartMillis int64  `protobuf:"varint,5,opt,name=startMillis,proto3" json:"startMillis,omitempty"`
	EndMillis   int64  `protobuf:"varint,6,opt,name=endMillis,proto3" json:"endMillis,omitempty"`
	// contains filtered or unexported fields
}

func (*AppliedRole) AsAnnotation

func (r *AppliedRole) AsAnnotation() (*Annotation, error)

func (*AppliedRole) Descriptor deprecated

func (*AppliedRole) Descriptor() ([]byte, []int)

Deprecated: Use AppliedRole.ProtoReflect.Descriptor instead.

func (*AppliedRole) GetEndMillis

func (x *AppliedRole) GetEndMillis() int64

func (*AppliedRole) GetRole

func (x *AppliedRole) GetRole() string

func (*AppliedRole) GetStartMillis

func (x *AppliedRole) GetStartMillis() int64

func (*AppliedRole) GetTag

func (x *AppliedRole) GetTag() string

func (*AppliedRole) GetUnique

func (x *AppliedRole) GetUnique() int64

func (*AppliedRole) GetVersion

func (x *AppliedRole) GetVersion() int64

func (*AppliedRole) ProtoMessage

func (*AppliedRole) ProtoMessage()

func (*AppliedRole) ProtoReflect

func (x *AppliedRole) ProtoReflect() protoreflect.Message

func (*AppliedRole) Reset

func (x *AppliedRole) Reset()

func (*AppliedRole) String

func (x *AppliedRole) String() string

type JsonPersist

type JsonPersist struct {
	Data string `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
	// contains filtered or unexported fields
}

how we store JSON data such as for dataset info

func (*JsonPersist) Descriptor deprecated

func (*JsonPersist) Descriptor() ([]byte, []int)

Deprecated: Use JsonPersist.ProtoReflect.Descriptor instead.

func (*JsonPersist) GetData

func (x *JsonPersist) GetData() string

func (*JsonPersist) ProtoMessage

func (*JsonPersist) ProtoMessage()

func (*JsonPersist) ProtoReflect

func (x *JsonPersist) ProtoReflect() protoreflect.Message

func (*JsonPersist) Reset

func (x *JsonPersist) Reset()

func (*JsonPersist) String

func (x *JsonPersist) String() string

type KeyOption

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

func WithDepthOffset

func WithDepthOffset(offset int) KeyOption

func WithType

func WithType(metaType string) KeyOption

func WithUnique

func WithUnique(unique int64) KeyOption

type KeyOptionKind

type KeyOptionKind int
const (
	Unique KeyOptionKind = iota
	MetaType
	DepthOffset
)

type KeyStore

type KeyStore interface {
	GetSignedJWTWithClaims(duration time.Duration, claims TokenClaims) (string, error)

	ValidateJWT(token string) (*TokenClaims, error)

	// GetSigningKey returns a credential signing key that has at least the required
	// life span remaining. Keys are shared across all access manager instances and
	// have a lifespan set on creation. Old keys are deleted when their life is over
	// and created when there is a need for a key that will outlive any current key.
	// Typically, the returned key will be an RSA key, but the type is not
	// guaranteed. It is guaranteed that the key type will correspond to the
	// advertised JWT signing method.
	GetSigningKey(ctx context.Context, requiredLife time.Duration) (any, int64, error)

	// GetJWTSigningMethod returns the signing method that corresponds to the keys
	// returned by this KeyStore instance. To use a KeyStore (ks) to sign a JWT with
	// a lifetime of at least one hour, you should use something like this:
	//
	// key, err = ks.GetSigningKey(ctx, time.Hour)
	// if err !=nil { ... }
	// token = jwt.NewWithClaims(ks.GetJWTSigningMethod(ctx)jwt.MapClaims{
	//"foo": "bar",
	//"nbf": time.Date(2015, 10, 10, 12, 0, 0, 0, time.UTC).Unix(),
	//})
	// ... add more fields to the token ...
	// signedJWT = token.SignedString(key)
	GetJWTSigningMethod(ctx context.Context) jwt.SigningMethod

	// GetPublicSigningKeys returns a list of public keys that can be used to verify
	// JWTs signed by this KeyStore. The keys are returned in a format that is
	// compatible with the `jwt.Parse` function and any unexpired credential will be
	// verifiable with one of the keys returned by this function.
	GetPublicSigningKeys(ctx context.Context) (map[int64]string, error)
}

type MetaStore

type MetaStore interface {
	AnnotationStore
	KeyStore
}

MetaStore allows access to annotations and keys. This version hides all implementation details and is what is advertised.

func OpenEtcdMetaStore

func OpenEtcdMetaStore(urls []string) (MetaStore, error)

OpenEtcdMetaStore connects to etcd and sets up a production style metadata store

type MetaStoreX

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

MetaStoreX is a MetaStore which uses unexported implementations so that internal tests can mess with things like time slipping or see through to the underlying persistence interface. Not advertised for normal use and only available via OpenTestStore

func OpenTestStore

func OpenTestStore(data string) (*MetaStoreX, error)

OpenTestStore creates an in-memory metadata store useful for testing. The data parameter is the name of an embedded file that contains a MetaTree in JSON format. This is used to bootstrap the store with some known data. The file is expected to be in the "metadata/sample" directory.

func (*MetaStoreX) Annotate

func (e *MetaStoreX) Annotate(ctx context.Context, path string, ax Notable) (int64, error)

func (*MetaStoreX) Close

func (e *MetaStoreX) Close()

func (*MetaStoreX) Delete

func (e *MetaStoreX) Delete(ctx context.Context, path string) error

func (*MetaStoreX) DeleteAnnotation

func (e *MetaStoreX) DeleteAnnotation(ctx context.Context, path string, tag string, version int64, unique int64) error

func (*MetaStoreX) Get

func (e *MetaStoreX) Get(ctx context.Context, path string, filters ...KeyOption) ([]*Annotation, error)

Get returns all of the metadata stored at a particular path in a raw form. The keys for the metadata returned is examined to ensure that it is in a valid format, but is otherwise uninterpreted.

func (*MetaStoreX) GetChildren

func (e *MetaStoreX) GetChildren(ctx context.Context, path string) ([]string, error)

func (*MetaStoreX) GetJWTSigningMethod

func (r *MetaStoreX) GetJWTSigningMethod(_ context.Context) jwt.SigningMethod

func (*MetaStoreX) GetPublicSigningKeys

func (r *MetaStoreX) GetPublicSigningKeys(ctx context.Context) (map[int64]string, error)

func (*MetaStoreX) GetSignedJWTWithClaims

func (r *MetaStoreX) GetSignedJWTWithClaims(duration time.Duration, claims TokenClaims) (string, error)

func (*MetaStoreX) GetSigningKey

func (r *MetaStoreX) GetSigningKey(ctx context.Context, requiredLife time.Duration) (any, int64, error)

GetSigningKey returns a new or cached key and the expiration time (unix seconds) of that key. The expiration time can be saved and used to recover the key directly using GetSpecificKey

func (*MetaStoreX) GetSpecificKey

func (r *MetaStoreX) GetSpecificKey(ctx context.Context, expiration int64) ([]byte, error)

GetSpecificKey returns a particular signing key (assuming it has not expired)

func (*MetaStoreX) GetTree

func (e *MetaStoreX) GetTree(ctx context.Context) (*MetaTree, error)

func (*MetaStoreX) IsFolder

func (e *MetaStoreX) IsFolder(ctx context.Context, path string) (bool, error)

func (*MetaStoreX) PutNode

func (e *MetaStoreX) PutNode(ctx context.Context, path string, version int64) (int64, error)

func (*MetaStoreX) PutTree

func (e *MetaStoreX) PutTree(ctx context.Context, tree *MetaTree) error

func (*MetaStoreX) ScanPath

func (e *MetaStoreX) ScanPath(ctx context.Context, path string, includeLast bool, checker func(path string, ace *ACE, abortScan error) error) error

func (*MetaStoreX) ValidateJWT

func (r *MetaStoreX) ValidateJWT(token string) (*TokenClaims, error)

type MetaTree

type MetaTree struct {
	Path     string
	Meta     []*Annotation
	Children []*MetaTree
}

A MetaTree is a useful way to pass around an instantiated tree but probably isn't what we want to use for anything but data transfer. The primary use is for injecting known data for tests or for bootstrapping the metadata with a minimal state.

func SampleMetaTree

func SampleMetaTree(base string) (*MetaTree, error)

SampleMetaTree reads an embedded metadata tree from a file an embedded file called `sample/<base>.json`. The base is the name of the file without the `.json` extension. The file should be in the `sample` directory and should contain a valid JSON representation of a MetaTree. The function returns an error if the file cannot be found or if the JSON is invalid.

If the base is not valid, an error is returned.

func (*MetaTree) Get

func (t *MetaTree) Get(keys ...string) (*MetaTree, error)

func (*MetaTree) GetPath

func (t *MetaTree) GetPath(key string) (*MetaTree, error)

func (*MetaTree) InjectOperatorPublicKey

func (m *MetaTree) InjectOperatorPublicKey(sshPublicKey []byte) error

InjectOperatorPublicKey secures `the-operator` with an ssh key. The key should be in the form of a line from the `authorized_keys` file for ssh. This is used during the bootstrapping of a secure universe.

func (*MetaTree) MarshalJSON

func (t *MetaTree) MarshalJSON() ([]byte, error)

MarshalJSON produces a JSON form from a metadata tree. This includes tags on the metadata so that the output can be read back in.

The only real gotcha if you read it back in is that all of the fake unique and version values inserted by MetaTree.adjust() will explicitly be there. That shouldn't be a problem, but it could be a surprise.

func (*MetaTree) UnmarshalJSON

func (t *MetaTree) UnmarshalJSON(b []byte) error

UnmarshalJSON extracts a metadata tree from JSON format. Note that the JSON format for metadata follows the conventions of the protojson package.

Also, most datasets stored in JSON files don't have versions, uniques, start times or end times. This doesn't usually matter since you can put in quasi-realistic versions and uniques using tree.adjust(), but it might catch one unaware when interesting values for those fields seem to appear without cause.

func (*MetaTree) Walk

func (t *MetaTree) Walk(direction TraversalOrder, f func(tx *MetaTree) error) error

Walk traverses a tree calling a function on each interior and leaf node. The order of traversal is controlled (roughly) by the first argument. If the function returns without error, then the traversal will continue, but if it returns an error, the traversal will be aborted and tha error will be returned.

type Notable

type Notable interface {
	AsAnnotation() (*Annotation, error)
}

type Operation

type Operation int32

the legal operations

const (
	Operation_INVALID   Operation = 0 // place-holder for impossible situations
	Operation_READ      Operation = 1 // ead from a dataset
	Operation_WRITE     Operation = 2 // rite to a dataset, create children of a directory
	Operation_VIEW      Operation = 3 // s an entity visible (could be a dataset, role, user, directory...)
	Operation_ADMIN     Operation = 4 // an permissions on an entity be modified?
	Operation_USEROLE   Operation = 5 // an a role be used in an ACL?
	Operation_APPLYROLE Operation = 6 // an a role be added to a principal?
	Operation_VOUCHFOR  Operation = 7 // can a plugin vouch for an identity?
)

func Op

func Op(op string) Operation

func (Operation) Descriptor

func (Operation) Descriptor() protoreflect.EnumDescriptor

func (Operation) Enum

func (x Operation) Enum() *Operation

func (Operation) EnumDescriptor deprecated

func (Operation) EnumDescriptor() ([]byte, []int)

Deprecated: Use Operation.Descriptor instead.

func (Operation) MarshalJSON

func (op Operation) MarshalJSON() ([]byte, error)

func (Operation) Number

func (x Operation) Number() protoreflect.EnumNumber

func (Operation) String

func (x Operation) String() string

func (Operation) Type

func (*Operation) UnmarshalJSON

func (op *Operation) UnmarshalJSON(b []byte) error

type RolePersist

type RolePersist struct {
	Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"`
	// contains filtered or unexported fields
}

the side data for an applied role annotation

func (*RolePersist) Descriptor deprecated

func (*RolePersist) Descriptor() ([]byte, []int)

Deprecated: Use RolePersist.ProtoReflect.Descriptor instead.

func (*RolePersist) GetPath

func (x *RolePersist) GetPath() string

func (*RolePersist) ProtoMessage

func (*RolePersist) ProtoMessage()

func (*RolePersist) ProtoReflect

func (x *RolePersist) ProtoReflect() protoreflect.Message

func (*RolePersist) Reset

func (x *RolePersist) Reset()

func (*RolePersist) String

func (x *RolePersist) String() string

type S3Urls

type S3Urls struct {
	Tag         string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
	Url         string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"`
	UrlWildcard string `protobuf:"bytes,3,opt,name=urlWildcard,proto3" json:"urlWildcard,omitempty"`
	// contains filtered or unexported fields
}

func (*S3Urls) Descriptor deprecated

func (*S3Urls) Descriptor() ([]byte, []int)

Deprecated: Use S3Urls.ProtoReflect.Descriptor instead.

func (*S3Urls) GetTag

func (x *S3Urls) GetTag() string

func (*S3Urls) GetUrl

func (x *S3Urls) GetUrl() string

func (*S3Urls) GetUrlWildcard

func (x *S3Urls) GetUrlWildcard() string

func (*S3Urls) ProtoMessage

func (*S3Urls) ProtoMessage()

func (*S3Urls) ProtoReflect

func (x *S3Urls) ProtoReflect() protoreflect.Message

func (*S3Urls) Reset

func (x *S3Urls) Reset()

func (*S3Urls) String

func (x *S3Urls) String() string

type SigningKey

type SigningKey struct {
	Created int64  `protobuf:"varint,1,opt,name=created,proto3" json:"created,omitempty"` // when was this key created
	Unique  int64  `protobuf:"varint,2,opt,name=unique,proto3" json:"unique,omitempty"`   // bits that identify this key, no relation to the key itself
	Key     []byte `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"`          // the key in PKCS1 format
	// contains filtered or unexported fields
}

how we store credential signing keys

func (*SigningKey) Descriptor deprecated

func (*SigningKey) Descriptor() ([]byte, []int)

Deprecated: Use SigningKey.ProtoReflect.Descriptor instead.

func (*SigningKey) GetCreated

func (x *SigningKey) GetCreated() int64

func (*SigningKey) GetKey

func (x *SigningKey) GetKey() []byte

func (*SigningKey) GetUnique

func (x *SigningKey) GetUnique() int64

func (*SigningKey) ProtoMessage

func (*SigningKey) ProtoMessage()

func (*SigningKey) ProtoReflect

func (x *SigningKey) ProtoReflect() protoreflect.Message

func (*SigningKey) Reset

func (x *SigningKey) Reset()

func (*SigningKey) String

func (x *SigningKey) String() string

type TaggedString

type TaggedString struct {
	Tag   string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
	Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
	// contains filtered or unexported fields
}

func (*TaggedString) Descriptor deprecated

func (*TaggedString) Descriptor() ([]byte, []int)

Deprecated: Use TaggedString.ProtoReflect.Descriptor instead.

func (*TaggedString) GetTag

func (x *TaggedString) GetTag() string

func (*TaggedString) GetValue

func (x *TaggedString) GetValue() string

func (*TaggedString) ProtoMessage

func (*TaggedString) ProtoMessage()

func (*TaggedString) ProtoReflect

func (x *TaggedString) ProtoReflect() protoreflect.Message

func (*TaggedString) Reset

func (x *TaggedString) Reset()

func (*TaggedString) String

func (x *TaggedString) String() string

type TokenClaims

type TokenClaims struct {
	jwt.RegisteredClaims
	Key      int64    `json:"key"`
	Identity string   `json:"id"`
	Roles    []string `json:"roles"`
}

func DefaultClaims

func DefaultClaims(id string, roles []string) TokenClaims

type TransactionFailure

type TransactionFailure struct {
	Msg  string
	Path string
}

func (TransactionFailure) Error

func (t TransactionFailure) Error() string

type TraversalOrder

type TraversalOrder int
const (
	TOP_DOWN TraversalOrder = iota
	BOTTOM_UP
)

type UserAnnotation

type UserAnnotation struct {
	Data        string `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
	Tag         string `protobuf:"bytes,2,opt,name=tag,proto3" json:"tag,omitempty"`
	Unique      int64  `protobuf:"varint,3,opt,name=unique,proto3" json:"unique,omitempty"`
	Version     int64  `protobuf:"varint,4,opt,name=version,proto3" json:"version,omitempty"`
	StartMillis int64  `protobuf:"varint,5,opt,name=startMillis,proto3" json:"startMillis,omitempty"`
	EndMillis   int64  `protobuf:"varint,6,opt,name=endMillis,proto3" json:"endMillis,omitempty"`
	// contains filtered or unexported fields
}

func (*UserAnnotation) AsAnnotation

func (r *UserAnnotation) AsAnnotation() (*Annotation, error)

func (*UserAnnotation) AsString

func (r *UserAnnotation) AsString(tag string) (string, error)

func (*UserAnnotation) Descriptor deprecated

func (*UserAnnotation) Descriptor() ([]byte, []int)

Deprecated: Use UserAnnotation.ProtoReflect.Descriptor instead.

func (*UserAnnotation) GetData

func (x *UserAnnotation) GetData() string

func (*UserAnnotation) GetEndMillis

func (x *UserAnnotation) GetEndMillis() int64

func (*UserAnnotation) GetStartMillis

func (x *UserAnnotation) GetStartMillis() int64

func (*UserAnnotation) GetTag

func (x *UserAnnotation) GetTag() string

func (*UserAnnotation) GetUnique

func (x *UserAnnotation) GetUnique() int64

func (*UserAnnotation) GetVersion

func (x *UserAnnotation) GetVersion() int64

func (*UserAnnotation) ProtoMessage

func (*UserAnnotation) ProtoMessage()

func (*UserAnnotation) ProtoReflect

func (x *UserAnnotation) ProtoReflect() protoreflect.Message

func (*UserAnnotation) Reset

func (x *UserAnnotation) Reset()

func (*UserAnnotation) String

func (x *UserAnnotation) String() string

Jump to

Keyboard shortcuts

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