Skip to content
This repository has been archived by the owner on Apr 25, 2024. It is now read-only.

Commit

Permalink
Merge pull request #121 from FabianKramm/master
Browse files Browse the repository at this point in the history
allow webhooks for spaces & accounts
  • Loading branch information
FabianKramm authored May 7, 2021
2 parents a1afb45 + 74b4508 commit cd5110c
Show file tree
Hide file tree
Showing 88 changed files with 19,389 additions and 0 deletions.
2 changes: 2 additions & 0 deletions chart/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ spec:
spec:
terminationGracePeriodSeconds: 10
serviceAccountName: {{ template "kiosk.serviceAccountName" . }}
nodeSelector:
{{ toYaml .Values.nodeSelector | indent 8 }}
containers:
- ports:
- name: webhook
Expand Down
2 changes: 2 additions & 0 deletions chart/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ replicaCount: 1

env: {}

nodeSelector: {}

readinessProbe:
enabled: true

Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@ require (
k8s.io/component-base v0.20.2
k8s.io/gengo v0.0.0-20201113003025-83324d819ded
k8s.io/klog v1.0.0
k8s.io/klog/v2 v2.4.0
k8s.io/kube-aggregator v0.20.2
k8s.io/kube-controller-manager v0.20.2
k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd
k8s.io/kubectl v0.20.2
k8s.io/utils v0.0.0-20210111153108-fddb29f9d009
sigs.k8s.io/apiserver-builder-alpha v1.18.0
sigs.k8s.io/controller-runtime v0.8.3
)
Expand Down
76 changes: 76 additions & 0 deletions pkg/apiserver/admission/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package admission

import (
"io/ioutil"
"net/http"
"time"

"k8s.io/klog/v2"

utilwait "k8s.io/apimachinery/pkg/util/wait"
"k8s.io/apiserver/pkg/admission"
webhookinit "k8s.io/apiserver/pkg/admission/plugin/webhook/initializer"
genericapiserver "k8s.io/apiserver/pkg/server"
"k8s.io/apiserver/pkg/server/egressselector"
"k8s.io/apiserver/pkg/util/webhook"
cacheddiscovery "k8s.io/client-go/discovery/cached/memory"
externalinformers "k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/restmapper"
)

// Config holds the configuration needed to for initialize the admission plugins
type Config struct {
CloudConfigFile string
LoopbackClientConfig *rest.Config
ExternalInformers externalinformers.SharedInformerFactory
}

// New sets up the plugins and admission start hooks needed for admission
func (c *Config) New(proxyTransport *http.Transport, egressSelector *egressselector.EgressSelector, serviceResolver webhook.ServiceResolver) ([]admission.PluginInitializer, genericapiserver.PostStartHookFunc, error) {
webhookAuthResolverWrapper := webhook.NewDefaultAuthenticationInfoResolverWrapper(proxyTransport, egressSelector, c.LoopbackClientConfig)
webhookPluginInitializer := webhookinit.NewPluginInitializer(webhookAuthResolverWrapper, serviceResolver)

var cloudConfig []byte
if c.CloudConfigFile != "" {
var err error
cloudConfig, err = ioutil.ReadFile(c.CloudConfigFile)
if err != nil {
klog.Fatalf("Error reading from cloud configuration file %s: %#v", c.CloudConfigFile, err)
}
}
clientset, err := kubernetes.NewForConfig(c.LoopbackClientConfig)
if err != nil {
return nil, nil, err
}

discoveryClient := cacheddiscovery.NewMemCacheClient(clientset.Discovery())
discoveryRESTMapper := restmapper.NewDeferredDiscoveryRESTMapper(discoveryClient)
kubePluginInitializer := NewPluginInitializer(
cloudConfig,
discoveryRESTMapper,
nil,
)

admissionPostStartHook := func(context genericapiserver.PostStartHookContext) error {
discoveryRESTMapper.Reset()
go utilwait.Until(discoveryRESTMapper.Reset, 30*time.Second, context.StopCh)
return nil
}

return []admission.PluginInitializer{webhookPluginInitializer, kubePluginInitializer}, admissionPostStartHook, nil
}
73 changes: 73 additions & 0 deletions pkg/apiserver/admission/initializer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package admission

import (
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apiserver/pkg/admission"
"k8s.io/apiserver/pkg/admission/initializer"
quota "k8s.io/apiserver/pkg/quota/v1"
)

// TODO add a `WantsToRun` which takes a stopCh. Might make it generic.

// WantsCloudConfig defines a function which sets CloudConfig for admission plugins that need it.
type WantsCloudConfig interface {
SetCloudConfig([]byte)
}

// WantsRESTMapper defines a function which sets RESTMapper for admission plugins that need it.
type WantsRESTMapper interface {
SetRESTMapper(meta.RESTMapper)
}

// PluginInitializer is used for initialization of the Kubernetes specific admission plugins.
type PluginInitializer struct {
cloudConfig []byte
restMapper meta.RESTMapper
quotaConfiguration quota.Configuration
}

var _ admission.PluginInitializer = &PluginInitializer{}

