From 364a599df305483f7697dab138ca42900eea8ca8 Mon Sep 17 00:00:00 2001 From: David Eads Date: Thu, 9 Aug 2018 11:57:11 -0400 Subject: [PATCH] move the handlers, servers, etc needed for a kubeapiserver to the kubeapiserver --- hack/import-restrictions.json | 1 + pkg/client/genericinformers/interface.go | 2 +- .../openshiftkubeapiserver}/handlers.go | 6 +- .../openshiftkubeapiserver}/handlers_test.go | 24 +- .../openshiftkubeapiserver}/nonapiserver.go | 24 +- .../openshiftkubeapiserver/patch.go | 235 ++++++++++++++++++ .../patch_authenticator.go} | 10 +- .../patch_authorizer.go} | 16 +- .../patch_handlerchain.go | 94 +++++++ .../patch_oauthserver.go | 63 +++++ .../service_proxy_handler.go | 6 +- .../webconsole_proxy.go | 8 +- .../origin/admission/plugin_initializer.go | 28 +++ pkg/cmd/server/origin/master.go | 126 +--------- pkg/cmd/server/origin/master_config.go | 5 +- .../server/origin/oauth_apiserver_adapter.go | 71 ------ test/integration/master_routes_test.go | 2 +- 17 files changed, 488 insertions(+), 233 deletions(-) rename pkg/cmd/{server/origin => openshift-kube-apiserver/openshiftkubeapiserver}/handlers.go (96%) rename pkg/cmd/{server/origin => openshift-kube-apiserver/openshiftkubeapiserver}/handlers_test.go (91%) rename pkg/cmd/{server/origin => openshift-kube-apiserver/openshiftkubeapiserver}/nonapiserver.go (78%) create mode 100644 pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver/patch.go rename pkg/cmd/{server/origin/authenticator.go => openshift-kube-apiserver/openshiftkubeapiserver/patch_authenticator.go} (96%) rename pkg/cmd/{server/origin/authorizer.go => openshift-kube-apiserver/openshiftkubeapiserver/patch_authorizer.go} (77%) create mode 100644 pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver/patch_handlerchain.go create mode 100644 pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver/patch_oauthserver.go rename pkg/cmd/{server/origin => openshift-kube-apiserver/openshiftkubeapiserver}/service_proxy_handler.go (96%) rename pkg/cmd/{server/origin => openshift-kube-apiserver/openshiftkubeapiserver}/webconsole_proxy.go (93%) delete mode 100644 pkg/cmd/server/origin/oauth_apiserver_adapter.go diff --git a/hack/import-restrictions.json b/hack/import-restrictions.json index 2f1de657ba0e..afefd42df4da 100644 --- a/hack/import-restrictions.json +++ b/hack/import-restrictions.json @@ -108,6 +108,7 @@ "ignoredSubTrees": [ "github.com/openshift/origin/pkg/oauthserver", + "github.com/openshift/origin/pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver", "github.com/openshift/origin/pkg/cmd/server/origin", "github.com/openshift/origin/pkg/cmd/server/apis/config/validation", "github.com/openshift/origin/pkg/oc/cli/admin", diff --git a/pkg/client/genericinformers/interface.go b/pkg/client/genericinformers/interface.go index a128f56d40e2..98ecb75319c4 100644 --- a/pkg/client/genericinformers/interface.go +++ b/pkg/client/genericinformers/interface.go @@ -13,7 +13,7 @@ type GenericResourceInformer interface { Start(stopCh <-chan struct{}) } -// genericInternalResourceInformerFunc will return an internal informer for any resource matching +// GenericInternalResourceInformerFunc will return an internal informer for any resource matching // its group resource, instead of the external version. Only valid for use where the type is accessed // via generic interfaces, such as the garbage collector with ObjectMeta. type GenericInternalResourceInformerFunc func(resource schema.GroupVersionResource) (informers.GenericInformer, error) diff --git a/pkg/cmd/server/origin/handlers.go b/pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver/handlers.go similarity index 96% rename from pkg/cmd/server/origin/handlers.go rename to pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver/handlers.go index c8ef6e136d7f..b45237e61e54 100644 --- a/pkg/cmd/server/origin/handlers.go +++ b/pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver/handlers.go @@ -1,4 +1,4 @@ -package origin +package openshiftkubeapiserver import ( "bytes" @@ -51,8 +51,8 @@ func (f *userAgentFilter) matches(verb, userAgent string) bool { // versionSkewFilter adds a filter that may deny requests from skewed // oc clients, since we know that those clients will strip unknown fields which can lead to unexpected outcomes -func (c *MasterConfig) versionSkewFilter(handler http.Handler) http.Handler { - filterConfig := c.Options.PolicyConfig.UserAgentMatchingConfig +func versionSkewFilter(handler http.Handler, kubeAPIServerConfig *configapi.MasterConfig) http.Handler { + filterConfig := kubeAPIServerConfig.PolicyConfig.UserAgentMatchingConfig if len(filterConfig.RequiredClients) == 0 && len(filterConfig.DeniedClients) == 0 { return handler } diff --git a/pkg/cmd/server/origin/handlers_test.go b/pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver/handlers_test.go similarity index 91% rename from pkg/cmd/server/origin/handlers_test.go rename to pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver/handlers_test.go index 4ed2a030c310..409591c8a4aa 100644 --- a/pkg/cmd/server/origin/handlers_test.go +++ b/pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver/handlers_test.go @@ -1,4 +1,4 @@ -package origin +package openshiftkubeapiserver import ( "io/ioutil" @@ -117,12 +117,12 @@ func TestVersionSkewFilterDenyOld(t *testing.T) { verbs := []string{"PATCH", "POST"} doNothingHandler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { }) - config := MasterConfig{} - config.Options.PolicyConfig.UserAgentMatchingConfig.DeniedClients = []configapi.UserAgentDenyRule{ + config := &configapi.MasterConfig{} + config.PolicyConfig.UserAgentMatchingConfig.DeniedClients = []configapi.UserAgentDenyRule{ {UserAgentMatchRule: configapi.UserAgentMatchRule{Regex: `\w+/v1\.1\.10 \(.+/.+\) kubernetes/\w{7}`, HTTPVerbs: verbs}, RejectionMessage: "rejected for reasons!"}, {UserAgentMatchRule: configapi.UserAgentMatchRule{Regex: `\w+/v(?:(?:1\.1\.1)|(?:1\.0\.1)) \(.+/.+\) openshift/\w{7}`, HTTPVerbs: verbs}, RejectionMessage: "rejected for reasons!"}, } - handler := config.versionSkewFilter(doNothingHandler) + handler := versionSkewFilter(doNothingHandler, config) server := httptest.NewServer(testHandlerChain(handler)) defer server.Close() @@ -164,13 +164,13 @@ func TestVersionSkewFilterDenySkewed(t *testing.T) { verbs := []string{"PUT", "DELETE"} doNothingHandler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { }) - config := MasterConfig{} - config.Options.PolicyConfig.UserAgentMatchingConfig.RequiredClients = []configapi.UserAgentMatchRule{ + config := &configapi.MasterConfig{} + config.PolicyConfig.UserAgentMatchingConfig.RequiredClients = []configapi.UserAgentMatchRule{ {Regex: `\w+/` + kubeServerVersion + ` \(.+/.+\) kubernetes/\w{7}`, HTTPVerbs: verbs}, {Regex: `\w+/` + openshiftServerVersion + ` \(.+/.+\) openshift/\w{7}`, HTTPVerbs: verbs}, } - config.Options.PolicyConfig.UserAgentMatchingConfig.DefaultRejectionMessage = "rejected for reasons!" - handler := config.versionSkewFilter(doNothingHandler) + config.PolicyConfig.UserAgentMatchingConfig.DefaultRejectionMessage = "rejected for reasons!" + handler := versionSkewFilter(doNothingHandler, config) server := httptest.NewServer(testHandlerChain(handler)) defer server.Close() @@ -215,14 +215,14 @@ func TestVersionSkewFilterSkippedOnNonAPIRequest(t *testing.T) { verbs := []string{"PUT", "DELETE"} doNothingHandler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { }) - config := MasterConfig{} - config.Options.PolicyConfig.UserAgentMatchingConfig.RequiredClients = []configapi.UserAgentMatchRule{ + config := &configapi.MasterConfig{} + config.PolicyConfig.UserAgentMatchingConfig.RequiredClients = []configapi.UserAgentMatchRule{ {Regex: `\w+/` + kubeServerVersion + ` \(.+/.+\) kubernetes/\w{7}`, HTTPVerbs: verbs}, {Regex: `\w+/` + openshiftServerVersion + ` \(.+/.+\) openshift/\w{7}`, HTTPVerbs: verbs}, } - config.Options.PolicyConfig.UserAgentMatchingConfig.DefaultRejectionMessage = "rejected for reasons!" + config.PolicyConfig.UserAgentMatchingConfig.DefaultRejectionMessage = "rejected for reasons!" - handler := config.versionSkewFilter(doNothingHandler) + handler := versionSkewFilter(doNothingHandler, config) server := httptest.NewServer(testHandlerChain(handler)) defer server.Close() diff --git a/pkg/cmd/server/origin/nonapiserver.go b/pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver/nonapiserver.go similarity index 78% rename from pkg/cmd/server/origin/nonapiserver.go rename to pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver/nonapiserver.go index fd81bec6ae1b..fec4578276f9 100644 --- a/pkg/cmd/server/origin/nonapiserver.go +++ b/pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver/nonapiserver.go @@ -1,13 +1,31 @@ -package origin +package openshiftkubeapiserver import ( "net/http" - genericmux "k8s.io/apiserver/pkg/server/mux" - + configapi "github.com/openshift/origin/pkg/cmd/server/apis/config" + oauthutil "github.com/openshift/origin/pkg/oauth/util" genericapiserver "k8s.io/apiserver/pkg/server" + genericmux "k8s.io/apiserver/pkg/server/mux" + "k8s.io/client-go/informers" ) +func NewOpenshiftNonAPIConfig(generiConfig *genericapiserver.Config, kubeInformers informers.SharedInformerFactory, kubeAPIServerConfig *configapi.MasterConfig) (*OpenshiftNonAPIConfig, error) { + var err error + ret := &OpenshiftNonAPIConfig{ + GenericConfig: &genericapiserver.RecommendedConfig{ + Config: *generiConfig, + SharedInformerFactory: kubeInformers, + }, + } + ret.ExtraConfig.OAuthMetadata, _, err = oauthutil.PrepOauthMetadata(*kubeAPIServerConfig) + if err != nil { + return nil, err + } + + return ret, nil +} + type NonAPIExtraConfig struct { OAuthMetadata []byte } diff --git a/pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver/patch.go b/pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver/patch.go new file mode 100644 index 000000000000..a0d46a558e64 --- /dev/null +++ b/pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver/patch.go @@ -0,0 +1,235 @@ +package openshiftkubeapiserver + +import ( + configapi "github.com/openshift/origin/pkg/cmd/server/apis/config" + usercache "github.com/openshift/origin/pkg/user/cache" + "k8s.io/apiserver/pkg/admission" + genericapiserver "k8s.io/apiserver/pkg/server" + cacheddiscovery "k8s.io/client-go/discovery/cached" + clientgoinformers "k8s.io/client-go/informers" + kexternalinformers "k8s.io/client-go/informers" + "k8s.io/client-go/rest" + "k8s.io/client-go/restmapper" + internalinformers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion" + kinternalinformers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion" + "k8s.io/kubernetes/pkg/master" + + oauthclient "github.com/openshift/client-go/oauth/clientset/versioned" + oauthinformer "github.com/openshift/client-go/oauth/informers/externalversions" + userclient "github.com/openshift/client-go/user/clientset/versioned" + userinformer "github.com/openshift/client-go/user/informers/externalversions" + originadmission "github.com/openshift/origin/pkg/cmd/server/origin/admission" + imageinformer "github.com/openshift/origin/pkg/image/generated/informers/internalversion" + imageclient "github.com/openshift/origin/pkg/image/generated/internalclientset" + quotainformer "github.com/openshift/origin/pkg/quota/generated/informers/internalversion" + quotaclient "github.com/openshift/origin/pkg/quota/generated/internalclientset" + securityinformer "github.com/openshift/origin/pkg/security/generated/informers/internalversion" + securityclient "github.com/openshift/origin/pkg/security/generated/internalclientset" + + "fmt" + "time" + + "github.com/openshift/origin/pkg/cmd/openshift-apiserver/openshiftapiserver" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/tools/cache" +) + +type KubeAPIServerServerPatchContext struct { + initialized bool + + RESTMapper *restmapper.DeferredDiscoveryRESTMapper + postStartHooks map[string]genericapiserver.PostStartHookFunc + informerStartFuncs []func(stopCh <-chan struct{}) +} + +type KubeAPIServerConfigFunc func(config *master.Config, internalInformers internalinformers.SharedInformerFactory, kubeInformers clientgoinformers.SharedInformerFactory, pluginInitializers *[]admission.PluginInitializer, stopCh <-chan struct{}) (genericapiserver.DelegationTarget, error) + +func NewOpenShiftKubeAPIServerConfigPatch(delegateAPIServer genericapiserver.DelegationTarget, kubeAPIServerConfig *configapi.MasterConfig) (KubeAPIServerConfigFunc, *KubeAPIServerServerPatchContext) { + patchContext := &KubeAPIServerServerPatchContext{ + postStartHooks: map[string]genericapiserver.PostStartHookFunc{}, + } + return func(config *master.Config, internalInformers internalinformers.SharedInformerFactory, kubeInformers clientgoinformers.SharedInformerFactory, pluginInitializers *[]admission.PluginInitializer, stopCh <-chan struct{}) (genericapiserver.DelegationTarget, error) { + kubeAPIServerInformers, err := NewInformers(internalInformers, kubeInformers, config.GenericConfig.LoopbackClientConfig) + if err != nil { + return nil, err + } + + // AUTHENTICATOR + authenticator, postStartHooks, err := NewAuthenticator( + *kubeAPIServerConfig, + config.GenericConfig.LoopbackClientConfig, + kubeAPIServerInformers.OpenshiftOAuthInformers.Oauth().V1().OAuthClients().Lister(), + kubeAPIServerInformers.OpenshiftUserInformers.User().V1().Groups()) + if err != nil { + return nil, err + } + config.GenericConfig.Authentication.Authenticator = authenticator + for key, fn := range postStartHooks { + patchContext.postStartHooks[key] = fn + } + // END AUTHENTICATOR + + // AUTHORIZER + authorizer := NewAuthorizer(internalInformers, kubeInformers) + config.GenericConfig.Authorization.Authorizer = authorizer + // END AUTHORIZER + + // ADMISSION + projectCache, err := openshiftapiserver.NewProjectCache(kubeAPIServerInformers.InternalKubernetesInformers.Core().InternalVersion().Namespaces(), config.GenericConfig.LoopbackClientConfig, kubeAPIServerConfig.ProjectConfig.DefaultNodeSelector) + if err != nil { + return nil, err + } + clusterQuotaMappingController := openshiftapiserver.NewClusterQuotaMappingController(kubeAPIServerInformers.InternalKubernetesInformers.Core().InternalVersion().Namespaces(), kubeAPIServerInformers.InternalOpenshiftQuotaInformers.Quota().InternalVersion().ClusterResourceQuotas()) + kubeClient, err := kubernetes.NewForConfig(config.GenericConfig.LoopbackClientConfig) + if err != nil { + return nil, err + } + discoveryClient := cacheddiscovery.NewMemCacheClient(kubeClient.Discovery()) + restMapper := restmapper.NewDeferredDiscoveryRESTMapper(discoveryClient) + admissionInitializer, err := originadmission.NewPluginInitializer(*kubeAPIServerConfig, config.GenericConfig.LoopbackClientConfig, kubeAPIServerInformers, config.GenericConfig.Authorization.Authorizer, projectCache, restMapper, clusterQuotaMappingController) + if err != nil { + return nil, err + } + *pluginInitializers = []admission.PluginInitializer{admissionInitializer} + // END ADMISSION + + // HANDLER CHAIN (with oauth server and web console) + config.GenericConfig.BuildHandlerChainFunc, postStartHooks, err = BuildHandlerChain(config.GenericConfig, kubeInformers, kubeAPIServerConfig, stopCh) + if err != nil { + return nil, err + } + for key, fn := range postStartHooks { + patchContext.postStartHooks[key] = fn + } + // END HANDLER CHAIN + + // CONSTRUCT DELEGATE + nonAPIServerConfig, err := NewOpenshiftNonAPIConfig(config.GenericConfig, kubeInformers, kubeAPIServerConfig) + if err != nil { + return nil, err + } + openshiftNonAPIServer, err := nonAPIServerConfig.Complete().New(delegateAPIServer) + if err != nil { + return nil, err + } + // END CONSTRUCT DELEGATE + + patchContext.informerStartFuncs = append(patchContext.informerStartFuncs, kubeAPIServerInformers.Start) + patchContext.RESTMapper = restMapper + patchContext.initialized = true + + return openshiftNonAPIServer.GenericAPIServer, nil + }, patchContext +} + +func (c *KubeAPIServerServerPatchContext) PatchServer(server *master.Master) error { + if !c.initialized { + return fmt.Errorf("not initialized with config") + } + + for name, fn := range c.postStartHooks { + server.GenericAPIServer.AddPostStartHookOrDie(name, fn) + } + server.GenericAPIServer.AddPostStartHookOrDie("openshift.io-startkubeinformers", func(context genericapiserver.PostStartHookContext) error { + for _, fn := range c.informerStartFuncs { + fn(context.StopCh) + } + return nil + }) + server.GenericAPIServer.AddPostStartHookOrDie("openshift.io-restmapperupdater", func(context genericapiserver.PostStartHookContext) error { + c.RESTMapper.Reset() + go func() { + wait.Until(func() { + c.RESTMapper.Reset() + }, 10*time.Second, context.StopCh) + }() + return nil + }) + + return nil +} + +// NewInformers is only exposed for the build's integration testing until it can be fixed more appropriately. +func NewInformers(internalInformers internalinformers.SharedInformerFactory, versionedInformers clientgoinformers.SharedInformerFactory, loopbackClientConfig *rest.Config) (*KubeAPIServerInformers, error) { + imageClient, err := imageclient.NewForConfig(loopbackClientConfig) + if err != nil { + return nil, err + } + oauthClient, err := oauthclient.NewForConfig(loopbackClientConfig) + if err != nil { + return nil, err + } + quotaClient, err := quotaclient.NewForConfig(loopbackClientConfig) + if err != nil { + return nil, err + } + securityClient, err := securityclient.NewForConfig(loopbackClientConfig) + if err != nil { + return nil, err + } + userClient, err := userclient.NewForConfig(loopbackClientConfig) + if err != nil { + return nil, err + } + + // TODO find a single place to create and start informers. During the 1.7 rebase this will come more naturally in a config object, + // before then we should try to eliminate our direct to storage access. It's making us do weird things. + const defaultInformerResyncPeriod = 10 * time.Minute + + ret := &KubeAPIServerInformers{ + InternalKubernetesInformers: internalInformers, + KubernetesInformers: versionedInformers, + InternalOpenshiftImageInformers: imageinformer.NewSharedInformerFactory(imageClient, defaultInformerResyncPeriod), + OpenshiftOAuthInformers: oauthinformer.NewSharedInformerFactory(oauthClient, defaultInformerResyncPeriod), + InternalOpenshiftQuotaInformers: quotainformer.NewSharedInformerFactory(quotaClient, defaultInformerResyncPeriod), + InternalOpenshiftSecurityInformers: securityinformer.NewSharedInformerFactory(securityClient, defaultInformerResyncPeriod), + OpenshiftUserInformers: userinformer.NewSharedInformerFactory(userClient, defaultInformerResyncPeriod), + } + if err := ret.OpenshiftUserInformers.User().V1().Groups().Informer().AddIndexers(cache.Indexers{ + usercache.ByUserIndexName: usercache.ByUserIndexKeys, + }); err != nil { + return nil, err + } + + return ret, nil +} + +type KubeAPIServerInformers struct { + InternalKubernetesInformers kinternalinformers.SharedInformerFactory + KubernetesInformers kexternalinformers.SharedInformerFactory + OpenshiftOAuthInformers oauthinformer.SharedInformerFactory + InternalOpenshiftImageInformers imageinformer.SharedInformerFactory + InternalOpenshiftQuotaInformers quotainformer.SharedInformerFactory + InternalOpenshiftSecurityInformers securityinformer.SharedInformerFactory + OpenshiftUserInformers userinformer.SharedInformerFactory +} + +func (i *KubeAPIServerInformers) GetInternalKubernetesInformers() kinternalinformers.SharedInformerFactory { + return i.InternalKubernetesInformers +} +func (i *KubeAPIServerInformers) GetKubernetesInformers() kexternalinformers.SharedInformerFactory { + return i.KubernetesInformers +} +func (i *KubeAPIServerInformers) GetInternalOpenshiftImageInformers() imageinformer.SharedInformerFactory { + return i.InternalOpenshiftImageInformers +} +func (i *KubeAPIServerInformers) GetInternalOpenshiftQuotaInformers() quotainformer.SharedInformerFactory { + return i.InternalOpenshiftQuotaInformers +} +func (i *KubeAPIServerInformers) GetInternalOpenshiftSecurityInformers() securityinformer.SharedInformerFactory { + return i.InternalOpenshiftSecurityInformers +} +func (i *KubeAPIServerInformers) GetOpenshiftUserInformers() userinformer.SharedInformerFactory { + return i.OpenshiftUserInformers +} + +func (i *KubeAPIServerInformers) Start(stopCh <-chan struct{}) { + i.InternalKubernetesInformers.Start(stopCh) + i.KubernetesInformers.Start(stopCh) + i.OpenshiftOAuthInformers.Start(stopCh) + i.InternalOpenshiftImageInformers.Start(stopCh) + i.InternalOpenshiftQuotaInformers.Start(stopCh) + i.InternalOpenshiftSecurityInformers.Start(stopCh) + i.OpenshiftUserInformers.Start(stopCh) +} diff --git a/pkg/cmd/server/origin/authenticator.go b/pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver/patch_authenticator.go similarity index 96% rename from pkg/cmd/server/origin/authenticator.go rename to pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver/patch_authenticator.go index d0aaa1ec249b..e5f99c058712 100644 --- a/pkg/cmd/server/origin/authenticator.go +++ b/pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver/patch_authenticator.go @@ -1,4 +1,4 @@ -package origin +package openshiftkubeapiserver import ( "crypto/x509" @@ -27,6 +27,7 @@ import ( oauthclientlister "github.com/openshift/client-go/oauth/listers/oauth/v1" userclient "github.com/openshift/client-go/user/clientset/versioned" usertypedclient "github.com/openshift/client-go/user/clientset/versioned/typed/user/v1" + userinformer "github.com/openshift/client-go/user/informers/externalversions/user/v1" "github.com/openshift/origin/pkg/apiserver/authentication/oauth" configapi "github.com/openshift/origin/pkg/cmd/server/apis/config" "github.com/openshift/origin/pkg/cmd/server/bootstrappolicy" @@ -38,7 +39,8 @@ import ( func NewAuthenticator( options configapi.MasterConfig, privilegedLoopbackConfig *rest.Config, - informers InformerAccess, + oauthClientLister oauthclientlister.OAuthClientLister, + groupInformer userinformer.GroupInformer, ) (authenticator.Request, map[string]genericapiserver.PostStartHookFunc, error) { kubeExternalClient, err := kclientsetexternal.NewForConfig(privilegedLoopbackConfig) if err != nil { @@ -64,11 +66,11 @@ func NewAuthenticator( return newAuthenticator( options, oauthClient.OAuthAccessTokens(), - informers.GetOpenshiftOauthInformers().Oauth().V1().OAuthClients().Lister(), + oauthClientLister, serviceAccountTokenGetter, userClient.User().Users(), apiClientCAs, - usercache.NewGroupCache(informers.GetOpenshiftUserInformers().User().V1().Groups()), + usercache.NewGroupCache(groupInformer), ) } diff --git a/pkg/cmd/server/origin/authorizer.go b/pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver/patch_authorizer.go similarity index 77% rename from pkg/cmd/server/origin/authorizer.go rename to pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver/patch_authorizer.go index 4fecf53e5f16..765b48266f6d 100644 --- a/pkg/cmd/server/origin/authorizer.go +++ b/pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver/patch_authorizer.go @@ -1,11 +1,13 @@ -package origin +package openshiftkubeapiserver import ( "k8s.io/apiserver/pkg/authentication/user" "k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/authorization/authorizerfactory" authorizerunion "k8s.io/apiserver/pkg/authorization/union" + "k8s.io/client-go/informers" "k8s.io/kubernetes/pkg/auth/nodeidentifier" + internalinformers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion" "k8s.io/kubernetes/plugin/pkg/auth/authorizer/node" rbacauthorizer "k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac" kbootstrappolicy "k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac/bootstrappolicy" @@ -14,8 +16,8 @@ import ( "github.com/openshift/origin/pkg/authorization/authorizer/scope" ) -func NewAuthorizer(informers InformerAccess, projectRequestDenyMessage string) authorizer.Authorizer { - rbacInformers := informers.GetKubernetesInformers().Rbac().V1() +func NewAuthorizer(internalInformers internalinformers.SharedInformerFactory, versionedInformers informers.SharedInformerFactory) authorizer.Authorizer { + rbacInformers := versionedInformers.Rbac().V1() scopeLimitedAuthorizer := scope.NewAuthorizer(rbacInformers.ClusterRoles().Lister()) @@ -29,10 +31,10 @@ func NewAuthorizer(informers InformerAccess, projectRequestDenyMessage string) a graph := node.NewGraph() node.AddGraphEventHandlers( graph, - informers.GetInternalKubernetesInformers().Core().InternalVersion().Nodes(), - informers.GetInternalKubernetesInformers().Core().InternalVersion().Pods(), - informers.GetInternalKubernetesInformers().Core().InternalVersion().PersistentVolumes(), - informers.GetKubernetesInformers().Storage().V1beta1().VolumeAttachments(), + internalInformers.Core().InternalVersion().Nodes(), + internalInformers.Core().InternalVersion().Pods(), + internalInformers.Core().InternalVersion().PersistentVolumes(), + versionedInformers.Storage().V1beta1().VolumeAttachments(), ) nodeAuthorizer := node.NewAuthorizer(graph, nodeidentifier.NewDefaultNodeIdentifier(), kbootstrappolicy.NodeRules()) diff --git a/pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver/patch_handlerchain.go b/pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver/patch_handlerchain.go new file mode 100644 index 000000000000..f783ce8262cd --- /dev/null +++ b/pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver/patch_handlerchain.go @@ -0,0 +1,94 @@ +package openshiftkubeapiserver + +import ( + "net/http" + "strings" + + "io/ioutil" + + "github.com/golang/glog" + "github.com/openshift/origin/pkg/cmd/openshift-apiserver/openshiftapiserver/configprocessing" + configapi "github.com/openshift/origin/pkg/cmd/server/apis/config" + "github.com/openshift/origin/pkg/oauth/urls" + genericapiserver "k8s.io/apiserver/pkg/server" + "k8s.io/client-go/informers" + aggregatorapiserver "k8s.io/kube-aggregator/pkg/apiserver" +) + +const ( + openShiftOAuthAPIPrefix = "/oauth" + openShiftLoginPrefix = "/login" + openShiftOAuthCallbackPrefix = "/oauth2callback" +) + +func BuildHandlerChain(genericConfig *genericapiserver.Config, kubeInformers informers.SharedInformerFactory, kubeAPIServerConfig *configapi.MasterConfig, stopCh <-chan struct{}) (func(apiHandler http.Handler, kc *genericapiserver.Config) http.Handler, map[string]genericapiserver.PostStartHookFunc, error) { + webconsoleProxyHandler, err := newWebConsoleProxy(genericConfig, kubeInformers, kubeAPIServerConfig) + if err != nil { + return nil, nil, err + } + oauthServerHandler, extraPostStartHooks, err := NewOAuthServerHandler(genericConfig, kubeAPIServerConfig) + if err != nil { + return nil, nil, err + } + + return func(apiHandler http.Handler, genericConfig *genericapiserver.Config) http.Handler { + // Machinery that let's use discover the Web Console Public URL + accessor := newWebConsolePublicURLAccessor(genericConfig.LoopbackClientConfig) + go accessor.Run(stopCh) + + // these are after the kube handler + handler := versionSkewFilter(apiHandler, kubeAPIServerConfig) + + // this is the normal kube handler chain + handler = genericapiserver.DefaultBuildHandlerChain(handler, genericConfig) + + // these handlers are all before the normal kube chain + handler = translateLegacyScopeImpersonation(handler) + handler = configprocessing.WithCacheControl(handler, "no-store") // protected endpoints should not be cached + + // redirects from / to /console if you're using a browser + handler = withAssetServerRedirect(handler, accessor) + + // these handlers are actually separate API servers which have their own handler chains. + // our server embeds these + handler = withConsoleRedirection(handler, webconsoleProxyHandler, accessor) + handler = withOAuthRedirection(kubeAPIServerConfig, handler, oauthServerHandler) + + return handler + }, + extraPostStartHooks, + nil +} + +func newWebConsoleProxy(genericConfig *genericapiserver.Config, kubeInformers informers.SharedInformerFactory, kubeAPIServerConfig *configapi.MasterConfig) (http.Handler, error) { + caBundle, err := ioutil.ReadFile(kubeAPIServerConfig.ControllerConfig.ServiceServingCert.Signer.CertFile) + if err != nil { + return nil, err + } + proxyHandler, err := newServiceProxyHandler("webconsole", "openshift-web-console", aggregatorapiserver.NewClusterIPServiceResolver(kubeInformers.Core().V1().Services().Lister()), caBundle, "OpenShift web console") + if err != nil { + return nil, err + } + return proxyHandler, nil +} + +func withOAuthRedirection(kubeAPIServerConfig *configapi.MasterConfig, handler, oauthServerHandler http.Handler) http.Handler { + if kubeAPIServerConfig.OAuthConfig == nil { + return handler + } + + glog.Infof("Starting OAuth2 API at %s", urls.OpenShiftOAuthAPIPrefix) + return WithPatternPrefixHandler(handler, oauthServerHandler, openShiftOAuthAPIPrefix, openShiftLoginPrefix, openShiftOAuthCallbackPrefix) +} + +func WithPatternPrefixHandler(handler http.Handler, patternHandler http.Handler, prefixes ...string) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + for _, p := range prefixes { + if strings.HasPrefix(req.URL.Path, p) { + patternHandler.ServeHTTP(w, req) + return + } + } + handler.ServeHTTP(w, req) + }) +} diff --git a/pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver/patch_oauthserver.go b/pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver/patch_oauthserver.go new file mode 100644 index 000000000000..4d076fe020fd --- /dev/null +++ b/pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver/patch_oauthserver.go @@ -0,0 +1,63 @@ +package openshiftkubeapiserver + +import ( + "net/http" + + "github.com/openshift/origin/pkg/oauthserver/oauthserver" + genericapiserver "k8s.io/apiserver/pkg/server" + "k8s.io/client-go/kubernetes" + + routeclient "github.com/openshift/client-go/route/clientset/versioned/typed/route/v1" + configapi "github.com/openshift/origin/pkg/cmd/server/apis/config" +) + +// TODO this is taking a very large config for a small piece of it. The information must be broken up at some point so that +// we can run this in a pod. This is an indication of leaky abstraction because it spent too much time in openshift start +func NewOAuthServerConfigFromMasterConfig(genericConfig *genericapiserver.Config, kubeAPIServerConfig *configapi.MasterConfig) (*oauthserver.OAuthServerConfig, error) { + oauthServerConfig, err := oauthserver.NewOAuthServerConfig(*kubeAPIServerConfig.OAuthConfig, genericConfig.LoopbackClientConfig) + if err != nil { + return nil, err + } + + oauthServerConfig.GenericConfig.CorsAllowedOriginList = genericConfig.CorsAllowedOriginList + oauthServerConfig.GenericConfig.SecureServing = genericConfig.SecureServing + oauthServerConfig.GenericConfig.AuditBackend = genericConfig.AuditBackend + oauthServerConfig.GenericConfig.AuditPolicyChecker = genericConfig.AuditPolicyChecker + + routeClient, err := routeclient.NewForConfig(genericConfig.LoopbackClientConfig) + if err != nil { + return nil, err + } + kubeClient, err := kubernetes.NewForConfig(genericConfig.LoopbackClientConfig) + if err != nil { + return nil, err + } + + oauthServerConfig.ExtraOAuthConfig.RouteClient = routeClient + oauthServerConfig.ExtraOAuthConfig.KubeClient = kubeClient + + // Build the list of valid redirect_uri prefixes for a login using the openshift-web-console client to redirect to + oauthServerConfig.ExtraOAuthConfig.AssetPublicAddresses = []string{kubeAPIServerConfig.OAuthConfig.AssetPublicURL} + + return oauthServerConfig, nil +} + +func NewOAuthServerHandler(genericConfig *genericapiserver.Config, kubeAPIServerConfig *configapi.MasterConfig) (http.Handler, map[string]genericapiserver.PostStartHookFunc, error) { + if kubeAPIServerConfig.OAuthConfig == nil { + return http.NotFoundHandler(), nil, nil + } + + config, err := NewOAuthServerConfigFromMasterConfig(genericConfig, kubeAPIServerConfig) + if err != nil { + return nil, nil, err + } + oauthServer, err := config.Complete().New(genericapiserver.NewEmptyDelegate()) + if err != nil { + return nil, nil, err + } + return oauthServer.GenericAPIServer.PrepareRun().GenericAPIServer.Handler.FullHandlerChain, + map[string]genericapiserver.PostStartHookFunc{ + "oauth.openshift.io-startoauthclientsbootstrapping": config.StartOAuthClientsBootstrapping, + }, + nil +} diff --git a/pkg/cmd/server/origin/service_proxy_handler.go b/pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver/service_proxy_handler.go similarity index 96% rename from pkg/cmd/server/origin/service_proxy_handler.go rename to pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver/service_proxy_handler.go index b5ae7fba8c4c..a595516911ad 100644 --- a/pkg/cmd/server/origin/service_proxy_handler.go +++ b/pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver/service_proxy_handler.go @@ -1,4 +1,4 @@ -package origin +package openshiftkubeapiserver import ( "context" @@ -90,8 +90,8 @@ type serviceProxyHandler struct { restConfig *restclient.Config } -// NewServiceProxyHandler is a simple proxy that doesn't handle upgrades, passes headers directly through, and doesn't assert any identity. -func NewServiceProxyHandler(serviceName string, serviceNamespace string, serviceResolver ServiceResolver, caBundle []byte, applicationDisplayName string) (*serviceProxyHandler, error) { +// newServiceProxyHandler is a simple proxy that doesn't handle upgrades, passes headers directly through, and doesn't assert any identity. +func newServiceProxyHandler(serviceName string, serviceNamespace string, serviceResolver ServiceResolver, caBundle []byte, applicationDisplayName string) (*serviceProxyHandler, error) { restConfig := &restclient.Config{ TLSClientConfig: restclient.TLSClientConfig{ ServerName: serviceName + "." + serviceNamespace + ".svc", diff --git a/pkg/cmd/server/origin/webconsole_proxy.go b/pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver/webconsole_proxy.go similarity index 93% rename from pkg/cmd/server/origin/webconsole_proxy.go rename to pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver/webconsole_proxy.go index 32257cea4a89..9beddda86c6a 100644 --- a/pkg/cmd/server/origin/webconsole_proxy.go +++ b/pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver/webconsole_proxy.go @@ -1,4 +1,4 @@ -package origin +package openshiftkubeapiserver import ( "fmt" @@ -40,7 +40,7 @@ func withAssetServerRedirect(handler http.Handler, accessor *webConsolePublicURL }) } -func (c *MasterConfig) withConsoleRedirection(handler, assetServerHandler http.Handler, accessor *webConsolePublicURLAccessor) http.Handler { +func withConsoleRedirection(handler, assetServerHandler http.Handler, accessor *webConsolePublicURLAccessor) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { // blacklist well known paths so we do not risk recursion deadlocks for _, prefix := range []string{"/apis", "/api", "/oapi", "/healthz", "/version"} { @@ -85,9 +85,9 @@ type webConsolePublicURLAccessor struct { polling time.Duration } -func newWebConsolePublicURLAccessor(clientConfig rest.Config) *webConsolePublicURLAccessor { +func newWebConsolePublicURLAccessor(clientConfig *rest.Config) *webConsolePublicURLAccessor { accessor := &webConsolePublicURLAccessor{ - configMapGetter: coreclientv1.NewForConfigOrDie(&clientConfig), + configMapGetter: coreclientv1.NewForConfigOrDie(clientConfig), } return accessor } diff --git a/pkg/cmd/server/origin/admission/plugin_initializer.go b/pkg/cmd/server/origin/admission/plugin_initializer.go index 97c2eaad8b73..c9caca43e0b2 100644 --- a/pkg/cmd/server/origin/admission/plugin_initializer.go +++ b/pkg/cmd/server/origin/admission/plugin_initializer.go @@ -147,3 +147,31 @@ func NewPluginInitializer( return admission.PluginInitializers{genericInitializer, webhookInitializer, kubePluginInitializer, openshiftPluginInitializer}, nil } + +type DefaultInformerAccess struct { + InternalKubernetesInformers kinternalinformers.SharedInformerFactory + KubernetesInformers kexternalinformers.SharedInformerFactory + InternalOpenshiftImageInformers imageinformer.SharedInformerFactory + InternalOpenshiftQuotaInformers quotainformer.SharedInformerFactory + InternalOpenshiftSecurityInformers securityinformer.SharedInformerFactory + OpenshiftUserInformers userinformer.SharedInformerFactory +} + +func (i *DefaultInformerAccess) GetInternalKubernetesInformers() kinternalinformers.SharedInformerFactory { + return i.InternalKubernetesInformers +} +func (i *DefaultInformerAccess) GetKubernetesInformers() kexternalinformers.SharedInformerFactory { + return i.KubernetesInformers +} +func (i *DefaultInformerAccess) GetInternalOpenshiftImageInformers() imageinformer.SharedInformerFactory { + return i.InternalOpenshiftImageInformers +} +func (i *DefaultInformerAccess) GetInternalOpenshiftQuotaInformers() quotainformer.SharedInformerFactory { + return i.InternalOpenshiftQuotaInformers +} +func (i *DefaultInformerAccess) GetInternalOpenshiftSecurityInformers() securityinformer.SharedInformerFactory { + return i.InternalOpenshiftSecurityInformers +} +func (i *DefaultInformerAccess) GetOpenshiftUserInformers() userinformer.SharedInformerFactory { + return i.OpenshiftUserInformers +} diff --git a/pkg/cmd/server/origin/master.go b/pkg/cmd/server/origin/master.go index 1837a205a3a0..c10559e2210d 100644 --- a/pkg/cmd/server/origin/master.go +++ b/pkg/cmd/server/origin/master.go @@ -4,7 +4,6 @@ import ( "fmt" "io/ioutil" "net/http" - "strings" "time" "github.com/golang/glog" @@ -19,22 +18,15 @@ import ( "github.com/openshift/origin/pkg/cmd/openshift-apiserver/openshiftapiserver" "github.com/openshift/origin/pkg/cmd/openshift-apiserver/openshiftapiserver/configprocessing" + "github.com/openshift/origin/pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver" "github.com/openshift/origin/pkg/cmd/server/bootstrappolicy" kubernetes "github.com/openshift/origin/pkg/cmd/server/kubernetes/master" cmdutil "github.com/openshift/origin/pkg/cmd/util" - "github.com/openshift/origin/pkg/oauth/urls" - oauthutil "github.com/openshift/origin/pkg/oauth/util" sccstorage "github.com/openshift/origin/pkg/security/apiserver/registry/securitycontextconstraints/etcd" "k8s.io/apimachinery/pkg/util/wait" kapiserveroptions "k8s.io/kubernetes/cmd/kube-apiserver/app/options" ) -const ( - openShiftOAuthAPIPrefix = "/oauth" - openShiftLoginPrefix = "/login" - openShiftOAuthCallbackPrefix = "/oauth2callback" -) - func (c *MasterConfig) newOpenshiftAPIConfig(kubeAPIServerConfig apiserver.Config) (*openshiftapiserver.OpenshiftAPIConfig, error) { // sccStorage must use the upstream RESTOptionsGetter to be in the correct location // this probably creates a duplicate cache, but there are not very many SCCs, so live with it to avoid further linkage @@ -94,22 +86,6 @@ func (c *MasterConfig) newOpenshiftAPIConfig(kubeAPIServerConfig apiserver.Confi return ret, ret.ExtraConfig.Validate() } -func (c *MasterConfig) newOpenshiftNonAPIConfig(kubeAPIServerConfig apiserver.Config) (*OpenshiftNonAPIConfig, error) { - var err error - ret := &OpenshiftNonAPIConfig{ - GenericConfig: &apiserver.RecommendedConfig{ - Config: kubeAPIServerConfig, - SharedInformerFactory: c.ClientGoKubeInformers, - }, - } - ret.ExtraConfig.OAuthMetadata, _, err = oauthutil.PrepOauthMetadata(c.Options) - if err != nil { - return nil, err - } - - return ret, nil -} - func (c *MasterConfig) withAPIExtensions(delegateAPIServer apiserver.DelegationTarget, kubeAPIServerOptions *kapiserveroptions.ServerRunOptions, kubeAPIServerConfig apiserver.Config) (apiserver.DelegationTarget, apiextensionsinformers.SharedInformerFactory, error) { apiExtensionsConfig, err := createAPIExtensionsConfig(kubeAPIServerConfig, c.ClientGoKubeInformers, kubeAPIServerOptions) if err != nil { @@ -123,7 +99,7 @@ func (c *MasterConfig) withAPIExtensions(delegateAPIServer apiserver.DelegationT } func (c *MasterConfig) withNonAPIRoutes(delegateAPIServer apiserver.DelegationTarget, kubeAPIServerConfig apiserver.Config) (apiserver.DelegationTarget, error) { - openshiftNonAPIConfig, err := c.newOpenshiftNonAPIConfig(kubeAPIServerConfig) + openshiftNonAPIConfig, err := openshiftkubeapiserver.NewOpenshiftNonAPIConfig(&kubeAPIServerConfig, c.ClientGoKubeInformers, &c.Options) if err != nil { return nil, err } @@ -171,40 +147,6 @@ func (c *MasterConfig) withKubeAPI(delegateAPIServer apiserver.DelegationTarget, return preparedKubeAPIServer.GenericAPIServer, nil } -func (c *MasterConfig) newWebConsoleProxy() (http.Handler, error) { - caBundle, err := ioutil.ReadFile(c.Options.ControllerConfig.ServiceServingCert.Signer.CertFile) - if err != nil { - return nil, err - } - proxyHandler, err := NewServiceProxyHandler("webconsole", "openshift-web-console", aggregatorapiserver.NewClusterIPServiceResolver(c.ClientGoKubeInformers.Core().V1().Services().Lister()), caBundle, "OpenShift web console") - if err != nil { - return nil, err - } - return proxyHandler, nil -} - -func (c *MasterConfig) newOAuthServerHandler(genericConfig *apiserver.Config) (http.Handler, map[string]apiserver.PostStartHookFunc, error) { - if c.Options.OAuthConfig == nil { - return http.NotFoundHandler(), nil, nil - } - - config, err := NewOAuthServerConfigFromMasterConfig(c, genericConfig.SecureServing.Listener) - if err != nil { - return nil, nil, err - } - config.GenericConfig.AuditBackend = genericConfig.AuditBackend - config.GenericConfig.AuditPolicyChecker = genericConfig.AuditPolicyChecker - oauthServer, err := config.Complete().New(apiserver.NewEmptyDelegate()) - if err != nil { - return nil, nil, err - } - return oauthServer.GenericAPIServer.PrepareRun().GenericAPIServer.Handler.FullHandlerChain, - map[string]apiserver.PostStartHookFunc{ - "oauth.openshift.io-StartOAuthClientsBootstrapping": config.StartOAuthClientsBootstrapping, - }, - nil -} - func (c *MasterConfig) withAggregator(delegateAPIServer apiserver.DelegationTarget, kubeAPIServerOptions *kapiserveroptions.ServerRunOptions, kubeAPIServerConfig apiserver.Config, apiExtensionsInformers apiextensionsinformers.SharedInformerFactory) (*aggregatorapiserver.APIAggregator, error) { aggregatorConfig, err := createAggregatorConfig( kubeAPIServerConfig, @@ -234,7 +176,7 @@ func (c *MasterConfig) Run(stopCh <-chan struct{}) error { var delegateAPIServer apiserver.DelegationTarget var extraPostStartHooks map[string]apiserver.PostStartHookFunc - c.kubeAPIServerConfig.GenericConfig.BuildHandlerChainFunc, extraPostStartHooks, err = c.buildHandlerChain(c.kubeAPIServerConfig.GenericConfig, stopCh) + c.kubeAPIServerConfig.GenericConfig.BuildHandlerChainFunc, extraPostStartHooks, err = openshiftkubeapiserver.BuildHandlerChain(c.kubeAPIServerConfig.GenericConfig, c.ClientGoKubeInformers, &c.Options, stopCh) if err != nil { return err } @@ -305,7 +247,7 @@ func (c *MasterConfig) RunKubeAPIServer(stopCh <-chan struct{}) error { var delegateAPIServer apiserver.DelegationTarget var extraPostStartHooks map[string]apiserver.PostStartHookFunc - c.kubeAPIServerConfig.GenericConfig.BuildHandlerChainFunc, extraPostStartHooks, err = c.buildHandlerChain(c.kubeAPIServerConfig.GenericConfig, stopCh) + c.kubeAPIServerConfig.GenericConfig.BuildHandlerChainFunc, extraPostStartHooks, err = openshiftkubeapiserver.BuildHandlerChain(c.kubeAPIServerConfig.GenericConfig, c.ClientGoKubeInformers, &c.Options, stopCh) if err != nil { return err } @@ -375,66 +317,6 @@ func (c *MasterConfig) RunKubeAPIServer(stopCh <-chan struct{}) error { return cmdutil.WaitForSuccessfulDial(true, c.Options.ServingInfo.BindNetwork, c.Options.ServingInfo.BindAddress, 100*time.Millisecond, 100*time.Millisecond, 100) } -func (c *MasterConfig) buildHandlerChain(genericConfig *apiserver.Config, stopCh <-chan struct{}) (func(apiHandler http.Handler, kc *apiserver.Config) http.Handler, map[string]apiserver.PostStartHookFunc, error) { - webconsoleProxyHandler, err := c.newWebConsoleProxy() - if err != nil { - return nil, nil, err - } - oauthServerHandler, extraPostStartHooks, err := c.newOAuthServerHandler(genericConfig) - if err != nil { - return nil, nil, err - } - - return func(apiHandler http.Handler, genericConfig *apiserver.Config) http.Handler { - // Machinery that let's use discover the Web Console Public URL - accessor := newWebConsolePublicURLAccessor(c.PrivilegedLoopbackClientConfig) - go accessor.Run(stopCh) - - // these are after the kube handler - handler := c.versionSkewFilter(apiHandler) - - // this is the normal kube handler chain - handler = apiserver.DefaultBuildHandlerChain(handler, genericConfig) - - // these handlers are all before the normal kube chain - handler = translateLegacyScopeImpersonation(handler) - handler = configprocessing.WithCacheControl(handler, "no-store") // protected endpoints should not be cached - - // redirects from / to /console if you're using a browser - handler = withAssetServerRedirect(handler, accessor) - - // these handlers are actually separate API servers which have their own handler chains. - // our server embeds these - handler = c.withConsoleRedirection(handler, webconsoleProxyHandler, accessor) - handler = c.withOAuthRedirection(handler, oauthServerHandler) - - return handler - }, - extraPostStartHooks, - nil -} - -func (c *MasterConfig) withOAuthRedirection(handler, oauthServerHandler http.Handler) http.Handler { - if c.Options.OAuthConfig == nil { - return handler - } - - glog.Infof("Starting OAuth2 API at %s", urls.OpenShiftOAuthAPIPrefix) - return WithPatternPrefixHandler(handler, oauthServerHandler, openShiftOAuthAPIPrefix, openShiftLoginPrefix, openShiftOAuthCallbackPrefix) -} - -func WithPatternPrefixHandler(handler http.Handler, patternHandler http.Handler, prefixes ...string) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - for _, p := range prefixes { - if strings.HasPrefix(req.URL.Path, p) { - patternHandler.ServeHTTP(w, req) - return - } - } - handler.ServeHTTP(w, req) - }) -} - // bootstrapData casts our policy data to the rbacrest helper that can // materialize the policy. func bootstrapData(data *bootstrappolicy.PolicyData) *rbacrest.PolicyData { diff --git a/pkg/cmd/server/origin/master_config.go b/pkg/cmd/server/origin/master_config.go index e64d33e84ca3..d15db0f280b2 100644 --- a/pkg/cmd/server/origin/master_config.go +++ b/pkg/cmd/server/origin/master_config.go @@ -24,6 +24,7 @@ import ( routeinformer "github.com/openshift/client-go/route/informers/externalversions" userinformer "github.com/openshift/client-go/user/informers/externalversions" authorizationinformer "github.com/openshift/origin/pkg/authorization/generated/informers/internalversion" + "github.com/openshift/origin/pkg/cmd/openshift-kube-apiserver/openshiftkubeapiserver" configapi "github.com/openshift/origin/pkg/cmd/server/apis/config" kubernetes "github.com/openshift/origin/pkg/cmd/server/kubernetes/master" originadmission "github.com/openshift/origin/pkg/cmd/server/origin/admission" @@ -149,11 +150,11 @@ func BuildMasterConfig( return nil, err } - authenticator, authenticatorPostStartHooks, err := NewAuthenticator(options, privilegedLoopbackConfig, informers) + authenticator, authenticatorPostStartHooks, err := openshiftkubeapiserver.NewAuthenticator(options, privilegedLoopbackConfig, informers.GetOpenshiftOauthInformers().Oauth().V1().OAuthClients().Lister(), informers.GetOpenshiftUserInformers().User().V1().Groups()) if err != nil { return nil, err } - authorizer := NewAuthorizer(informers, options.ProjectConfig.ProjectRequestMessage) + authorizer := openshiftkubeapiserver.NewAuthorizer(informers.GetInternalKubernetesInformers(), informers.GetKubernetesInformers()) projectCache, err := openshiftapiserver.NewProjectCache(informers.GetInternalKubernetesInformers().Core().InternalVersion().Namespaces(), privilegedLoopbackConfig, options.ProjectConfig.DefaultNodeSelector) if err != nil { return nil, err diff --git a/pkg/cmd/server/origin/oauth_apiserver_adapter.go b/pkg/cmd/server/origin/oauth_apiserver_adapter.go deleted file mode 100644 index 7d16c066b2f7..000000000000 --- a/pkg/cmd/server/origin/oauth_apiserver_adapter.go +++ /dev/null @@ -1,71 +0,0 @@ -package origin - -import ( - "net" - "strconv" - - apiserveroptions "k8s.io/apiserver/pkg/server/options" - utilflag "k8s.io/apiserver/pkg/util/flag" - - routeclient "github.com/openshift/client-go/route/clientset/versioned/typed/route/v1" - "github.com/openshift/library-go/pkg/crypto" - "github.com/openshift/origin/pkg/oauthserver/oauthserver" -) - -// TODO this is taking a very large config for a small piece of it. The information must be broken up at some point so that -// we can run this in a pod. This is an indication of leaky abstraction because it spent too much time in openshift start -func NewOAuthServerConfigFromMasterConfig(masterConfig *MasterConfig, listener net.Listener) (*oauthserver.OAuthServerConfig, error) { - options := masterConfig.Options - servingConfig := options.ServingInfo - oauthConfig := masterConfig.Options.OAuthConfig - - oauthServerConfig, err := oauthserver.NewOAuthServerConfig(*oauthConfig, &masterConfig.PrivilegedLoopbackClientConfig) - if err != nil { - return nil, err - } - - oauthServerConfig.GenericConfig.CorsAllowedOriginList = options.CORSAllowedOrigins - - // TODO pull this out into a function - host, portString, err := net.SplitHostPort(servingConfig.BindAddress) - if err != nil { - return nil, err - } - port, err := strconv.Atoi(portString) - if err != nil { - return nil, err - } - secureServingOptions := apiserveroptions.SecureServingOptions{} - secureServingOptions.Listener = listener - secureServingOptions.BindAddress = net.ParseIP(host) - secureServingOptions.BindNetwork = servingConfig.BindNetwork - secureServingOptions.BindPort = port - secureServingOptions.ServerCert.CertKey.CertFile = servingConfig.ServerCert.CertFile - secureServingOptions.ServerCert.CertKey.KeyFile = servingConfig.ServerCert.KeyFile - for _, nc := range servingConfig.NamedCertificates { - sniCert := utilflag.NamedCertKey{ - CertFile: nc.CertFile, - KeyFile: nc.KeyFile, - Names: nc.Names, - } - secureServingOptions.SNICertKeys = append(secureServingOptions.SNICertKeys, sniCert) - } - if err := secureServingOptions.ApplyTo(&oauthServerConfig.GenericConfig.Config.SecureServing); err != nil { - return nil, err - } - oauthServerConfig.GenericConfig.SecureServing.MinTLSVersion = crypto.TLSVersionOrDie(servingConfig.MinTLSVersion) - oauthServerConfig.GenericConfig.SecureServing.CipherSuites = crypto.CipherSuitesOrDie(servingConfig.CipherSuites) - - routeClient, err := routeclient.NewForConfig(&masterConfig.PrivilegedLoopbackClientConfig) - if err != nil { - return nil, err - } - // TODO pass a privileged client config through during construction. It is NOT a loopback client. - oauthServerConfig.ExtraOAuthConfig.RouteClient = routeClient - oauthServerConfig.ExtraOAuthConfig.KubeClient = masterConfig.PrivilegedLoopbackKubernetesClientsetExternal - - // Build the list of valid redirect_uri prefixes for a login using the openshift-web-console client to redirect to - oauthServerConfig.ExtraOAuthConfig.AssetPublicAddresses = []string{oauthConfig.AssetPublicURL} - - return oauthServerConfig, nil -} diff --git a/test/integration/master_routes_test.go b/test/integration/master_routes_test.go index e1ae4442d018..a3b3a65d590d 100644 --- a/test/integration/master_routes_test.go +++ b/test/integration/master_routes_test.go @@ -119,7 +119,7 @@ var expectedIndex = []string{ "/healthz/poststarthook/generic-apiserver-start-informers", "/healthz/poststarthook/image.openshift.io-apiserver-caches", "/healthz/poststarthook/kube-apiserver-autoregistration", - "/healthz/poststarthook/oauth.openshift.io-StartOAuthClientsBootstrapping", + "/healthz/poststarthook/oauth.openshift.io-startoauthclientsbootstrapping", "/healthz/poststarthook/openshift.io-restmapperupdater", "/healthz/poststarthook/openshift.io-startinformers", "/healthz/poststarthook/project.openshift.io-projectauthorizationcache",