Skip to content

Commit

Permalink
feat: Add validation webhook for protected resources (#176)
Browse files Browse the repository at this point in the history
To protect resources from deletion/updating added label
`app.edp.epam.com/edit-protection`.
The label can have values: delete update delete-update
  • Loading branch information
zmotso committed Feb 24, 2025
1 parent b631135 commit 5378d86
Show file tree
Hide file tree
Showing 13 changed files with 650 additions and 19 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ ENV ASSETS_DIR=/usr/local/bin \
USER_UID=1001

RUN apk add --no-cache ca-certificates=20241121-r1 \
openssh-client==9.3_p2-r2 \
openssh-client==9.3_p2-r3 \
git==2.40.4-r0

RUN adduser -h ${HOME} -s /bin/ash -D -u ${USER_UID} codebase-operator
Expand Down
9 changes: 8 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ validate-docs: api-docs helm-docs ## Validate helm and api docs
@git diff -s --exit-code docs/api.md || (echo " Run 'make api-docs' to address the issue." && git diff && exit 1)

# Run tests
test: fmt vet
test: fmt vet envtest
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" \
KUBECONFIG=${CURRENT_DIR}/hack/kubecfg-stub.yaml go test ./... -coverprofile=coverage.out `go list ./...`

.PHONY: fmt
Expand Down Expand Up @@ -201,3 +202,9 @@ update-bitbucket-swagger: ## Update bitbucket swagger file
.PHONY: generate-bitbucket-api-client
generate-bitbucket-api-client: oapi-codegen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
$(OAPICODEGEN) -config oapicfg.yaml hack/bitbucket_api.json

ENVTEST=$(LOCALBIN)/setup-envtest
.PHONY: envtest
envtest: $(ENVTEST) ## Download envtest-setup locally if necessary.
$(ENVTEST): $(LOCALBIN)
$(call go-get-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest,release-0.16)
61 changes: 61 additions & 0 deletions config/webhook/manifests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,66 @@ kind: ValidatingWebhookConfiguration
metadata:
name: validating-webhook-configuration
webhooks:
- admissionReviewVersions:
- v1
clientConfig:
service:
name: webhook-service
namespace: system
path: /validate-v2-edp-epam-com-v1-codebasebranch
failurePolicy: Fail
name: codebasebranch.epam.com
rules:
- apiGroups:
- v2.edp.epam.com
apiVersions:
- v1
operations:
- UPDATE
- DELETE
resources:
- codebasebranchs
sideEffects: None
- admissionReviewVersions:
- v1
clientConfig:
service:
name: webhook-service
namespace: system
path: /validate-v2-edp-epam-com-v1-codebaseimagestream
failurePolicy: Fail
name: codebaseimagestream.epam.com
rules:
- apiGroups:
- v2.edp.epam.com
apiVersions:
- v1
operations:
- UPDATE
- DELETE
resources:
- codebaseimagestreams
sideEffects: None
- admissionReviewVersions:
- v1
clientConfig:
service:
name: webhook-service
namespace: system
path: /validate-v2-edp-epam-com-v1-gitserver
failurePolicy: Fail
name: gitserver.epam.com
rules:
- apiGroups:
- v2.edp.epam.com
apiVersions:
- v1
operations:
- UPDATE
- DELETE
resources:
- gitservers
sideEffects: None
- admissionReviewVersions:
- v1
clientConfig:
Expand All @@ -21,6 +81,7 @@ webhooks:
operations:
- CREATE
- UPDATE
- DELETE
resources:
- codebases
sideEffects: None
75 changes: 75 additions & 0 deletions deploy-templates/templates/validation_webhook.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,80 @@ metadata:
{{- include "codebase-operator.labels" . | nindent 4 }}
name: edp-codebase-operator-validating-webhook-configuration-{{ .Release.Namespace }}
webhooks:
- admissionReviewVersions:
- v1
clientConfig:
service:
name: edp-codebase-operator-webhook-service
namespace: {{ .Release.Namespace }}
path: /validate-v2-edp-epam-com-v1-codebasebranch
failurePolicy: Fail
name: codebasebranch.epam.com
namespaceSelector:
matchExpressions:
- key: kubernetes.io/metadata.name
operator: In
values:
- {{ .Release.Namespace }}
rules:
- apiGroups:
- v2.edp.epam.com
apiVersions:
- v1
operations:
- UPDATE
- DELETE
resources:
- codebasebranchs
sideEffects: None
- admissionReviewVersions:
- v1
clientConfig:
service:
name: edp-codebase-operator-webhook-service
namespace: {{ .Release.Namespace }}
path: /validate-v2-edp-epam-com-v1-codebaseimagestream
failurePolicy: Fail
name: codebaseimagestream.epam.com
rules:
- apiGroups:
- v2.edp.epam.com
apiVersions:
- v1
operations:
- UPDATE
- DELETE
resources:
- codebaseimagestreams
scope: Namespaced
sideEffects: None
- admissionReviewVersions:
- v1
clientConfig:
service:
name: edp-codebase-operator-webhook-service
namespace: {{ .Release.Namespace }}
path: /validate-v2-edp-epam-com-v1-gitserver
failurePolicy: Fail
name: gitserver.epam.com
namespaceSelector:
matchExpressions:
- key: kubernetes.io/metadata.name
operator: In
values:
- {{ .Release.Namespace }}
rules:
- apiGroups:
- v2.edp.epam.com
apiVersions:
- v1
operations:
- UPDATE
- DELETE
resources:
- gitservers
scope: Namespaced
sideEffects: None
- admissionReviewVersions:
- v1
clientConfig:
Expand All @@ -28,6 +102,7 @@ webhooks:
operations:
- CREATE
- UPDATE
- DELETE
resources:
- codebases
scope: Namespaced
Expand Down
6 changes: 5 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ require (
github.com/go-resty/resty/v2 v2.6.0
github.com/jarcoal/httpmock v1.0.8
github.com/oapi-codegen/runtime v1.1.1
github.com/onsi/ginkgo/v2 v2.19.0
github.com/onsi/gomega v1.34.1
github.com/openshift/api v3.9.0+incompatible
github.com/stretchr/testify v1.10.0
github.com/tektoncd/pipeline v0.59.0
Expand Down Expand Up @@ -61,6 +63,7 @@ require (
github.com/go-openapi/jsonpointer v0.19.6 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect
github.com/go-openapi/swag v0.22.3 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v4 v4.5.1 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
Expand All @@ -71,6 +74,7 @@ require (
github.com/google/go-containerregistry v0.19.1 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
Expand Down Expand Up @@ -122,7 +126,7 @@ require (
google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect
google.golang.org/grpc v1.63.2 // indirect
google.golang.org/protobuf v1.33.0 // indirect
google.golang.org/protobuf v1.34.1 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
Expand Down
16 changes: 8 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -294,8 +294,8 @@ github.com/go-resty/resty/v2 v2.6.0 h1:joIR5PNLM2EFqqESUjCMGXrWmXNHEU9CEiK813oKY
github.com/go-resty/resty/v2 v2.6.0/go.mod h1:PwvJS6hvaPkjtjNg9ph+VrSD92bi5Zq73w/BIH7cC3Q=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/gobuffalo/flect v0.2.4/go.mod h1:1ZyCLIbg0YD7sDkzvFdPoOydPtD8y9JQnrOROolUcM8=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
Expand Down Expand Up @@ -409,8 +409,9 @@ github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLe
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg=
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
Expand Down Expand Up @@ -587,10 +588,9 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4=
github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o=
github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
Expand Down Expand Up @@ -1335,8 +1335,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down
15 changes: 11 additions & 4 deletions pkg/webhook/codebase_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (

const listLimit = 1000

//+kubebuilder:webhook:path=/validate-v2-edp-epam-com-v1-codebase,mutating=false,failurePolicy=fail,sideEffects=None,groups=v2.edp.epam.com,resources=codebases,verbs=create;update,versions=v1,name=vcodebase.kb.io,admissionReviewVersions=v1
//+kubebuilder:webhook:path=/validate-v2-edp-epam-com-v1-codebase,mutating=false,failurePolicy=fail,sideEffects=None,groups=v2.edp.epam.com,resources=codebases,verbs=create;update;delete,versions=v1,name=vcodebase.kb.io,admissionReviewVersions=v1

// CodebaseValidationWebhook is a webhook for validating Codebase CRD.
type CodebaseValidationWebhook struct {
Expand Down Expand Up @@ -96,7 +96,7 @@ func (r *CodebaseValidationWebhook) ValidateCreate(ctx context.Context, obj runt
}

// ValidateUpdate is a webhook for validating the updating of the Codebase CR.
func (r *CodebaseValidationWebhook) ValidateUpdate(ctx context.Context, _, newObj runtime.Object) (warnings admission.Warnings, err error) {
func (r *CodebaseValidationWebhook) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (warnings admission.Warnings, err error) {
req, err := admission.RequestFromContext(ctx)
if err != nil {
return nil, fmt.Errorf("expected admission.Request in ctx: %w", err)
Expand All @@ -115,18 +115,25 @@ func (r *CodebaseValidationWebhook) ValidateUpdate(ctx context.Context, _, newOb
return nil, fmt.Errorf("codebase %s is invalid: %w", updatedCodebase.Name, err)
}

if err = checkResourceProtectionFromModificationOnUpdate(oldObj, newObj); err != nil {
return nil, err
}

return nil, nil
}

// ValidateDelete is a webhook for validating the deleting of the Codebase CR.
// It is skipped for now. Add kubebuilder:webhook:verbs=delete to enable it.
func (r *CodebaseValidationWebhook) ValidateDelete(ctx context.Context, _ runtime.Object) (warnings admission.Warnings, err error) {
func (r *CodebaseValidationWebhook) ValidateDelete(ctx context.Context, obj runtime.Object) (warnings admission.Warnings, err error) {
req, err := admission.RequestFromContext(ctx)
if err != nil {
return nil, fmt.Errorf("expected admission.Request in ctx: %w", err)
}

r.log.Info("validate delete", "name", req.Name)

if err = checkResourceProtectionFromModificationOnDelete(obj); err != nil {
return nil, err
}

return nil, nil
}
Loading

0 comments on commit 5378d86

Please sign in to comment.