Skip to content

Add conversions from RBAC resources to origin resources #13334

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

Merged
merged 2 commits into from
Mar 20, 2017

Conversation

enj
Copy link
Contributor

@enj enj commented Mar 10, 2017

Trello ref: https://trello.com/c/viECLnNa

@deads2k It would probably take ~3 conversions to build a semantic compare function - assuming unsetUnpreservedFields and sortAndDeduplicateRulesFields do not invalidate the tests.

cc @liggitt

Signed-off-by: Monis Khan [email protected]

@enj enj requested a review from deads2k March 10, 2017 02:24
@enj
Copy link
Contributor Author

enj commented Mar 10, 2017

[test]

}
}

func ConvertRBACClusterRole(in *rbac.ClusterRole) *api.ClusterRole {
Copy link
Contributor

Choose a reason for hiding this comment

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

Make the names look like the generated ones: Convert_rbac_ClusterRole_To_api_ClusterRole and actually register these with other pkg/authorization/api conversions.

}
}

func convertRBACPolicyRules(in []rbac.PolicyRule) []api.PolicyRule {
Copy link
Contributor

Choose a reason for hiding this comment

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

you need a comment about AttributeRestrictions

}
}

func convertOriginPolicyRule(in []api.PolicyRule) []rbac.PolicyRule {
Copy link
Contributor

Choose a reason for hiding this comment

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

I guess that comment goes here.

subjects := make([]rbac.Subject, 0, len(in))
for _, subject := range in {
s := rbac.Subject{
Kind: subject.Kind,
Copy link
Contributor

Choose a reason for hiding this comment

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

origin kinds collapse down to just User and Group from SystemUser and SystemGroup.


func convertOriginRoleRef(in *kapi.ObjectReference) rbac.RoleRef {
return rbac.RoleRef{
APIGroup: in.APIVersion,
Copy link
Contributor

Choose a reason for hiding this comment

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

This is fixed in kube to rbac.authorization.k8s.io.

func convertOriginRoleRef(in *kapi.ObjectReference) rbac.RoleRef {
return rbac.RoleRef{
APIGroup: in.APIVersion,
Kind: in.Kind,
Copy link
Contributor

Choose a reason for hiding this comment

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

I didn't think we filled in a Kind. I thought we triggered on empty namespace or not.

return subjects
}

func convertOriginRoleRef(in *kapi.ObjectReference) rbac.RoleRef {
Copy link
Contributor

Choose a reason for hiding this comment

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

If we reference a role (not clusterrole) from a different namespace this needs to return an error so we can catch it.

Also, we'll want an upgrade preflight check or at least warning about the condition. We may have to provide a script for a cluster-admin to denormalize automatically. @liggitt necessary to make the script?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think detection is fine

for _, subject := range in {
s := rbac.Subject{
Kind: subject.Kind,
APIVersion: subject.APIVersion,
Copy link
Contributor

Choose a reason for hiding this comment

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

@liggitt want to specify our group here? It's what its for and it should work... Alternatively, we could avoid rocking the boat.

Copy link
Contributor

Choose a reason for hiding this comment

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

if we want to use the upstream authorizer eventually, I don't want want to have to rewrite these into subjects it recognizes

Copy link
Contributor

Choose a reason for hiding this comment

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

are we still working with v1alpha1 RBAC here?

Copy link
Contributor

Choose a reason for hiding this comment

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

are we still working with v1alpha1 RBAC here?

Internal to internal.

Copy link
Contributor

Choose a reason for hiding this comment

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

for _, subject := range in {
s := kapi.ObjectReference{
Kind: subject.Kind,
APIVersion: subject.APIVersion,
Copy link
Contributor

Choose a reason for hiding this comment

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

This shouldn't carry through.

subjects := make([]kapi.ObjectReference, 0, len(in))
for _, subject := range in {
s := kapi.ObjectReference{
Kind: subject.Kind,
Copy link
Contributor

Choose a reason for hiding this comment

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

You'll need to use the subject determination code. Take a look at the conversions we have from Users and Groups to Subjects and you'll find the helpers to determine SystemUser and SystemGroup

func convertRBACRoleRef(in *rbac.RoleRef) kapi.ObjectReference {
return kapi.ObjectReference{
APIVersion: in.APIGroup,
Kind: in.Kind,
Copy link
Contributor

Choose a reason for hiding this comment

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

This won't match up.

}

func convertRBACRoleRef(in *rbac.RoleRef) kapi.ObjectReference {
return kapi.ObjectReference{
Copy link
Contributor

Choose a reason for hiding this comment

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

You'll need to fill in a namespace for the local role reference

@enj
Copy link
Contributor Author

enj commented Mar 10, 2017

@deads2k PTAL

Fuzzing tests are failing right now because they do not follow the kind requirements - I will update those soon.

func convertOriginRoleRef(in *api.ObjectReference) rbac.RoleRef {
return rbac.RoleRef{
APIGroup: in.APIVersion,
Kind: in.Kind, // TODO leave empty?
Copy link
Contributor

Choose a reason for hiding this comment

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

When the origin roleref namespace is empty, the rbacRoleRef kind should be "ClusterRole". Otherwise, it should be "Role"


func convertOriginRoleRef(in *api.ObjectReference) rbac.RoleRef {
return rbac.RoleRef{
APIGroup: in.APIVersion,
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm expecting the APIGroup to pinned to the correct rbac value.

func convertOriginRoleRef(in *api.ObjectReference) rbac.RoleRef {
return rbac.RoleRef{
APIGroup: in.APIVersion,
Kind: in.Kind, // TODO leave empty?
Copy link
Contributor

Choose a reason for hiding this comment

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

When the origin roleref namespace equals the current namespace, then the Kind should be "Role"

for _, subject := range in {
s := rbac.Subject{
Name: subject.Name,
APIVersion: rbac.GroupName, // TODO what to use here?
Copy link
Contributor

Choose a reason for hiding this comment

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

It's pinned. Look it up in the rbac code.

subjects := make([]api.ObjectReference, 0, len(in))
for _, subject := range in {
s := api.ObjectReference{
APIVersion: rbac.GroupName, // TODO what do we want here?
Copy link
Contributor

Choose a reason for hiding this comment

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

This is empty. You really should read the existing code that builds origin subject references.

return determineKind(GroupKind, SystemGroupKind, group, groupNameValidator)
}

func determineKind(base, fallback, name string, nameValidator validation.ValidateNameFunc) string {
Copy link
Contributor

Choose a reason for hiding this comment

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

No. Inline into callers.

}
}

func unsetUnpreservedFields(subjects []api.ObjectReference, roleRef *api.ObjectReference) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Fix the fuzz functions instead to create values that could actually exist.

@enj
Copy link
Contributor Author

enj commented Mar 14, 2017

@deads2k PTAL

}
}

func getKind(namespace string) string {
Copy link
Contributor

Choose a reason for hiding this comment

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

originRoleRefKind? Something to demonstrate how specific it is.


func convertRBACRoleRef(in *rbac.RoleRef, namespace string) api.ObjectReference {
return api.ObjectReference{
Kind: getKind(namespace),
Copy link
Contributor

Choose a reason for hiding this comment

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

I didn't think that origin rolerefs respected kind.

return subjects, nil
}

func convertRBACRoleRef(in *rbac.RoleRef, namespace string) api.ObjectReference {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you name these functions as Convert_foo_to_bar? Obviously the signature won't match, but it will help remind me as I read it. Also, godoc on for the args. namespace isn't obvious.


case rbac.UserKind:
if len(uservalidation.ValidateUserName(subject.Name, false)) != 0 {
subject.Name = fmt.Sprintf("validusername%d", i)
Copy link
Contributor

Choose a reason for hiding this comment

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

we want some user names that are SystemUsers too.

}

case rbac.ServiceAccountKind:
if len(validation.ValidateNamespaceName(subject.Namespace, false)) != 0 {
Copy link
Contributor

Choose a reason for hiding this comment

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

RBAC service account references aren't required to have namespaces. Some shouldn't have them.

subject.Name = ":" + subject.Name

case ServiceAccountKind:
if len(validation.ValidateNamespaceName(subject.Namespace, false)) != 0 {
Copy link
Contributor

Choose a reason for hiding this comment

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

some SA subject namespaces should be empty.

@enj enj force-pushed the enj/f/rbac_conversions branch from 1e8cc68 to 054bab7 Compare March 14, 2017 18:20
@enj
Copy link
Contributor Author

enj commented Mar 14, 2017

@liggitt Any comments?

func convert_api_PolicyRules_To_rbac_PolicyRules(in []PolicyRule) []rbac.PolicyRule {
rules := make([]rbac.PolicyRule, 0, len(in))
for _, rule := range in {
r := rbac.PolicyRule{ // AttributeRestrictions is lost, but our authorizor ignores that field now
Copy link
Contributor

@liggitt liggitt Mar 15, 2017

Choose a reason for hiding this comment

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

it ignores it, but only after converting subjectaccessreviews with an IsSelfSubjectAccessReview restriction to selfsubjectaccessreviews.authorization.k8s.io... just dropping it escalates that permission

Copy link
Contributor

Choose a reason for hiding this comment

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

if we see a rule with that restriction, we need to limit the rule to the things that restriction would allow, and convert subjectaccessreviews resources to selfsubjectaccessreviews.authorization.k8s.io resources

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, that would have been unfortunate. Annotation to roundtrip through the rbac role maybe?

Copy link
Contributor

Choose a reason for hiding this comment

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

if we round-trip and end up with a rule that allows selfsubjectaccessreviews.authorization.k8s.io, that's sufficient

Verbs: rule.Verbs.List(),
Resources: rule.Resources.List(),
ResourceNames: rule.ResourceNames.List(),
NonResourceURLs: rule.NonResourceURLs.List(),
Copy link
Contributor

Choose a reason for hiding this comment

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

do we allow mixing resource and non-resource bits in the same rule? upstream does not, so we potentially need to split rules

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We do not allow mixing.

Copy link
Contributor

Choose a reason for hiding this comment

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

awesome

@liggitt
Copy link
Contributor

liggitt commented Mar 15, 2017

@deads2k did we fix up mixed-case resources in conversion or in the authorizer? do we need to downcase on our way out to kube?

@enj
Copy link
Contributor Author

enj commented Mar 15, 2017

did we fix up mixed-case resources in conversion or in the authorizer?

No such luck.

oc create

apiVersion: v1
kind: ClusterRole
metadata:
  name: foobar
rules:
- apiGroups:
  - ""
  resources:
  - configmapS
  - Endpoints
  - persistentvolumeclAIms
  - PODS
  verbs:
  - GET
  - lIst
  - wAtch

oc get clusterrole foobar -o yaml

apiVersion: v1
kind: ClusterRole
metadata:
  creationTimestamp: 2017-03-15T22:09:25Z
  name: foobar
  resourceVersion: "986"
  selfLink: /oapi/v1/clusterrolesfoobar
  uid: 0cc20af8-09cc-11e7-8ccc-507b9dac97ff
rules:
- apiGroups:
  - ""
  attributeRestrictions: null
  resources:
  - Endpoints
  - PODS
  - configmapS
  - persistentvolumeclAIms
  verbs:
  - GET
  - lIst
  - wAtch

@enj
Copy link
Contributor Author

enj commented Mar 15, 2017

So in the authorizer we normalize APIGroups, Verbs, and Resources. We do not normalize ResourceNames, NonResourceURLs, or Subresources. The Subresources part might have been an oversight during #13286.

}

// rules with AttributeRestrictions should not be preserved during conversion
func TestAttributeRestrictionsRuleLoss(t *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't this function be using a two way covers check? Also, that probably needs checking come to think of it.

@deads2k
Copy link
Contributor

deads2k commented Mar 17, 2017

@liggitt as I recall, we did the tolower thing because in 3.0, we had mixed case paths. I think we're far enough out that I'd be willing to say, "those clients need to be fixed" at this point. I'm thinking we tolower everything as a migration step (oc migrate) and write the conversion to preserve case. Thoughts?

@deads2k
Copy link
Contributor

deads2k commented Mar 17, 2017

Oh, and we stop tolowering in our authorizer for 3.6.

@openshift-bot openshift-bot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Mar 17, 2017
@deads2k
Copy link
Contributor

deads2k commented Mar 17, 2017

@enj We're going with the oadm migrate. You need another card?

@deads2k
Copy link
Contributor

deads2k commented Mar 17, 2017

@enj I think you should remove the normalization commit and remind me to look at this on Monday.

@enj enj force-pushed the enj/f/rbac_conversions branch from 65ffbdf to bf34a59 Compare March 17, 2017 19:48
@openshift-bot
Copy link
Contributor

Evaluated for origin test up to bf34a59

@openshift-bot
Copy link
Contributor

continuous-integration/openshift-jenkins/test SUCCESS (https://ci.openshift.redhat.com/jenkins/job/test_pull_request_origin/293/) (Base Commit: 9e19032)

@enj
Copy link
Contributor Author

enj commented Mar 17, 2017

@deads2k @liggitt I opened #13429 #13430 #13432 to track the remaining issues.

RBAC conversions no longer normalize and use Covers to test attribute restrictions.

Let me know if you want to merge this as-is and have separate PRs for each of those fixes or if you want me to add some of the fixes here.

@openshift-bot openshift-bot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Mar 17, 2017
@deads2k
Copy link
Contributor

deads2k commented Mar 20, 2017

lgtm [merge]

@openshift-bot
Copy link
Contributor

Evaluated for origin merge up to bf34a59

@openshift-bot
Copy link
Contributor

openshift-bot commented Mar 20, 2017

continuous-integration/openshift-jenkins/merge SUCCESS (https://ci.openshift.redhat.com/jenkins/job/merge_pull_request_origin/149/) (Base Commit: 612dcfb) (Image: devenv-rhel7_6087)

@deads2k
Copy link
Contributor

deads2k commented Mar 20, 2017

@enj add validation for a role and cluster role that makes including any attributerestrictions invalid. It may frustrate some people who have serialized roles that include these, but it also forces them to look at why and see that their rule won't work.

Other paths that I decided against:

  1. conversion drops the rule entirely. No warning to a user that their intent is no longer fulfilled.
  2. conversion changes the rule to selfSAR. Doesn't work during rolling upgrades.
  3. doing nothing. During a rolling upgrade, you can create a rule that does nothing on the current server but allows power on the older servers.

@openshift-bot openshift-bot merged commit 13708b0 into openshift:master Mar 20, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants