package origin import ( "crypto/rsa" "crypto/x509" "errors" "fmt" "path" "time" newetcdclient "github.com/coreos/etcd/client" etcdclient "github.com/coreos/go-etcd/etcd" "github.com/golang/glog" "k8s.io/kubernetes/pkg/admission" kapi "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/apiserver" "k8s.io/kubernetes/pkg/client/cache" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/client/restclient" kclient "k8s.io/kubernetes/pkg/client/unversioned" clientadapter "k8s.io/kubernetes/pkg/client/unversioned/adapters/internalclientset" sacontroller "k8s.io/kubernetes/pkg/controller/serviceaccount" genericapiserveroptions "k8s.io/kubernetes/pkg/genericapiserver/options" kubeletclient "k8s.io/kubernetes/pkg/kubelet/client" "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/serviceaccount" "k8s.io/kubernetes/pkg/storage" etcdstorage "k8s.io/kubernetes/pkg/storage/etcd" kutilrand "k8s.io/kubernetes/pkg/util/rand" "k8s.io/kubernetes/pkg/util/sets" "k8s.io/kubernetes/pkg/watch" "github.com/openshift/origin/pkg/auth/authenticator" "github.com/openshift/origin/pkg/auth/authenticator/anonymous" "github.com/openshift/origin/pkg/auth/authenticator/request/bearertoken" "github.com/openshift/origin/pkg/auth/authenticator/request/paramtoken" "github.com/openshift/origin/pkg/auth/authenticator/request/unionrequest" "github.com/openshift/origin/pkg/auth/authenticator/request/x509request" "github.com/openshift/origin/pkg/auth/group" authnregistry "github.com/openshift/origin/pkg/auth/oauth/registry" "github.com/openshift/origin/pkg/auth/userregistry/identitymapper" authorizationapi "github.com/openshift/origin/pkg/authorization/api" "github.com/openshift/origin/pkg/authorization/authorizer" "github.com/openshift/origin/pkg/authorization/authorizer/scope" clusterpolicyregistry "github.com/openshift/origin/pkg/authorization/registry/clusterpolicy" clusterpolicyetcd "github.com/openshift/origin/pkg/authorization/registry/clusterpolicy/etcd" clusterpolicybindingregistry "github.com/openshift/origin/pkg/authorization/registry/clusterpolicybinding" clusterpolicybindingetcd "github.com/openshift/origin/pkg/authorization/registry/clusterpolicybinding/etcd" policyregistry "github.com/openshift/origin/pkg/authorization/registry/policy" policyetcd "github.com/openshift/origin/pkg/authorization/registry/policy/etcd" policybindingregistry "github.com/openshift/origin/pkg/authorization/registry/policybinding" policybindingetcd "github.com/openshift/origin/pkg/authorization/registry/policybinding/etcd" "github.com/openshift/origin/pkg/authorization/rulevalidation" osclient "github.com/openshift/origin/pkg/client" oadmission "github.com/openshift/origin/pkg/cmd/server/admission" configapi "github.com/openshift/origin/pkg/cmd/server/api" "github.com/openshift/origin/pkg/cmd/server/bootstrappolicy" "github.com/openshift/origin/pkg/cmd/server/etcd" "github.com/openshift/origin/pkg/cmd/util/plug" "github.com/openshift/origin/pkg/cmd/util/pluginconfig" "github.com/openshift/origin/pkg/cmd/util/variable" "github.com/openshift/origin/pkg/controller/shared" imageadmission "github.com/openshift/origin/pkg/image/admission" accesstokenregistry "github.com/openshift/origin/pkg/oauth/registry/oauthaccesstoken" accesstokenetcd "github.com/openshift/origin/pkg/oauth/registry/oauthaccesstoken/etcd" projectauth "github.com/openshift/origin/pkg/project/auth" projectcache "github.com/openshift/origin/pkg/project/cache" "github.com/openshift/origin/pkg/quota" quotaadmission "github.com/openshift/origin/pkg/quota/admission/resourcequota" "github.com/openshift/origin/pkg/quota/controller/clusterquotamapping" "github.com/openshift/origin/pkg/serviceaccounts" usercache "github.com/openshift/origin/pkg/user/cache" groupregistry "github.com/openshift/origin/pkg/user/registry/group" groupstorage "github.com/openshift/origin/pkg/user/registry/group/etcd" userregistry "github.com/openshift/origin/pkg/user/registry/user" useretcd "github.com/openshift/origin/pkg/user/registry/user/etcd" "github.com/openshift/origin/pkg/util/leaderlease" "github.com/openshift/origin/pkg/util/restoptions" ) // MasterConfig defines the required parameters for starting the OpenShift master type MasterConfig struct { Options configapi.MasterConfig // RESTOptionsGetter provides access to storage and RESTOptions for a particular resource RESTOptionsGetter restoptions.Getter RuleResolver rulevalidation.AuthorizationRuleResolver Authenticator authenticator.Request Authorizer authorizer.Authorizer AuthorizationAttributeBuilder authorizer.AuthorizationAttributeBuilder GroupCache *usercache.GroupCache ProjectAuthorizationCache *projectauth.AuthorizationCache ProjectCache *projectcache.ProjectCache ClusterQuotaMappingController *clusterquotamapping.ClusterQuotaMappingController // RequestContextMapper maps requests to contexts RequestContextMapper kapi.RequestContextMapper AdmissionControl admission.Interface TLS bool ControllerPlug plug.Plug ControllerPlugStart func() // ImageFor is a function that returns the appropriate image to use for a named component ImageFor func(component string) string // TODO: remove direct access to EtcdHelper, require selecting by providing target resource EtcdHelper storage.Interface KubeletClientConfig *kubeletclient.KubeletClientConfig // ClientCAs will be used to request client certificates in connections to the API. // This CertPool should contain all the CAs that will be used for client certificate verification. ClientCAs *x509.CertPool // APIClientCAs is used to verify client certificates presented for API auth APIClientCAs *x509.CertPool // PluginInitializer carries types used when instantiating both origin and kubernetes admission control plugins PluginInitializer oadmission.PluginInitializer // PrivilegedLoopbackClientConfig is the client configuration used to call OpenShift APIs from system components // To apply different access control to a system component, create a client config specifically for that component. PrivilegedLoopbackClientConfig restclient.Config // PrivilegedLoopbackKubernetesClient is the client used to call Kubernetes APIs from system components, // built from KubeClientConfig. It should only be accessed via the *Client() helper methods. To apply // different access control to a system component, create a separate client/config specifically for // that component. PrivilegedLoopbackKubernetesClient *kclient.Client // PrivilegedLoopbackOpenShiftClient is the client used to call OpenShift APIs from system components, // built from PrivilegedLoopbackClientConfig. It should only be accessed via the *Client() helper methods. // To apply different access control to a system component, create a separate client/config specifically // for that component. PrivilegedLoopbackOpenShiftClient *osclient.Client // Informers is a shared factory for getting SharedInformers. It is important to get your informers, indexers, and listers // from here so that we only end up with a single cache of objects Informers shared.InformerFactory } // BuildMasterConfig builds and returns the OpenShift master configuration based on the // provided options func BuildMasterConfig(options configapi.MasterConfig) (*MasterConfig, error) { client, err := etcd.EtcdClient(options.EtcdClientInfo) if err != nil { return nil, err } etcdClient, err := etcd.MakeNewEtcdClient(options.EtcdClientInfo) if err != nil { return nil, err } groupVersion := unversioned.GroupVersion{Group: "", Version: options.EtcdStorageConfig.OpenShiftStorageVersion} etcdHelper, err := NewEtcdStorage(etcdClient, groupVersion, options.EtcdStorageConfig.OpenShiftStoragePrefix) if err != nil { return nil, fmt.Errorf("Error setting up server storage: %v", err) } restOptsGetter := restoptions.NewConfigGetter(options) clientCAs, err := configapi.GetClientCertCAPool(options) if err != nil { return nil, err } apiClientCAs, err := configapi.GetAPIClientCertCAPool(options) if err != nil { return nil, err } privilegedLoopbackKubeClient, _, err := configapi.GetKubeClient(options.MasterClients.OpenShiftLoopbackKubeConfig) if err != nil { return nil, err } privilegedLoopbackOpenShiftClient, privilegedLoopbackClientConfig, err := configapi.GetOpenShiftClient(options.MasterClients.OpenShiftLoopbackKubeConfig) if err != nil { return nil, err } customListerWatchers := shared.DefaultListerWatcherOverrides{} if err := addAuthorizationListerWatchers(customListerWatchers, restOptsGetter); err != nil { return nil, err } informerFactory := shared.NewInformerFactory(privilegedLoopbackKubeClient, privilegedLoopbackOpenShiftClient, customListerWatchers, 10*time.Minute) imageTemplate := variable.NewDefaultImageTemplate() imageTemplate.Format = options.ImageConfig.Format imageTemplate.Latest = options.ImageConfig.Latest requestContextMapper := kapi.NewRequestContextMapper() groupStorage, err := groupstorage.NewREST(restOptsGetter) if err != nil { return nil, err } groupCache := usercache.NewGroupCache(groupregistry.NewRegistry(groupStorage)) projectCache := projectcache.NewProjectCache(privilegedLoopbackKubeClient.Namespaces(), options.ProjectConfig.DefaultNodeSelector) clusterQuotaMappingController := clusterquotamapping.NewClusterQuotaMappingController(informerFactory.Namespaces(), informerFactory.ClusterResourceQuotas()) kubeletClientConfig := configapi.GetKubeletClientConfig(options) // in-order list of plug-ins that should intercept admission decisions (origin only intercepts) admissionControlPluginNames := []string{ "ProjectRequestLimit", "OriginNamespaceLifecycle", "PodNodeConstraints", "JenkinsBootstrapper", "BuildByStrategy", imageadmission.PluginName, quotaadmission.PluginName, } if len(options.AdmissionConfig.PluginOrderOverride) > 0 { admissionControlPluginNames = options.AdmissionConfig.PluginOrderOverride } quotaRegistry := quota.NewOriginQuotaRegistry(privilegedLoopbackOpenShiftClient) ruleResolver := rulevalidation.NewDefaultRuleResolver( informerFactory.Policies().Lister(), informerFactory.PolicyBindings().Lister(), informerFactory.ClusterPolicies().Lister().ClusterPolicies(), informerFactory.ClusterPolicyBindings().Lister().ClusterPolicyBindings(), ) authorizer := newAuthorizer(ruleResolver, informerFactory, options.ProjectConfig.ProjectRequestMessage) pluginInitializer := oadmission.PluginInitializer{ OpenshiftClient: privilegedLoopbackOpenShiftClient, ProjectCache: projectCache, OriginQuotaRegistry: quotaRegistry, Authorizer: authorizer, JenkinsPipelineConfig: options.JenkinsPipelineConfig, RESTClientConfig: *privilegedLoopbackClientConfig, } plugins := []admission.Interface{} clientsetClient := clientadapter.FromUnversionedClient(privilegedLoopbackKubeClient) for _, pluginName := range admissionControlPluginNames { configFile, err := pluginconfig.GetPluginConfig(options.AdmissionConfig.PluginConfig[pluginName]) if err != nil { return nil, err } plugin := admission.InitPlugin(pluginName, clientsetClient, configFile) if plugin != nil { plugins = append(plugins, plugin) } } pluginInitializer.Initialize(plugins) // ensure that plugins have been properly initialized if err := oadmission.Validate(plugins); err != nil { return nil, err } admissionController := admission.NewChainHandler(plugins...) // TODO: look up storage by resource serviceAccountTokenGetter, err := newServiceAccountTokenGetter(options, etcdClient) if err != nil { return nil, err } authenticator, err := newAuthenticator(options, restOptsGetter, serviceAccountTokenGetter, apiClientCAs, groupCache) if err != nil { return nil, err } plug, plugStart := newControllerPlug(options, client) config := &MasterConfig{ Options: options, RESTOptionsGetter: restOptsGetter, RuleResolver: ruleResolver, Authenticator: authenticator, Authorizer: authorizer, AuthorizationAttributeBuilder: newAuthorizationAttributeBuilder(requestContextMapper), GroupCache: groupCache, ProjectAuthorizationCache: newProjectAuthorizationCache(authorizer, privilegedLoopbackKubeClient, informerFactory), ProjectCache: projectCache, ClusterQuotaMappingController: clusterQuotaMappingController, RequestContextMapper: requestContextMapper, AdmissionControl: admissionController, TLS: configapi.UseTLS(options.ServingInfo.ServingInfo), ControllerPlug: plug, ControllerPlugStart: plugStart, ImageFor: imageTemplate.ExpandOrDie, EtcdHelper: etcdHelper, KubeletClientConfig: kubeletClientConfig, ClientCAs: clientCAs, APIClientCAs: apiClientCAs, PluginInitializer: pluginInitializer, PrivilegedLoopbackClientConfig: *privilegedLoopbackClientConfig, PrivilegedLoopbackOpenShiftClient: privilegedLoopbackOpenShiftClient, PrivilegedLoopbackKubernetesClient: privilegedLoopbackKubeClient, Informers: informerFactory, } return config, nil } func newControllerPlug(options configapi.MasterConfig, client *etcdclient.Client) (plug.Plug, func()) { switch { case options.ControllerLeaseTTL > 0: // TODO: replace with future API for leasing from Kube id := fmt.Sprintf("master-%s", kutilrand.String(8)) leaser := leaderlease.NewEtcd( client, path.Join(options.EtcdStorageConfig.OpenShiftStoragePrefix, "leases/controllers"), id, uint64(options.ControllerLeaseTTL), ) leased := plug.NewLeased(leaser) return leased, func() { glog.V(2).Infof("Attempting to acquire controller lease as %s, renewing every %d seconds", id, options.ControllerLeaseTTL) go leased.Run() } default: return plug.New(!options.PauseControllers), func() {} } } func newServiceAccountTokenGetter(options configapi.MasterConfig, client newetcdclient.Client) (serviceaccount.ServiceAccountTokenGetter, error) { var tokenGetter serviceaccount.ServiceAccountTokenGetter if options.KubernetesMasterConfig == nil { // When we're running against an external Kubernetes, use the external kubernetes client to validate service account tokens // This prevents infinite auth loops if the privilegedLoopbackKubeClient authenticates using a service account token kubeClient, _, err := configapi.GetKubeClient(options.MasterClients.ExternalKubernetesKubeConfig) if err != nil { return nil, err } tokenGetter = sacontroller.NewGetterFromClient(clientadapter.FromUnversionedClient(kubeClient)) } else { // When we're running in-process, go straight to etcd (using the KubernetesStorageVersion/KubernetesStoragePrefix, since service accounts are kubernetes objects) codec := kapi.Codecs.LegacyCodec(unversioned.GroupVersion{Group: kapi.GroupName, Version: options.EtcdStorageConfig.KubernetesStorageVersion}) ketcdHelper := etcdstorage.NewEtcdStorage(client, codec, options.EtcdStorageConfig.KubernetesStoragePrefix, false, genericapiserveroptions.DefaultDeserializationCacheSize) tokenGetter = sacontroller.NewGetterFromStorageInterface(ketcdHelper) } return tokenGetter, nil } func newAuthenticator(config configapi.MasterConfig, restOptionsGetter restoptions.Getter, tokenGetter serviceaccount.ServiceAccountTokenGetter, apiClientCAs *x509.CertPool, groupMapper identitymapper.UserToGroupMapper) (authenticator.Request, error) { authenticators := []authenticator.Request{} tokenAuthenticators := []authenticator.Request{} // ServiceAccount token if len(config.ServiceAccountConfig.PublicKeyFiles) > 0 { publicKeys := []*rsa.PublicKey{} for _, keyFile := range config.ServiceAccountConfig.PublicKeyFiles { publicKey, err := serviceaccount.ReadPublicKey(keyFile) if err != nil { return nil, fmt.Errorf("Error reading service account key file %s: %v", keyFile, err) } publicKeys = append(publicKeys, publicKey) } serviceAccountTokenAuthenticator := serviceaccount.JWTTokenAuthenticator(publicKeys, true, tokenGetter) tokenAuthenticators = append(tokenAuthenticators, bearertoken.New(serviceAccountTokenAuthenticator, true)) } // OAuth token if config.OAuthConfig != nil { oauthTokenAuthenticator, err := getEtcdTokenAuthenticator(restOptionsGetter, groupMapper) if err != nil { return nil, fmt.Errorf("Error building OAuth token authenticator: %v", err) } oauthTokenRequestAuthenticators := []authenticator.Request{ bearertoken.New(oauthTokenAuthenticator, true), // Allow token as access_token param for WebSockets paramtoken.New("access_token", oauthTokenAuthenticator, true), } tokenAuthenticators = append(tokenAuthenticators, // if you have a bearer token, you're a human (usually) // if you change this, have a look at the impersonationFilter where we attach groups to the impersonated user group.NewGroupAdder(unionrequest.NewUnionAuthentication(oauthTokenRequestAuthenticators...), []string{bootstrappolicy.AuthenticatedOAuthGroup})) } if len(tokenAuthenticators) > 0 { authenticators = append(authenticators, unionrequest.NewUnionAuthentication(tokenAuthenticators...)) } if configapi.UseTLS(config.ServingInfo.ServingInfo) { // build cert authenticator // TODO: add "system:" prefix in authenticator, limit cert to username // TODO: add "system:" prefix to groups in authenticator, limit cert to group name opts := x509request.DefaultVerifyOptions() opts.Roots = apiClientCAs certauth := x509request.New(opts, x509request.SubjectToUserConversion) authenticators = append(authenticators, certauth) } ret := &unionrequest.Authenticator{ FailOnError: true, Handlers: []authenticator.Request{ // if you change this, have a look at the impersonationFilter where we attach groups to the impersonated user group.NewGroupAdder(&unionrequest.Authenticator{FailOnError: true, Handlers: authenticators}, []string{bootstrappolicy.AuthenticatedGroup}), anonymous.NewAuthenticator(), }, } return ret, nil } func newProjectAuthorizationCache(authorizer authorizer.Authorizer, kubeClient *kclient.Client, informerFactory shared.InformerFactory) *projectauth.AuthorizationCache { return projectauth.NewAuthorizationCache( projectauth.NewAuthorizerReviewer(authorizer), kubeClient.Namespaces(), informerFactory.ClusterPolicies().Lister(), informerFactory.ClusterPolicyBindings().Lister(), informerFactory.Policies().Lister(), informerFactory.PolicyBindings().Lister(), ) } func addAuthorizationListerWatchers(customListerWatchers shared.DefaultListerWatcherOverrides, optsGetter restoptions.Getter) error { lw, err := newClusterPolicyLW(optsGetter) if err != nil { return err } customListerWatchers[authorizationapi.Resource("clusterpolicies")] = lw lw, err = newClusterPolicyBindingLW(optsGetter) if err != nil { return err } customListerWatchers[authorizationapi.Resource("clusterpolicybindings")] = lw lw, err = newPolicyLW(optsGetter) if err != nil { return err } customListerWatchers[authorizationapi.Resource("policies")] = lw lw, err = newPolicyBindingLW(optsGetter) if err != nil { return err } customListerWatchers[authorizationapi.Resource("policybindings")] = lw return nil } func newClusterPolicyLW(optsGetter restoptions.Getter) (cache.ListerWatcher, error) { ctx := kapi.WithNamespace(kapi.NewContext(), kapi.NamespaceAll) storage, err := clusterpolicyetcd.NewStorage(optsGetter) if err != nil { return nil, err } registry := clusterpolicyregistry.NewRegistry(storage) return &cache.ListWatch{ ListFunc: func(options kapi.ListOptions) (runtime.Object, error) { return registry.ListClusterPolicies(ctx, &options) }, WatchFunc: func(options kapi.ListOptions) (watch.Interface, error) { return registry.WatchClusterPolicies(ctx, &options) }, }, nil } func newClusterPolicyBindingLW(optsGetter restoptions.Getter) (cache.ListerWatcher, error) { ctx := kapi.WithNamespace(kapi.NewContext(), kapi.NamespaceAll) storage, err := clusterpolicybindingetcd.NewStorage(optsGetter) if err != nil { return nil, err } registry := clusterpolicybindingregistry.NewRegistry(storage) return &cache.ListWatch{ ListFunc: func(options kapi.ListOptions) (runtime.Object, error) { return registry.ListClusterPolicyBindings(ctx, &options) }, WatchFunc: func(options kapi.ListOptions) (watch.Interface, error) { return registry.WatchClusterPolicyBindings(ctx, &options) }, }, nil } func newPolicyLW(optsGetter restoptions.Getter) (cache.ListerWatcher, error) { ctx := kapi.WithNamespace(kapi.NewContext(), kapi.NamespaceAll) storage, err := policyetcd.NewStorage(optsGetter) if err != nil { return nil, err } registry := policyregistry.NewRegistry(storage) return &cache.ListWatch{ ListFunc: func(options kapi.ListOptions) (runtime.Object, error) { return registry.ListPolicies(ctx, &options) }, WatchFunc: func(options kapi.ListOptions) (watch.Interface, error) { return registry.WatchPolicies(ctx, &options) }, }, nil } func newPolicyBindingLW(optsGetter restoptions.Getter) (cache.ListerWatcher, error) { ctx := kapi.WithNamespace(kapi.NewContext(), kapi.NamespaceAll) storage, err := policybindingetcd.NewStorage(optsGetter) if err != nil { return nil, err } registry := policybindingregistry.NewRegistry(storage) return &cache.ListWatch{ ListFunc: func(options kapi.ListOptions) (runtime.Object, error) { return registry.ListPolicyBindings(ctx, &options) }, WatchFunc: func(options kapi.ListOptions) (watch.Interface, error) { return registry.WatchPolicyBindings(ctx, &options) }, }, nil } func newAuthorizer(ruleResolver rulevalidation.AuthorizationRuleResolver, informerFactory shared.InformerFactory, projectRequestDenyMessage string) authorizer.Authorizer { messageMaker := authorizer.NewForbiddenMessageResolver(projectRequestDenyMessage) roleBasedAuthorizer := authorizer.NewAuthorizer(ruleResolver, messageMaker) scopeLimitedAuthorizer := scope.NewAuthorizer(roleBasedAuthorizer, informerFactory.ClusterPolicies().Lister().ClusterPolicies(), messageMaker) return scopeLimitedAuthorizer } func newAuthorizationAttributeBuilder(requestContextMapper kapi.RequestContextMapper) authorizer.AuthorizationAttributeBuilder { // Default API request resolver requestInfoResolver := &apiserver.RequestInfoResolver{APIPrefixes: sets.NewString("api", "osapi", "oapi", "apis"), GrouplessAPIPrefixes: sets.NewString("api", "osapi", "oapi")} // Wrap with a resolver that detects unsafe requests and modifies verbs/resources appropriately so policy can address them separately browserSafeRequestInfoResolver := authorizer.NewBrowserSafeRequestInfoResolver( requestContextMapper, sets.NewString(bootstrappolicy.AuthenticatedGroup), requestInfoResolver, ) authorizationAttributeBuilder := authorizer.NewAuthorizationAttributeBuilder(requestContextMapper, browserSafeRequestInfoResolver) return authorizationAttributeBuilder } func getEtcdTokenAuthenticator(optsGetter restoptions.Getter, groupMapper identitymapper.UserToGroupMapper) (authenticator.Token, error) { // this never does a create for access tokens, so we don't need to be able to validate scopes against the client accessTokenStorage, err := accesstokenetcd.NewREST(optsGetter, nil) if err != nil { return nil, err } accessTokenRegistry := accesstokenregistry.NewRegistry(accessTokenStorage) userStorage, err := useretcd.NewREST(optsGetter) if err != nil { return nil, err } userRegistry := userregistry.NewRegistry(userStorage) return authnregistry.NewTokenAuthenticator(accessTokenRegistry, userRegistry, groupMapper), nil } // KubeClient returns the kubernetes client object func (c *MasterConfig) KubeClient() *kclient.Client { return c.PrivilegedLoopbackKubernetesClient } // PolicyClient returns the policy client object // It must have the following capabilities: // list, watch all policyBindings in all namespaces // list, watch all policies in all namespaces // create resourceAccessReviews in all namespaces func (c *MasterConfig) PolicyClient() *osclient.Client { return c.PrivilegedLoopbackOpenShiftClient } // ServiceAccountRoleBindingClient returns the client object used to bind roles to service accounts // It must have the following capabilities: // get, list, update, create policyBindings and clusterPolicyBindings in all namespaces func (c *MasterConfig) ServiceAccountRoleBindingClient() *osclient.Client { return c.PrivilegedLoopbackOpenShiftClient } // SdnClient returns the sdn client object // It must have the capability to get/list/watch/create/delete // HostSubnets. And have the capability to get ClusterNetwork. func (c *MasterConfig) SdnClient() *osclient.Client { return c.PrivilegedLoopbackOpenShiftClient } // DeploymentClient returns the deployment client object func (c *MasterConfig) DeploymentClient() *kclient.Client { return c.PrivilegedLoopbackKubernetesClient } // DNSServerClient returns the DNS server client object // It must have the following capabilities: // list, watch all services in all namespaces func (c *MasterConfig) DNSServerClient() *kclient.Client { return c.PrivilegedLoopbackKubernetesClient } // BuildLogClient returns the build log client object func (c *MasterConfig) BuildLogClient() *kclient.Client { return c.PrivilegedLoopbackKubernetesClient } // BuildConfigWebHookClient returns the webhook client object func (c *MasterConfig) BuildConfigWebHookClient() *osclient.Client { return c.PrivilegedLoopbackOpenShiftClient } // BuildControllerClients returns the build controller client objects func (c *MasterConfig) BuildControllerClients() (*osclient.Client, *kclient.Client) { _, osClient, kClient, err := c.GetServiceAccountClients(bootstrappolicy.InfraBuildControllerServiceAccountName) if err != nil { glog.Fatal(err) } return osClient, kClient } // BuildPodControllerClients returns the build pod controller client objects func (c *MasterConfig) BuildPodControllerClients() (*osclient.Client, *kclient.Client) { return c.PrivilegedLoopbackOpenShiftClient, c.PrivilegedLoopbackKubernetesClient } // BuildImageChangeTriggerControllerClients returns the build image change trigger controller client objects func (c *MasterConfig) BuildImageChangeTriggerControllerClients() (*osclient.Client, *kclient.Client) { return c.PrivilegedLoopbackOpenShiftClient, c.PrivilegedLoopbackKubernetesClient } // BuildConfigChangeControllerClients returns the build config change controller client objects func (c *MasterConfig) BuildConfigChangeControllerClients() (*osclient.Client, *kclient.Client) { return c.PrivilegedLoopbackOpenShiftClient, c.PrivilegedLoopbackKubernetesClient } // ImageChangeControllerClient returns the openshift client object func (c *MasterConfig) ImageChangeControllerClient() *osclient.Client { return c.PrivilegedLoopbackOpenShiftClient } // ImageImportControllerClient returns the deployment client object func (c *MasterConfig) ImageImportControllerClient() *osclient.Client { return c.PrivilegedLoopbackOpenShiftClient } // DeploymentConfigScaleClient returns the client used by the Scale subresource registry func (c *MasterConfig) DeploymentConfigScaleClient() *kclient.Client { return c.PrivilegedLoopbackKubernetesClient } // DeploymentControllerClients returns the deployment controller client objects func (c *MasterConfig) DeploymentControllerClients() (*osclient.Client, *kclient.Client) { _, osClient, kClient, err := c.GetServiceAccountClients(bootstrappolicy.InfraDeploymentControllerServiceAccountName) if err != nil { glog.Fatal(err) } return osClient, kClient } // DeployerPodControllerClient returns the deployer pod controller client object func (c *MasterConfig) DeployerPodControllerClient() *kclient.Client { return c.PrivilegedLoopbackKubernetesClient } // DeploymentConfigClients returns deploymentConfig and deployment client objects func (c *MasterConfig) DeploymentConfigClients() (*osclient.Client, *kclient.Client) { return c.PrivilegedLoopbackOpenShiftClient, c.PrivilegedLoopbackKubernetesClient } // DeploymentConfigControllerClients returns the deploymentConfig controller client objects func (c *MasterConfig) DeploymentConfigControllerClients() (*osclient.Client, *kclient.Client) { return c.PrivilegedLoopbackOpenShiftClient, c.PrivilegedLoopbackKubernetesClient } // DeploymentTriggerControllerClients returns the deploymentConfig trigger controller client objects func (c *MasterConfig) DeploymentTriggerControllerClients() (*osclient.Client, *kclient.Client) { return c.PrivilegedLoopbackOpenShiftClient, c.PrivilegedLoopbackKubernetesClient } // DeploymentImageChangeTriggerControllerClient returns the deploymentConfig image change controller client object func (c *MasterConfig) DeploymentImageChangeTriggerControllerClient() *osclient.Client { return c.PrivilegedLoopbackOpenShiftClient } // DeploymentLogClient returns the deployment log client object func (c *MasterConfig) DeploymentLogClient() *kclient.Client { return c.PrivilegedLoopbackKubernetesClient } // SecurityAllocationControllerClient returns the security allocation controller client object func (c *MasterConfig) SecurityAllocationControllerClient() *kclient.Client { return c.PrivilegedLoopbackKubernetesClient } // SDNControllerClients returns the SDN controller client objects func (c *MasterConfig) SDNControllerClients() (*osclient.Client, *kclient.Client) { return c.PrivilegedLoopbackOpenShiftClient, c.PrivilegedLoopbackKubernetesClient } // RouteAllocatorClients returns the route allocator client objects func (c *MasterConfig) RouteAllocatorClients() (*osclient.Client, *kclient.Client) { return c.PrivilegedLoopbackOpenShiftClient, c.PrivilegedLoopbackKubernetesClient } // ImageStreamSecretClient returns the client capable of retrieving secrets for an image secret wrapper func (c *MasterConfig) ImageStreamSecretClient() *kclient.Client { return c.PrivilegedLoopbackKubernetesClient } // ImageStreamImportSecretClient returns the client capable of retrieving image secrets for a namespace func (c *MasterConfig) ImageStreamImportSecretClient() *osclient.Client { return c.PrivilegedLoopbackOpenShiftClient } // ResourceQuotaManagerClients returns the client capable of retrieving resources needed for resource quota // evaluation func (c *MasterConfig) ResourceQuotaManagerClients() (*osclient.Client, *internalclientset.Clientset) { return c.PrivilegedLoopbackOpenShiftClient, clientadapter.FromUnversionedClient(c.PrivilegedLoopbackKubernetesClient) } // WebConsoleEnabled says whether web ui is not a disabled feature and asset service is configured. func (c *MasterConfig) WebConsoleEnabled() bool { return c.Options.AssetConfig != nil && !c.Options.DisabledFeatures.Has(configapi.FeatureWebConsole) } // OriginNamespaceControllerClients returns a client for openshift and kubernetes. // The openshift client object must have authority to delete openshift content in any namespace // The kubernetes client object must have authority to execute a finalize request on a namespace func (c *MasterConfig) OriginNamespaceControllerClients() (*osclient.Client, *kclient.Client) { return c.PrivilegedLoopbackOpenShiftClient, c.PrivilegedLoopbackKubernetesClient } // NewEtcdStorage returns a storage interface for the provided storage version. func NewEtcdStorage(client newetcdclient.Client, version unversioned.GroupVersion, prefix string) (oshelper storage.Interface, err error) { return etcdstorage.NewEtcdStorage(client, kapi.Codecs.LegacyCodec(version), prefix, false, genericapiserveroptions.DefaultDeserializationCacheSize), nil } // GetServiceAccountClients returns an OpenShift and Kubernetes client with the credentials of the // named service account in the infra namespace func (c *MasterConfig) GetServiceAccountClients(name string) (*restclient.Config, *osclient.Client, *kclient.Client, error) { if len(name) == 0 { return nil, nil, nil, errors.New("No service account name specified") } return serviceaccounts.Clients( c.PrivilegedLoopbackClientConfig, &serviceaccounts.ClientLookupTokenRetriever{Client: c.PrivilegedLoopbackKubernetesClient}, c.Options.PolicyConfig.OpenShiftInfrastructureNamespace, name, ) }