Skip to content

Commit 341a9d1

Browse files
committed
feat: add validating webhook for run-levels
Signed-off-by: SequeI <[email protected]>
1 parent 47c578c commit 341a9d1

File tree

10 files changed

+144
-5
lines changed

10 files changed

+144
-5
lines changed

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,8 @@ help: ## Display this help.
113113
##@ Development
114114

115115
.PHONY: manifests
116-
manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
117-
$(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
116+
manifests: controller-gen ## Generate ClusterRole and CustomResourceDefinition objects.
117+
$(CONTROLLER_GEN) rbac:roleName=manager-role crd paths="./..." output:crd:artifacts:config=config/crd/bases
118118

119119
.PHONY: generate
120120
generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.

api/v1alpha1/securesign_types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ type SecuresignTSAStatus struct {
7373
//+kubebuilder:printcolumn:name="Rekor URL",type=string,JSONPath=`.status.rekor.url`,description="The rekor url"
7474
//+kubebuilder:printcolumn:name="Fulcio URL",type=string,JSONPath=`.status.fulcio.url`,description="The fulcio url"
7575
//+kubebuilder:printcolumn:name="Tuf URL",type=string,JSONPath=`.status.tuf.url`,description="The tuf url"
76+
//+kubebuilder:webhook:path=/validate,mutating=false,failurePolicy=fail,groups=rhtas.redhat.com,resources=securesigns,verbs=create,versions=v1alpha1,name=securesign.rhtas.redhat.com,sideEffects=None,admissionReviewVersions=v1
7677

7778
// Securesign is the Schema for the securesigns API
7879
type Securesign struct {

cmd/main.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ import (
6262
"github.com/securesign/operator/internal/controller/trillian"
6363
"github.com/securesign/operator/internal/controller/tsa"
6464
"github.com/securesign/operator/internal/controller/tuf"
65+
rhtas_webhook "github.com/securesign/operator/internal/webhook"
6566
//+kubebuilder:scaffold:imports
6667
)
6768

@@ -195,6 +196,17 @@ func main() {
195196
os.Exit(1)
196197
}
197198

199+
if err := ctrl.NewWebhookManagedBy(mgr).
200+
For(&rhtasv1alpha1.Securesign{}).
201+
WithValidator(&rhtas_webhook.SecureSignValidator{
202+
Client: mgr.GetClient(),
203+
}).
204+
WithCustomPath("/validate").
205+
Complete(); err != nil {
206+
setupLog.Error(err, "unable to create SecureSign validating webhook")
207+
os.Exit(1)
208+
}
209+
198210
setupController("securesign", securesign.NewReconciler, mgr)
199211
setupController("fulcio", fulcio.NewReconciler, mgr)
200212
setupController("trillian", trillian.NewReconciler, mgr)

config/default/kustomization.yaml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@ namePrefix: rhtas-
1515
#commonLabels:
1616
# someName: someValue
1717

18-
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
19-
# crd/kustomization.yaml
20-
#- ../webhook
2118
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required.
2219
#- ../certmanager
2320
# [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'.
@@ -26,6 +23,7 @@ resources:
2623
- ../rbac
2724
- ../manager
2825
- ../prometheus
26+
- ../webhook
2927

3028
patches:
3129
- path: manager_metrics_patch.yaml

config/manager/manager.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ spec:
6767
- --leader-elect
6868
image: controller:latest
6969
name: manager
70+
volumeMounts:
71+
- name: webhook-cert
72+
mountPath: /tmp/k8s-webhook-server/serving-certs
73+
readOnly: true
7074
securityContext:
7175
allowPrivilegeEscalation: false
7276
readOnlyRootFilesystem: true
@@ -97,3 +101,8 @@ spec:
97101
memory: 64Mi
98102
serviceAccountName: operator-controller-manager
99103
terminationGracePeriodSeconds: 10
104+
volumes:
105+
- name: webhook-cert
106+
secret:
107+
secretName: webhook-server-tls
108+

config/webhook/kustomization.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
resources:
2+
- service.yaml
3+
- webhook.yaml

config/webhook/service.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
apiVersion: v1
2+
kind: Service
3+
metadata:
4+
name: controller-manager-webhook-service
5+
namespace: system
6+
labels:
7+
control-plane: operator-controller-manager
8+
annotations:
9+
service.beta.openshift.io/serving-cert-secret-name: webhook-server-tls
10+
spec:
11+
ports:
12+
- name: https-webhook
13+
port: 443
14+
targetPort: 9443
15+
protocol: TCP
16+
selector:
17+
control-plane: operator-controller-manager

config/webhook/webhook.yaml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
apiVersion: admissionregistration.k8s.io/v1
3+
kind: ValidatingWebhookConfiguration
4+
metadata:
5+
name: validation.securesigns.rhtas.redhat.com
6+
annotations:
7+
service.beta.openshift.io/inject-cabundle: "true"
8+
webhooks:
9+
- admissionReviewVersions:
10+
- v1
11+
clientConfig:
12+
service:
13+
name: controller-manager-webhook-service
14+
namespace: system
15+
path: /validate
16+
failurePolicy: Fail
17+
name: validation.securesigns.rhtas.redhat.com
18+
rules:
19+
- apiGroups:
20+
- rhtas.redhat.com
21+
apiVersions:
22+
- v1alpha1
23+
operations:
24+
- CREATE
25+
resources:
26+
- securesigns
27+
sideEffects: None
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package webhooks
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1"
8+
corev1 "k8s.io/api/core/v1"
9+
"k8s.io/apimachinery/pkg/runtime"
10+
"k8s.io/apimachinery/pkg/types"
11+
logf "sigs.k8s.io/controller-runtime/pkg/log"
12+
admission "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
13+
)
14+
15+
func (v *SecureSignValidator) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
16+
reqLog := logf.FromContext(ctx)
17+
operandCR, ok := obj.(*rhtasv1alpha1.Securesign)
18+
if !ok {
19+
return nil, fmt.Errorf("expected SecureSign CR but got %T", obj)
20+
}
21+
22+
targetNamespace := operandCR.GetNamespace()
23+
24+
if targetNamespace == "default" {
25+
reqLog.Info("Validation failed: Deployment blocked in 'default' namespace.")
26+
return nil, fmt.Errorf("installation into the 'default' namespace is prohibited by RHTAS policy")
27+
}
28+
29+
ns := &corev1.Namespace{}
30+
31+
if err := v.Client.Get(ctx, types.NamespacedName{Name: targetNamespace}, ns); err != nil {
32+
reqLog.Error(err, "Failed to retrieve target namespace object for validation.")
33+
return nil, fmt.Errorf("failed to retrieve target namespace %s: %w", targetNamespace, err)
34+
}
35+
36+
runLevel, found := ns.Labels["openshift.io/run-level"]
37+
if found && reservedRunLevels[runLevel] {
38+
reqLog.Info("Validation failed: Deployment blocked in reserved namespace.",
39+
"namespace", targetNamespace, "run-level", runLevel)
40+
return nil, fmt.Errorf("installation into reserved OpenShift namespace '%s' (run-level %s) is prohibited by RHTAS policy", targetNamespace, runLevel)
41+
}
42+
43+
return nil, nil
44+
}
45+
46+
func (v *SecureSignValidator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) {
47+
return nil, nil
48+
}
49+
50+
func (v *SecureSignValidator) ValidateDelete(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
51+
return nil, nil
52+
}

internal/webhook/webhooks.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package webhooks
2+
3+
import (
4+
"sigs.k8s.io/controller-runtime/pkg/client"
5+
admission "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
6+
)
7+
8+
// SecureSignValidator checks for namespace security policy compliance.
9+
type SecureSignValidator struct {
10+
Client client.Client
11+
}
12+
13+
var _ admission.CustomValidator = &SecureSignValidator{}
14+
15+
// Reserved OpenShift run-level labels to block
16+
var reservedRunLevels = map[string]bool{
17+
"0": true, // Critical infrastructure
18+
"1": true, // Infrastructure
19+
"9": true, // General platform services
20+
}

0 commit comments

Comments
 (0)