Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move project creation to use RBAC objects #15973

Merged
merged 1 commit into from
Sep 6, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions pkg/cmd/server/bootstrappolicy/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -913,6 +913,12 @@ func newOriginRoleBinding(bindingName, roleName, namespace string) *rbac.RoleBin
return builder
}

func newOriginRoleBindingForClusterRole(bindingName, roleName, namespace string) *rbac.RoleBindingBuilder {
builder := rbac.NewRoleBindingForClusterRole(roleName, namespace)
builder.RoleBinding.Name = bindingName
return builder
}

func newOriginClusterBinding(bindingName, roleName string) *rbac.ClusterRoleBindingBuilder {
builder := rbac.NewClusterBinding(roleName)
builder.ClusterRoleBinding.Name = bindingName
Expand Down
48 changes: 12 additions & 36 deletions pkg/cmd/server/bootstrappolicy/project_policy.go
Original file line number Diff line number Diff line change
@@ -1,44 +1,20 @@
package bootstrappolicy

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apiserver/pkg/authentication/serviceaccount"
kapi "k8s.io/kubernetes/pkg/api"

authorizationapi "github.com/openshift/origin/pkg/authorization/apis/authorization"
"k8s.io/kubernetes/pkg/apis/rbac"
)

func GetBootstrapServiceAccountProjectRoleBindings(namespace string) []authorizationapi.RoleBinding {
return []authorizationapi.RoleBinding{
{
ObjectMeta: metav1.ObjectMeta{
Name: ImagePullerRoleBindingName,
Namespace: namespace,
},
RoleRef: kapi.ObjectReference{
Name: ImagePullerRoleName,
},
Subjects: []kapi.ObjectReference{{Kind: authorizationapi.SystemGroupKind, Name: serviceaccount.MakeNamespaceGroupName(namespace)}},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: ImageBuilderRoleBindingName,
Namespace: namespace,
},
RoleRef: kapi.ObjectReference{
Name: ImageBuilderRoleName,
},
Subjects: []kapi.ObjectReference{{Kind: authorizationapi.ServiceAccountKind, Name: BuilderServiceAccountName}},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: DeployerRoleBindingName,
Namespace: namespace,
},
RoleRef: kapi.ObjectReference{
Name: DeployerRoleName,
},
Subjects: []kapi.ObjectReference{{Kind: authorizationapi.ServiceAccountKind, Name: DeployerServiceAccountName}},
},
func GetBootstrapServiceAccountProjectRoleBindings(namespace string) []rbac.RoleBinding {
return []rbac.RoleBinding{
newOriginRoleBindingForClusterRole(ImagePullerRoleBindingName, ImagePullerRoleName, namespace).
Groups(serviceaccount.MakeNamespaceGroupName(namespace)).
BindingOrDie(),
newOriginRoleBindingForClusterRole(ImageBuilderRoleBindingName, ImageBuilderRoleName, namespace).
SAs(namespace, BuilderServiceAccountName).
BindingOrDie(),
newOriginRoleBindingForClusterRole(DeployerRoleBindingName, DeployerRoleName, namespace).
SAs(namespace, DeployerServiceAccountName).
BindingOrDie(),
}
}
11 changes: 9 additions & 2 deletions pkg/cmd/server/origin/openshift_apiserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/openshift/origin/pkg/api/v1"
"github.com/openshift/origin/pkg/authorization/authorizer"
authorizationinformer "github.com/openshift/origin/pkg/authorization/generated/informers/internalversion"
authorizationregistryutil "github.com/openshift/origin/pkg/authorization/registry/util"
buildapiserver "github.com/openshift/origin/pkg/build/apiserver"
osclient "github.com/openshift/origin/pkg/client"
configapi "github.com/openshift/origin/pkg/cmd/server/api"
Expand Down Expand Up @@ -625,15 +626,21 @@ func EnsureNamespaceServiceAccountRoleBindings(kubeClientInternal kclientsetinte
}

hasErrors := false
for _, binding := range bootstrappolicy.GetBootstrapServiceAccountProjectRoleBindings(namespace.Name) {
for _, rbacBinding := range bootstrappolicy.GetBootstrapServiceAccountProjectRoleBindings(namespace.Name) {
binding, err := authorizationregistryutil.RoleBindingFromRBAC(&rbacBinding)
if err != nil {
glog.Errorf("Could not convert Role Binding %s in the %q namespace: %v\n", rbacBinding.Name, namespace.Name, err)
hasErrors = true
continue
}
addRole := &policy.RoleModificationOptions{
RoleName: binding.RoleRef.Name,
RoleNamespace: binding.RoleRef.Namespace,
RoleBindingAccessor: policy.NewLocalRoleBindingAccessor(namespace.Name, deprecatedOpenshiftClient),
Subjects: binding.Subjects,
}
if err := retry.RetryOnConflict(retry.DefaultRetry, func() error { return addRole.AddRole() }); err != nil {
glog.Errorf("Could not add service accounts to the %v role in the %q namespace: %v\n", binding.RoleRef.Name, namespace.Name, err)
glog.Errorf("Could not add service accounts to the %s role in the %q namespace: %v\n", binding.RoleRef.Name, namespace.Name, err)
hasErrors = true
}
}
Expand Down
9 changes: 8 additions & 1 deletion pkg/oc/admin/project/new_project.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"

oapi "github.com/openshift/origin/pkg/api"
authorizationregistryutil "github.com/openshift/origin/pkg/authorization/registry/util"
"github.com/openshift/origin/pkg/client"
"github.com/openshift/origin/pkg/cmd/server/bootstrappolicy"
"github.com/openshift/origin/pkg/cmd/util/clientcmd"
Expand Down Expand Up @@ -127,7 +128,13 @@ func (o *NewProjectOptions) Run(useNodeSelector bool) error {
}
}

