From ad916a82da8c760e6a6d85f6b195b8aaf463aefd Mon Sep 17 00:00:00 2001 From: deads2k Date: Tue, 17 Mar 2015 07:50:51 -0400 Subject: [PATCH] separate out bootstrap policy --- pkg/cmd/openshift/openshift.go | 4 +- .../{certs => admin}/create_allcerts.go | 2 +- .../admin/create_bootstrappolicy_file.go | 111 ++++++++++++++ .../{certs => admin}/create_clientcert.go | 2 +- .../server/{certs => admin}/create_comands.go | 4 +- .../{certs => admin}/create_kubeconfig.go | 2 +- .../create_nodeclientcerts.go | 2 +- .../{certs => admin}/create_servercert.go | 2 +- .../{certs => admin}/create_signercert.go | 2 +- .../server/{certs => admin}/default_certs.go | 2 +- .../server/admin/overwrite_bootstrappolicy.go | 141 ++++++++++++++++++ .../{certs => admin}/signer_cert_args.go | 2 +- pkg/cmd/server/api/latest/helpers.go | 32 ++++ pkg/cmd/server/api/types.go | 7 + pkg/cmd/server/api/v1/types.go | 7 + pkg/cmd/server/api/validation/validation.go | 46 ++++-- pkg/cmd/server/bootstrappolicy/policy.go | 5 + pkg/cmd/server/origin/master.go | 65 ++------ pkg/cmd/server/origin/master_config.go | 4 +- pkg/cmd/server/start/certs_args.go | 9 +- pkg/cmd/server/start/command_test.go | 11 +- pkg/cmd/server/start/master_args.go | 26 ++-- pkg/cmd/server/start/node_args.go | 6 +- pkg/cmd/server/start/policy_args.go | 24 +++ pkg/cmd/server/start/start_allinone.go | 13 +- pkg/cmd/server/start/start_master.go | 32 +++- pkg/cmd/server/start/start_node.go | 32 ++-- test/integration/bootstrap_policy_test.go | 36 +++++ test/integration/server_test.go | 1 + 29 files changed, 506 insertions(+), 126 deletions(-) rename pkg/cmd/server/{certs => admin}/create_allcerts.go (99%) create mode 100644 pkg/cmd/server/admin/create_bootstrappolicy_file.go rename pkg/cmd/server/{certs => admin}/create_clientcert.go (99%) rename pkg/cmd/server/{certs => admin}/create_comands.go (80%) rename pkg/cmd/server/{certs => admin}/create_kubeconfig.go (99%) rename pkg/cmd/server/{certs => admin}/create_nodeclientcerts.go (99%) rename pkg/cmd/server/{certs => admin}/create_servercert.go (99%) rename pkg/cmd/server/{certs => admin}/create_signercert.go (99%) rename pkg/cmd/server/{certs => admin}/default_certs.go (99%) create mode 100644 pkg/cmd/server/admin/overwrite_bootstrappolicy.go rename pkg/cmd/server/{certs => admin}/signer_cert_args.go (98%) create mode 100644 pkg/cmd/server/api/latest/helpers.go create mode 100644 pkg/cmd/server/start/policy_args.go diff --git a/pkg/cmd/openshift/openshift.go b/pkg/cmd/openshift/openshift.go index 8b82423c0870..ea3ca104d531 100644 --- a/pkg/cmd/openshift/openshift.go +++ b/pkg/cmd/openshift/openshift.go @@ -18,7 +18,7 @@ import ( "github.com/openshift/origin/pkg/cmd/infra/builder" "github.com/openshift/origin/pkg/cmd/infra/deployer" "github.com/openshift/origin/pkg/cmd/infra/router" - "github.com/openshift/origin/pkg/cmd/server/certs" + "github.com/openshift/origin/pkg/cmd/server/admin" "github.com/openshift/origin/pkg/cmd/server/start" "github.com/openshift/origin/pkg/cmd/templates" "github.com/openshift/origin/pkg/cmd/util/clientcmd" @@ -81,7 +81,7 @@ func NewCommandOpenShift() *cobra.Command { startAllInOne, _ := start.NewCommandStartAllInOne() root.AddCommand(startAllInOne) - root.AddCommand(certs.NewCommandAdmin()) + root.AddCommand(admin.NewCommandAdmin()) root.AddCommand(cli.NewCommandCLI("cli", "openshift cli")) root.AddCommand(cli.NewCmdKubectl("kube")) root.AddCommand(newExperimentalCommand("openshift", "ex")) diff --git a/pkg/cmd/server/certs/create_allcerts.go b/pkg/cmd/server/admin/create_allcerts.go similarity index 99% rename from pkg/cmd/server/certs/create_allcerts.go rename to pkg/cmd/server/admin/create_allcerts.go index 58581d3622e0..1a4ba4957111 100644 --- a/pkg/cmd/server/certs/create_allcerts.go +++ b/pkg/cmd/server/admin/create_allcerts.go @@ -1,4 +1,4 @@ -package certs +package admin import ( "errors" diff --git a/pkg/cmd/server/admin/create_bootstrappolicy_file.go b/pkg/cmd/server/admin/create_bootstrappolicy_file.go new file mode 100644 index 000000000000..a14998b72651 --- /dev/null +++ b/pkg/cmd/server/admin/create_bootstrappolicy_file.go @@ -0,0 +1,111 @@ +package admin + +import ( + "bytes" + "errors" + "fmt" + "io/ioutil" + "os" + "path" + + "github.com/golang/glog" + "github.com/spf13/cobra" + + kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl" + + "github.com/openshift/origin/pkg/api/latest" + "github.com/openshift/origin/pkg/cmd/server/bootstrappolicy" + "github.com/openshift/origin/pkg/template/api" +) + +const ( + DefaultPolicyFile = "openshift.local.policy/policy.json" + CreateBootstrapPolicyFileCommand = "create-bootstrap-policy-file" + CreateBootstrapPolicyFileFullCommand = "openshift admin " + CreateBootstrapPolicyFileCommand +) + +type CreateBootstrapPolicyFileOptions struct { + File string + + MasterAuthorizationNamespace string + OpenShiftSharedResourcesNamespace string +} + +func NewCommandCreateBootstrapPolicyFile() *cobra.Command { + options := &CreateBootstrapPolicyFileOptions{} + + cmd := &cobra.Command{ + Use: CreateBootstrapPolicyFileCommand, + Short: "Create bootstrap policy for OpenShift.", + Run: func(c *cobra.Command, args []string) { + if err := options.Validate(args); err != nil { + fmt.Println(err.Error()) + c.Help() + return + } + + if err := options.CreateBootstrapPolicyFile(); err != nil { + glog.Fatal(err) + } + }, + } + + flags := cmd.Flags() + + flags.StringVar(&options.File, "filename", DefaultPolicyFile, "The policy template file that will be written with roles and bindings.") + + flags.StringVar(&options.MasterAuthorizationNamespace, "master-namespace", "master", "Global authorization namespace.") + flags.StringVar(&options.OpenShiftSharedResourcesNamespace, "openshift-namespace", "openshift", "Namespace for shared openshift resources.") + + return cmd +} + +func (o CreateBootstrapPolicyFileOptions) Validate(args []string) error { + if len(args) != 0 { + return errors.New("no arguments are supported") + } + if len(o.File) == 0 { + return errors.New("filename must be provided") + } + if len(o.MasterAuthorizationNamespace) == 0 { + return errors.New("master-namespace must be provided") + } + if len(o.OpenShiftSharedResourcesNamespace) == 0 { + return errors.New("openshift-namespace must be provided") + } + + return nil +} + +func (o CreateBootstrapPolicyFileOptions) CreateBootstrapPolicyFile() error { + if err := os.MkdirAll(path.Dir(o.File), os.FileMode(0755)); err != nil { + return err + } + + policyTemplate := &api.Template{} + + roles := bootstrappolicy.GetBootstrapRoles(o.MasterAuthorizationNamespace, o.OpenShiftSharedResourcesNamespace) + for i := range roles { + policyTemplate.Objects = append(policyTemplate.Objects, &roles[i]) + } + + roleBindings := bootstrappolicy.GetBootstrapRoleBindings(o.MasterAuthorizationNamespace, o.OpenShiftSharedResourcesNamespace) + for i := range roleBindings { + policyTemplate.Objects = append(policyTemplate.Objects, &roleBindings[i]) + } + + versionedPolicyTemplate, err := kapi.Scheme.ConvertToVersion(policyTemplate, latest.Version) + if err != nil { + return err + } + + buffer := &bytes.Buffer{} + (&kubectl.JSONPrinter{}).PrintObj(versionedPolicyTemplate, buffer) + + if err := ioutil.WriteFile(o.File, buffer.Bytes(), 0644); err != nil { + return err + } + + return nil +} diff --git a/pkg/cmd/server/certs/create_clientcert.go b/pkg/cmd/server/admin/create_clientcert.go similarity index 99% rename from pkg/cmd/server/certs/create_clientcert.go rename to pkg/cmd/server/admin/create_clientcert.go index f3c58a4d6f9f..5d08ea0a6271 100644 --- a/pkg/cmd/server/certs/create_clientcert.go +++ b/pkg/cmd/server/admin/create_clientcert.go @@ -1,4 +1,4 @@ -package certs +package admin import ( "errors" diff --git a/pkg/cmd/server/certs/create_comands.go b/pkg/cmd/server/admin/create_comands.go similarity index 80% rename from pkg/cmd/server/certs/create_comands.go rename to pkg/cmd/server/admin/create_comands.go index d64f5b84270e..f65de86a8044 100644 --- a/pkg/cmd/server/certs/create_comands.go +++ b/pkg/cmd/server/admin/create_comands.go @@ -1,4 +1,4 @@ -package certs +package admin import ( "github.com/spf13/cobra" @@ -13,6 +13,8 @@ func NewCommandAdmin() *cobra.Command { }, } + cmd.AddCommand(NewCommandOverwriteBootstrapPolicy()) + cmd.AddCommand(NewCommandCreateBootstrapPolicyFile()) cmd.AddCommand(NewCommandCreateKubeConfig()) cmd.AddCommand(NewCommandCreateAllCerts()) cmd.AddCommand(NewCommandCreateClientCert()) diff --git a/pkg/cmd/server/certs/create_kubeconfig.go b/pkg/cmd/server/admin/create_kubeconfig.go similarity index 99% rename from pkg/cmd/server/certs/create_kubeconfig.go rename to pkg/cmd/server/admin/create_kubeconfig.go index 67d5777f0f65..35be417eaf3b 100644 --- a/pkg/cmd/server/certs/create_kubeconfig.go +++ b/pkg/cmd/server/admin/create_kubeconfig.go @@ -1,4 +1,4 @@ -package certs +package admin import ( "errors" diff --git a/pkg/cmd/server/certs/create_nodeclientcerts.go b/pkg/cmd/server/admin/create_nodeclientcerts.go similarity index 99% rename from pkg/cmd/server/certs/create_nodeclientcerts.go rename to pkg/cmd/server/admin/create_nodeclientcerts.go index 2dda39957920..6c22dd59b1e2 100644 --- a/pkg/cmd/server/certs/create_nodeclientcerts.go +++ b/pkg/cmd/server/admin/create_nodeclientcerts.go @@ -1,4 +1,4 @@ -package certs +package admin import ( "errors" diff --git a/pkg/cmd/server/certs/create_servercert.go b/pkg/cmd/server/admin/create_servercert.go similarity index 99% rename from pkg/cmd/server/certs/create_servercert.go rename to pkg/cmd/server/admin/create_servercert.go index ca88fbd93430..f83f5f8870db 100644 --- a/pkg/cmd/server/certs/create_servercert.go +++ b/pkg/cmd/server/admin/create_servercert.go @@ -1,4 +1,4 @@ -package certs +package admin import ( "errors" diff --git a/pkg/cmd/server/certs/create_signercert.go b/pkg/cmd/server/admin/create_signercert.go similarity index 99% rename from pkg/cmd/server/certs/create_signercert.go rename to pkg/cmd/server/admin/create_signercert.go index 56f9a1bbec99..88d73a876566 100644 --- a/pkg/cmd/server/certs/create_signercert.go +++ b/pkg/cmd/server/admin/create_signercert.go @@ -1,4 +1,4 @@ -package certs +package admin import ( "errors" diff --git a/pkg/cmd/server/certs/default_certs.go b/pkg/cmd/server/admin/default_certs.go similarity index 99% rename from pkg/cmd/server/certs/default_certs.go rename to pkg/cmd/server/admin/default_certs.go index e3d29bf79b11..7c066783720d 100644 --- a/pkg/cmd/server/certs/default_certs.go +++ b/pkg/cmd/server/admin/default_certs.go @@ -1,4 +1,4 @@ -package certs +package admin import ( "fmt" diff --git a/pkg/cmd/server/admin/overwrite_bootstrappolicy.go b/pkg/cmd/server/admin/overwrite_bootstrappolicy.go new file mode 100644 index 000000000000..e5bdef7812a6 --- /dev/null +++ b/pkg/cmd/server/admin/overwrite_bootstrappolicy.go @@ -0,0 +1,141 @@ +package admin + +import ( + "errors" + "fmt" + + "github.com/golang/glog" + "github.com/spf13/cobra" + + "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + "github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta" + "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl" + "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/resource" + utilerrors "github.com/GoogleCloudPlatform/kubernetes/pkg/util/errors" + + "github.com/GoogleCloudPlatform/kubernetes/pkg/tools" + "github.com/openshift/origin/pkg/api/latest" + authorizationapi "github.com/openshift/origin/pkg/authorization/api" + authorizationetcd "github.com/openshift/origin/pkg/authorization/registry/etcd" + roleregistry "github.com/openshift/origin/pkg/authorization/registry/role" + rolebindingregistry "github.com/openshift/origin/pkg/authorization/registry/rolebinding" + configapilatest "github.com/openshift/origin/pkg/cmd/server/api/latest" + configvalidation "github.com/openshift/origin/pkg/cmd/server/api/validation" + "github.com/openshift/origin/pkg/cmd/server/etcd" + cmdclientcmd "github.com/openshift/origin/pkg/cmd/util/clientcmd" + templateapi "github.com/openshift/origin/pkg/template/api" +) + +type OverwriteBootstrapPolicyOptions struct { + File string + MasterConfigFile string +} + +func NewCommandOverwriteBootstrapPolicy() *cobra.Command { + options := &OverwriteBootstrapPolicyOptions{} + + cmd := &cobra.Command{ + Use: "overwrite-policy", + Short: "Overwrite policy for OpenShift. DANGER: THIS BYPASSES ALL ACCESS CONTROL CHECKS AND WRITES DIRECTLY TO ETCD!", + Run: func(c *cobra.Command, args []string) { + if err := options.Validate(args); err != nil { + fmt.Println(err.Error()) + c.Help() + return + } + + if err := options.OverwriteBootstrapPolicy(); err != nil { + glog.Fatal(err) + } + }, + } + + flags := cmd.Flags() + + flags.StringVar(&options.File, "filename", "", "The policy template file containing roles and bindings. One can be created with '"+CreateBootstrapPolicyFileFullCommand+"'.") + flags.StringVar(&options.MasterConfigFile, "master-config", "master.yaml", "Location of the master configuration file to run from in order to connect to etcd and directly modify the policy.") + + return cmd +} + +func (o OverwriteBootstrapPolicyOptions) Validate(args []string) error { + if len(args) != 0 { + return errors.New("no arguments are supported") + } + if len(o.File) == 0 { + return errors.New("filename must be provided") + } + if len(o.MasterConfigFile) == 0 { + return errors.New("master-config must be provided") + } + + return nil +} + +func (o OverwriteBootstrapPolicyOptions) OverwriteBootstrapPolicy() error { + masterConfig, err := configapilatest.ReadAndResolveMasterConfig(o.MasterConfigFile) + if err != nil { + return err + } + if err := configvalidation.ValidateNamespace(masterConfig.PolicyConfig.MasterAuthorizationNamespace, "masterAuthorizationNamespace"); len(err) > 0 { + return utilerrors.NewAggregate(err) + } + + etcdHelper, err := etcd.NewOpenShiftEtcdHelper(masterConfig.EtcdClientInfo.URL) + if err != nil { + return err + } + + return OverwriteBootstrapPolicy(etcdHelper, masterConfig.PolicyConfig.MasterAuthorizationNamespace, o.File) +} + +func OverwriteBootstrapPolicy(etcdHelper tools.EtcdHelper, masterNamespace, policyFile string) error { + mapper := cmdclientcmd.ShortcutExpander{kubectl.ShortcutExpander{latest.RESTMapper}} + typer := api.Scheme + clientMapper := resource.ClientMapperFunc(func(mapping *meta.RESTMapping) (resource.RESTClient, error) { + return nil, nil + }) + + r := resource.NewBuilder(mapper, typer, clientMapper). + FilenameParam(policyFile). + Flatten(). + Do() + + if r.Err() != nil { + return r.Err() + } + + registry := authorizationetcd.New(etcdHelper) + roleRegistry := roleregistry.NewVirtualRegistry(registry) + roleBindingRegistry := rolebindingregistry.NewVirtualRegistry(registry, registry, masterNamespace) + + return r.Visit(func(info *resource.Info) error { + template, ok := info.Object.(*templateapi.Template) + if !ok { + return errors.New("policy must be contained in a template. One can be created with '" + CreateBootstrapPolicyFileFullCommand + "'.") + } + + for _, item := range template.Objects { + switch castObject := item.(type) { + case *authorizationapi.Role: + ctx := api.WithNamespace(api.NewContext(), castObject.Namespace) + roleRegistry.DeleteRole(ctx, castObject.Name) + if err := roleRegistry.CreateRole(ctx, castObject); err != nil { + return err + } + + case *authorizationapi.RoleBinding: + ctx := api.WithNamespace(api.NewContext(), castObject.Namespace) + roleBindingRegistry.DeleteRoleBinding(ctx, castObject.Name) + if err := roleBindingRegistry.CreateRoleBinding(ctx, castObject, true); err != nil { + return err + } + + default: + return errors.New("only roles and rolebindings may be created in this mode") + } + } + + return nil + }) +} diff --git a/pkg/cmd/server/certs/signer_cert_args.go b/pkg/cmd/server/admin/signer_cert_args.go similarity index 98% rename from pkg/cmd/server/certs/signer_cert_args.go rename to pkg/cmd/server/admin/signer_cert_args.go index 8d342afc18c2..9c25989f07cd 100644 --- a/pkg/cmd/server/certs/signer_cert_args.go +++ b/pkg/cmd/server/admin/signer_cert_args.go @@ -1,4 +1,4 @@ -package certs +package admin import ( "errors" diff --git a/pkg/cmd/server/api/latest/helpers.go b/pkg/cmd/server/api/latest/helpers.go new file mode 100644 index 000000000000..e887f840fea2 --- /dev/null +++ b/pkg/cmd/server/api/latest/helpers.go @@ -0,0 +1,32 @@ +package latest + +import ( + "io/ioutil" + "path" + + configapi "github.com/openshift/origin/pkg/cmd/server/api" +) + +func ReadMasterConfig(filename string) (*configapi.MasterConfig, error) { + data, err := ioutil.ReadFile(filename) + if err != nil { + return nil, err + } + + config := &configapi.MasterConfig{} + + if err := Codec.DecodeInto(data, config); err != nil { + return nil, err + } + return config, nil +} + +func ReadAndResolveMasterConfig(filename string) (*configapi.MasterConfig, error) { + masterConfig, err := ReadMasterConfig(filename) + if err != nil { + return nil, err + } + + configapi.ResolveMasterConfigPaths(masterConfig, path.Dir(filename)) + return masterConfig, nil +} diff --git a/pkg/cmd/server/api/types.go b/pkg/cmd/server/api/types.go index 4bf621a45edd..7d498eff604e 100644 --- a/pkg/cmd/server/api/types.go +++ b/pkg/cmd/server/api/types.go @@ -64,6 +64,13 @@ type MasterConfig struct { ImageConfig ImageConfig + PolicyConfig PolicyConfig +} + +type PolicyConfig struct { + // BootstrapPolicyFile points to a template that contains roles and rolebindings that will be created if no policy object exists in the master namespace + BootstrapPolicyFile string + // MasterAuthorizationNamespace is the global namespace for Policy MasterAuthorizationNamespace string // OpenShiftSharedResourcesNamespace is the namespace where shared OpenShift resources live (like shared templates) diff --git a/pkg/cmd/server/api/v1/types.go b/pkg/cmd/server/api/v1/types.go index 5db5367759ed..3be4ab311a2a 100644 --- a/pkg/cmd/server/api/v1/types.go +++ b/pkg/cmd/server/api/v1/types.go @@ -64,6 +64,13 @@ type MasterConfig struct { ImageConfig ImageConfig `json:"imageConfig"` + PolicyConfig PolicyConfig +} + +type PolicyConfig struct { + // BootstrapPolicyFile points to a template that contains roles and rolebindings that will be created if no policy object exists in the master namespace + BootstrapPolicyFile string `json:"bootstrapPolicyFile"` + // MasterAuthorizationNamespace is the global namespace for Policy MasterAuthorizationNamespace string `json:"masterAuthorizationNamespace"` // OpenShiftSharedResourcesNamespace is the namespace where shared OpenShift resources live (like shared templates) diff --git a/pkg/cmd/server/api/validation/validation.go b/pkg/cmd/server/api/validation/validation.go index 6badb998bd6c..9fb95eacf403 100644 --- a/pkg/cmd/server/api/validation/validation.go +++ b/pkg/cmd/server/api/validation/validation.go @@ -59,11 +59,7 @@ func ValidateServingInfo(info api.ServingInfo) errs.ValidationErrorList { func ValidateKubeConfig(path string, field string) errs.ValidationErrorList { allErrs := errs.ValidationErrorList{} - if len(path) == 0 { - allErrs = append(allErrs, errs.NewFieldRequired(field, path)) - } else if _, err := os.Stat(path); err != nil { - allErrs = append(allErrs, errs.NewFieldInvalid(field, path, "could not read file")) - } + allErrs = append(allErrs, ValidateFile(path, field)...) // TODO: load and parse return allErrs @@ -82,11 +78,7 @@ func ValidateMasterConfig(config *api.MasterConfig) errs.ValidationErrorList { allErrs = append(allErrs, ValidateBindAddress(config.DNSConfig.BindAddress).Prefix("dnsConfig")...) } - if len(config.MasterAuthorizationNamespace) == 0 { - allErrs = append(allErrs, errs.NewFieldRequired("masterAuthorizationNamespace", config.MasterAuthorizationNamespace)) - } else if ok, _ := kvalidation.ValidateNamespaceName(config.MasterAuthorizationNamespace, false); !ok { - allErrs = append(allErrs, errs.NewFieldInvalid("masterAuthorizationNamespace", config.MasterAuthorizationNamespace, "must be a valid namespace")) - } + allErrs = append(allErrs, ValidatePolicyConfig(config.PolicyConfig).Prefix("policyConfig")...) allErrs = append(allErrs, ValidateKubeConfig(config.MasterClients.DeployerKubeConfig, "deployerKubeConfig").Prefix("masterClients")...) allErrs = append(allErrs, ValidateKubeConfig(config.MasterClients.OpenShiftLoopbackKubeConfig, "openShiftLoopbackKubeConfig").Prefix("masterClients")...) @@ -95,6 +87,28 @@ func ValidateMasterConfig(config *api.MasterConfig) errs.ValidationErrorList { return allErrs } +func ValidatePolicyConfig(config api.PolicyConfig) errs.ValidationErrorList { + allErrs := errs.ValidationErrorList{} + + allErrs = append(allErrs, ValidateFile(config.BootstrapPolicyFile, "bootstrapPolicyFile")...) + allErrs = append(allErrs, ValidateNamespace(config.MasterAuthorizationNamespace, "masterAuthorizationNamespace")...) + allErrs = append(allErrs, ValidateNamespace(config.OpenShiftSharedResourcesNamespace, "openShiftSharedResourcesNamespace")...) + + return allErrs +} + +func ValidateNamespace(namespace, field string) errs.ValidationErrorList { + allErrs := errs.ValidationErrorList{} + + if len(namespace) == 0 { + allErrs = append(allErrs, errs.NewFieldRequired(field, namespace)) + } else if ok, _ := kvalidation.ValidateNamespaceName(namespace, false); !ok { + allErrs = append(allErrs, errs.NewFieldInvalid(field, namespace, "must be a valid namespace")) + } + + return allErrs +} + func ValidateNodeConfig(config *api.NodeConfig) errs.ValidationErrorList { allErrs := errs.ValidationErrorList{} @@ -112,6 +126,18 @@ func ValidateNodeConfig(config *api.NodeConfig) errs.ValidationErrorList { return allErrs } +func ValidateFile(path string, field string) errs.ValidationErrorList { + allErrs := errs.ValidationErrorList{} + + if len(path) == 0 { + allErrs = append(allErrs, errs.NewFieldRequired(field, path)) + } else if _, err := os.Stat(path); err != nil { + allErrs = append(allErrs, errs.NewFieldInvalid(field, path, "could not read file")) + } + + return allErrs +} + func ValidateAllInOneConfig(master *api.MasterConfig, node *api.NodeConfig) errs.ValidationErrorList { allErrs := errs.ValidationErrorList{} diff --git a/pkg/cmd/server/bootstrappolicy/policy.go b/pkg/cmd/server/bootstrappolicy/policy.go index cac396e4361a..6476d58f2a7b 100644 --- a/pkg/cmd/server/bootstrappolicy/policy.go +++ b/pkg/cmd/server/bootstrappolicy/policy.go @@ -7,6 +7,11 @@ import ( authorizationapi "github.com/openshift/origin/pkg/authorization/api" ) +const ( + DefaultMasterAuthorizationNamespace = "master" + DefaultOpenShiftSharedResourcesNamespace = "openshift" +) + const ( UnauthenticatedUsername = "system:anonymous" InternalComponentUsername = "system:openshift-client" diff --git a/pkg/cmd/server/origin/master.go b/pkg/cmd/server/origin/master.go index 897d0fa370e8..ce39ad8b8453 100644 --- a/pkg/cmd/server/origin/master.go +++ b/pkg/cmd/server/origin/master.go @@ -87,8 +87,8 @@ import ( roleregistry "github.com/openshift/origin/pkg/authorization/registry/role" rolebindingregistry "github.com/openshift/origin/pkg/authorization/registry/rolebinding" subjectaccessreviewregistry "github.com/openshift/origin/pkg/authorization/registry/subjectaccessreview" + "github.com/openshift/origin/pkg/cmd/server/admin" configapi "github.com/openshift/origin/pkg/cmd/server/api" - "github.com/openshift/origin/pkg/cmd/server/bootstrappolicy" routeplugin "github.com/openshift/origin/plugins/route/allocation/simple" ) @@ -266,7 +266,7 @@ func (c *MasterConfig) InstallProtectedAPI(container *restful.Container) []strin "policies": policyregistry.NewREST(authorizationEtcd), "policyBindings": policybindingregistry.NewREST(authorizationEtcd), "roles": roleregistry.NewREST(roleregistry.NewVirtualRegistry(authorizationEtcd)), - "roleBindings": rolebindingregistry.NewREST(rolebindingregistry.NewVirtualRegistry(authorizationEtcd, authorizationEtcd, c.Options.MasterAuthorizationNamespace)), + "roleBindings": rolebindingregistry.NewREST(rolebindingregistry.NewVirtualRegistry(authorizationEtcd, authorizationEtcd, c.Options.PolicyConfig.MasterAuthorizationNamespace)), "resourceAccessReviews": resourceaccessreviewregistry.NewREST(c.Authorizer), "subjectAccessReviews": subjectaccessreviewregistry.NewREST(c.Authorizer), } @@ -406,7 +406,6 @@ func (c *MasterConfig) Run(protected []APIInstaller, unprotected []APIInstaller) c.ensureComponentAuthorizationRules() c.ensureMasterAuthorizationNamespace() go util.Forever(func() { - c.ensureComponentAuthorizationRules() c.ensureMasterAuthorizationNamespace() }, 10*time.Second) } @@ -423,9 +422,9 @@ func (c *MasterConfig) getRequestContextMapper() kapi.RequestContextMapper { func (c *MasterConfig) ensureMasterAuthorizationNamespace() { // ensure that master namespace actually exists - namespace, err := c.KubeClient().Namespaces().Get(c.Options.MasterAuthorizationNamespace) + namespace, err := c.KubeClient().Namespaces().Get(c.Options.PolicyConfig.MasterAuthorizationNamespace) if err != nil { - namespace = &kapi.Namespace{ObjectMeta: kapi.ObjectMeta{Name: c.Options.MasterAuthorizationNamespace}} + namespace = &kapi.Namespace{ObjectMeta: kapi.ObjectMeta{Name: c.Options.PolicyConfig.MasterAuthorizationNamespace}} kapi.FillObjectMetaSystemFields(api.NewContext(), &namespace.ObjectMeta) _, err = c.KubeClient().Namespaces().Create(namespace) if err != nil { @@ -437,60 +436,18 @@ func (c *MasterConfig) ensureMasterAuthorizationNamespace() { // ensureComponentAuthorizationRules initializes the global policies func (c *MasterConfig) ensureComponentAuthorizationRules() { registry := authorizationetcd.New(c.EtcdHelper) + ctx := kapi.WithNamespace(kapi.NewContext(), c.Options.PolicyConfig.MasterAuthorizationNamespace) - roleRegistry := roleregistry.NewVirtualRegistry(registry) - for _, role := range bootstrappolicy.GetBootstrapRoles(c.Options.MasterAuthorizationNamespace, c.Options.OpenShiftSharedResourcesNamespace) { - ctx := kapi.WithNamespace(kapi.NewContext(), role.Namespace) + if _, err := registry.GetPolicy(ctx, authorizationapi.PolicyName); kapierror.IsNotFound(err) { + glog.Infof("No master policy found. Creating bootstrap policy based on: %v", c.Options.PolicyConfig.BootstrapPolicyFile) - if _, err := roleRegistry.GetRole(ctx, role.Name); kapierror.IsNotFound(err) { - if err := roleRegistry.CreateRole(ctx, &role); err != nil { - glog.Errorf("Error creating role: %#v due to %v\n", role, err) - } - - } else if err != nil { - glog.Errorf("Error get role: %#v due to %v\n", role, err) + if err := admin.OverwriteBootstrapPolicy(c.EtcdHelper, c.Options.PolicyConfig.MasterAuthorizationNamespace, c.Options.PolicyConfig.BootstrapPolicyFile); err != nil { + glog.Errorf("Error creating bootstrap policy: %v", err) } - } - - roleBindingRegistry := rolebindingregistry.NewVirtualRegistry(registry, registry, c.Options.MasterAuthorizationNamespace) - for _, roleBinding := range bootstrappolicy.GetBootstrapRoleBindings(c.Options.MasterAuthorizationNamespace, c.Options.OpenShiftSharedResourcesNamespace) { - ctx := kapi.WithNamespace(kapi.NewContext(), roleBinding.Namespace) - - if _, err := roleBindingRegistry.GetRoleBinding(ctx, roleBinding.Name); kapierror.IsNotFound(err) { - // if this is a binding for a non-master namespaced role. That means that the policy binding must be provisioned - if roleBinding.RoleRef.Namespace != c.Options.MasterAuthorizationNamespace { - policyBindingName := roleBinding.RoleRef.Namespace - if _, err := registry.GetPolicyBinding(ctx, policyBindingName); kapierror.IsNotFound(err) { - policyBinding := &authorizationapi.PolicyBinding{ - ObjectMeta: kapi.ObjectMeta{ - Namespace: roleBinding.Namespace, - Name: policyBindingName, - }, - - PolicyRef: kapi.ObjectReference{ - Namespace: roleBinding.RoleRef.Namespace, - Name: authorizationapi.PolicyName, - }, - } - - if err := registry.CreatePolicyBinding(ctx, policyBinding); err != nil { - glog.Errorf("Error creating policyBinding: %#v due to %v\n", policyBinding, err) - } - - } else if err != nil { - glog.Errorf("Error getting policyBinding: %#v due to %v\n", policyBindingName, err) - } - } - if err := roleBindingRegistry.CreateRoleBinding(ctx, &roleBinding, true); err != nil { - glog.Errorf("Error creating roleBinding: %#v due to %v\n", roleBinding, err) - } - - } else if err != nil { - glog.Errorf("Error getting roleBinding: %#v due to %v\n", roleBinding, err) - } + } else { + glog.V(2).Infof("Ignoring bootstrap policy file because master policy found") } - } func (c *MasterConfig) authorizationFilter(handler http.Handler) http.Handler { diff --git a/pkg/cmd/server/origin/master_config.go b/pkg/cmd/server/origin/master_config.go index de8b86fe8913..099c637e717e 100644 --- a/pkg/cmd/server/origin/master_config.go +++ b/pkg/cmd/server/origin/master_config.go @@ -133,11 +133,11 @@ func BuildMasterConfig(options configapi.MasterConfig) (*MasterConfig, error) { Options: options, Authenticator: newAuthenticator(options.ServingInfo, etcdHelper, apiClientCAs), - Authorizer: newAuthorizer(policyCache, options.MasterAuthorizationNamespace), + Authorizer: newAuthorizer(policyCache, options.PolicyConfig.MasterAuthorizationNamespace), AuthorizationAttributeBuilder: newAuthorizationAttributeBuilder(requestContextMapper), PolicyCache: policyCache, - ProjectAuthorizationCache: newProjectAuthorizationCache(options.MasterAuthorizationNamespace, openshiftClient, kubeClient), + ProjectAuthorizationCache: newProjectAuthorizationCache(options.PolicyConfig.MasterAuthorizationNamespace, openshiftClient, kubeClient), RequestContextMapper: requestContextMapper, diff --git a/pkg/cmd/server/start/certs_args.go b/pkg/cmd/server/start/certs_args.go index 91781068d351..6c3719709a73 100644 --- a/pkg/cmd/server/start/certs_args.go +++ b/pkg/cmd/server/start/certs_args.go @@ -11,10 +11,13 @@ type CertArgs struct { } func BindCertArgs(args *CertArgs, flags *pflag.FlagSet, prefix string) { - flags.BoolVar(&args.CreateCerts, prefix+"create-certs", true, "Create any missing certificates required for launch or for writing the config file.") - flags.StringVar(&args.CertDir, prefix+"cert-dir", "openshift.local.certificates", "The certificate data directory.") + flags.BoolVar(&args.CreateCerts, prefix+"create-certs", args.CreateCerts, "Create any missing certificates required for launch or for writing the config file.") + flags.StringVar(&args.CertDir, prefix+"cert-dir", args.CertDir, "The certificate data directory.") } func NewDefaultCertArgs() *CertArgs { - return &CertArgs{CreateCerts: true} + return &CertArgs{ + CreateCerts: true, + CertDir: "openshift.local.certificates", + } } diff --git a/pkg/cmd/server/start/command_test.go b/pkg/cmd/server/start/command_test.go index 26439b501846..4728bf42f4ce 100644 --- a/pkg/cmd/server/start/command_test.go +++ b/pkg/cmd/server/start/command_test.go @@ -10,6 +10,7 @@ import ( "github.com/spf13/cobra" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" + utilerrors "github.com/GoogleCloudPlatform/kubernetes/pkg/util/errors" configapi "github.com/openshift/origin/pkg/cmd/server/api" "github.com/openshift/origin/pkg/cmd/server/api/validation" @@ -43,19 +44,19 @@ func TestCommandBindingListenHttp(t *testing.T) { t.Errorf("Expected %v, got %v", valueToSet, nodeArgs.ListenArg.ListenAddr.String()) } - // Ensure there are no errors other than missing client kubeconfig files + // Ensure there are no errors other than missing client kubeconfig files and missing bootstrap policy files masterErrs := validation.ValidateMasterConfig(masterCfg).Filter(func(e error) bool { - return strings.Contains(e.Error(), "masterClients.") + return strings.Contains(e.Error(), "masterClients.") || strings.Contains(e.Error(), "policyConfig.bootstrapPolicyFile") }) if len(masterErrs) != 0 { - t.Errorf("Unexpected validation errors: %#v", masterErrs) + t.Errorf("Unexpected validation errors: %v", utilerrors.NewAggregate(masterErrs)) } nodeErrs := validation.ValidateNodeConfig(nodeCfg).Filter(func(e error) bool { return strings.Contains(e.Error(), "masterKubeConfig") }) if len(nodeErrs) != 0 { - t.Errorf("Unexpected validation errors: %#v", nodeErrs) + t.Errorf("Unexpected validation errors: %v", utilerrors.NewAggregate(nodeErrs)) } } @@ -305,6 +306,7 @@ func executeMasterCommand(args []string) *MasterArgs { argsToUse = append(argsToUse, "master") argsToUse = append(argsToUse, args...) argsToUse = append(argsToUse, "--write-config") + argsToUse = append(argsToUse, "--create-policy-file=false") argsToUse = append(argsToUse, "--create-certs=false") argsToUse = append(argsToUse, "--config="+fakeConfigFile.Name()) @@ -341,6 +343,7 @@ func executeAllInOneCommandWithConfigs(args []string) (*MasterArgs, *configapi.M argsToUse = append(argsToUse, args...) argsToUse = append(argsToUse, "--write-config") argsToUse = append(argsToUse, "--create-certs=false") + argsToUse = append(argsToUse, "--create-policy-file=false") argsToUse = append(argsToUse, "--master-config="+fakeMasterConfigFile.Name()) argsToUse = append(argsToUse, "--node-config="+fakeNodeConfigFile.Name()) diff --git a/pkg/cmd/server/start/master_args.go b/pkg/cmd/server/start/master_args.go index 8ba22a61bd89..f9f8f6f84356 100644 --- a/pkg/cmd/server/start/master_args.go +++ b/pkg/cmd/server/start/master_args.go @@ -12,9 +12,10 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/openshift/origin/pkg/cmd/flagtypes" + "github.com/openshift/origin/pkg/cmd/server/admin" configapi "github.com/openshift/origin/pkg/cmd/server/api" latestconfigapi "github.com/openshift/origin/pkg/cmd/server/api/latest" - "github.com/openshift/origin/pkg/cmd/server/certs" + "github.com/openshift/origin/pkg/cmd/server/bootstrappolicy" cmdutil "github.com/openshift/origin/pkg/cmd/util" ) @@ -43,6 +44,7 @@ type MasterArgs struct { CORSAllowedOrigins util.StringList ListenArg *ListenArg + PolicyArgs *PolicyArgs ImageFormatArgs *ImageFormatArgs KubeConnectionArgs *KubeConnectionArgs CertArgs *CertArgs @@ -75,6 +77,7 @@ func NewDefaultMasterArgs() *MasterArgs { DNSBindAddr: flagtypes.Addr{Value: "0.0.0.0:53", DefaultScheme: "http", DefaultPort: 53, AllowPrefix: true}.Default(), ListenArg: NewDefaultListenArg(), + PolicyArgs: NewDefaultPolicyArgs(), ImageFormatArgs: NewDefaultImageFormatArgs(), KubeConnectionArgs: NewDefaultKubeConnectionArgs(), CertArgs: NewDefaultCertArgs(), @@ -168,9 +171,9 @@ func (args MasterArgs) BuildSerializeableMasterConfig() (*configapi.MasterConfig }, MasterClients: configapi.MasterClients{ - DeployerKubeConfig: certs.DefaultKubeConfigFilename(args.CertArgs.CertDir, "openshift-deployer"), - OpenShiftLoopbackKubeConfig: certs.DefaultKubeConfigFilename(args.CertArgs.CertDir, "openshift-client"), - KubernetesKubeConfig: certs.DefaultKubeConfigFilename(args.CertArgs.CertDir, "kube-client"), + DeployerKubeConfig: admin.DefaultKubeConfigFilename(args.CertArgs.CertDir, "openshift-deployer"), + OpenShiftLoopbackKubeConfig: admin.DefaultKubeConfigFilename(args.CertArgs.CertDir, "openshift-client"), + KubernetesKubeConfig: admin.DefaultKubeConfigFilename(args.CertArgs.CertDir, "kube-client"), }, EtcdClientInfo: configapi.RemoteConnectionInfo{ @@ -180,8 +183,11 @@ func (args MasterArgs) BuildSerializeableMasterConfig() (*configapi.MasterConfig ClientCert: configapi.CertInfo{}, }, - MasterAuthorizationNamespace: "master", - OpenShiftSharedResourcesNamespace: "openshift", + PolicyConfig: configapi.PolicyConfig{ + BootstrapPolicyFile: args.PolicyArgs.PolicyFile, + MasterAuthorizationNamespace: bootstrappolicy.DefaultMasterAuthorizationNamespace, + OpenShiftSharedResourcesNamespace: bootstrappolicy.DefaultOpenShiftSharedResourcesNamespace, + }, ImageConfig: configapi.ImageConfig{ Format: args.ImageFormatArgs.ImageTemplate.Format, @@ -190,11 +196,11 @@ func (args MasterArgs) BuildSerializeableMasterConfig() (*configapi.MasterConfig } if args.ListenArg.UseTLS() { - config.ServingInfo.ServerCert = certs.DefaultMasterServingCertInfo(args.CertArgs.CertDir) - config.ServingInfo.ClientCA = certs.DefaultRootCAFile(args.CertArgs.CertDir) + config.ServingInfo.ServerCert = admin.DefaultMasterServingCertInfo(args.CertArgs.CertDir) + config.ServingInfo.ClientCA = admin.DefaultRootCAFile(args.CertArgs.CertDir) - config.AssetConfig.ServingInfo.ServerCert = certs.DefaultAssetServingCertInfo(args.CertArgs.CertDir) - config.AssetConfig.ServingInfo.ClientCA = certs.DefaultRootCAFile(args.CertArgs.CertDir) + config.AssetConfig.ServingInfo.ServerCert = admin.DefaultAssetServingCertInfo(args.CertArgs.CertDir) + config.AssetConfig.ServingInfo.ClientCA = admin.DefaultRootCAFile(args.CertArgs.CertDir) } return config, nil diff --git a/pkg/cmd/server/start/node_args.go b/pkg/cmd/server/start/node_args.go index e8434f7b630d..3d7d1e9cbfda 100644 --- a/pkg/cmd/server/start/node_args.go +++ b/pkg/cmd/server/start/node_args.go @@ -13,9 +13,9 @@ import ( "github.com/golang/glog" "github.com/spf13/pflag" + "github.com/openshift/origin/pkg/cmd/server/admin" configapi "github.com/openshift/origin/pkg/cmd/server/api" latestconfigapi "github.com/openshift/origin/pkg/cmd/server/api/latest" - "github.com/openshift/origin/pkg/cmd/server/certs" cmdutil "github.com/openshift/origin/pkg/cmd/util" ) @@ -94,11 +94,11 @@ func (args NodeArgs) BuildSerializeableNodeConfig() (*configapi.NodeConfig, erro DNSDomain: args.ClusterDomain, DNSIP: dnsIP, - MasterKubeConfig: certs.DefaultNodeKubeConfigFile(args.CertArgs.CertDir, args.NodeName), + MasterKubeConfig: admin.DefaultNodeKubeConfigFile(args.CertArgs.CertDir, args.NodeName), } if args.ListenArg.UseTLS() { - config.ServingInfo.ServerCert = certs.DefaultNodeServingCertInfo(args.CertArgs.CertDir, args.NodeName) + config.ServingInfo.ServerCert = admin.DefaultNodeServingCertInfo(args.CertArgs.CertDir, args.NodeName) } return config, nil diff --git a/pkg/cmd/server/start/policy_args.go b/pkg/cmd/server/start/policy_args.go new file mode 100644 index 000000000000..409f4ff47edb --- /dev/null +++ b/pkg/cmd/server/start/policy_args.go @@ -0,0 +1,24 @@ +package start + +import ( + "github.com/spf13/pflag" + + "github.com/openshift/origin/pkg/cmd/server/admin" +) + +type PolicyArgs struct { + PolicyFile string + CreatePolicyFile bool + OverwritePolicyFile bool +} + +func BindPolicyArgs(args *PolicyArgs, flags *pflag.FlagSet, prefix string) { + flags.BoolVar(&args.CreatePolicyFile, prefix+"create-policy-file", args.CreatePolicyFile, "Create bootstrap policy if none is present.") +} + +func NewDefaultPolicyArgs() *PolicyArgs { + return &PolicyArgs{ + CreatePolicyFile: true, + PolicyFile: admin.DefaultPolicyFile, + } +} diff --git a/pkg/cmd/server/start/start_allinone.go b/pkg/cmd/server/start/start_allinone.go index 575850acbd5b..ebc3c041b0de 100644 --- a/pkg/cmd/server/start/start_allinone.go +++ b/pkg/cmd/server/start/start_allinone.go @@ -12,7 +12,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/util" - "github.com/openshift/origin/pkg/cmd/server/certs" + "github.com/openshift/origin/pkg/cmd/server/admin" _ "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/admit" _ "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/limitranger" @@ -93,6 +93,7 @@ func NewCommandStartAllInOne() (*cobra.Command, *AllInOneOptions) { BindMasterArgs(masterArgs, flags, "") BindNodeArgs(nodeArgs, flags, "") BindListenArg(listenArg, flags, "") + BindPolicyArgs(options.MasterArgs.PolicyArgs, flags, "") BindImageFormatArgs(imageFormatArgs, flags, "") BindKubeConnectionArgs(kubeConnectionArgs, flags, "") BindCertArgs(certArgs, flags, "") @@ -172,11 +173,11 @@ func (o AllInOneOptions) StartAllInOne() error { // if either one of these wants to mint certs, make sure the signer is present BEFORE they start up to make sure they always share if o.MasterArgs.CertArgs.CreateCerts || o.NodeArgs.CertArgs.CreateCerts { - signerOptions := &certs.CreateSignerCertOptions{ - CertFile: certs.DefaultCertFilename(o.NodeArgs.CertArgs.CertDir, "ca"), - KeyFile: certs.DefaultKeyFilename(o.NodeArgs.CertArgs.CertDir, "ca"), - SerialFile: certs.DefaultSerialFilename(o.NodeArgs.CertArgs.CertDir, "ca"), - Name: certs.DefaultSignerName(), + signerOptions := &admin.CreateSignerCertOptions{ + CertFile: admin.DefaultCertFilename(o.NodeArgs.CertArgs.CertDir, "ca"), + KeyFile: admin.DefaultKeyFilename(o.NodeArgs.CertArgs.CertDir, "ca"), + SerialFile: admin.DefaultSerialFilename(o.NodeArgs.CertArgs.CertDir, "ca"), + Name: admin.DefaultSignerName(), } if _, err := signerOptions.CreateSignerCert(); err != nil { diff --git a/pkg/cmd/server/start/start_master.go b/pkg/cmd/server/start/start_master.go index ca2f864e9622..a11d936404de 100644 --- a/pkg/cmd/server/start/start_master.go +++ b/pkg/cmd/server/start/start_master.go @@ -20,10 +20,11 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/client/record" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" + "github.com/openshift/origin/pkg/cmd/server/admin" configapi "github.com/openshift/origin/pkg/cmd/server/api" configapilatest "github.com/openshift/origin/pkg/cmd/server/api/latest" "github.com/openshift/origin/pkg/cmd/server/api/validation" - "github.com/openshift/origin/pkg/cmd/server/certs" + "github.com/openshift/origin/pkg/cmd/server/bootstrappolicy" "github.com/openshift/origin/pkg/cmd/server/etcd" "github.com/openshift/origin/pkg/cmd/server/kubernetes" "github.com/openshift/origin/pkg/cmd/server/origin" @@ -103,6 +104,7 @@ func NewCommandStartMaster() (*cobra.Command, *MasterOptions) { BindMasterArgs(options.MasterArgs, flags, "") BindListenArg(options.MasterArgs.ListenArg, flags, "") + BindPolicyArgs(options.MasterArgs.PolicyArgs, flags, "") BindImageFormatArgs(options.MasterArgs.ImageFormatArgs, flags, "") BindKubeConnectionArgs(options.MasterArgs.KubeConnectionArgs, flags, "") BindCertArgs(options.MasterArgs.CertArgs, flags, "") @@ -159,12 +161,18 @@ func (o MasterOptions) StartMaster() error { func (o MasterOptions) RunMaster() error { startUsingConfigFile := !o.WriteConfigOnly && (len(o.ConfigFile) > 0) mintCerts := o.MasterArgs.CertArgs.CreateCerts && !startUsingConfigFile + writeBootstrapPolicy := o.MasterArgs.PolicyArgs.CreatePolicyFile && !startUsingConfigFile if mintCerts { if err := o.CreateCerts(); err != nil { return nil } } + if writeBootstrapPolicy { + if err := o.CreateBootstrapPolicy(); err != nil { + return nil + } + } var masterConfig *configapi.MasterConfig var err error @@ -218,13 +226,23 @@ func (o MasterOptions) RunMaster() error { return nil } +func (o MasterOptions) CreateBootstrapPolicy() error { + writeBootstrapPolicy := admin.CreateBootstrapPolicyFileOptions{ + File: o.MasterArgs.PolicyArgs.PolicyFile, + MasterAuthorizationNamespace: bootstrappolicy.DefaultMasterAuthorizationNamespace, + OpenShiftSharedResourcesNamespace: bootstrappolicy.DefaultOpenShiftSharedResourcesNamespace, + } + + return writeBootstrapPolicy.CreateBootstrapPolicyFile() +} + func (o MasterOptions) CreateCerts() error { - signerName := certs.DefaultSignerName() + signerName := admin.DefaultSignerName() hostnames, err := o.MasterArgs.GetServerCertHostnames() if err != nil { return err } - mintAllCertsOptions := certs.CreateAllCertsOptions{ + mintAllCertsOptions := admin.CreateAllCertsOptions{ CertDir: o.MasterArgs.CertArgs.CertDir, SignerName: signerName, Hostnames: hostnames.List(), @@ -234,7 +252,7 @@ func (o MasterOptions) CreateCerts() error { return err } - rootCAFile := certs.DefaultRootCAFile(o.MasterArgs.CertArgs.CertDir) + rootCAFile := admin.DefaultRootCAFile(o.MasterArgs.CertArgs.CertDir) masterAddr, err := o.MasterArgs.GetMasterAddress() if err != nil { return err @@ -243,8 +261,8 @@ func (o MasterOptions) CreateCerts() error { if err != nil { return err } - for _, clientCertInfo := range certs.DefaultClientCerts(o.MasterArgs.CertArgs.CertDir) { - createKubeConfigOptions := certs.CreateKubeConfigOptions{ + for _, clientCertInfo := range admin.DefaultClientCerts(o.MasterArgs.CertArgs.CertDir) { + createKubeConfigOptions := admin.CreateKubeConfigOptions{ APIServerURL: masterAddr.String(), PublicAPIServerURL: publicMasterAddr.String(), APIServerCAFile: rootCAFile, @@ -254,7 +272,7 @@ func (o MasterOptions) CreateCerts() error { KeyFile: clientCertInfo.CertLocation.KeyFile, UserNick: clientCertInfo.SubDir, - KubeConfigFile: certs.DefaultKubeConfigFilename(o.MasterArgs.CertArgs.CertDir, clientCertInfo.SubDir), + KubeConfigFile: admin.DefaultKubeConfigFilename(o.MasterArgs.CertArgs.CertDir, clientCertInfo.SubDir), } if _, err := createKubeConfigOptions.CreateKubeConfig(); err != nil { diff --git a/pkg/cmd/server/start/start_node.go b/pkg/cmd/server/start/start_node.go index 53d549642766..d2c6b365f578 100644 --- a/pkg/cmd/server/start/start_node.go +++ b/pkg/cmd/server/start/start_node.go @@ -19,10 +19,10 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/client/record" "github.com/openshift/origin/pkg/cmd/server/kubernetes" + "github.com/openshift/origin/pkg/cmd/server/admin" configapi "github.com/openshift/origin/pkg/cmd/server/api" configapilatest "github.com/openshift/origin/pkg/cmd/server/api/latest" "github.com/openshift/origin/pkg/cmd/server/api/validation" - "github.com/openshift/origin/pkg/cmd/server/certs" cmdutil "github.com/openshift/origin/pkg/cmd/util" "github.com/openshift/origin/pkg/cmd/util/docker" ) @@ -204,23 +204,23 @@ func (o NodeOptions) RunNode() error { } func (o NodeOptions) CreateCerts() error { - signerOptions := &certs.CreateSignerCertOptions{ - CertFile: certs.DefaultCertFilename(o.NodeArgs.CertArgs.CertDir, "ca"), - KeyFile: certs.DefaultKeyFilename(o.NodeArgs.CertArgs.CertDir, "ca"), - SerialFile: certs.DefaultSerialFilename(o.NodeArgs.CertArgs.CertDir, "ca"), - Name: certs.DefaultSignerName(), + signerOptions := &admin.CreateSignerCertOptions{ + CertFile: admin.DefaultCertFilename(o.NodeArgs.CertArgs.CertDir, "ca"), + KeyFile: admin.DefaultKeyFilename(o.NodeArgs.CertArgs.CertDir, "ca"), + SerialFile: admin.DefaultSerialFilename(o.NodeArgs.CertArgs.CertDir, "ca"), + Name: admin.DefaultSignerName(), } if _, err := signerOptions.CreateSignerCert(); err != nil { return err } - getSignerOptions := &certs.GetSignerCertOptions{ - CertFile: certs.DefaultCertFilename(o.NodeArgs.CertArgs.CertDir, "ca"), - KeyFile: certs.DefaultKeyFilename(o.NodeArgs.CertArgs.CertDir, "ca"), - SerialFile: certs.DefaultSerialFilename(o.NodeArgs.CertArgs.CertDir, "ca"), + getSignerOptions := &admin.GetSignerCertOptions{ + CertFile: admin.DefaultCertFilename(o.NodeArgs.CertArgs.CertDir, "ca"), + KeyFile: admin.DefaultKeyFilename(o.NodeArgs.CertArgs.CertDir, "ca"), + SerialFile: admin.DefaultSerialFilename(o.NodeArgs.CertArgs.CertDir, "ca"), } - serverCertInfo := certs.DefaultNodeServingCertInfo(o.NodeArgs.CertArgs.CertDir, o.NodeArgs.NodeName) - nodeServerCertOptions := certs.CreateServerCertOptions{ + serverCertInfo := admin.DefaultNodeServingCertInfo(o.NodeArgs.CertArgs.CertDir, o.NodeArgs.NodeName) + nodeServerCertOptions := admin.CreateServerCertOptions{ GetSignerCertOptions: getSignerOptions, CertFile: serverCertInfo.CertFile, @@ -233,8 +233,8 @@ func (o NodeOptions) CreateCerts() error { return err } - clientCertInfo := certs.DefaultNodeClientCertInfo(o.NodeArgs.CertArgs.CertDir, o.NodeArgs.NodeName) - mintNodeClientCert := certs.CreateNodeClientCertOptions{ + clientCertInfo := admin.DefaultNodeClientCertInfo(o.NodeArgs.CertArgs.CertDir, o.NodeArgs.NodeName) + mintNodeClientCert := admin.CreateNodeClientCertOptions{ GetSignerCertOptions: getSignerOptions, CertFile: clientCertInfo.CertFile, KeyFile: clientCertInfo.KeyFile, @@ -249,7 +249,7 @@ func (o NodeOptions) CreateCerts() error { return err } - createKubeConfigOptions := certs.CreateKubeConfigOptions{ + createKubeConfigOptions := admin.CreateKubeConfigOptions{ APIServerURL: masterAddr.String(), APIServerCAFile: getSignerOptions.CertFile, ServerNick: "master", @@ -258,7 +258,7 @@ func (o NodeOptions) CreateCerts() error { KeyFile: mintNodeClientCert.KeyFile, UserNick: o.NodeArgs.NodeName, - KubeConfigFile: certs.DefaultNodeKubeConfigFile(o.NodeArgs.CertArgs.CertDir, o.NodeArgs.NodeName), + KubeConfigFile: admin.DefaultNodeKubeConfigFile(o.NodeArgs.CertArgs.CertDir, o.NodeArgs.NodeName), } if _, err := createKubeConfigOptions.CreateKubeConfig(); err != nil { return err diff --git a/test/integration/bootstrap_policy_test.go b/test/integration/bootstrap_policy_test.go index b0380bf00120..86ece8070460 100644 --- a/test/integration/bootstrap_policy_test.go +++ b/test/integration/bootstrap_policy_test.go @@ -10,7 +10,10 @@ import ( kapierror "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" + authorizationapi "github.com/openshift/origin/pkg/authorization/api" "github.com/openshift/origin/pkg/client" + "github.com/openshift/origin/pkg/cmd/server/admin" + "github.com/openshift/origin/pkg/cmd/server/etcd" "github.com/openshift/origin/pkg/cmd/util/tokencmd" ) @@ -68,3 +71,36 @@ func TestAuthenticatedUsersAgainstOpenshiftNamespace(t *testing.T) { t.Errorf("unexpected error: %v", err) } } + +func TestOverwritePolicyCommand(t *testing.T) { + masterConfig, clusterAdminKubeConfig, err := StartTestMaster() + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + client, _, _, err := GetClusterAdminClient(clusterAdminKubeConfig) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + + if err := client.Policies(masterConfig.PolicyConfig.MasterAuthorizationNamespace).Delete(authorizationapi.PolicyName); err != nil { + t.Errorf("unexpected error: %v", err) + } + + if _, err := client.Policies(masterConfig.PolicyConfig.MasterAuthorizationNamespace).List(labels.Everything(), labels.Everything()); err == nil || !strings.Contains(err.Error(), "Forbidden") { + t.Errorf("unexpected error: %v", err) + } + + etcdHelper, err := etcd.NewOpenShiftEtcdHelper(masterConfig.EtcdClientInfo.URL) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + + if err := admin.OverwriteBootstrapPolicy(etcdHelper, masterConfig.PolicyConfig.MasterAuthorizationNamespace, masterConfig.PolicyConfig.BootstrapPolicyFile); err != nil { + t.Errorf("unexpected error: %v", err) + } + + if _, err := client.Policies(masterConfig.PolicyConfig.MasterAuthorizationNamespace).List(labels.Everything(), labels.Everything()); err != nil { + t.Errorf("unexpected error: %v", err) + } +} diff --git a/test/integration/server_test.go b/test/integration/server_test.go index 88d272149029..a4abebb42972 100644 --- a/test/integration/server_test.go +++ b/test/integration/server_test.go @@ -31,6 +31,7 @@ func setupStartOptions() (*start.MasterArgs, *start.NodeArgs, *start.ListenArg, basedir := path.Join(os.TempDir(), "openshift-integration-tests") nodeArgs.VolumeDir = path.Join(basedir, "volume") masterArgs.EtcdDir = path.Join(basedir, "etcd") + masterArgs.PolicyArgs.PolicyFile = path.Join(basedir, "policy", "policy.json") certArgs.CertDir = path.Join(basedir, "cert") // don't wait for nodes to come up