Esempio n. 1
0
// ChangedClusterRoles returns the roles that must be created and/or updated to
// match the recommended bootstrap policy
func (o *ReconcileClusterRolesOptions) ChangedClusterRoles() ([]*authorizationapi.ClusterRole, []*authorizationapi.ClusterRole, error) {
	changedRoles := []*authorizationapi.ClusterRole{}
	skippedRoles := []*authorizationapi.ClusterRole{}

	rolesToReconcile := sets.NewString(o.RolesToReconcile...)
	rolesNotFound := sets.NewString(o.RolesToReconcile...)
	bootstrapClusterRoles := bootstrappolicy.GetBootstrapClusterRoles()
	for i := range bootstrapClusterRoles {
		expectedClusterRole := &bootstrapClusterRoles[i]
		if (len(rolesToReconcile) > 0) && !rolesToReconcile.Has(expectedClusterRole.Name) {
			continue
		}
		rolesNotFound.Delete(expectedClusterRole.Name)

		actualClusterRole, err := o.RoleClient.Get(expectedClusterRole.Name)
		if kapierrors.IsNotFound(err) {
			changedRoles = append(changedRoles, expectedClusterRole)
			continue
		}
		if err != nil {
			return nil, nil, err
		}

		// Copy any existing labels/annotations, so the displayed update is correct
		// This assumes bootstrap roles will not set any labels/annotations
		// These aren't actually used during update; the latest labels/annotations are pulled from the existing object again
		expectedClusterRole.Labels = actualClusterRole.Labels
		expectedClusterRole.Annotations = actualClusterRole.Annotations

		_, extraRules := rulevalidation.Covers(expectedClusterRole.Rules, actualClusterRole.Rules)
		_, missingRules := rulevalidation.Covers(actualClusterRole.Rules, expectedClusterRole.Rules)

		// We need to reconcile:
		// 1. if we're missing rules
		// 2. if there are extra rules we need to remove
		if (len(missingRules) > 0) || (!o.Union && len(extraRules) > 0) {
			if o.Union {
				expectedClusterRole.Rules = append(expectedClusterRole.Rules, extraRules...)
			}

			if actualClusterRole.Annotations[ReconcileProtectAnnotation] == "true" {
				skippedRoles = append(skippedRoles, expectedClusterRole)
			} else {
				changedRoles = append(changedRoles, expectedClusterRole)
			}
		}
	}

	if len(rolesNotFound) != 0 {
		// return the known changes and the error so that a caller can decide if he wants a partial update
		return changedRoles, skippedRoles, fmt.Errorf("did not find requested cluster role %s", rolesNotFound.List())
	}

	return changedRoles, skippedRoles, nil
}
Esempio n. 2
0
func (d *ClusterRoles) Check() types.DiagnosticResult {
	r := types.NewDiagnosticResult(ClusterRolesName)

	reconcileOptions := &policycmd.ReconcileClusterRolesOptions{
		Confirmed:  false,
		Union:      false,
		Out:        ioutil.Discard,
		RoleClient: d.ClusterRolesClient.ClusterRoles(),
	}

	changedClusterRoles, err := reconcileOptions.ChangedClusterRoles()
	if err != nil {
		r.Error("CRD1000", err, fmt.Sprintf("Error inspecting ClusterRoles: %v", err))
		return r
	}

	// success
	if len(changedClusterRoles) == 0 {
		return r
	}

	for _, changedClusterRole := range changedClusterRoles {
		actualClusterRole, err := d.ClusterRolesClient.ClusterRoles().Get(changedClusterRole.Name)
		if kerrs.IsNotFound(err) {
			r.Error("CRD1002", nil, fmt.Sprintf("clusterrole/%s is missing.\n\nUse the `oadm policy reconcile-cluster-roles` command to create the role.", changedClusterRole.Name))
			continue
		}
		if err != nil {
			r.Error("CRD1001", err, fmt.Sprintf("Unable to get clusterrole/%s: %v", changedClusterRole.Name, err))
		}

		_, missingRules := rulevalidation.Covers(actualClusterRole.Rules, changedClusterRole.Rules)
		if len(missingRules) == 0 {
			r.Warn("CRD1003", nil, fmt.Sprintf("clusterrole/%s has changed, but the existing role has more permissions than the new role.\n\nUse the `oadm policy reconcile-cluster-roles` command to update the role to reduce permissions.", changedClusterRole.Name))
			_, extraRules := rulevalidation.Covers(changedClusterRole.Rules, actualClusterRole.Rules)
			for _, extraRule := range extraRules {
				r.Info("CRD1008", fmt.Sprintf("clusterrole/%s has extra permission %v.", changedClusterRole.Name, extraRule))
			}
			continue
		}

		r.Error("CRD1005", nil, fmt.Sprintf("clusterrole/%s has changed and the existing role does not have enough permissions.\n\nUse the `oadm policy reconcile-cluster-roles` command to update the role.", changedClusterRole.Name))
		for _, missingRule := range missingRules {
			r.Info("CRD1007", fmt.Sprintf("clusterrole/%s is missing permission %v.", changedClusterRole.Name, missingRule))
		}
		r.Debug("CRD1006", fmt.Sprintf("clusterrole/%s is now %v.", changedClusterRole.Name, changedClusterRole))
	}

	return r
}
Esempio n. 3
0
func (d *ClusterRoles) Check() types.DiagnosticResult {
	r := types.NewDiagnosticResult(ClusterRolesName)

	reconcileOptions := &policycmd.ReconcileClusterRolesOptions{
		Confirmed:  false,
		Union:      false,
		Out:        ioutil.Discard,
		RoleClient: d.ClusterRolesClient.ClusterRoles(),
	}

	changedClusterRoles, _, err := reconcileOptions.ChangedClusterRoles()
	if err != nil {
		r.Error("CRD1000", err, fmt.Sprintf("Error inspecting ClusterRoles: %v", err))
		return r
	}

	// success
	if len(changedClusterRoles) == 0 {
		return r
	}

	for _, changedClusterRole := range changedClusterRoles {
		actualClusterRole, err := d.ClusterRolesClient.ClusterRoles().Get(changedClusterRole.Name)
		if kerrs.IsNotFound(err) {
			r.Error("CRD1002", nil, fmt.Sprintf(clusterRoleMissing, changedClusterRole.Name))
			continue
		}
		if err != nil {
			r.Error("CRD1001", err, fmt.Sprintf("Unable to get clusterrole/%s: %v", changedClusterRole.Name, err))
		}

		_, missingRules := rulevalidation.Covers(actualClusterRole.Rules, changedClusterRole.Rules)
		if len(missingRules) == 0 {
			r.Info("CRD1003", fmt.Sprintf(clusterRoleReduced, changedClusterRole.Name))
			_, extraRules := rulevalidation.Covers(changedClusterRole.Rules, actualClusterRole.Rules)
			for _, extraRule := range extraRules {
				r.Info("CRD1008", fmt.Sprintf("clusterrole/%s has extra permission %v.", changedClusterRole.Name, extraRule))
			}
			continue
		}

		r.Error("CRD1005", nil, fmt.Sprintf(clusterRoleChanged, changedClusterRole.Name))
		for _, missingRule := range missingRules {
			r.Info("CRD1007", fmt.Sprintf("clusterrole/%s is missing permission %v.", changedClusterRole.Name, missingRule))
		}
		r.Debug("CRD1006", fmt.Sprintf("clusterrole/%s is now %v.", changedClusterRole.Name, changedClusterRole))
	}

	return r
}
Esempio n. 4
0
func (m *VirtualStorage) confirmNoEscalation(ctx kapi.Context, roleBinding *authorizationapi.RoleBinding) error {
	modifyingRole, err := m.getReferencedRole(roleBinding.RoleRef)
	if err != nil {
		return err
	}

	ruleResolver := rulevalidation.NewDefaultRuleResolver(
		m.PolicyRegistry,
		m.BindingRegistry,
		m.ClusterPolicyRegistry,
		m.ClusterPolicyBindingRegistry,
	)
	ownerLocalRules, err := ruleResolver.GetEffectivePolicyRules(ctx)
	if err != nil {
		return kapierrors.NewInternalError(err)
	}
	masterContext := kapi.WithNamespace(ctx, "")
	ownerGlobalRules, err := ruleResolver.GetEffectivePolicyRules(masterContext)
	if err != nil {
		return kapierrors.NewInternalError(err)
	}

	ownerRules := make([]authorizationapi.PolicyRule, 0, len(ownerGlobalRules)+len(ownerLocalRules))
	ownerRules = append(ownerRules, ownerLocalRules...)
	ownerRules = append(ownerRules, ownerGlobalRules...)

	ownerRightsCover, missingRights := rulevalidation.Covers(ownerRules, modifyingRole.Rules)
	if !ownerRightsCover {
		user, _ := kapi.UserFrom(ctx)
		return kapierrors.NewUnauthorized(fmt.Sprintf("attempt to grant extra privileges: %v user=%v ownerrules=%v", missingRights, user, ownerRules))
	}

	return nil
}
Esempio n. 5
0
// ChangedClusterRoles returns the roles that must be created and/or updated to
// match the recommended bootstrap policy
func (o *ReconcileClusterRolesOptions) ChangedClusterRoles() ([]*authorizationapi.ClusterRole, error) {
	changedRoles := []*authorizationapi.ClusterRole{}

	bootstrapClusterRoles := bootstrappolicy.GetBootstrapClusterRoles()
	for i := range bootstrapClusterRoles {
		expectedClusterRole := &bootstrapClusterRoles[i]

		actualClusterRole, err := o.RoleClient.Get(expectedClusterRole.Name)
		if kapierrors.IsNotFound(err) {
			changedRoles = append(changedRoles, expectedClusterRole)
			continue
		}
		if err != nil {
			return nil, err
		}

		if !kapi.Semantic.DeepEqual(expectedClusterRole.Rules, actualClusterRole.Rules) {
			if o.Union {
				_, missingRules := rulevalidation.Covers(expectedClusterRole.Rules, actualClusterRole.Rules)
				expectedClusterRole.Rules = append(expectedClusterRole.Rules, missingRules...)
			}
			changedRoles = append(changedRoles, expectedClusterRole)
		}
	}

	return changedRoles, nil
}
Esempio n. 6
0
// ChangedClusterRoles returns the roles that must be created and/or updated to
// match the recommended bootstrap policy
func (o *ReconcileClusterRolesOptions) ChangedClusterRoles() ([]*authorizationapi.ClusterRole, error) {
	changedRoles := []*authorizationapi.ClusterRole{}

	bootstrapClusterRoles := bootstrappolicy.GetBootstrapClusterRoles()
	for i := range bootstrapClusterRoles {
		expectedClusterRole := &bootstrapClusterRoles[i]

		actualClusterRole, err := o.RoleClient.Get(expectedClusterRole.Name)
		if kapierrors.IsNotFound(err) {
			changedRoles = append(changedRoles, expectedClusterRole)
			continue
		}
		if err != nil {
			return nil, err
		}

		// Copy any existing labels/annotations, so the displayed update is correct
		// This assumes bootstrap roles will not set any labels/annotations
		// These aren't actually used during update; the latest labels/annotations are pulled from the existing object again
		expectedClusterRole.Labels = actualClusterRole.Labels
		expectedClusterRole.Annotations = actualClusterRole.Annotations

		if !kapi.Semantic.DeepEqual(expectedClusterRole.Rules, actualClusterRole.Rules) {
			if o.Union {
				_, missingRules := rulevalidation.Covers(expectedClusterRole.Rules, actualClusterRole.Rules)
				expectedClusterRole.Rules = append(expectedClusterRole.Rules, missingRules...)
			}
			changedRoles = append(changedRoles, expectedClusterRole)
		}
	}

	return changedRoles, nil
}
Esempio n. 7
0
// leave this in place so I can use when converting the SAs
func DisableTestClusterRoles(t *testing.T) {
	currentRoles := bootstrappolicy.GetBootstrapClusterRoles()
	oldRoles := oldGetBootstrapClusterRoles()

	// old roles don't have the SAs appended, so run through them.  The SAs haven't been converted yet
	for i := range oldRoles {
		oldRole := oldRoles[i]
		newRole := currentRoles[i]

		if oldRole.Name != newRole.Name {
			t.Fatalf("%v vs %v", oldRole.Name, newRole.Name)
		}

		// @liggitt don't whine about a temporary test fataling
		if covers, missing := rulevalidation.Covers(oldRole.Rules, newRole.Rules); !covers {
			t.Fatalf("%v/%v: %#v", oldRole.Name, newRole.Name, missing)
		}
		if covers, missing := rulevalidation.Covers(newRole.Rules, oldRole.Rules); !covers {
			t.Fatalf("%v/%v: %#v", oldRole.Name, newRole.Name, missing)
		}
	}
}
Esempio n. 8
0
func filterRulesByScopes(rules []authorizationapi.PolicyRule, scopes []string, namespace string, clusterPolicyGetter client.ClusterPolicyLister) ([]authorizationapi.PolicyRule, error) {
	scopeRules, err := scope.ScopesToRules(scopes, namespace, clusterPolicyGetter)
	if err != nil {
		return nil, err
	}

	filteredRules := []authorizationapi.PolicyRule{}
	for _, rule := range rules {
		if allowed, _ := rulevalidation.Covers(scopeRules, []authorizationapi.PolicyRule{rule}); allowed {
			filteredRules = append(filteredRules, rule)
		}
	}

	return filteredRules, nil
}
Esempio n. 9
0
// Some roles should always cover others
func TestCovers(t *testing.T) {
	allRoles := bootstrappolicy.GetBootstrapClusterRoles()
	var admin *authorizationapi.ClusterRole
	var editor *authorizationapi.ClusterRole
	var viewer *authorizationapi.ClusterRole
	var registryAdmin *authorizationapi.ClusterRole
	var registryEditor *authorizationapi.ClusterRole
	var registryViewer *authorizationapi.ClusterRole

	for i := range allRoles {
		role := allRoles[i]
		switch role.Name {
		case bootstrappolicy.AdminRoleName:
			admin = &role
		case bootstrappolicy.EditRoleName:
			editor = &role
		case bootstrappolicy.ViewRoleName:
			viewer = &role
		case bootstrappolicy.RegistryAdminRoleName:
			registryAdmin = &role
		case bootstrappolicy.RegistryEditorRoleName:
			registryEditor = &role
		case bootstrappolicy.RegistryViewerRoleName:
			registryViewer = &role
		}
	}

	if covers, _ := rulevalidation.Covers(admin.Rules, editor.Rules); !covers {
		t.Errorf("failed to cover")
	}
	if covers, _ := rulevalidation.Covers(admin.Rules, editor.Rules); !covers {
		t.Errorf("failed to cover")
	}
	if covers, _ := rulevalidation.Covers(admin.Rules, viewer.Rules); !covers {
		t.Errorf("failed to cover")
	}
	if covers, _ := rulevalidation.Covers(admin.Rules, registryAdmin.Rules); !covers {
		t.Errorf("failed to cover")
	}
	if covers, _ := rulevalidation.Covers(registryAdmin.Rules, registryEditor.Rules); !covers {
		t.Errorf("failed to cover")
	}
	if covers, _ := rulevalidation.Covers(registryAdmin.Rules, registryViewer.Rules); !covers {
		t.Errorf("failed to cover")
	}
}
Esempio n. 10
0
// Some roles should always cover others
func TestCovers(t *testing.T) {
	allRoles := bootstrappolicy.GetBootstrapClusterRoles()
	var admin *authorizationapi.ClusterRole
	var editor *authorizationapi.ClusterRole
	var viewer *authorizationapi.ClusterRole
	var registryAdmin *authorizationapi.ClusterRole
	var registryEditor *authorizationapi.ClusterRole
	var registryViewer *authorizationapi.ClusterRole
	var systemMaster *authorizationapi.ClusterRole
	var systemDiscovery *authorizationapi.ClusterRole
	var clusterAdmin *authorizationapi.ClusterRole
	var storageAdmin *authorizationapi.ClusterRole

	for i := range allRoles {
		role := allRoles[i]
		switch role.Name {
		case bootstrappolicy.AdminRoleName:
			admin = &role
		case bootstrappolicy.EditRoleName:
			editor = &role
		case bootstrappolicy.ViewRoleName:
			viewer = &role
		case bootstrappolicy.RegistryAdminRoleName:
			registryAdmin = &role
		case bootstrappolicy.RegistryEditorRoleName:
			registryEditor = &role
		case bootstrappolicy.RegistryViewerRoleName:
			registryViewer = &role
		case bootstrappolicy.MasterRoleName:
			systemMaster = &role
		case bootstrappolicy.DiscoveryRoleName:
			systemDiscovery = &role
		case bootstrappolicy.ClusterAdminRoleName:
			clusterAdmin = &role
		case bootstrappolicy.StorageAdminRoleName:
			storageAdmin = &role
		}
	}

	if covers, miss := rulevalidation.Covers(admin.Rules, editor.Rules); !covers {
		t.Errorf("failed to cover: %#v", miss)
	}
	if covers, miss := rulevalidation.Covers(admin.Rules, editor.Rules); !covers {
		t.Errorf("failed to cover: %#v", miss)
	}
	if covers, miss := rulevalidation.Covers(admin.Rules, viewer.Rules); !covers {
		t.Errorf("failed to cover: %#v", miss)
	}
	if covers, miss := rulevalidation.Covers(admin.Rules, registryAdmin.Rules); !covers {
		t.Errorf("failed to cover: %#v", miss)
	}
	if covers, miss := rulevalidation.Covers(clusterAdmin.Rules, storageAdmin.Rules); !covers {
		t.Errorf("failed to cover: %#v", miss)
	}
	if covers, miss := rulevalidation.Covers(registryAdmin.Rules, registryEditor.Rules); !covers {
		t.Errorf("failed to cover: %#v", miss)
	}
	if covers, miss := rulevalidation.Covers(registryAdmin.Rules, registryViewer.Rules); !covers {
		t.Errorf("failed to cover: %#v", miss)
	}

	// Make sure we can auto-reconcile discovery
	if covers, miss := rulevalidation.Covers(systemMaster.Rules, systemDiscovery.Rules); !covers {
		t.Errorf("failed to cover: %#v", miss)
	}
	// Make sure the master has full permissions
	if covers, miss := rulevalidation.Covers(systemMaster.Rules, clusterAdmin.Rules); !covers {
		t.Errorf("failed to cover: %#v", miss)
	}
}