for _, binding := range bootstrappolicy.GetBootstrapServiceAccountProjectRoleBindings(o.ProjectName) {
for _, rbacBinding := range bootstrappolicy.GetBootstrapServiceAccountProjectRoleBindings(o.ProjectName) {
binding, err := authorizationregistryutil.RoleBindingFromRBAC(&rbacBinding)
if err != nil {
fmt.Printf("Could not convert Role Binding %s in the %q namespace: %v\n", rbacBinding.Name, o.ProjectName, err)
errs = append(errs, err)
continue
}
addRole := &policy.RoleModificationOptions{
RoleName: binding.RoleRef.Name,
RoleNamespace: binding.RoleRef.Namespace,
Expand Down
38 changes: 19 additions & 19 deletions pkg/project/registry/projectrequest/delegated/delegated.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
kapierror "k8s.io/apimachinery/pkg/api/errors"
metainternal "k8s.io/apimachinery/pkg/apis/meta/internalversion"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
Expand All @@ -19,6 +18,7 @@ import (
"k8s.io/apiserver/pkg/registry/rest"
restclient "k8s.io/client-go/rest"
kapi "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/rbac"
rbaclisters "k8s.io/kubernetes/pkg/client/listers/rbac/internalversion"
"k8s.io/kubernetes/pkg/client/retry"
"k8s.io/kubernetes/pkg/kubectl/resource"
Expand Down Expand Up @@ -133,20 +133,26 @@ func (r *REST) Create(ctx apirequest.Context, obj runtime.Object, includeUniniti

// one of the items in this list should be the project. We are going to locate it, remove it from the list, create it separately
var projectFromTemplate *projectapi.Project
var lastRoleBinding *authorizationapi.RoleBinding
lastRoleBindingName := ""
objectsToCreate := &kapi.List{}
for i := range list.Objects {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for _, lobj := range list.Objects {
	switch t := lobj.(type) {
	case *projectapi.Project:
		projectFromTemplate = t
		// don't add this to the list to create.  We'll create the project separately.
		continue
	case *rbac.RoleBinding:
		lastRoleBindingName = t.Name
	case *authorizationapi.RoleBinding:
		lastRoleBindingName = t.Name
	default:
		// no-op we only skip creation of project
	}

	objectsToCreate.Items = append(objectsToCreate.Items, lobj)
}

@liggitt any reason we were doing list.Objects[i] before? Also, do we want to error if we see more than one project in the template?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@liggitt any reason we were doing list.Objects[i] before?

so we didn't have to reason about range variable reuse outside the loop

Also, do we want to error if we see more than one project in the template?

probably

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so we didn't have to reason about range variable reuse outside the loop

At worst it would only shadow a var outside the loop (I picked a unique name to avoid that as well)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

at worst, you'd reuse a memory address and actually append the same item to the list of items to create N times

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

at worst, you'd reuse a memory address and actually append the same item to the list of items to create N times

Ah you are correct, I always forget the "don't use range vars + append together".

for i := range list.Objects {
	switch t := list.Objects[i].(type) {
	case *projectapi.Project:
		projectFromTemplate = t
		// don't add this to the list to create.  We'll create the project separately.
		continue
	case *rbac.RoleBinding:
		lastRoleBindingName = t.Name
	case *authorizationapi.RoleBinding:
		lastRoleBindingName = t.Name
	default:
		// no-op we only skip creation of project
	}
	// use list.Objects[i] in append to avoid range memory address reuse
	objectsToCreate.Items = append(objectsToCreate.Items, list.Objects[i])
}

if templateProject, ok := list.Objects[i].(*projectapi.Project); ok {
projectFromTemplate = templateProject
switch t := list.Objects[i].(type) {
case *projectapi.Project:
if projectFromTemplate != nil {
return nil, kapierror.NewInternalError(fmt.Errorf("the project template (%s/%s) is not correctly configured: must contain only one project resource", r.templateNamespace, r.templateName))
}
projectFromTemplate = t
// don't add this to the list to create. We'll create the project separately.
continue
case *rbac.RoleBinding:
lastRoleBindingName = t.Name
case *authorizationapi.RoleBinding:
lastRoleBindingName = t.Name
default:
// noop, we care only for special handling projects and roles
}

if roleBinding, ok := list.Objects[i].(*authorizationapi.RoleBinding); ok {
// keep track of the rolebinding, but still add it to the list
lastRoleBinding = roleBinding
}

// use list.Objects[i] in append to avoid range memory address reuse
objectsToCreate.Items = append(objectsToCreate.Items, list.Objects[i])
}
if projectFromTemplate == nil {
Expand Down Expand Up @@ -187,8 +193,8 @@ func (r *REST) Create(ctx apirequest.Context, obj runtime.Object, includeUniniti
}

// wait for a rolebinding if we created one
if lastRoleBinding != nil {
r.waitForRoleBinding(createdProject.Name, lastRoleBinding.Name)
if len(lastRoleBindingName) != 0 {
r.waitForRoleBinding(createdProject.Name, lastRoleBindingName)
}

return r.openshiftClient.Projects().Get(createdProject.Name, metav1.GetOptions{})
Expand All @@ -201,14 +207,8 @@ func (r *REST) waitForRoleBinding(namespace, name string) {
backoff := retry.DefaultBackoff
backoff.Steps = 6 // this effectively waits for 6-ish seconds
err := wait.ExponentialBackoff(backoff, func() (bool, error) {
roleBindings, _ := r.roleBindings.RoleBindings(namespace).List(labels.Everything())
for _, roleBinding := range roleBindings {
if roleBinding.Name == name {
return true, nil
}
}

return false, nil
_, err := r.roleBindings.RoleBindings(namespace).Get(name)
return err == nil, nil
})

if err != nil {
Expand Down
16 changes: 6 additions & 10 deletions pkg/project/registry/projectrequest/delegated/sample_template.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@ package delegated

import (
"k8s.io/apimachinery/pkg/runtime"
kapi "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/rbac"
"k8s.io/kubernetes/pkg/apis/rbac/v1beta1"

oapi "github.com/openshift/origin/pkg/api"
authorizationapi "github.com/openshift/origin/pkg/authorization/apis/authorization"
authorizationapiv1 "github.com/openshift/origin/pkg/authorization/apis/authorization/v1"
"github.com/openshift/origin/pkg/cmd/server/bootstrappolicy"
projectapi "github.com/openshift/origin/pkg/project/apis/project"
projectapiv1 "github.com/openshift/origin/pkg/project/apis/project/v1"
Expand Down Expand Up @@ -46,17 +45,14 @@ func DefaultTemplate() *templateapi.Template {

serviceAccountRoleBindings := bootstrappolicy.GetBootstrapServiceAccountProjectRoleBindings(ns)
for i := range serviceAccountRoleBindings {
if err := templateapi.AddObjectsToTemplate(ret, []runtime.Object{&serviceAccountRoleBindings[i]}, authorizationapiv1.SchemeGroupVersion); err != nil {
if err := templateapi.AddObjectsToTemplate(ret, []runtime.Object{&serviceAccountRoleBindings[i]}, v1beta1.SchemeGroupVersion); err != nil {
panic(err)
}
}

binding := &authorizationapi.RoleBinding{}
binding.Name = bootstrappolicy.AdminRoleName
binding.Namespace = ns
binding.Subjects = []kapi.ObjectReference{{Kind: authorizationapi.UserKind, Name: "${" + ProjectAdminUserParam + "}"}}
binding.RoleRef.Name = bootstrappolicy.AdminRoleName
if err := templateapi.AddObjectsToTemplate(ret, []runtime.Object{binding}, authorizationapiv1.SchemeGroupVersion); err != nil {
binding := rbac.NewRoleBindingForClusterRole(bootstrappolicy.AdminRoleName, ns).Users("${" + ProjectAdminUserParam + "}").BindingOrDie()

if err := templateapi.AddObjectsToTemplate(ret, []runtime.Object{&binding}, v1beta1.SchemeGroupVersion); err != nil {
// this should never happen because we're tightly controlling what goes in.
panic(err)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,46 +1,45 @@
apiVersion: v1
items:
- apiVersion: v1
groupNames:
- system:serviceaccounts:myproject
- apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
creationTimestamp: null
name: system:image-pullers
namespace: myproject
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:image-puller
subjects:
- kind: SystemGroup
- kind: Group
name: system:serviceaccounts:myproject
userNames: null
- apiVersion: v1
groupNames: null
- apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
creationTimestamp: null
name: system:image-builders
namespace: myproject
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:image-builder
subjects:
- kind: ServiceAccount
name: builder
userNames:
- system:serviceaccount:myproject:builder
- apiVersion: v1
groupNames: null
namespace: myproject
- apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
creationTimestamp: null
name: system:deployers
namespace: myproject
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:deployer
subjects:
- kind: ServiceAccount
name: deployer
userNames:
- system:serviceaccount:myproject:deployer
namespace: myproject
kind: List
metadata: {}