mirror of https://github.com/k3s-io/k3s
Merge pull request #53722 from deads2k/rbac-01-allow-star
Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. allow */subresource in rbac policy rules xref #29698 xref #38756 xref #49504 xref #38810 Allow `*/subresource` format in RBAC policy rules to support polymorphic subresources like `*/scale` for HPA. @DirectXMan12 fyi ```release-note RBAC PolicyRules now allow resource=`*/<subresource>` to cover `any-resource/<subresource>`. For example, `*/scale` covers `replicationcontroller/scale`. ```pull/6/head
commit
900c0761e3
|
@ -64461,7 +64461,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"resources": {
|
"resources": {
|
||||||
"description": "Resources is a list of resources this rule applies to. ResourceAll represents all resources. \"*\" means all.",
|
"description": "Resources is a list of resources this rule applies to. \"*\" means all in the specified apiGroups.\n \"*/foo\" represents the subresource 'foo' for all resources in the specified apiGroups.",
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
@ -64812,7 +64812,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"resources": {
|
"resources": {
|
||||||
"description": "Resources is a list of resources this rule applies to. ResourceAll represents all resources. \"*\" means all.",
|
"description": "Resources is a list of resources this rule applies to. \"*\" means all in the specified apiGroups.\n \"*/foo\" represents the subresource 'foo' for all resources in the specified apiGroups.",
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
@ -73180,7 +73180,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"resources": {
|
"resources": {
|
||||||
"description": "Resources is a list of resources this rule applies to. ResourceAll represents all resources.",
|
"description": "Resources is a list of resources this rule applies to. '*' represents all resources in the specified apiGroups. '*/foo' represents the subresource 'foo' for all resources in the specified apiGroups.",
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
|
|
@ -785,7 +785,7 @@
|
||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"description": "Resources is a list of resources this rule applies to. ResourceAll represents all resources. \"*\" means all."
|
"description": "Resources is a list of resources this rule applies to. \"*\" means all in the specified apiGroups.\n \"*/foo\" represents the subresource 'foo' for all resources in the specified apiGroups."
|
||||||
},
|
},
|
||||||
"resourceNames": {
|
"resourceNames": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
|
|
@ -785,7 +785,7 @@
|
||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"description": "Resources is a list of resources this rule applies to. ResourceAll represents all resources. \"*\" means all."
|
"description": "Resources is a list of resources this rule applies to. \"*\" means all in the specified apiGroups.\n \"*/foo\" represents the subresource 'foo' for all resources in the specified apiGroups."
|
||||||
},
|
},
|
||||||
"resourceNames": {
|
"resourceNames": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
|
|
@ -3818,7 +3818,7 @@
|
||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"description": "Resources is a list of resources this rule applies to. ResourceAll represents all resources."
|
"description": "Resources is a list of resources this rule applies to. '*' represents all resources in the specified apiGroups. '*/foo' represents the subresource 'foo' for all resources in the specified apiGroups."
|
||||||
},
|
},
|
||||||
"resourceNames": {
|
"resourceNames": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
|
|
@ -1432,7 +1432,8 @@ When an object is created, the system will populate this list with the current s
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">resources</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">resources</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Resources is a list of resources this rule applies to. ResourceAll represents all resources. "*" means all.</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">Resources is a list of resources this rule applies to. "<strong>" means all in the specified apiGroups.<br>
|
||||||
|
"</strong>/foo" represents the subresource <em>foo</em> for all resources in the specified apiGroups.</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">string array</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">string array</p></td>
|
||||||
<td class="tableblock halign-left valign-top"></td>
|
<td class="tableblock halign-left valign-top"></td>
|
||||||
|
|
|
@ -1452,7 +1452,8 @@ When an object is created, the system will populate this list with the current s
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">resources</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">resources</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Resources is a list of resources this rule applies to. ResourceAll represents all resources. "*" means all.</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">Resources is a list of resources this rule applies to. "<strong>" means all in the specified apiGroups.<br>
|
||||||
|
"</strong>/foo" represents the subresource <em>foo</em> for all resources in the specified apiGroups.</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">string array</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">string array</p></td>
|
||||||
<td class="tableblock halign-left valign-top"></td>
|
<td class="tableblock halign-left valign-top"></td>
|
||||||
|
|
|
@ -1682,7 +1682,7 @@ Examples:<br>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">resources</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">resources</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Resources is a list of resources this rule applies to. ResourceAll represents all resources.</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">Resources is a list of resources this rule applies to. <em><strong></em> represents all resources in the specified apiGroups. <em></strong>/foo</em> represents the subresource <em>foo</em> for all resources in the specified apiGroups.</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||||
<td class="tableblock halign-left valign-top"><p class="tableblock">string array</p></td>
|
<td class="tableblock halign-left valign-top"><p class="tableblock">string array</p></td>
|
||||||
<td class="tableblock halign-left valign-top"></td>
|
<td class="tableblock halign-left valign-top"></td>
|
||||||
|
|
|
@ -205,7 +205,8 @@ type ResourceRule struct {
|
||||||
// APIGroups is the name of the APIGroup that contains the resources. If multiple API groups are specified, any action requested against one of
|
// APIGroups is the name of the APIGroup that contains the resources. If multiple API groups are specified, any action requested against one of
|
||||||
// the enumerated resources in any API group will be allowed. "*" means all.
|
// the enumerated resources in any API group will be allowed. "*" means all.
|
||||||
APIGroups []string
|
APIGroups []string
|
||||||
// Resources is a list of resources this rule applies to. ResourceAll represents all resources. "*" means all.
|
// Resources is a list of resources this rule applies to. "*" means all in the specified apiGroups.
|
||||||
|
// "*/foo" represents the subresource 'foo' for all resources in the specified apiGroups.
|
||||||
Resources []string
|
Resources []string
|
||||||
// ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed. "*" means all.
|
// ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed. "*" means all.
|
||||||
ResourceNames []string
|
ResourceNames []string
|
||||||
|
|
|
@ -55,14 +55,29 @@ func APIGroupMatches(rule *PolicyRule, requestedGroup string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func ResourceMatches(rule *PolicyRule, requestedResource string) bool {
|
func ResourceMatches(rule *PolicyRule, combinedRequestedResource, requestedSubresource string) bool {
|
||||||
for _, ruleResource := range rule.Resources {
|
for _, ruleResource := range rule.Resources {
|
||||||
|
// if everything is allowed, we match
|
||||||
if ruleResource == ResourceAll {
|
if ruleResource == ResourceAll {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if ruleResource == requestedResource {
|
// if we have an exact match, we match
|
||||||
|
if ruleResource == combinedRequestedResource {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We can also match a */subresource.
|
||||||
|
// if there isn't a subresource, then continue
|
||||||
|
if len(requestedSubresource) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// if the rule isn't in the format */subresource, then we don't match, continue
|
||||||
|
if len(ruleResource) == len(requestedSubresource)+2 &&
|
||||||
|
strings.HasPrefix(ruleResource, "*/") &&
|
||||||
|
strings.HasSuffix(ruleResource, requestedSubresource) {
|
||||||
|
return true
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
|
|
@ -70,3 +70,108 @@ func TestHelpersRoundTrip(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestResourceMatches(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
ruleResources []string
|
||||||
|
combinedRequestedResource string
|
||||||
|
requestedSubresource string
|
||||||
|
expected bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "all matches 01",
|
||||||
|
ruleResources: []string{"*"},
|
||||||
|
combinedRequestedResource: "foo",
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "checks all rules",
|
||||||
|
ruleResources: []string{"doesn't match", "*"},
|
||||||
|
combinedRequestedResource: "foo",
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "matches exact rule",
|
||||||
|
ruleResources: []string{"foo/bar"},
|
||||||
|
combinedRequestedResource: "foo/bar",
|
||||||
|
requestedSubresource: "bar",
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "matches exact rule 02",
|
||||||
|
ruleResources: []string{"foo/bar"},
|
||||||
|
combinedRequestedResource: "foo",
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "matches subresource",
|
||||||
|
ruleResources: []string{"*/scale"},
|
||||||
|
combinedRequestedResource: "foo/scale",
|
||||||
|
requestedSubresource: "scale",
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "doesn't match partial subresource hit",
|
||||||
|
ruleResources: []string{"foo/bar", "*/other"},
|
||||||
|
combinedRequestedResource: "foo/other/segment",
|
||||||
|
requestedSubresource: "other/segment",
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "matches subresource with multiple slashes",
|
||||||
|
ruleResources: []string{"*/other/segment"},
|
||||||
|
combinedRequestedResource: "foo/other/segment",
|
||||||
|
requestedSubresource: "other/segment",
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "doesn't fail on empty",
|
||||||
|
ruleResources: []string{""},
|
||||||
|
combinedRequestedResource: "foo/other/segment",
|
||||||
|
requestedSubresource: "other/segment",
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "doesn't fail on slash",
|
||||||
|
ruleResources: []string{"/"},
|
||||||
|
combinedRequestedResource: "foo/other/segment",
|
||||||
|
requestedSubresource: "other/segment",
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "doesn't fail on missing subresource",
|
||||||
|
ruleResources: []string{"*/"},
|
||||||
|
combinedRequestedResource: "foo/other/segment",
|
||||||
|
requestedSubresource: "other/segment",
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "doesn't match on not star",
|
||||||
|
ruleResources: []string{"*something/other/segment"},
|
||||||
|
combinedRequestedResource: "foo/other/segment",
|
||||||
|
requestedSubresource: "other/segment",
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "doesn't match on something else",
|
||||||
|
ruleResources: []string{"something/other/segment"},
|
||||||
|
combinedRequestedResource: "foo/other/segment",
|
||||||
|
requestedSubresource: "other/segment",
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
rule := &rbac.PolicyRule{
|
||||||
|
Resources: tc.ruleResources,
|
||||||
|
}
|
||||||
|
actual := rbac.ResourceMatches(rule, tc.combinedRequestedResource, tc.requestedSubresource)
|
||||||
|
if tc.expected != actual {
|
||||||
|
t.Errorf("expected %v, got %v", tc.expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -48,7 +48,8 @@ type PolicyRule struct {
|
||||||
// APIGroups is the name of the APIGroup that contains the resources.
|
// APIGroups is the name of the APIGroup that contains the resources.
|
||||||
// If multiple API groups are specified, any action requested against one of the enumerated resources in any API group will be allowed.
|
// If multiple API groups are specified, any action requested against one of the enumerated resources in any API group will be allowed.
|
||||||
APIGroups []string
|
APIGroups []string
|
||||||
// Resources is a list of resources this rule applies to. ResourceAll represents all resources.
|
// Resources is a list of resources this rule applies to. '*' represents all resources in the specified apiGroups.
|
||||||
|
// '*/foo' represents the subresource 'foo' for all resources in the specified apiGroups.
|
||||||
Resources []string
|
Resources []string
|
||||||
// ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed.
|
// ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed.
|
||||||
ResourceNames []string
|
ResourceNames []string
|
||||||
|
|
|
@ -105,6 +105,31 @@ func hasAll(set, contains []string) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func resourceCoversAll(setResources, coversResources []string) bool {
|
||||||
|
// if we have a star or an exact match on all resources, then we match
|
||||||
|
if has(setResources, rbac.ResourceAll) || hasAll(setResources, coversResources) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, path := range coversResources {
|
||||||
|
// if we have an exact match, then we match.
|
||||||
|
if has(setResources, path) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// if we're not a subresource, then we definitely don't match. fail.
|
||||||
|
if !strings.Contains(path, "/") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
tokens := strings.SplitN(path, "/", 2)
|
||||||
|
resourceToCheck := "*/" + tokens[1]
|
||||||
|
if !has(setResources, resourceToCheck) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func nonResourceURLsCoversAll(set, covers []string) bool {
|
func nonResourceURLsCoversAll(set, covers []string) bool {
|
||||||
for _, path := range covers {
|
for _, path := range covers {
|
||||||
covered := false
|
covered := false
|
||||||
|
@ -133,7 +158,7 @@ func nonResourceURLCovers(ownerPath, subPath string) bool {
|
||||||
func ruleCovers(ownerRule, subRule rbac.PolicyRule) bool {
|
func ruleCovers(ownerRule, subRule rbac.PolicyRule) bool {
|
||||||
verbMatches := has(ownerRule.Verbs, rbac.VerbAll) || hasAll(ownerRule.Verbs, subRule.Verbs)
|
verbMatches := has(ownerRule.Verbs, rbac.VerbAll) || hasAll(ownerRule.Verbs, subRule.Verbs)
|
||||||
groupMatches := has(ownerRule.APIGroups, rbac.APIGroupAll) || hasAll(ownerRule.APIGroups, subRule.APIGroups)
|
groupMatches := has(ownerRule.APIGroups, rbac.APIGroupAll) || hasAll(ownerRule.APIGroups, subRule.APIGroups)
|
||||||
resourceMatches := has(ownerRule.Resources, rbac.ResourceAll) || hasAll(ownerRule.Resources, subRule.Resources)
|
resourceMatches := resourceCoversAll(ownerRule.Resources, subRule.Resources)
|
||||||
nonResourceURLMatches := nonResourceURLsCoversAll(ownerRule.NonResourceURLs, subRule.NonResourceURLs)
|
nonResourceURLMatches := nonResourceURLsCoversAll(ownerRule.NonResourceURLs, subRule.NonResourceURLs)
|
||||||
|
|
||||||
resourceNameMatches := false
|
resourceNameMatches := false
|
||||||
|
|
|
@ -45,6 +45,20 @@ func TestCoversExactMatch(t *testing.T) {
|
||||||
}.test(t)
|
}.test(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCoversSubresourceWildcard(t *testing.T) {
|
||||||
|
escalationTest{
|
||||||
|
ownerRules: []rbac.PolicyRule{
|
||||||
|
{APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"*/scale"}},
|
||||||
|
},
|
||||||
|
servantRules: []rbac.PolicyRule{
|
||||||
|
{APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"foo/scale"}},
|
||||||
|
},
|
||||||
|
|
||||||
|
expectedCovered: true,
|
||||||
|
expectedUncoveredRules: []rbac.PolicyRule{},
|
||||||
|
}.test(t)
|
||||||
|
}
|
||||||
|
|
||||||
func TestCoversMultipleRulesCoveringSingleRule(t *testing.T) {
|
func TestCoversMultipleRulesCoveringSingleRule(t *testing.T) {
|
||||||
escalationTest{
|
escalationTest{
|
||||||
ownerRules: []rbac.PolicyRule{
|
ownerRules: []rbac.PolicyRule{
|
||||||
|
|
|
@ -156,10 +156,7 @@ func buildControllerRoles() ([]rbac.ClusterRole, []rbac.ClusterRoleBinding) {
|
||||||
Rules: []rbac.PolicyRule{
|
Rules: []rbac.PolicyRule{
|
||||||
rbac.NewRule("get", "list", "watch").Groups(autoscalingGroup).Resources("horizontalpodautoscalers").RuleOrDie(),
|
rbac.NewRule("get", "list", "watch").Groups(autoscalingGroup).Resources("horizontalpodautoscalers").RuleOrDie(),
|
||||||
rbac.NewRule("update").Groups(autoscalingGroup).Resources("horizontalpodautoscalers/status").RuleOrDie(),
|
rbac.NewRule("update").Groups(autoscalingGroup).Resources("horizontalpodautoscalers/status").RuleOrDie(),
|
||||||
rbac.NewRule("get", "update").Groups(legacyGroup).Resources("replicationcontrollers/scale").RuleOrDie(),
|
rbac.NewRule("get", "update").Groups("*").Resources("*/scale").RuleOrDie(),
|
||||||
// TODO this should be removable when the HPA contoller is fixed
|
|
||||||
rbac.NewRule("get", "update").Groups(extensionsGroup).Resources("replicationcontrollers/scale").RuleOrDie(),
|
|
||||||
rbac.NewRule("get", "update").Groups(extensionsGroup, appsGroup).Resources("deployments/scale", "replicasets/scale").RuleOrDie(),
|
|
||||||
rbac.NewRule("list").Groups(legacyGroup).Resources("pods").RuleOrDie(),
|
rbac.NewRule("list").Groups(legacyGroup).Resources("pods").RuleOrDie(),
|
||||||
// TODO: restrict this to the appropriate namespace
|
// TODO: restrict this to the appropriate namespace
|
||||||
rbac.NewRule("get").Groups(legacyGroup).Resources("services/proxy").Names("https:heapster:", "http:heapster:").RuleOrDie(),
|
rbac.NewRule("get").Groups(legacyGroup).Resources("services/proxy").Names("https:heapster:", "http:heapster:").RuleOrDie(),
|
||||||
|
|
|
@ -445,25 +445,9 @@ items:
|
||||||
verbs:
|
verbs:
|
||||||
- update
|
- update
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- ""
|
- '*'
|
||||||
resources:
|
resources:
|
||||||
- replicationcontrollers/scale
|
- '*/scale'
|
||||||
verbs:
|
|
||||||
- get
|
|
||||||
- update
|
|
||||||
- apiGroups:
|
|
||||||
- extensions
|
|
||||||
resources:
|
|
||||||
- replicationcontrollers/scale
|
|
||||||
verbs:
|
|
||||||
- get
|
|
||||||
- update
|
|
||||||
- apiGroups:
|
|
||||||
- apps
|
|
||||||
- extensions
|
|
||||||
resources:
|
|
||||||
- deployments/scale
|
|
||||||
- replicasets/scale
|
|
||||||
verbs:
|
verbs:
|
||||||
- get
|
- get
|
||||||
- update
|
- update
|
||||||
|
|
|
@ -174,14 +174,14 @@ func RulesAllow(requestAttributes authorizer.Attributes, rules ...rbac.PolicyRul
|
||||||
|
|
||||||
func RuleAllows(requestAttributes authorizer.Attributes, rule *rbac.PolicyRule) bool {
|
func RuleAllows(requestAttributes authorizer.Attributes, rule *rbac.PolicyRule) bool {
|
||||||
if requestAttributes.IsResourceRequest() {
|
if requestAttributes.IsResourceRequest() {
|
||||||
resource := requestAttributes.GetResource()
|
combinedResource := requestAttributes.GetResource()
|
||||||
if len(requestAttributes.GetSubresource()) > 0 {
|
if len(requestAttributes.GetSubresource()) > 0 {
|
||||||
resource = requestAttributes.GetResource() + "/" + requestAttributes.GetSubresource()
|
combinedResource = requestAttributes.GetResource() + "/" + requestAttributes.GetSubresource()
|
||||||
}
|
}
|
||||||
|
|
||||||
return rbac.VerbMatches(rule, requestAttributes.GetVerb()) &&
|
return rbac.VerbMatches(rule, requestAttributes.GetVerb()) &&
|
||||||
rbac.APIGroupMatches(rule, requestAttributes.GetAPIGroup()) &&
|
rbac.APIGroupMatches(rule, requestAttributes.GetAPIGroup()) &&
|
||||||
rbac.ResourceMatches(rule, resource) &&
|
rbac.ResourceMatches(rule, combinedResource, requestAttributes.GetSubresource()) &&
|
||||||
rbac.ResourceNameMatches(rule, requestAttributes.GetName())
|
rbac.ResourceNameMatches(rule, requestAttributes.GetName())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -224,13 +224,19 @@ func TestAuthorizer(t *testing.T) {
|
||||||
{
|
{
|
||||||
// test subresource resolution
|
// test subresource resolution
|
||||||
clusterRoles: []*rbac.ClusterRole{
|
clusterRoles: []*rbac.ClusterRole{
|
||||||
newClusterRole("admin", newRule("*", "*", "pods/status", "*")),
|
newClusterRole("admin",
|
||||||
|
newRule("*", "*", "pods/status", "*"),
|
||||||
|
newRule("*", "*", "*/scale", "*"),
|
||||||
|
),
|
||||||
},
|
},
|
||||||
roleBindings: []*rbac.RoleBinding{
|
roleBindings: []*rbac.RoleBinding{
|
||||||
newRoleBinding("ns1", "admin", bindToClusterRole, "User:admin", "Group:admins"),
|
newRoleBinding("ns1", "admin", bindToClusterRole, "User:admin", "Group:admins"),
|
||||||
},
|
},
|
||||||
shouldPass: []authorizer.Attributes{
|
shouldPass: []authorizer.Attributes{
|
||||||
&defaultAttributes{"admin", "", "get", "pods", "status", "ns1", ""},
|
&defaultAttributes{"admin", "", "get", "pods", "status", "ns1", ""},
|
||||||
|
&defaultAttributes{"admin", "", "get", "pods", "scale", "ns1", ""},
|
||||||
|
&defaultAttributes{"admin", "", "get", "deployments", "scale", "ns1", ""},
|
||||||
|
&defaultAttributes{"admin", "", "get", "anything", "scale", "ns1", ""},
|
||||||
},
|
},
|
||||||
shouldFail: []authorizer.Attributes{
|
shouldFail: []authorizer.Attributes{
|
||||||
&defaultAttributes{"admin", "", "get", "pods", "", "ns1", ""},
|
&defaultAttributes{"admin", "", "get", "pods", "", "ns1", ""},
|
||||||
|
|
|
@ -121,7 +121,8 @@ message ResourceRule {
|
||||||
// +optional
|
// +optional
|
||||||
repeated string apiGroups = 2;
|
repeated string apiGroups = 2;
|
||||||
|
|
||||||
// Resources is a list of resources this rule applies to. ResourceAll represents all resources. "*" means all.
|
// Resources is a list of resources this rule applies to. "*" means all in the specified apiGroups.
|
||||||
|
// "*/foo" represents the subresource 'foo' for all resources in the specified apiGroups.
|
||||||
// +optional
|
// +optional
|
||||||
repeated string resources = 3;
|
repeated string resources = 3;
|
||||||
|
|
||||||
|
|
|
@ -241,7 +241,8 @@ type ResourceRule struct {
|
||||||
// the enumerated resources in any API group will be allowed. "*" means all.
|
// the enumerated resources in any API group will be allowed. "*" means all.
|
||||||
// +optional
|
// +optional
|
||||||
APIGroups []string `json:"apiGroups,omitempty" protobuf:"bytes,2,rep,name=apiGroups"`
|
APIGroups []string `json:"apiGroups,omitempty" protobuf:"bytes,2,rep,name=apiGroups"`
|
||||||
// Resources is a list of resources this rule applies to. ResourceAll represents all resources. "*" means all.
|
// Resources is a list of resources this rule applies to. "*" means all in the specified apiGroups.
|
||||||
|
// "*/foo" represents the subresource 'foo' for all resources in the specified apiGroups.
|
||||||
// +optional
|
// +optional
|
||||||
Resources []string `json:"resources,omitempty" protobuf:"bytes,3,rep,name=resources"`
|
Resources []string `json:"resources,omitempty" protobuf:"bytes,3,rep,name=resources"`
|
||||||
// ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed. "*" means all.
|
// ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed. "*" means all.
|
||||||
|
|
|
@ -76,7 +76,7 @@ var map_ResourceRule = map[string]string{
|
||||||
"": "ResourceRule is the list of actions the subject is allowed to perform on resources. The list ordering isn't significant, may contain duplicates, and possibly be incomplete.",
|
"": "ResourceRule is the list of actions the subject is allowed to perform on resources. The list ordering isn't significant, may contain duplicates, and possibly be incomplete.",
|
||||||
"verbs": "Verb is a list of kubernetes resource API verbs, like: get, list, watch, create, update, delete, proxy. \"*\" means all.",
|
"verbs": "Verb is a list of kubernetes resource API verbs, like: get, list, watch, create, update, delete, proxy. \"*\" means all.",
|
||||||
"apiGroups": "APIGroups is the name of the APIGroup that contains the resources. If multiple API groups are specified, any action requested against one of the enumerated resources in any API group will be allowed. \"*\" means all.",
|
"apiGroups": "APIGroups is the name of the APIGroup that contains the resources. If multiple API groups are specified, any action requested against one of the enumerated resources in any API group will be allowed. \"*\" means all.",
|
||||||
"resources": "Resources is a list of resources this rule applies to. ResourceAll represents all resources. \"*\" means all.",
|
"resources": "Resources is a list of resources this rule applies to. \"*\" means all in the specified apiGroups.\n \"*/foo\" represents the subresource 'foo' for all resources in the specified apiGroups.",
|
||||||
"resourceNames": "ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed. \"*\" means all.",
|
"resourceNames": "ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed. \"*\" means all.",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -121,7 +121,8 @@ message ResourceRule {
|
||||||
// +optional
|
// +optional
|
||||||
repeated string apiGroups = 2;
|
repeated string apiGroups = 2;
|
||||||
|
|
||||||
// Resources is a list of resources this rule applies to. ResourceAll represents all resources. "*" means all.
|
// Resources is a list of resources this rule applies to. "*" means all in the specified apiGroups.
|
||||||
|
// "*/foo" represents the subresource 'foo' for all resources in the specified apiGroups.
|
||||||
// +optional
|
// +optional
|
||||||
repeated string resources = 3;
|
repeated string resources = 3;
|
||||||
|
|
||||||
|
|
|
@ -241,7 +241,8 @@ type ResourceRule struct {
|
||||||
// the enumerated resources in any API group will be allowed. "*" means all.
|
// the enumerated resources in any API group will be allowed. "*" means all.
|
||||||
// +optional
|
// +optional
|
||||||
APIGroups []string `json:"apiGroups,omitempty" protobuf:"bytes,2,rep,name=apiGroups"`
|
APIGroups []string `json:"apiGroups,omitempty" protobuf:"bytes,2,rep,name=apiGroups"`
|
||||||
// Resources is a list of resources this rule applies to. ResourceAll represents all resources. "*" means all.
|
// Resources is a list of resources this rule applies to. "*" means all in the specified apiGroups.
|
||||||
|
// "*/foo" represents the subresource 'foo' for all resources in the specified apiGroups.
|
||||||
// +optional
|
// +optional
|
||||||
Resources []string `json:"resources,omitempty" protobuf:"bytes,3,rep,name=resources"`
|
Resources []string `json:"resources,omitempty" protobuf:"bytes,3,rep,name=resources"`
|
||||||
// ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed. "*" means all.
|
// ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed. "*" means all.
|
||||||
|
|
|
@ -76,7 +76,7 @@ var map_ResourceRule = map[string]string{
|
||||||
"": "ResourceRule is the list of actions the subject is allowed to perform on resources. The list ordering isn't significant, may contain duplicates, and possibly be incomplete.",
|
"": "ResourceRule is the list of actions the subject is allowed to perform on resources. The list ordering isn't significant, may contain duplicates, and possibly be incomplete.",
|
||||||
"verbs": "Verb is a list of kubernetes resource API verbs, like: get, list, watch, create, update, delete, proxy. \"*\" means all.",
|
"verbs": "Verb is a list of kubernetes resource API verbs, like: get, list, watch, create, update, delete, proxy. \"*\" means all.",
|
||||||
"apiGroups": "APIGroups is the name of the APIGroup that contains the resources. If multiple API groups are specified, any action requested against one of the enumerated resources in any API group will be allowed. \"*\" means all.",
|
"apiGroups": "APIGroups is the name of the APIGroup that contains the resources. If multiple API groups are specified, any action requested against one of the enumerated resources in any API group will be allowed. \"*\" means all.",
|
||||||
"resources": "Resources is a list of resources this rule applies to. ResourceAll represents all resources. \"*\" means all.",
|
"resources": "Resources is a list of resources this rule applies to. \"*\" means all in the specified apiGroups.\n \"*/foo\" represents the subresource 'foo' for all resources in the specified apiGroups.",
|
||||||
"resourceNames": "ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed. \"*\" means all.",
|
"resourceNames": "ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed. \"*\" means all.",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -85,7 +85,8 @@ message PolicyRule {
|
||||||
// +optional
|
// +optional
|
||||||
repeated string apiGroups = 2;
|
repeated string apiGroups = 2;
|
||||||
|
|
||||||
// Resources is a list of resources this rule applies to. ResourceAll represents all resources.
|
// Resources is a list of resources this rule applies to. '*' represents all resources in the specified apiGroups.
|
||||||
|
// '*/foo' represents the subresource 'foo' for all resources in the specified apiGroups.
|
||||||
// +optional
|
// +optional
|
||||||
repeated string resources = 3;
|
repeated string resources = 3;
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,8 @@ type PolicyRule struct {
|
||||||
// the enumerated resources in any API group will be allowed.
|
// the enumerated resources in any API group will be allowed.
|
||||||
// +optional
|
// +optional
|
||||||
APIGroups []string `json:"apiGroups,omitempty" protobuf:"bytes,2,rep,name=apiGroups"`
|
APIGroups []string `json:"apiGroups,omitempty" protobuf:"bytes,2,rep,name=apiGroups"`
|
||||||
// Resources is a list of resources this rule applies to. ResourceAll represents all resources.
|
// Resources is a list of resources this rule applies to. '*' represents all resources in the specified apiGroups.
|
||||||
|
// '*/foo' represents the subresource 'foo' for all resources in the specified apiGroups.
|
||||||
// +optional
|
// +optional
|
||||||
Resources []string `json:"resources,omitempty" protobuf:"bytes,3,rep,name=resources"`
|
Resources []string `json:"resources,omitempty" protobuf:"bytes,3,rep,name=resources"`
|
||||||
// ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed.
|
// ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed.
|
||||||
|
|
|
@ -72,7 +72,7 @@ var map_PolicyRule = map[string]string{
|
||||||
"": "PolicyRule holds information that describes a policy rule, but does not contain information about who the rule applies to or which namespace the rule applies to.",
|
"": "PolicyRule holds information that describes a policy rule, but does not contain information about who the rule applies to or which namespace the rule applies to.",
|
||||||
"verbs": "Verbs is a list of Verbs that apply to ALL the ResourceKinds and AttributeRestrictions contained in this rule. VerbAll represents all kinds.",
|
"verbs": "Verbs is a list of Verbs that apply to ALL the ResourceKinds and AttributeRestrictions contained in this rule. VerbAll represents all kinds.",
|
||||||
"apiGroups": "APIGroups is the name of the APIGroup that contains the resources. If multiple API groups are specified, any action requested against one of the enumerated resources in any API group will be allowed.",
|
"apiGroups": "APIGroups is the name of the APIGroup that contains the resources. If multiple API groups are specified, any action requested against one of the enumerated resources in any API group will be allowed.",
|
||||||
"resources": "Resources is a list of resources this rule applies to. ResourceAll represents all resources.",
|
"resources": "Resources is a list of resources this rule applies to. '*' represents all resources in the specified apiGroups. '*/foo' represents the subresource 'foo' for all resources in the specified apiGroups.",
|
||||||
"resourceNames": "ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed.",
|
"resourceNames": "ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed.",
|
||||||
"nonResourceURLs": "NonResourceURLs is a set of partial urls that a user should have access to. *s are allowed, but only as the full, final step in the path Since non-resource URLs are not namespaced, this field is only applicable for ClusterRoles referenced from a ClusterRoleBinding. Rules can either apply to API resources (such as \"pods\" or \"secrets\") or non-resource URL paths (such as \"/api\"), but not both.",
|
"nonResourceURLs": "NonResourceURLs is a set of partial urls that a user should have access to. *s are allowed, but only as the full, final step in the path Since non-resource URLs are not namespaced, this field is only applicable for ClusterRoles referenced from a ClusterRoleBinding. Rules can either apply to API resources (such as \"pods\" or \"secrets\") or non-resource URL paths (such as \"/api\"), but not both.",
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue