Skip to content
Open
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
7 changes: 7 additions & 0 deletions .github/actions/kind-cluster/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,10 @@ runs:
shell: bash
run: |
kustomize build --enable-helm ./ci/nfs/overlay/ | kubectl apply -f -

- name: Install Cert-Manager
shell: bash
run: |
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.19.1/cert-manager.yaml
kubectl wait --for=condition=available deployment/cert-manager-webhook -n cert-manager --timeout=5m
kubectl wait --for=condition=available deployment/cert-manager -n cert-manager --timeout=5m
2 changes: 1 addition & 1 deletion .tekton/rhtas-operator-bundle-pull-request.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ spec:
- name: image-expires-after
value: 5d
- name: manager-pipelinerun-selector
value: appstudio.openshift.io/application=operator,appstudio.openshift.io/component=rhtas-operator,pipelinesascode.tekton.dev/sha={{revision}},pipelinesascode.tekton.dev/event-type in (pull_request,incoming)
value: appstudio.openshift.io/application=operator,appstudio.openshift.io/component=rhtas-operator,pipelinesascode.tekton.dev/sha={{revision}},pipelinesascode.tekton.dev/event-type in (pull_request,incoming,retest-all-comment)
- name: manager-registry-url
value: registry.redhat.io/rhtas/rhtas-rhel9-operator
pipelineRef:
Expand Down
23 changes: 17 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,20 @@ CONTAINER_TOOL ?= docker
SHELL = /usr/bin/env bash -o pipefail
.SHELLFLAGS = -ec

OPENSHIFT ?=

KUSTOMIZE_OVERLAY := config/overlays/kubernetes
CONFIG_DEFAULT=config/default

ifeq ($(OPENSHIFT), true)
KUSTOMIZE_OVERLAY := config/overlays/openshift
$(info Platform explicitly configured via flag/env: openshift=$(OPENSHIFT))
else ifneq ($(OPENSHIFT),)
$(info Platform explicitly configured via flag/env: openshift=$(OPENSHIFT))
else
$(info Platform auto-detected: openshift=false (Defaulting to Kubernetes overlay))
endif

.PHONY: all
all: build

Expand All @@ -108,8 +120,8 @@ help: ## Display this help.
##@ Development

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

.PHONY: generate
generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
Expand Down Expand Up @@ -201,8 +213,7 @@ endif
build-installer: manifests generate kustomize ## Generate a consolidated YAML with CRDs and deployment.
mkdir -p dist
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
$(KUSTOMIZE) build ${CONFIG_DEFAULT} > dist/install.yaml

$(KUSTOMIZE) build ${KUSTOMIZE_OVERLAY} > dist/install.yaml
##@ Deployment

ifndef ignore-not-found
Expand All @@ -220,12 +231,12 @@ uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified
.PHONY: deploy
deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config.
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
$(KUSTOMIZE) build ${CONFIG_DEFAULT} | $(KUBECTL) apply --server-side -f -
$(KUSTOMIZE) build ${KUSTOMIZE_OVERLAY} | $(KUBECTL) apply --server-side -f -


.PHONY: undeploy
undeploy: kustomize ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
$(KUSTOMIZE) build ${CONFIG_DEFAULT} | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f -
$(KUSTOMIZE) build ${KUSTOMIZE_OVERLAY} | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f -

##@ Dependencies

