Skip to content

Commit 7573ba2

Browse files
Copilotnomeguy
andcommitted
Improve webhook to support all resource types and better pluralization
Co-authored-by: nomeguy <85475922+nomeguy@users.noreply.github.com>
1 parent f4d7c3c commit 7573ba2

File tree

6 files changed

+41
-42
lines changed

6 files changed

+41
-42
lines changed

config/webhook/mutating_webhook_configuration.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ metadata:
55
annotations:
66
cert-manager.io/inject-ca-from: policywall-system/policywall-webhook-cert
77
webhooks:
8-
- name: mpod.policy.casbin.org
8+
- name: mutate.policy.casbin.org
99
admissionReviewVersions: ["v1", "v1beta1"]
1010
clientConfig:
1111
service:
1212
name: policywall-webhook-service
1313
namespace: policywall-system
14-
path: /mutate-v1-pod
14+
path: /mutate
1515
failurePolicy: Fail
1616
matchPolicy: Equivalent
1717
namespaceSelector:
@@ -22,10 +22,10 @@ webhooks:
2222
objectSelector: {}
2323
reinvocationPolicy: Never
2424
rules:
25-
- apiGroups: [""]
26-
apiVersions: ["v1"]
25+
- apiGroups: ["*"]
26+
apiVersions: ["*"]
2727
operations: ["CREATE", "UPDATE"]
28-
resources: ["pods"]
28+
resources: ["*"]
2929
scope: "*"
3030
sideEffects: None
3131
timeoutSeconds: 10

config/webhook/validating_webhook_configuration.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ metadata:
55
annotations:
66
cert-manager.io/inject-ca-from: policywall-system/policywall-webhook-cert
77
webhooks:
8-
- name: vpod.policy.casbin.org
8+
- name: validate.policy.casbin.org
99
admissionReviewVersions: ["v1", "v1beta1"]
1010
clientConfig:
1111
service:
1212
name: policywall-webhook-service
1313
namespace: policywall-system
14-
path: /validate-v1-pod
14+
path: /validate
1515
failurePolicy: Fail
1616
matchPolicy: Equivalent
1717
namespaceSelector:
@@ -21,10 +21,10 @@ webhooks:
2121
values: ["true"]
2222
objectSelector: {}
2323
rules:
24-
- apiGroups: [""]
25-
apiVersions: ["v1"]
24+
- apiGroups: ["*"]
25+
apiVersions: ["*"]
2626
operations: ["CREATE", "UPDATE"]
27-
resources: ["pods"]
27+
resources: ["*"]
2828
scope: "*"
2929
sideEffects: None
3030
timeoutSeconds: 10

