diff --git a/pkg/transforms/transformer.go b/pkg/transforms/transformer.go index dcec23ed..5e24eff9 100644 --- a/pkg/transforms/transformer.go +++ b/pkg/transforms/transformer.go @@ -412,6 +412,9 @@ func TransformRoutine(input chan *Event, output chan NodeEvent) { } trans = PolicyReportResourceBuilder(&typedResource) + case [2]string{"ValidatingAdmissionPolicyBinding", "admissionregistration.k8s.io"}: + trans = VapBindingResourceBuilder(event.Resource) + default: generic := GenericResourceBuilder(event.Resource, event.AdditionalPrinterColumns...) diff --git a/pkg/transforms/vapbinding.go b/pkg/transforms/vapbinding.go new file mode 100644 index 00000000..410b1f11 --- /dev/null +++ b/pkg/transforms/vapbinding.go @@ -0,0 +1,56 @@ +// Copyright Contributors to the Open Cluster Management project + +package transforms + +import ( + "strings" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" +) +type VapBindingResource struct { + node Node +} + +// Validating admission policy Binding +// Ref: https://kubernetes.io/docs/reference/access-authn-authz/validating-admission-policy/ +func VapBindingResourceBuilder(v *unstructured.Unstructured) *VapBindingResource { + node := transformCommon(v) // Start off with the common properties + + typeMeta := metav1.TypeMeta{ + Kind: v.GetKind(), + APIVersion: v.GetAPIVersion(), + } + + apiGroupVersion(typeMeta, &node) // add kind, apigroup and version + // Extract the properties specific to this type + + node.Properties["validationActions"], _, _ = unstructured.NestedStringSlice(v.Object, "spec", "validationActions") + node.Properties["policyName"], _, _ = unstructured.NestedString(v.Object, "spec", "policyName") + + owners := v.GetOwnerReferences() + fromGK := false + + for _, o := range owners { + if strings.HasPrefix(o.APIVersion, "constraints.gatekeeper.sh") { + fromGK = true + + break + } + } + + node.Properties["_ownedByGatekeeper"] = fromGK + + return &VapBindingResource{node: node} +} + +// BuildNode construct the node for VapBindingResource +func (v VapBindingResource) BuildNode() Node { + return v.node +} + +// BuildEdges construct the edges for VapBindingResource +func (v VapBindingResource) BuildEdges(ns NodeStore) []Edge { + // no op for now to implement interface + return []Edge{} +} diff --git a/pkg/transforms/vapbinding_test.go b/pkg/transforms/vapbinding_test.go new file mode 100644 index 00000000..4cb24752 --- /dev/null +++ b/pkg/transforms/vapbinding_test.go @@ -0,0 +1,23 @@ +// Copyright Contributors to the Open Cluster Management project + +package transforms + +import ( + "testing" + + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" +) +func TestVapBinding(t *testing.T) { + var object map[string]interface{} + UnmarshalFile("vapbinding.json", &object, t) + + unstructured := &unstructured.Unstructured{ + Object: object, + } + + node := VapBindingResourceBuilder(unstructured).BuildNode() + + AssertDeepEqual("validationActions", node.Properties["validationActions"], []string{"Deny", "Warn", "Audit"}, t) + AssertEqual("_ownedByGatekeeper", node.Properties["_ownedByGatekeeper"], true, t) + AssertEqual("policyName", node.Properties["policyName"], "demo-policy.example.com", t) +} diff --git a/test-data/vapbinding.json b/test-data/vapbinding.json new file mode 100644 index 00000000..599d0b3f --- /dev/null +++ b/test-data/vapbinding.json @@ -0,0 +1,30 @@ +{ + "apiVersion": "admissionregistration.k8s.io/v1", + "kind": "ValidatingAdmissionPolicyBinding", + "metadata": { + "name": "demo-binding-test.example.com", + "ownerReferences": [ + { + "apiVersion": "constraints.gatekeeper.sh/v1beta1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "Constraint", + "name": "all-must-have-owner", + "uid": "dd427962-73e3-4484-8898-6b44ffe5256c" + } + ] + }, + "spec": { + "policyName": "demo-policy.example.com", + "validationActions": [ + "Deny","Warn","Audit" + ], + "matchResources": { + "namespaceSelector": { + "matchLabels": { + "environment": "test" + } + } + } + } + }