// NewPluginInitializer constructs new instance of PluginInitializer
// TODO: switch these parameters to use the builder pattern or just make them
// all public, this construction method is pointless boilerplate.
func NewPluginInitializer(
cloudConfig []byte,
restMapper meta.RESTMapper,
quotaConfiguration quota.Configuration,
) *PluginInitializer {
return &PluginInitializer{
cloudConfig: cloudConfig,
restMapper: restMapper,
quotaConfiguration: quotaConfiguration,
}
}

// Initialize checks the initialization interfaces implemented by each plugin
// and provide the appropriate initialization data
func (i *PluginInitializer) Initialize(plugin admission.Interface) {
if wants, ok := plugin.(WantsCloudConfig); ok {
wants.SetCloudConfig(i.cloudConfig)
}

if wants, ok := plugin.(WantsRESTMapper); ok {
wants.SetRESTMapper(i.restMapper)
}

if wants, ok := plugin.(initializer.WantsQuotaConfiguration); ok {
wants.SetQuotaConfiguration(i.quotaConfiguration)
}
}
66 changes: 66 additions & 0 deletions pkg/apiserver/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@ package apiserver

import (
"bytes"
"crypto/tls"
"flag"
"fmt"
"github.com/loft-sh/kiosk/pkg/apiserver/admission"
"github.com/loft-sh/kiosk/pkg/util/certhelper"
utilnet "k8s.io/apimachinery/pkg/util/net"
"net/http"
"net/url"
"os"
"path/filepath"
"strconv"
Expand All @@ -40,11 +44,14 @@ import (
genericfilters "k8s.io/apiserver/pkg/server/filters"
genericoptions "k8s.io/apiserver/pkg/server/options"
"k8s.io/apiserver/pkg/util/feature"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/apiserver/pkg/util/webhook"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/klog"
aggregatorapiserver "k8s.io/kube-aggregator/pkg/apiserver"
openapi "k8s.io/kube-openapi/pkg/common"
"sigs.k8s.io/apiserver-builder-alpha/pkg/apiserver"
"sigs.k8s.io/apiserver-builder-alpha/pkg/builders"
Expand Down Expand Up @@ -279,6 +286,32 @@ func (o ServerOptions) Config(tweakConfigFuncs ...func(config *apiserver.Config)
}
}

if os.Getenv("DISABLE_WEBHOOKS") != "true" {
proxyTransport := CreateNodeDialer()
admissionConfig := &admission.Config{
ExternalInformers: kubeInformerFactory,
LoopbackClientConfig: serverConfig.LoopbackClientConfig,
}
serviceResolver := buildServiceResolver(false, serverConfig.LoopbackClientConfig.Host, kubeInformerFactory)
pluginInitializers, admissionPostStartHook, err := admissionConfig.New(proxyTransport, serverConfig.EgressSelector, serviceResolver)
if err != nil {
return nil, fmt.Errorf("failed to create admission plugin initializer: %v", err)
}
if err := serverConfig.AddPostStartHook("start-kube-apiserver-admission-initializer", admissionPostStartHook); err != nil {
return nil, err
}

err = o.RecommendedOptions.Admission.ApplyTo(
&serverConfig.Config,
kubeInformerFactory,
serverConfig.LoopbackClientConfig,
utilfeature.DefaultFeatureGate,
pluginInitializers...)
if err != nil {
return nil, fmt.Errorf("failed to initialize admission: %v", err)
}
}

err = applyOptions(
&serverConfig.Config,
// o.RecommendedOptions.Etcd.ApplyTo,
Expand Down Expand Up @@ -315,6 +348,39 @@ func (o ServerOptions) Config(tweakConfigFuncs ...func(config *apiserver.Config)
return config, nil
}

// CreateNodeDialer creates the dialer infrastructure to connect to the nodes.
func CreateNodeDialer() *http.Transport {
// Setup nodeTunneler if needed
var proxyDialerFn utilnet.DialFunc

// Proxying to pods and services is IP-based... don't expect to be able to verify the hostname
proxyTLSClientConfig := &tls.Config{InsecureSkipVerify: true}
proxyTransport := utilnet.SetTransportDefaults(&http.Transport{
DialContext: proxyDialerFn,
TLSClientConfig: proxyTLSClientConfig,
})
return proxyTransport
}

func buildServiceResolver(enabledAggregatorRouting bool, hostname string, informer informers.SharedInformerFactory) webhook.ServiceResolver {
var serviceResolver webhook.ServiceResolver
if enabledAggregatorRouting {
serviceResolver = aggregatorapiserver.NewEndpointServiceResolver(
informer.Core().V1().Services().Lister(),
informer.Core().V1().Endpoints().Lister(),
)
} else {
serviceResolver = aggregatorapiserver.NewClusterIPServiceResolver(
informer.Core().V1().Services().Lister(),
)
}
// resolve kubernetes.default.svc locally
if localHost, err := url.Parse(hostname); err == nil {
serviceResolver = aggregatorapiserver.NewLoopbackServiceResolver(serviceResolver, localHost)
}
return serviceResolver
}

func (o *ServerOptions) buildLoopback() (*rest.Config, informers.SharedInformerFactory, error) {
var loopbackConfig *rest.Config
var err error
Expand Down
29 changes: 29 additions & 0 deletions vendor/github.com/mxk/go-flowrate/LICENSE

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit cd5110c

Please sign in to comment.