Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions docs.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,27 @@
# auditlog.cattle.io/v1

## AuditPolicy

### Validation Checks

#### Invalid Fields - Create

Users cannot create an `AuditPolicy` which violates the following constraints:

- `.Spec.Filters[].Action` must be one of `allow` or `deny`
- `.Spec.Filters[].RequestURI` must be valid regex
- `.Spec.AdditionalRedactions[].Headers[]` must be valid regez
- `.Spec.AdditionalRedactions[].Paths[]` must be valid jsonpath

#### Invalid Fields - Update

Users cannot update an `AuditPolicy` which violates the following constraints:

- `.Spec.Filters[].Action` must be one of `allow` or `deny`
- `.Spec.Filters[].RequestURI` must be valid regex
- `.Spec.AdditionalRedactions[].Headers[]` must be valid regez
- `.Spec.AdditionalRedactions[].Paths[]` must be valid jsonpath

# catalog.cattle.io/v1

## ClusterRepo
Expand Down
7 changes: 4 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,9 @@ require (
github.com/go-ldap/ldap/v3 v3.4.10
github.com/gorilla/mux v1.8.1
github.com/rancher/dynamiclistener v0.7.0
github.com/rancher/jsonpath v0.0.0-20250620213443-ad24535cf0c1
github.com/rancher/lasso v0.2.3-rc3
github.com/rancher/rancher/pkg/apis v0.0.0-20250624062103-8bf56b046af7
github.com/rancher/rancher/pkg/apis v0.0.0-20250628053911-e6fa86c1c800
github.com/rancher/rke v1.8.0-rc.4
github.com/rancher/wrangler/v3 v3.2.2-rc.3
github.com/robfig/cron v1.2.0
Expand All @@ -59,7 +60,7 @@ require (
k8s.io/client-go v12.0.0+incompatible
k8s.io/kubernetes v1.33.1
k8s.io/pod-security-admission v0.32.1
k8s.io/utils v0.0.0-20241210054802-24370beab758
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397
sigs.k8s.io/controller-runtime v0.21.0
sigs.k8s.io/yaml v1.4.0
)
Expand Down Expand Up @@ -98,7 +99,7 @@ require (
github.com/prometheus/procfs v0.15.1 // indirect
github.com/rancher/aks-operator v1.12.0-rc.1 // indirect
github.com/rancher/eks-operator v1.12.0-rc.1 // indirect
github.com/rancher/fleet/pkg/apis v0.12.0 // indirect
github.com/rancher/fleet/pkg/apis v0.13.0-alpha.5 // indirect
github.com/rancher/gke-operator v1.12.0-rc.1 // indirect
github.com/rancher/norman v0.6.1 // indirect
github.com/spf13/pflag v1.0.6 // indirect
Expand Down
14 changes: 8 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -126,16 +126,18 @@ github.com/rancher/dynamiclistener v0.7.0 h1:+jyfZ4lVamc1UbKWo8V8dhSPtCgRZYaY8nm
github.com/rancher/dynamiclistener v0.7.0/go.mod h1:Q2YA42xp7Xc69JiSlJ8GpvLvze261T0iQ/TP4RdMCYk=
github.com/rancher/eks-operator v1.12.0-rc.1 h1:xQ9rMqz+T3UOrGsUnjr3j49SRfEM1FJJ+DDCDb7h5II=
github.com/rancher/eks-operator v1.12.0-rc.1/go.mod h1:w7ZzRD/Hhxqltlz7XWAgvviYWhmXpwwB7mfTPOZu99E=
github.com/rancher/fleet/pkg/apis v0.12.0 h1:ZzDB63LFLrtwu0wOMDSrmtboixEnwPnNS4sY0KfCr9M=
github.com/rancher/fleet/pkg/apis v0.12.0/go.mod h1:aPeCke/1zE63hh4rojpm12hc0tZfwuEn0WXrhM4/PXM=
github.com/rancher/fleet/pkg/apis v0.13.0-alpha.5 h1:mSMSgEOaf3vPEFJ0/F/IC1XX+Dda56PebVuafZcR+Yo=
github.com/rancher/fleet/pkg/apis v0.13.0-alpha.5/go.mod h1:Qvt5nNrVgwboBZJy3dMNcVC9fncUFKaVPpbj+LdeYEs=
github.com/rancher/gke-operator v1.12.0-rc.1 h1:fMk5S4cvRfZvreaSz/NM9iWewWI8QIOoYI4L0ZHakyo=
github.com/rancher/gke-operator v1.12.0-rc.1/go.mod h1:O1/6RFU05XW6vOEJ0a7xvboBSy5X6EE8DZqzikMK9tg=
github.com/rancher/jsonpath v0.0.0-20250620213443-ad24535cf0c1 h1:vRtxuvIF0UarXIAwGYNwSFoRYJadVnOrD8kx2qrZyN8=
github.com/rancher/jsonpath v0.0.0-20250620213443-ad24535cf0c1/go.mod h1:xavYr3cNyyAeA72nMVB60+q/EJ8Anu+loQWFJyXOeP8=
github.com/rancher/lasso v0.2.3-rc3 h1:kkYnARdFeY6A9E2XnjfQbG8CssHQwobPMIFqPRGpVxc=
github.com/rancher/lasso v0.2.3-rc3/go.mod h1:G+KeeOaKRjp+qGp0bV6VbLhYrq1vHbJPbDh40ejg5yE=
github.com/rancher/norman v0.6.1 h1:JVIxkWZcbxtrcSK4WIwsmyB07TzTvoqqf/R0fZB7ylk=
github.com/rancher/norman v0.6.1/go.mod h1:jRcnEruyY6olqtImy+q+zw0/iXX7YqLF4/K4kh5hR40=
github.com/rancher/rancher/pkg/apis v0.0.0-20250624062103-8bf56b046af7 h1:h2PdLfqEiJJyYv6Fy823cfX5rJdt2lfa4i9RVYrbKcE=
github.com/rancher/rancher/pkg/apis v0.0.0-20250624062103-8bf56b046af7/go.mod h1:OCn4rNvTXZ3mki8aaZorlIz8UukEq5gRqphXxt9G3I8=
github.com/rancher/rancher/pkg/apis v0.0.0-20250628053911-e6fa86c1c800 h1:X6b36q0MT30IaO4TPEuNOq1AcqF/Vr1Qi+Es7MRA4/Q=
github.com/rancher/rancher/pkg/apis v0.0.0-20250628053911-e6fa86c1c800/go.mod h1:OCn4rNvTXZ3mki8aaZorlIz8UukEq5gRqphXxt9G3I8=
github.com/rancher/rke v1.7.2 h1:+2fcl0gCjRHzf1ev9C9ptQ1pjYbDngC1Qv8V/0ki/dk=
github.com/rancher/rke v1.7.2/go.mod h1:+x++Mvl0A3jIzNLiu8nkraqZXiHg6VPWv0Xl4iQCg+A=
github.com/rancher/wrangler/v3 v3.2.2-rc.3 h1:ObcqAxQkQFP6r1YI3zJhi9v9PE+UUNNZpelz6NSpQnc=
Expand Down Expand Up @@ -339,8 +341,8 @@ k8s.io/kubernetes v1.33.1 h1:86+VVY/f11taZdpEZrNciLw1MIQhu6BFXf/OMFn5EUg=
k8s.io/kubernetes v1.33.1/go.mod h1:2nWuPk0seE4+6sd0x60wQ6rYEXcV7SoeMbU0YbFm/5k=
k8s.io/pod-security-admission v0.33.1 h1:amePfcTDgLHB1wpZFIO7chW3Pc/ikeYbniuMTQEcaB4=
k8s.io/pod-security-admission v0.33.1/go.mod h1:3gSyP5JPgte2EHjQheA81299vISL6D7DDvk2m9RQj6k=
k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0=
k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y=
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/cluster-api v1.10.2 h1:xfvtNu4Fy/41grL0ryH5xSKQjpJEWdO8HiV2lPCCozQ=
sigs.k8s.io/cluster-api v1.10.2/go.mod h1:/b9Un5Imprib6S7ZOcJitC2ep/5wN72b0pXpMQFfbTw=
sigs.k8s.io/controller-runtime v0.21.0 h1:CYfjpEuicjUecRk+KAeyYh+ouUBn4llGyDYytIGcJS8=
Expand Down
9 changes: 8 additions & 1 deletion pkg/codegen/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"strings"
"text/template"

auditlogv1 "github.com/rancher/rancher/pkg/apis/auditlog.cattle.io/v1"
catalogv1 "github.com/rancher/rancher/pkg/apis/catalog.cattle.io/v1"
v3 "github.com/rancher/rancher/pkg/apis/management.cattle.io/v3"
v1 "github.com/rancher/rancher/pkg/apis/provisioning.cattle.io/v1"
Expand Down Expand Up @@ -109,7 +110,13 @@ func main() {
&rbacv1.ClusterRole{},
&rbacv1.ClusterRoleBinding{},
},
}}); err != nil {
},
"auditlog.cattle.io": {
Types: []interface{}{
&auditlogv1.AuditPolicy{},
},
},
}); err != nil {
fmt.Printf("ERROR: %v\n", err)
}
}
Expand Down
62 changes: 62 additions & 0 deletions pkg/generated/objects/auditlog.cattle.io/v1/objects.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package v1

import (
"encoding/json"
"fmt"

"github.com/rancher/rancher/pkg/apis/auditlog.cattle.io/v1"
admissionv1 "k8s.io/api/admission/v1"
)

// AuditPolicyOldAndNewFromRequest gets the old and new AuditPolicy objects, respectively, from the webhook request.
// If the request is a Delete operation, then the new object is the zero value for AuditPolicy.
// Similarly, if the request is a Create operation, then the old object is the zero value for AuditPolicy.
func AuditPolicyOldAndNewFromRequest(request *admissionv1.AdmissionRequest) (*v1.AuditPolicy, *v1.AuditPolicy, error) {
if request == nil {
return nil, nil, fmt.Errorf("nil request")
}

object := &v1.AuditPolicy{}
oldObject := &v1.AuditPolicy{}

if request.Operation != admissionv1.Delete {
err := json.Unmarshal(request.Object.Raw, object)
if err != nil {
return nil, nil, fmt.Errorf("failed to unmarshal request object: %w", err)
}
}

if request.Operation == admissionv1.Create {
return oldObject, object, nil
}

err := json.Unmarshal(request.OldObject.Raw, oldObject)
if err != nil {
return nil, nil, fmt.Errorf("failed to unmarshal request oldObject: %w", err)
}

return oldObject, object, nil
}

// AuditPolicyFromRequest returns a AuditPolicy object from the webhook request.
// If the operation is a Delete operation, then the old object is returned.
// Otherwise, the new object is returned.
func AuditPolicyFromRequest(request *admissionv1.AdmissionRequest) (*v1.AuditPolicy, error) {
if request == nil {
return nil, fmt.Errorf("nil request")
}

object := &v1.AuditPolicy{}
raw := request.Object.Raw

if request.Operation == admissionv1.Delete {
raw = request.OldObject.Raw
}

err := json.Unmarshal(raw, object)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal request object: %w", err)
}

return object, nil
}
19 changes: 19 additions & 0 deletions pkg/resources/auditlog.cattle.io/v1/auditpolicy/AuditPolicy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
## Validation Checks

### Invalid Fields - Create

Users cannot create an `AuditPolicy` which violates the following constraints:

- `.Spec.Filters[].Action` must be one of `allow` or `deny`
- `.Spec.Filters[].RequestURI` must be valid regex
- `.Spec.AdditionalRedactions[].Headers[]` must be valid regez
- `.Spec.AdditionalRedactions[].Paths[]` must be valid jsonpath

### Invalid Fields - Update

Users cannot update an `AuditPolicy` which violates the following constraints:

- `.Spec.Filters[].Action` must be one of `allow` or `deny`
- `.Spec.Filters[].RequestURI` must be valid regex
- `.Spec.AdditionalRedactions[].Headers[]` must be valid regez
- `.Spec.AdditionalRedactions[].Paths[]` must be valid jsonpath
121 changes: 121 additions & 0 deletions pkg/resources/auditlog.cattle.io/v1/auditpolicy/validator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package v1

