Skip to content

Commit

Permalink
Add mutating webhook to set fsGroupChangePolicy field (#582)
Browse files Browse the repository at this point in the history
* Add mutating webhook to set fsGroupChangePolicy field

* Added decoder, debug logging

* Fix path

* Add missing name

* Fix typo

* Add sample podAnnotator

* Try defaulter

* Do webhook registration earlier

* Add webhook server configuration annotations

* Test cert-dir annotation

* Remove webhook-server annotation

* Fix typo

* Logging

* Add webhook server

* Naming

* Formatting

* Try different registration

* Move registration after start

* Try registering FsGroupPolicySetter again

* Move registration back up again

* ...

* use port 9443 again

* Update annotation

* Add scheme

* Fix setting FSGroupChangePolicy

* Remove samples

* Make webhook configurable

* Remove useless check

* Since fsGroup is set by default, also enable webhook by default

* Move code

* Remove  webhook.Options (we're using the default port anyway)
  • Loading branch information
eberlep authored Sep 16, 2024
1 parent c7ed72e commit ffbc3ba
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 0 deletions.
25 changes: 25 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,23 @@ import (
"github.com/metal-stack/v"
coreosv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
zalando "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1"
appsv1 "k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
"k8s.io/client-go/tools/clientcmd"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
"sigs.k8s.io/controller-runtime/pkg/webhook"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"

databasev1 "github.com/fi-ts/postgreslet/api/v1"
"github.com/fi-ts/postgreslet/controllers"
"github.com/fi-ts/postgreslet/pkg/etcdmanager"
"github.com/fi-ts/postgreslet/pkg/lbmanager"
"github.com/fi-ts/postgreslet/pkg/operatormanager"
"github.com/fi-ts/postgreslet/pkg/webhooks"
firewall "github.com/metal-stack/firewall-controller/api/v1"
"github.com/spf13/viper"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
Expand Down Expand Up @@ -84,6 +88,7 @@ const (
tlsClusterIssuerFlg = "tls-cluster-issuer"
tlsSubDomainFlg = "tls-sub-domain"
enablePatroniFailsafeModeFlg = "enable-patroni-failsafe-mode"
enableFsGroupChangePolicyWebhookFlg = "enable-fsgroup-change-policy-webhook"
)

var (
Expand All @@ -98,6 +103,7 @@ func init() {
_ = firewall.AddToScheme(scheme)
_ = zalando.AddToScheme(scheme)
_ = coreosv1.AddToScheme(scheme)
_ = appsv1.AddToScheme(scheme)
// +kubebuilder:scaffold:scheme
_ = cmapi.AddToScheme(scheme)
}
Expand Down Expand Up @@ -143,6 +149,7 @@ func main() {
enableBootstrapStandbyFromS3 bool
enableSuperUserForDBO bool
enablePatroniFailsafeMode bool
enableFsGroupChangePolicyWebhook bool

portRangeStart int
portRangeSize int
Expand Down Expand Up @@ -305,6 +312,9 @@ func main() {
viper.SetDefault(enablePatroniFailsafeModeFlg, true)
enablePatroniFailsafeMode = viper.GetBool(enablePatroniFailsafeModeFlg)

viper.SetDefault(enableFsGroupChangePolicyWebhookFlg, true)
enableFsGroupChangePolicyWebhook = viper.GetBool(enableFsGroupChangePolicyWebhookFlg)

ctrl.Log.Info("flag",
metricsAddrSvcMgrFlg, metricsAddrSvcMgr,
metricsAddrCtrlMgrFlg, metricsAddrCtrlMgr,
Expand Down Expand Up @@ -349,6 +359,7 @@ func main() {
tlsClusterIssuerFlg, tlsClusterIssuer,
tlsSubDomainFlg, tlsSubDomain,
enablePatroniFailsafeModeFlg, enablePatroniFailsafeMode,
enableFsGroupChangePolicyWebhookFlg, enableFsGroupChangePolicyWebhook,
)

svcClusterConf := ctrl.GetConfigOrDie()
Expand Down Expand Up @@ -486,6 +497,19 @@ func main() {
}
// +kubebuilder:scaffold:builder

if enableFsGroupChangePolicyWebhook {
svcClusterMgr.GetWebhookServer().Register(
"/mutate-apps-v1-statefulset",
&webhook.Admission{
Handler: &webhooks.FsGroupChangePolicySetter{
SvcClient: svcClusterMgr.GetClient(),
Decoder: admission.NewDecoder(svcClusterMgr.GetScheme()),
Log: ctrl.Log.WithName("webhooks").WithName("FsGroupChangePolicySetter"),
},
},
)
}

ctx := context.Background()

// update all existing operators to the current version
Expand All @@ -506,4 +530,5 @@ func main() {
setupLog.Error(err, "problem running control plane cluster manager")
os.Exit(1)
}

}
51 changes: 51 additions & 0 deletions pkg/webhooks/fsGroupChangePolicySetter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package webhooks

import (
"context"
"encoding/json"
"net/http"

"github.com/go-logr/logr"
appsv1 "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1"
"sigs.k8s.io/controller-runtime/pkg/client"

"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
)

// +kubebuilder:webhook:path=/mutate-apps-v1-statefulset,mutating=true,failurePolicy=ignore,groups=apps,resources=statefulsets,verbs=create;update,versions=v1,name=fsgroupchangepolicy.postgres.fits.cloud

// FsGroupChangePolicySetter Adds securityContext.fsGroupChangePolicy=OnRootMismatch when the securityContext.fsGroup field is set
type FsGroupChangePolicySetter struct {
SvcClient client.Client
Decoder *admission.Decoder
Log logr.Logger
}

func (a *FsGroupChangePolicySetter) Handle(ctx context.Context, req admission.Request) admission.Response {
log := a.Log.WithValues("name", req.Name, "ns", req.Namespace)
log.V(1).Info("handling admission request")

sts := &appsv1.StatefulSet{}
err := a.Decoder.Decode(req, sts)
if err != nil {
log.Error(err, "failed to decode request")
return admission.Errored(http.StatusBadRequest, err)
}

// when the fsGroup field is set, also set the fsGroupChangePolicy to OnRootMismatch
if sts.Spec.Template.Spec.SecurityContext != nil && sts.Spec.Template.Spec.SecurityContext.FSGroup != nil {
p := v1.FSGroupChangeOnRootMismatch
sts.Spec.Template.Spec.SecurityContext.FSGroupChangePolicy = &p
log.V(1).Info("Mutating StatefulSet", "sts", sts)
}

marshaledSts, err := json.Marshal(sts)
if err != nil {
log.Error(err, "failed to marshal response")
return admission.Errored(http.StatusInternalServerError, err)
}

log.V(1).Info("done")
return admission.PatchResponseFromRaw(req.Object.Raw, marshaledSts)
}

0 comments on commit ffbc3ba

Please sign in to comment.