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

reconcile cluster roles instead of overwriting #15654

Merged
merged 3 commits into from
Aug 8, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
121 changes: 52 additions & 69 deletions pkg/cmd/server/origin/ensure.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
kapierror "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
apirequest "k8s.io/apiserver/pkg/endpoints/request"
genericapiserver "k8s.io/apiserver/pkg/server"
kapi "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/rbac"
Expand All @@ -18,90 +17,74 @@ import (
"github.com/openshift/origin/pkg/oc/admin/policy"

authorizationapi "github.com/openshift/origin/pkg/authorization/apis/authorization"
clusterpolicyregistry "github.com/openshift/origin/pkg/authorization/registry/clusterpolicy"
clusterpolicystorage "github.com/openshift/origin/pkg/authorization/registry/clusterpolicy/etcd"
"github.com/openshift/origin/pkg/cmd/server/admin"
"github.com/openshift/origin/pkg/cmd/server/bootstrappolicy"
)

// ensureComponentAuthorizationRules initializes the cluster policies
func (c *MasterConfig) ensureComponentAuthorizationRules(context genericapiserver.PostStartHookContext) error {
clusterPolicyStorage, err := clusterpolicystorage.NewREST(c.RESTOptionsGetter)
if err != nil {
glog.Errorf("Error creating policy storage: %v", err)
return nil
}
clusterPolicyRegistry := clusterpolicyregistry.NewRegistry(clusterPolicyStorage)
ctx := apirequest.WithNamespace(apirequest.NewContext(), "")

if _, err := clusterPolicyRegistry.GetClusterPolicy(ctx, authorizationapi.PolicyName, &metav1.GetOptions{}); kapierror.IsNotFound(err) {
glog.Infof("No cluster policy found. Creating bootstrap policy based on: %v", c.Options.PolicyConfig.BootstrapPolicyFile)

if err := admin.OverwriteBootstrapPolicy(c.RESTOptionsGetter, c.Options.PolicyConfig.BootstrapPolicyFile, admin.CreateBootstrapPolicyFileFullCommand, true, ioutil.Discard); err != nil {
glog.Errorf("Error creating bootstrap policy: %v", err)
}

// these are namespaced, so we can't reconcile them. Just try to put them in until we work against rbac
// This only had to hold us until the transition is complete
// TODO remove this block and use a post-starthook
// ensure bootstrap namespaced roles are created or reconciled
for namespace, roles := range kbootstrappolicy.NamespaceRoles() {
for _, rbacRole := range roles {
role := &authorizationapi.Role{}
if err := authorizationapi.Convert_rbac_Role_To_authorization_Role(&rbacRole, role, nil); err != nil {
utilruntime.HandleError(fmt.Errorf("unable to convert role.%s/%s in %v: %v", rbac.GroupName, rbacRole.Name, namespace, err))
continue
}
if _, err := c.PrivilegedLoopbackOpenShiftClient.Roles(namespace).Create(role); err != nil {
// don't fail on failures, try to create as many as you can
utilruntime.HandleError(fmt.Errorf("unable to reconcile role.%s/%s in %v: %v", rbac.GroupName, role.Name, namespace, err))
}
}
}

// ensure bootstrap namespaced rolebindings are created or reconciled
for namespace, roleBindings := range kbootstrappolicy.NamespaceRoleBindings() {
for _, rbacRoleBinding := range roleBindings {
roleBinding := &authorizationapi.RoleBinding{}
if err := authorizationapi.Convert_rbac_RoleBinding_To_authorization_RoleBinding(&rbacRoleBinding, roleBinding, nil); err != nil {
utilruntime.HandleError(fmt.Errorf("unable to convert rolebinding.%s/%s in %v: %v", rbac.GroupName, rbacRoleBinding.Name, namespace, err))
continue
}
if _, err := c.PrivilegedLoopbackOpenShiftClient.RoleBindings(namespace).Create(roleBinding); err != nil {
// don't fail on failures, try to create as many as you can
utilruntime.HandleError(fmt.Errorf("unable to reconcile rolebinding.%s/%s in %v: %v", rbac.GroupName, roleBinding.Name, namespace, err))
}
}
}

} else {
glog.V(2).Infof("Ignoring bootstrap policy file because cluster policy found")
}

// Reconcile roles that must exist for the cluster to function
// Be very judicious about what is placed in this list, since it will be enforced on every server start
reconcileRoles := &policy.ReconcileClusterRolesOptions{
RolesToReconcile: []string{bootstrappolicy.DiscoveryRoleName},
reconcileRole := &policy.ReconcileClusterRolesOptions{
RolesToReconcile: nil, // means all
Confirmed: true,
Union: true,
Out: ioutil.Discard,
RoleClient: c.PrivilegedLoopbackOpenShiftClient.ClusterRoles(),
}
if err := reconcileRoles.RunReconcileClusterRoles(nil, nil); err != nil {
glog.Errorf("Could not auto reconcile roles: %v\n", err)
if err := reconcileRole.RunReconcileClusterRoles(nil, nil); err != nil {
glog.Errorf("Could not reconcile: %v", err)
}

// Reconcile rolebindings that must exist for the cluster to function
// Be very judicious about what is placed in this list, since it will be enforced on every server start
reconcileRoleBindings := &policy.ReconcileClusterRoleBindingsOptions{
RolesToReconcile: []string{bootstrappolicy.DiscoveryRoleName},
reconcileRoleBinding := &policy.ReconcileClusterRoleBindingsOptions{
RolesToReconcile: nil, // means all
Confirmed: true,
Union: true,
Out: ioutil.Discard,
RoleBindingClient: c.PrivilegedLoopbackOpenShiftClient.ClusterRoleBindings(),
}
if err := reconcileRoleBindings.RunReconcileClusterRoleBindings(nil, nil); err != nil {
glog.Errorf("Could not auto reconcile role bindings: %v\n", err)
if err := reconcileRoleBinding.RunReconcileClusterRoleBindings(nil, nil); err != nil {
glog.Errorf("Could not reconcile: %v", err)
}

// these are namespaced, so we can't reconcile them. Just try to put them in until we work against rbac
// This only had to hold us until the transition is complete
// ensure bootstrap namespaced roles are created or reconciled
for namespace, roles := range kbootstrappolicy.NamespaceRoles() {
for _, rbacRole := range roles {
role := &authorizationapi.Role{}
if err := authorizationapi.Convert_rbac_Role_To_authorization_Role(&rbacRole, role, nil); err != nil {
utilruntime.HandleError(fmt.Errorf("unable to convert role.%s/%s in %v: %v", rbac.GroupName, rbacRole.Name, namespace, err))
continue
}
if _, err := c.PrivilegedLoopbackOpenShiftClient.Roles(namespace).Create(role); err != nil && !kapierror.IsAlreadyExists(err) {
// don't fail on failures, try to create as many as you can
utilruntime.HandleError(fmt.Errorf("unable to reconcile role.%s/%s in %v: %v", rbac.GroupName, role.Name, namespace, err))
}
}
}
for _, role := range bootstrappolicy.GetBootstrapOpenshiftRoles(c.Options.PolicyConfig.OpenShiftSharedResourcesNamespace) {
if _, err := c.PrivilegedLoopbackOpenShiftClient.Roles(c.Options.PolicyConfig.OpenShiftSharedResourcesNamespace).Create(&role); err != nil && !kapierror.IsAlreadyExists(err) {
// don't fail on failures, try to create as many as you can
utilruntime.HandleError(fmt.Errorf("unable to reconcile role.%s/%s in %v: %v", rbac.GroupName, role.Name, c.Options.PolicyConfig.OpenShiftSharedResourcesNamespace, err))
}
}

// ensure bootstrap namespaced rolebindings are created or reconciled
for namespace, roleBindings := range kbootstrappolicy.NamespaceRoleBindings() {
for _, rbacRoleBinding := range roleBindings {
roleBinding := &authorizationapi.RoleBinding{}
if err := authorizationapi.Convert_rbac_RoleBinding_To_authorization_RoleBinding(&rbacRoleBinding, roleBinding, nil); err != nil {
utilruntime.HandleError(fmt.Errorf("unable to convert rolebinding.%s/%s in %v: %v", rbac.GroupName, rbacRoleBinding.Name, namespace, err))
continue
}
if _, err := c.PrivilegedLoopbackOpenShiftClient.RoleBindings(namespace).Create(roleBinding); err != nil && !kapierror.IsAlreadyExists(err) {
// don't fail on failures, try to create as many as you can
utilruntime.HandleError(fmt.Errorf("unable to reconcile rolebinding.%s/%s in %v: %v", rbac.GroupName, roleBinding.Name, namespace, err))
}
}
}
for _, roleBinding := range bootstrappolicy.GetBootstrapOpenshiftRoleBindings(c.Options.PolicyConfig.OpenShiftSharedResourcesNamespace) {
if _, err := c.PrivilegedLoopbackOpenShiftClient.RoleBindings(c.Options.PolicyConfig.OpenShiftSharedResourcesNamespace).Create(&roleBinding); err != nil && !kapierror.IsAlreadyExists(err) {
// don't fail on failures, try to create as many as you can
utilruntime.HandleError(fmt.Errorf("unable to reconcile rolebinding.%s/%s in %v: %v", rbac.GroupName, roleBinding.Name, c.Options.PolicyConfig.OpenShiftSharedResourcesNamespace, err))
}
}

return nil
Expand Down
26 changes: 0 additions & 26 deletions pkg/cmd/server/origin/openshift_apiserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package origin
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strings"
"time"
Expand Down Expand Up @@ -429,31 +428,6 @@ func (c *OpenshiftAPIConfig) ensureOpenShiftInfraNamespace(context genericapiser
return nil
}

for _, role := range bootstrappolicy.ControllerRoles() {
reconcileRole := &policy.ReconcileClusterRolesOptions{
RolesToReconcile: []string{role.Name},
Confirmed: true,
Union: true,
Out: ioutil.Discard,
RoleClient: c.DeprecatedOpenshiftClient.ClusterRoles(),
}
if err := reconcileRole.RunReconcileClusterRoles(nil, nil); err != nil {
glog.Errorf("Could not reconcile %v: %v\n", role.Name, err)
}
}
for _, roleBinding := range bootstrappolicy.ControllerRoleBindings() {
reconcileRoleBinding := &policy.ReconcileClusterRoleBindingsOptions{
RolesToReconcile: []string{roleBinding.RoleRef.Name},
Confirmed: true,
Union: true,
Out: ioutil.Discard,
RoleBindingClient: c.DeprecatedOpenshiftClient.ClusterRoleBindings(),
}
if err := reconcileRoleBinding.RunReconcileClusterRoleBindings(nil, nil); err != nil {
glog.Errorf("Could not reconcile %v: %v\n", roleBinding.Name, err)
}
}

EnsureNamespaceServiceAccountRoleBindings(c.KubeClientInternal, c.DeprecatedOpenshiftClient, namespace)
return nil
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/diagnostics/cluster/rolebindings.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func (d *ClusterRoleBindings) Check() types.DiagnosticResult {
RoleBindingClient: d.ClusterRoleBindingsClient.ClusterRoleBindings(),
}

changedClusterRoleBindings, err := reconcileOptions.ChangedClusterRoleBindings()
changedClusterRoleBindings, _, err := reconcileOptions.ChangedClusterRoleBindings()
if policycmd.IsClusterRoleBindingLookupError(err) {
// we got a partial match, so we log the error that stopped us from getting a full match
// but continue to interpret the partial results that we did get
Expand Down
24 changes: 18 additions & 6 deletions pkg/oc/admin/policy/reconcile_clusterrolebindings.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,19 @@ func (o *ReconcileClusterRoleBindingsOptions) Validate() error {
}

func (o *ReconcileClusterRoleBindingsOptions) RunReconcileClusterRoleBindings(cmd *cobra.Command, f *clientcmd.Factory) error {
changedClusterRoleBindings, fetchErr := o.ChangedClusterRoleBindings()
changedClusterRoleBindings, skippedClusterRoleBindings, fetchErr := o.ChangedClusterRoleBindings()
if fetchErr != nil && !IsClusterRoleBindingLookupError(fetchErr) {
// we got an error that isn't due to a partial match, so we can't continue
return fetchErr
}

if len(skippedClusterRoleBindings) > 0 {
fmt.Fprintf(o.Err, "Skipped reconciling roles with the annotation %s=true\n", ReconcileProtectAnnotation)
for _, role := range skippedClusterRoleBindings {
fmt.Fprintf(o.Err, "skipped: clusterrolebinding/%s\n", role.Name)
}
}

if len(changedClusterRoleBindings) == 0 {
return fetchErr
}
Expand Down Expand Up @@ -195,8 +202,9 @@ func (o *ReconcileClusterRoleBindingsOptions) RunReconcileClusterRoleBindings(cm
// ChangedClusterRoleBindings returns the role bindings that must be created and/or updated to
// match the recommended bootstrap policy. If roles to reconcile are provided, but not all are
// found, all partial results are returned.
func (o *ReconcileClusterRoleBindingsOptions) ChangedClusterRoleBindings() ([]*authorizationapi.ClusterRoleBinding, error) {
func (o *ReconcileClusterRoleBindingsOptions) ChangedClusterRoleBindings() ([]*authorizationapi.ClusterRoleBinding, []*authorizationapi.ClusterRoleBinding, error) {
changedRoleBindings := []*authorizationapi.ClusterRoleBinding{}
skippedRoleBindings := []*authorizationapi.ClusterRoleBinding{}

rolesToReconcile := sets.NewString(o.RolesToReconcile...)
rolesNotFound := sets.NewString(o.RolesToReconcile...)
Expand All @@ -216,7 +224,7 @@ func (o *ReconcileClusterRoleBindingsOptions) ChangedClusterRoleBindings() ([]*a
continue
}
if err != nil {
return nil, err
return nil, nil, err
}

// Copy any existing labels/annotations, so the displayed update is correct
Expand All @@ -226,16 +234,20 @@ func (o *ReconcileClusterRoleBindingsOptions) ChangedClusterRoleBindings() ([]*a
expectedClusterRoleBinding.Annotations = actualClusterRoleBinding.Annotations

if updatedClusterRoleBinding, needsUpdating := computeUpdatedBinding(*expectedClusterRoleBinding, *actualClusterRoleBinding, o.ExcludeSubjects, o.Union); needsUpdating {
changedRoleBindings = append(changedRoleBindings, updatedClusterRoleBinding)
if actualClusterRoleBinding.Annotations[ReconcileProtectAnnotation] == "true" {
skippedRoleBindings = append(skippedRoleBindings, updatedClusterRoleBinding)
} else {
changedRoleBindings = append(changedRoleBindings, updatedClusterRoleBinding)
}
}
}

if len(rolesNotFound) != 0 {
// return the known changes and the error so that a caller can decide if he wants a partial update
return changedRoleBindings, NewClusterRoleBindingLookupError(rolesNotFound.List())
return changedRoleBindings, skippedRoleBindings, NewClusterRoleBindingLookupError(rolesNotFound.List())
}

return changedRoleBindings, nil
return changedRoleBindings, skippedRoleBindings, nil
}

// ReplaceChangedRoleBindings will reconcile all the changed system role bindings back to the recommended bootstrap policy
Expand Down