import (
"errors"
"fmt"
"regexp"

jsonpath "github.com/rancher/jsonpath/pkg"
auditlogv1 "github.com/rancher/rancher/pkg/apis/auditlog.cattle.io/v1"
"github.com/rancher/webhook/pkg/admission"
v1 "github.com/rancher/webhook/pkg/generated/objects/auditlog.cattle.io/v1"
admissionv1 "k8s.io/api/admission/v1"
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/validation/field"
)

var gvr = schema.GroupVersionResource{
Group: auditlogv1.SchemeGroupVersion.Group,
Version: auditlogv1.SchemeGroupVersion.Version,
Resource: "auditpolicies",
}

var _ admission.ValidatingAdmissionHandler = &validator{}

type validator struct {
}

// Admitters implements admission.ValidatingAdmissionHandler.
func (v *validator) Admitters() []admission.Admitter {
return []admission.Admitter{
&admitter{},
}
}

// GVR implements admission.ValidatingAdmissionHandler.
func (v *validator) GVR() schema.GroupVersionResource {
return gvr
}

// Operations implements admission.ValidatingAdmissionHandler.
func (v *validator) Operations() []admissionregistrationv1.OperationType {
return []admissionregistrationv1.OperationType{
admissionregistrationv1.Create,
admissionregistrationv1.Update,
}
}

// ValidatingWebhook implements admission.ValidatingAdmissionHandler.
func (v *validator) ValidatingWebhook(clientConfig admissionregistrationv1.WebhookClientConfig) []admissionregistrationv1.ValidatingWebhook {
return []admissionregistrationv1.ValidatingWebhook{
*admission.NewDefaultValidatingWebhook(v, clientConfig, admissionregistrationv1.ClusterScope, v.Operations()),
}
}

type admitter struct {
}

func (a *admitter) Admit(req *admission.Request) (*admissionv1.AdmissionResponse, error) {
if req.Operation != admissionv1.Create && req.Operation != admissionv1.Update {
return admission.ResponseAllowed(), nil
}

policy, err := v1.AuditPolicyFromRequest(&req.AdmissionRequest)
if err != nil {
return nil, fmt.Errorf("failed to get AuditPolicy from request: %w", err)
}

path := field.NewPath("auditpolicy", "spec")

var fieldErr *field.Error
if err := a.validateFields(policy, path); err != nil {
if errors.As(err, &fieldErr) {
return admission.ResponseBadRequest(fieldErr.Error()), nil
}

return nil, fmt.Errorf("failed to validate fields on AuditPolicy")
}

return nil, fmt.Errorf("nyi")
}

func (a *admitter) validateFields(policy *auditlogv1.AuditPolicy, path *field.Path) error {
if policy.Spec.Verbosity.Level < 0 || policy.Spec.Verbosity.Level > 3 {
return field.Invalid(path.Child("verbosity", "level"), policy.Spec.Verbosity.Level, ".spec.verbosity.level must be >= 0 or <= 3")
}

for i, filter := range policy.Spec.Filters {
path := path.Child("filters").Index(i)

if filter.Action != auditlogv1.FilterActionAllow && filter.Action != auditlogv1.FilterActionDeny {
return field.NotSupported(path, filter.Action, []string{string(auditlogv1.FilterActionAllow), string(auditlogv1.FilterActionDeny)})
}

if _, err := regexp.Compile(filter.RequestURI); err != nil {
return field.Invalid(path, filter.RequestURI, err.Error())
}
}

for i, redaction := range policy.Spec.AdditionalRedactions {
path := path.Child("additionalRedactions").Index(i)

for j, header := range redaction.Headers {
path := path.Child("headers").Index(j)

if _, err := regexp.Compile(header); err != nil {
return field.Invalid(path, header, err.Error())
}
}

for j, jp := range redaction.Paths {
path := path.Child("paths").Index(j)

if _, err := jsonpath.Parse(jp); err != nil {
return field.Invalid(path, jp, err.Error())
}
}
}

return nil
}
Loading
Loading