Expand Down
1 change: 1 addition & 0 deletions api/v1alpha1/securesign_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ type SecuresignTSAStatus struct {
//+kubebuilder:printcolumn:name="Rekor URL",type=string,JSONPath=`.status.rekor.url`,description="The rekor url"
//+kubebuilder:printcolumn:name="Fulcio URL",type=string,JSONPath=`.status.fulcio.url`,description="The fulcio url"
//+kubebuilder:printcolumn:name="Tuf URL",type=string,JSONPath=`.status.tuf.url`,description="The tuf url"
//+kubebuilder:webhook:path=/validate,mutating=false,failurePolicy=fail,groups=rhtas.redhat.com,resources=securesigns,verbs=create;update,versions=v1alpha1,name=validation.securesigns.rhtas.redhat.com,sideEffects=None,admissionReviewVersions=v1

// Securesign is the Schema for the securesigns API
type Securesign struct {
Expand Down
12 changes: 12 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ import (
"github.com/securesign/operator/internal/controller/trillian"
"github.com/securesign/operator/internal/controller/tsa"
"github.com/securesign/operator/internal/controller/tuf"
rhtas_webhook "github.com/securesign/operator/internal/webhook"
//+kubebuilder:scaffold:imports
)

Expand Down Expand Up @@ -207,6 +208,17 @@ func main() {
os.Exit(1)
}

if err := ctrl.NewWebhookManagedBy(mgr).
For(&rhtasv1alpha1.Securesign{}).
WithValidator(&rhtas_webhook.SecureSignValidator{
Client: mgr.GetClient(),
}).
WithValidatorCustomPath("/validate").
Complete(); err != nil {
setupLog.Error(err, "unable to create SecureSign validating webhook")
os.Exit(1)
}

setupController("securesign", securesign.NewReconciler, mgr)
setupController("fulcio", fulcio.NewReconciler, mgr)
setupController("trillian", trillian.NewReconciler, mgr)
Expand Down
4 changes: 1 addition & 3 deletions config/default/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@ namePrefix: rhtas-
#commonLabels:
# someName: someValue

# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
# crd/kustomization.yaml
#- ../webhook
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required.
#- ../certmanager
# [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'.
Expand All @@ -26,6 +23,7 @@ resources:
- ../rbac
- ../manager
- ../prometheus
- ../webhook

patches:
- path: manager_metrics_patch.yaml
Expand Down
8 changes: 8 additions & 0 deletions config/manager/manager.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ spec:
- --leader-elect
image: controller:latest
name: manager
volumeMounts:
- name: webhook-cert
mountPath: /tmp/k8s-webhook-server/serving-certs
readOnly: true
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
Expand Down Expand Up @@ -97,3 +101,7 @@ spec:
memory: 64Mi
serviceAccountName: operator-controller-manager
terminationGracePeriodSeconds: 10
volumes:
- name: webhook-cert
secret:
secretName: webhook-server-tls
21 changes: 21 additions & 0 deletions config/overlays/kubernetes/cert_resources.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: selfsigned-issuer
namespace: openshift-rhtas-operator
spec:
selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: webhook-serving-cert
namespace: openshift-rhtas-operator
spec:
secretName: webhook-server-tls
issuerRef:
name: selfsigned-issuer
kind: Issuer
dnsNames:
- rhtas-controller-manager-webhook-service.openshift-rhtas-operator.svc
- rhtas-controller-manager-webhook-service.openshift-rhtas-operator.svc.cluster.local
14 changes: 14 additions & 0 deletions config/overlays/kubernetes/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

namespace: openshift-rhtas-operator

resources:
- ../../default
- cert_resources.yaml

patches:
- path: webhook_patch.yaml
target:
kind: ValidatingWebhookConfiguration
name: validation.securesigns.rhtas.redhat.com
6 changes: 6 additions & 0 deletions config/overlays/kubernetes/webhook_patch.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: validation.securesigns.rhtas.redhat.com
annotations:
cert-manager.io/inject-ca-from: openshift-rhtas-operator/webhook-serving-cert
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: validation.securesigns.rhtas.redhat.com
annotations:
service.beta.openshift.io/inject-cabundle: "true"
16 changes: 16 additions & 0 deletions config/overlays/openshift/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- ../../default

patches:
- path: serving_cert_annotation_patch.yaml
target:
kind: Service
name: controller-manager-webhook-service

- path: inject_ca_bundle_annotation_patch.yaml
target:
kind: ValidatingWebhookConfiguration
name: validation.securesigns.rhtas.redhat.com
9 changes: 9 additions & 0 deletions config/overlays/openshift/serving_cert_annotation_patch.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
apiVersion: v1
kind: Service
metadata:
name: controller-manager-webhook-service
namespace: openshift-rhtas-operator
labels:
control-plane: controller-manager
annotations:
service.beta.openshift.io/serving-cert-secret-name: webhook-server-tls
3 changes: 3 additions & 0 deletions config/webhook/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
resources:
- service.yaml
- webhook.yaml
15 changes: 15 additions & 0 deletions config/webhook/service.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: controller-manager-webhook-service
namespace: openshift-rhtas-operator
labels:
control-plane: operator-controller-manager
spec:
ports:
- name: https-webhook
port: 443
targetPort: 9443
protocol: TCP
selector:
control-plane: operator-controller-manager
26 changes: 26 additions & 0 deletions config/webhook/webhook.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: validation.securesigns.rhtas.redhat.com
webhooks:
- admissionReviewVersions:
- v1
clientConfig:
service:
name: controller-manager-webhook-service
namespace: openshift-rhtas-operator
path: /validate
failurePolicy: Fail
name: validation.securesigns.rhtas.redhat.com
rules:
- apiGroups:
- rhtas.redhat.com
apiVersions:
- v1alpha1
operations:
- CREATE
- UPDATE
resources:
- securesigns
sideEffects: None
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ require (
github.com/operator-framework/api v0.35.0
github.com/operator-framework/operator-lib v0.19.0
github.com/robfig/cron/v3 v3.0.1
github.com/stretchr/testify v1.11.1
golang.org/x/net v0.46.0
google.golang.org/protobuf v1.36.10
k8s.io/api v0.34.1
Expand Down
64 changes: 64 additions & 0 deletions internal/webhook/securesign_validator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package webhooks

import (
"context"
"fmt"

rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
logf "sigs.k8s.io/controller-runtime/pkg/log"
admission "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
)

func (v *SecureSignValidator) validateNamespacePolicy(ctx context.Context, operandCR *rhtasv1alpha1.Securesign) (admission.Warnings, error) {
reqLog := logf.FromContext(ctx)
targetNamespace := operandCR.GetNamespace()

if targetNamespace == "default" {
reqLog.Info("Validation failed: Deployment blocked in 'default' namespace.")
return nil, fmt.Errorf("installation into the 'default' namespace is prohibited by RHTAS policy")
}

ns := &corev1.Namespace{}

if err := v.Client.Get(ctx, types.NamespacedName{Name: targetNamespace}, ns); err != nil {
if apierrors.IsNotFound(err) {
return nil, nil
}
reqLog.Error(err, "Failed to retrieve target namespace object for validation.")
return nil, fmt.Errorf("failed to retrieve target namespace %s: %w", targetNamespace, err)
}

runLevel, found := ns.Labels["openshift.io/run-level"]
if found && reservedRunLevels[runLevel] {
reqLog.Info("Validation failed: Deployment blocked in reserved namespace.",
"namespace", targetNamespace, "run-level", runLevel)
return nil, fmt.Errorf("installation into reserved OpenShift namespace '%s' (run-level %s) is prohibited by RHTAS policy", targetNamespace, runLevel)
}

return nil, nil
}

func (v *SecureSignValidator) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
operandCR, ok := obj.(*rhtasv1alpha1.Securesign)
if !ok {
return nil, fmt.Errorf("expected SecureSign CR but got %T", obj)
}
return v.validateNamespacePolicy(ctx, operandCR)
}

func (v *SecureSignValidator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) {
operandCR, ok := newObj.(*rhtasv1alpha1.Securesign)
if !ok {
return nil, fmt.Errorf("expected SecureSign CR but got %T", newObj)
}
return v.validateNamespacePolicy(ctx, operandCR)
}

func (v *SecureSignValidator) ValidateDelete(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
// Allow all delete operations
return nil, nil
}
Loading