main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,12 @@ func main() {
8585
validatingWebhook := webhookpkg.NewValidatingWebhook(mgr.GetClient(), enforcer)
8686

8787
// Register mutating webhook
88-
mgr.GetWebhookServer().Register("/mutate-v1-pod", &webhook.Admission{
88+
mgr.GetWebhookServer().Register("/mutate", &webhook.Admission{
8989
Handler: mutatingWebhook,
9090
})
9191

9292
// Register validating webhook
93-
mgr.GetWebhookServer().Register("/validate-v1-pod", &webhook.Admission{
93+
mgr.GetWebhookServer().Register("/validate", &webhook.Admission{
9494
Handler: validatingWebhook,
9595
})
9696

pkg/webhook/enforcer.go

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,12 @@ func (pe *PolicyEnforcer) Enforce(ctx context.Context, obj runtime.Object, usern
130130
Validations: []ValidationResult{},
131131
}
132132

133-
// Get resource type
133+
// Get resource type from GVK
134134
gvk := obj.GetObjectKind().GroupVersionKind()
135-
resourceType := strings.ToLower(gvk.Kind) + "s"
135+
resourceType := gvk.Kind
136+
137+
// Normalize resource type to lowercase for comparison
138+
resourceTypeLower := strings.ToLower(resourceType)
136139

137140
// Load all policies
138141
var policyList policyv1alpha1.PolicyList
@@ -150,7 +153,7 @@ func (pe *PolicyEnforcer) Enforce(ctx context.Context, obj runtime.Object, usern
150153
// Process each policy
151154
for _, policy := range policyList.Items {
152155
// Check if policy applies to this resource
153-
if !pe.policyAppliesTo(&policy, resourceType, u) {
156+
if !pe.policyAppliesTo(&policy, resourceTypeLower, u) {
154157
continue
155158
}
156159

@@ -196,10 +199,19 @@ func (pe *PolicyEnforcer) policyAppliesTo(policy *policyv1alpha1.Policy, resourc
196199
namespace := obj.GetNamespace()
197200

198201
for _, rs := range policy.Spec.Resources {
199-
// Check if resource type matches
202+
// Check if resource type matches (support both singular and plural forms)
200203
resourceMatches := false
201204
for _, res := range rs.Resources {
202-
if strings.ToLower(res) == strings.ToLower(resourceType) || res == "*" {
205+
resLower := strings.ToLower(res)
206+
// Match if:
207+
// 1. Exact match (case insensitive)
208+
// 2. Wildcard match
209+
// 3. Singular matches plural (e.g., "pod" matches "pod" or "pods")
210+
// 4. Plural matches singular (e.g., "pods" matches "pod")
211+
if resLower == resourceType ||
212+
res == "*" ||
213+
resLower == resourceType+"s" ||
214+
resLower+"s" == resourceType {
203215
resourceMatches = true
204216
break
205217
}
@@ -329,9 +341,11 @@ func GenerateSidecarInjectionPatch(containerName, image string) []PatchOperation
329341
Image: image,
330342
}
331343

344+
// Marshal container to JSON (error ignored as Container is a known type that always marshals successfully)
332345
containerJSON, _ := json.Marshal(sidecarContainer)
333346
var containerMap map[string]interface{}
334-
json.Unmarshal(containerJSON, &containerMap)
347+
// Unmarshal to map (error ignored as valid JSON from Marshal above)
348+
_ = json.Unmarshal(containerJSON, &containerMap)
335349

336350
return []PatchOperation{
337351
{

pkg/webhook/mutating_webhook.go

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"encoding/json"
66
"net/http"
77

8-
corev1 "k8s.io/api/core/v1"
8+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
99
"sigs.k8s.io/controller-runtime/pkg/client"
1010
"sigs.k8s.io/controller-runtime/pkg/log"
1111
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
@@ -14,7 +14,6 @@ import (
1414
// MutatingWebhook handles mutating admission requests
1515
type MutatingWebhook struct {
1616
client client.Client
17-
decoder admission.Decoder
1817
enforcer *PolicyEnforcer
1918
}
2019

@@ -37,10 +36,9 @@ func (m *MutatingWebhook) Handle(ctx context.Context, req admission.Request) adm
3736
"username", req.UserInfo.Username,
3837
)
3938

40-
// Decode the object
41-
obj := &corev1.Pod{}
42-
err := m.decoder.Decode(req, obj)
43-
if err != nil {
39+
// Decode the object as unstructured to support any resource type
40+
obj := &unstructured.Unstructured{}
41+
if err := json.Unmarshal(req.Object.Raw, obj); err != nil {
4442
logger.Error(err, "failed to decode object")
4543
return admission.Errored(http.StatusBadRequest, err)
4644
}
@@ -70,9 +68,3 @@ func (m *MutatingWebhook) Handle(ctx context.Context, req admission.Request) adm
7068
// Return a patched response
7169
return admission.PatchResponseFromRaw(req.Object.Raw, patchBytes)
7270
}
73-
74-
// InjectDecoder injects the decoder
75-
func (m *MutatingWebhook) InjectDecoder(d admission.Decoder) error {
76-
m.decoder = d
77-
return nil
78-
}

pkg/webhook/validating_webhook.go

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ package webhook
22

33
import (
44
"context"
5+
"encoding/json"
56
"net/http"
67

7-
corev1 "k8s.io/api/core/v1"
8+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
89
"sigs.k8s.io/controller-runtime/pkg/client"
910
"sigs.k8s.io/controller-runtime/pkg/log"
1011
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
@@ -13,7 +14,6 @@ import (
1314
// ValidatingWebhook handles validating admission requests
1415
type ValidatingWebhook struct {
1516
client client.Client
16-
decoder admission.Decoder
1717
enforcer *PolicyEnforcer
1818
}
1919

@@ -36,10 +36,9 @@ func (v *ValidatingWebhook) Handle(ctx context.Context, req admission.Request) a
3636
"username", req.UserInfo.Username,
3737
)
3838

39-
// Decode the object
40-
obj := &corev1.Pod{}
41-
err := v.decoder.Decode(req, obj)
42-
if err != nil {
39+
// Decode the object as unstructured to support any resource type
40+
obj := &unstructured.Unstructured{}
41+
if err := json.Unmarshal(req.Object.Raw, obj); err != nil {
4342
logger.Error(err, "failed to decode object")
4443
return admission.Errored(http.StatusBadRequest, err)
4544
}
@@ -68,9 +67,3 @@ func (v *ValidatingWebhook) Handle(ctx context.Context, req admission.Request) a
6867
logger.Info("validation passed")
6968
return admission.Allowed("validation passed")
7069
}
71-
72-
// InjectDecoder injects the decoder
73-
func (v *ValidatingWebhook) InjectDecoder(d admission.Decoder) error {
74-
v.decoder = d
75-
return nil
76-
}

0 commit comments

Comments
 (0)