diff --git a/cmd/schema-generator/main.go b/cmd/schema-generator/main.go index 3652921..2eae665 100644 --- a/cmd/schema-generator/main.go +++ b/cmd/schema-generator/main.go @@ -138,7 +138,6 @@ func main() { schema.AddConnectEntities(cedarschema) } cedarschema.SortActionEntities() - // TODO: ENTITY TAGS: this is just here until we get real key/value map support schema.ModifyObjectMetaMaps(cedarschema) data, err := json.MarshalIndent(cedarschema, "", "\t") diff --git a/docs/Demo.md b/docs/Demo.md index d9500e3..3544dfe 100644 --- a/docs/Demo.md +++ b/docs/Demo.md @@ -317,12 +317,8 @@ These types of admission rules are already possible today with general purpose t #### Key/Value maps - -For now, the webhook modifies labels and annotations into a list of structure with the fields "key" and "value", so policy can be written against it. -Once cedar-go [adds support for entity tags][cedar-go-entity-tags], we'll refactor to use that structure and syntax. -That will be a breaking change to any policy using the current key/value structure. -[cedar-go-entity-tags]: https://github.com/cedar-policy/cedar-go/issues/47 +The webhook modifies labels, annotations, and other key/value string pairs into a set of structure with the fields "key" and "value", so policy can be written against it. ```cedar // authorization policy allowing sample-user to make actions on configmaps in default namespace diff --git a/docs/FutureFeatures.md b/docs/FutureFeatures.md index d8ddab9..e42b6d0 100644 --- a/docs/FutureFeatures.md +++ b/docs/FutureFeatures.md @@ -65,8 +65,9 @@ forbid ( action in k8s::admission::Action::"update", resource is core::v1::Pod ) when { - context has cluster.tags.stage && - context.cluster.tags.stage == "prod" && + context has cluster && + context.cluster.hasTag("stage") && + context.cluster.getTag("stage") == "prod" && resource.spec has ephemeralContainers }; ``` diff --git a/docs/Limitations.md b/docs/Limitations.md index fe931a7..028f805 100644 --- a/docs/Limitations.md +++ b/docs/Limitations.md @@ -62,50 +62,6 @@ permit ( }; ``` -## Entity Tags (key/value maps) - -Cedar's Rust implementation and CLI gained support for entity tags (key/value maps) in [Cedar v4.2.0][4.2]. -Until [cedar-go supports entity tags][go-entity-tags], we've manually added `KeyValue` and `KeyValues` types into the `meta::v1` namespace to support key/value labels. -Any Kubernetes types in admission that consist of `map[string]string{}` or `map[string][]string{}` are converted to a Set of KeyValue or KeyValueStringSlice. -```cedarschema -namespace meta::v1 { - type KeyValue = { - "key": __cedar::String, - "value"?: __cedar::String - }; - type KeyValueStringSlice = { - "key": __cedar::String, - "value"?: Set < __cedar::String > - }; - entity ObjectMeta = { - "annotations"?: Set < meta::v1::KeyValue >, - "labels"?: Set < meta::v1::KeyValue >, - "name"?: __cedar::String, - "namespace"?: __cedar::String, - // ... - }; - // ... -} -``` - -Similarly, the Authorization namespace `k8s::` includes a custom `Extra` type to support key/value maps on Users, ServiceAccounts, and Nodes. -```cedarschema -namespace k8s { - type Extra = { - "key": __cedar::String, - "values"?: Set < __cedar::String > - }; - entity User in [Group] = { - "extra"?: Set < Extra >, - "name": __cedar::String - }; - // ... -} -``` - -[4.2]: https://github.com/cedar-policy/cedar/releases/tag/v4.2.0 -[go-entity-tags]: https://github.com/cedar-policy/cedar-go/issues/47 - ## Expressiveness limitations A core tenet of Cedar is to be analyzable, meaning that the language can verify that a policy is valid and will not error. diff --git a/internal/schema/admission.go b/internal/schema/admission.go index 4231a5e..7af2d26 100644 --- a/internal/schema/admission.go +++ b/internal/schema/admission.go @@ -1,8 +1,6 @@ package schema // ModifyObjectMetaMaps modifies the ObjectMeta maps in the schema -// -// TODO: ENTITY TAGS: This is a hack until Cedar supports maps in the schema func ModifyObjectMetaMaps(schema CedarSchema) { ns, ok := schema["meta::v1"] if !ok { diff --git a/internal/schema/convert/openapi.go b/internal/schema/convert/openapi.go index c01afa9..60a4b40 100644 --- a/internal/schema/convert/openapi.go +++ b/internal/schema/convert/openapi.go @@ -437,8 +437,6 @@ func RefToEntityShape(api *spec3.OpenAPI, schemaKind string) (schema.EntityShape continue } - // TODO: ENTITY TAGS: this is just here until we get real key/value map support - // for string/string maps, hack to use custom KeyValue or KeyValueSlice types knownKeyValueStringMapAttributes := map[string][]string{ "io.k8s.api.core.v1.ConfigMap": {"data", "binaryData"}, // format is []byte, should we exclude? "io.k8s.api.core.v1.CSIPersistentVolumeSource": {"volumeAttributes"}, @@ -491,7 +489,7 @@ func RefToEntityShape(api *spec3.OpenAPI, schemaKind string) (schema.EntityShape } klog.V(5).InfoS("Skipping object type", "kind", schemaKind, "attribute", attrName, "attrDef", attrDef) - // skip until k/v objects are supported + // skip until k/v objects are supported? continue default: klog.V(5).Infof("Skipping %s attr %s type %s", schemaKind, attrName, attrDef.Type[0]) diff --git a/internal/schema/user_entities.go b/internal/schema/user_entities.go index 0aad249..5ea7347 100644 --- a/internal/schema/user_entities.go +++ b/internal/schema/user_entities.go @@ -85,7 +85,6 @@ func NodeEntity() Entity { } } -// TODO: ENTITY TAGS: this is just here until we get real key/value map support func ExtraEntityShape() EntityShape { return EntityShape{ Type: RecordType, @@ -96,7 +95,6 @@ func ExtraEntityShape() EntityShape { } } -// TODO: ENTITY TAGS: this is just here until we get real key/value map support func ExtraEntity() Entity { return Entity{ MemberOfTypes: []string{}, diff --git a/internal/server/authorizer/entitiy_builders.go b/internal/server/authorizer/entitiy_builders.go index f9852f9..c523fa4 100644 --- a/internal/server/authorizer/entitiy_builders.go +++ b/internal/server/authorizer/entitiy_builders.go @@ -70,7 +70,6 @@ func ImpersonatedResourceToCedarEntity(attributes authorizer.Attributes) cedarty ID: cedartypes.String(attributes.GetName()), } respAttributes[cedartypes.String("name")] = cedartypes.String(attributes.GetName()) - // TODO: ENTITY TAGS: Migrate to entity tags case "userextras": uid = cedartypes.EntityUID{ Type: schema.ExtraValueEntityType, diff --git a/internal/server/entities/admission.go b/internal/server/entities/admission.go index 81c10e6..0ff7885 100644 --- a/internal/server/entities/admission.go +++ b/internal/server/entities/admission.go @@ -99,32 +99,6 @@ func (a *authorizerAttributeWrapper) GetPath() string func (a *authorizerAttributeWrapper) GetFieldSelector() (fields.Requirements, error) { return nil, nil } func (a *authorizerAttributeWrapper) GetLabelSelector() (labels.Requirements, error) { return nil, nil } -// type cedarEntityValueWrapper struct { -// cedartypes.Entity -// } - -// var _ cedartypes.Value = &cedarEntityValueWrapper{} - -// func (e cedarEntityValueWrapper) Equal(v cedartypes.Value) bool { -// return false -// } - -// func (e cedarEntityValueWrapper) ExplicitMarshalJSON() ([]byte, error) { -// return json.Marshal(e.Entity) -// } - -// func (e cedarEntityValueWrapper) MarshalCedar() []byte { -// return []byte{} -// } - -// func (e cedarEntityValueWrapper) String() string { -// return "" -// } - -// func (e cedarEntityValueWrapper) hash() uint64 { -// return 0 -// } - func UnstructuredFromAdmissionRequestObject(data []byte) (*unstructured.Unstructured, error) { if data == nil { return nil, errors.New("unstructured data is nil") @@ -216,7 +190,7 @@ func walkObject(i int, group, version, kind, keyName string, obj any) (cedartype return nil, nil } - // TODO: ENTITY TAGS: This is a hack until key/value objects are supported + // TODO: This is a hack of referencing attribute names until walking schema for nested entities is supported // g/v/k/attrNames knownKeyValueStringMapAttributes := map[string]map[string]map[string][]string{ "core": { diff --git a/internal/server/entities/user.go b/internal/server/entities/user.go index 4400898..bb8f295 100644 --- a/internal/server/entities/user.go +++ b/internal/server/entities/user.go @@ -71,7 +71,6 @@ func UserToCedarEntity(user user.Info) (cedartypes.EntityUID, cedartypes.EntityM attributes[cedartypes.String("name")] = cedartypes.String(parts[3]) } - // TODO: ENTITY TAGS: use entity tags once supported extraValues := []cedartypes.Value{} for k, v := range user.GetExtra() { extraVV := []cedartypes.Value{}