add field and label selectors to authorization attributes

Co-authored-by: Jordan Liggitt <liggitt@google.com>
This commit is contained in:
David Eads
2024-05-23 15:12:26 -04:00
committed by Jordan Liggitt
parent f5e5bef2e0
commit 92e3445e9d
25 changed files with 2388 additions and 226 deletions

View File

@@ -24,6 +24,8 @@ import (
rbacv1 "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apiserver/pkg/authentication/user"
"k8s.io/apiserver/pkg/authorization/authorizer"
rbacv1helpers "k8s.io/kubernetes/pkg/apis/rbac/v1"
@@ -135,6 +137,12 @@ func (d *defaultAttributes) GetAPIGroup() string { return d.apiGroup }
func (d *defaultAttributes) GetAPIVersion() string { return "" }
func (d *defaultAttributes) IsResourceRequest() bool { return true }
func (d *defaultAttributes) GetPath() string { return "" }
func (d *defaultAttributes) GetFieldSelector() (fields.Requirements, error) {
panic("not supported for RBAC")
}
func (d *defaultAttributes) GetLabelSelector() (labels.Requirements, error) {
panic("not supported for RBAC")
}
func TestAuthorizer(t *testing.T) {
tests := []struct {
@@ -263,135 +271,139 @@ func TestAuthorizer(t *testing.T) {
}
func TestRuleMatches(t *testing.T) {
type requestToTest struct {
request authorizer.AttributesRecord
expected bool
}
tests := []struct {
name string
rule rbacv1.PolicyRule
requestsToExpected map[authorizer.AttributesRecord]bool
requestsToExpected []*requestToTest
}{
{
name: "star verb, exact match other",
rule: rbacv1helpers.NewRule("*").Groups("group1").Resources("resource1").RuleOrDie(),
requestsToExpected: map[authorizer.AttributesRecord]bool{
resourceRequest("verb1").Group("group1").Resource("resource1").New(): true,
resourceRequest("verb1").Group("group2").Resource("resource1").New(): false,
resourceRequest("verb1").Group("group1").Resource("resource2").New(): false,
resourceRequest("verb1").Group("group2").Resource("resource2").New(): false,
resourceRequest("verb2").Group("group1").Resource("resource1").New(): true,
resourceRequest("verb2").Group("group2").Resource("resource1").New(): false,
resourceRequest("verb2").Group("group1").Resource("resource2").New(): false,
resourceRequest("verb2").Group("group2").Resource("resource2").New(): false,
requestsToExpected: []*requestToTest{
{resourceRequest("verb1").Group("group1").Resource("resource1").New(), true},
{resourceRequest("verb1").Group("group2").Resource("resource1").New(), false},
{resourceRequest("verb1").Group("group1").Resource("resource2").New(), false},
{resourceRequest("verb1").Group("group2").Resource("resource2").New(), false},
{resourceRequest("verb2").Group("group1").Resource("resource1").New(), true},
{resourceRequest("verb2").Group("group2").Resource("resource1").New(), false},
{resourceRequest("verb2").Group("group1").Resource("resource2").New(), false},
{resourceRequest("verb2").Group("group2").Resource("resource2").New(), false},
},
},
{
name: "star group, exact match other",
rule: rbacv1helpers.NewRule("verb1").Groups("*").Resources("resource1").RuleOrDie(),
requestsToExpected: map[authorizer.AttributesRecord]bool{
resourceRequest("verb1").Group("group1").Resource("resource1").New(): true,
resourceRequest("verb1").Group("group2").Resource("resource1").New(): true,
resourceRequest("verb1").Group("group1").Resource("resource2").New(): false,
resourceRequest("verb1").Group("group2").Resource("resource2").New(): false,
resourceRequest("verb2").Group("group1").Resource("resource1").New(): false,
resourceRequest("verb2").Group("group2").Resource("resource1").New(): false,
resourceRequest("verb2").Group("group1").Resource("resource2").New(): false,
resourceRequest("verb2").Group("group2").Resource("resource2").New(): false,
requestsToExpected: []*requestToTest{
{resourceRequest("verb1").Group("group1").Resource("resource1").New(), true},
{resourceRequest("verb1").Group("group2").Resource("resource1").New(), true},
{resourceRequest("verb1").Group("group1").Resource("resource2").New(), false},
{resourceRequest("verb1").Group("group2").Resource("resource2").New(), false},
{resourceRequest("verb2").Group("group1").Resource("resource1").New(), false},
{resourceRequest("verb2").Group("group2").Resource("resource1").New(), false},
{resourceRequest("verb2").Group("group1").Resource("resource2").New(), false},
{resourceRequest("verb2").Group("group2").Resource("resource2").New(), false},
},
},
{
name: "star resource, exact match other",
rule: rbacv1helpers.NewRule("verb1").Groups("group1").Resources("*").RuleOrDie(),
requestsToExpected: map[authorizer.AttributesRecord]bool{
resourceRequest("verb1").Group("group1").Resource("resource1").New(): true,
resourceRequest("verb1").Group("group2").Resource("resource1").New(): false,
resourceRequest("verb1").Group("group1").Resource("resource2").New(): true,
resourceRequest("verb1").Group("group2").Resource("resource2").New(): false,
resourceRequest("verb2").Group("group1").Resource("resource1").New(): false,
resourceRequest("verb2").Group("group2").Resource("resource1").New(): false,
resourceRequest("verb2").Group("group1").Resource("resource2").New(): false,
resourceRequest("verb2").Group("group2").Resource("resource2").New(): false,
requestsToExpected: []*requestToTest{
{resourceRequest("verb1").Group("group1").Resource("resource1").New(), true},
{resourceRequest("verb1").Group("group2").Resource("resource1").New(), false},
{resourceRequest("verb1").Group("group1").Resource("resource2").New(), true},
{resourceRequest("verb1").Group("group2").Resource("resource2").New(), false},
{resourceRequest("verb2").Group("group1").Resource("resource1").New(), false},
{resourceRequest("verb2").Group("group2").Resource("resource1").New(), false},
{resourceRequest("verb2").Group("group1").Resource("resource2").New(), false},
{resourceRequest("verb2").Group("group2").Resource("resource2").New(), false},
},
},
{
name: "tuple expansion",
rule: rbacv1helpers.NewRule("verb1", "verb2").Groups("group1", "group2").Resources("resource1", "resource2").RuleOrDie(),
requestsToExpected: map[authorizer.AttributesRecord]bool{
resourceRequest("verb1").Group("group1").Resource("resource1").New(): true,
resourceRequest("verb1").Group("group2").Resource("resource1").New(): true,
resourceRequest("verb1").Group("group1").Resource("resource2").New(): true,
resourceRequest("verb1").Group("group2").Resource("resource2").New(): true,
resourceRequest("verb2").Group("group1").Resource("resource1").New(): true,
resourceRequest("verb2").Group("group2").Resource("resource1").New(): true,
resourceRequest("verb2").Group("group1").Resource("resource2").New(): true,
resourceRequest("verb2").Group("group2").Resource("resource2").New(): true,
requestsToExpected: []*requestToTest{
{resourceRequest("verb1").Group("group1").Resource("resource1").New(), true},
{resourceRequest("verb1").Group("group2").Resource("resource1").New(), true},
{resourceRequest("verb1").Group("group1").Resource("resource2").New(), true},
{resourceRequest("verb1").Group("group2").Resource("resource2").New(), true},
{resourceRequest("verb2").Group("group1").Resource("resource1").New(), true},
{resourceRequest("verb2").Group("group2").Resource("resource1").New(), true},
{resourceRequest("verb2").Group("group1").Resource("resource2").New(), true},
{resourceRequest("verb2").Group("group2").Resource("resource2").New(), true},
},
},
{
name: "subresource expansion",
rule: rbacv1helpers.NewRule("*").Groups("*").Resources("resource1/subresource1").RuleOrDie(),
requestsToExpected: map[authorizer.AttributesRecord]bool{
resourceRequest("verb1").Group("group1").Resource("resource1").Subresource("subresource1").New(): true,
resourceRequest("verb1").Group("group2").Resource("resource1").Subresource("subresource2").New(): false,
resourceRequest("verb1").Group("group1").Resource("resource2").Subresource("subresource1").New(): false,
resourceRequest("verb1").Group("group2").Resource("resource2").Subresource("subresource1").New(): false,
resourceRequest("verb2").Group("group1").Resource("resource1").Subresource("subresource1").New(): true,
resourceRequest("verb2").Group("group2").Resource("resource1").Subresource("subresource2").New(): false,
resourceRequest("verb2").Group("group1").Resource("resource2").Subresource("subresource1").New(): false,
resourceRequest("verb2").Group("group2").Resource("resource2").Subresource("subresource1").New(): false,
requestsToExpected: []*requestToTest{
{resourceRequest("verb1").Group("group1").Resource("resource1").Subresource("subresource1").New(), true},
{resourceRequest("verb1").Group("group2").Resource("resource1").Subresource("subresource2").New(), false},
{resourceRequest("verb1").Group("group1").Resource("resource2").Subresource("subresource1").New(), false},
{resourceRequest("verb1").Group("group2").Resource("resource2").Subresource("subresource1").New(), false},
{resourceRequest("verb2").Group("group1").Resource("resource1").Subresource("subresource1").New(), true},
{resourceRequest("verb2").Group("group2").Resource("resource1").Subresource("subresource2").New(), false},
{resourceRequest("verb2").Group("group1").Resource("resource2").Subresource("subresource1").New(), false},
{resourceRequest("verb2").Group("group2").Resource("resource2").Subresource("subresource1").New(), false},
},
},
{
name: "star nonresource, exact match other",
rule: rbacv1helpers.NewRule("verb1").URLs("*").RuleOrDie(),
requestsToExpected: map[authorizer.AttributesRecord]bool{
nonresourceRequest("verb1").URL("/foo").New(): true,
nonresourceRequest("verb1").URL("/foo/bar").New(): true,
nonresourceRequest("verb1").URL("/foo/baz").New(): true,
nonresourceRequest("verb1").URL("/foo/bar/one").New(): true,
nonresourceRequest("verb1").URL("/foo/baz/one").New(): true,
nonresourceRequest("verb2").URL("/foo").New(): false,
nonresourceRequest("verb2").URL("/foo/bar").New(): false,
nonresourceRequest("verb2").URL("/foo/baz").New(): false,
nonresourceRequest("verb2").URL("/foo/bar/one").New(): false,
nonresourceRequest("verb2").URL("/foo/baz/one").New(): false,
requestsToExpected: []*requestToTest{
{nonresourceRequest("verb1").URL("/foo").New(), true},
{nonresourceRequest("verb1").URL("/foo/bar").New(), true},
{nonresourceRequest("verb1").URL("/foo/baz").New(), true},
{nonresourceRequest("verb1").URL("/foo/bar/one").New(), true},
{nonresourceRequest("verb1").URL("/foo/baz/one").New(), true},
{nonresourceRequest("verb2").URL("/foo").New(), false},
{nonresourceRequest("verb2").URL("/foo/bar").New(), false},
{nonresourceRequest("verb2").URL("/foo/baz").New(), false},
{nonresourceRequest("verb2").URL("/foo/bar/one").New(), false},
{nonresourceRequest("verb2").URL("/foo/baz/one").New(), false},
},
},
{
name: "star nonresource subpath",
rule: rbacv1helpers.NewRule("verb1").URLs("/foo/*").RuleOrDie(),
requestsToExpected: map[authorizer.AttributesRecord]bool{
nonresourceRequest("verb1").URL("/foo").New(): false,
nonresourceRequest("verb1").URL("/foo/bar").New(): true,
nonresourceRequest("verb1").URL("/foo/baz").New(): true,
nonresourceRequest("verb1").URL("/foo/bar/one").New(): true,
nonresourceRequest("verb1").URL("/foo/baz/one").New(): true,
nonresourceRequest("verb1").URL("/notfoo").New(): false,
nonresourceRequest("verb1").URL("/notfoo/bar").New(): false,
nonresourceRequest("verb1").URL("/notfoo/baz").New(): false,
nonresourceRequest("verb1").URL("/notfoo/bar/one").New(): false,
nonresourceRequest("verb1").URL("/notfoo/baz/one").New(): false,
requestsToExpected: []*requestToTest{
{nonresourceRequest("verb1").URL("/foo").New(), false},
{nonresourceRequest("verb1").URL("/foo/bar").New(), true},
{nonresourceRequest("verb1").URL("/foo/baz").New(), true},
{nonresourceRequest("verb1").URL("/foo/bar/one").New(), true},
{nonresourceRequest("verb1").URL("/foo/baz/one").New(), true},
{nonresourceRequest("verb1").URL("/notfoo").New(), false},
{nonresourceRequest("verb1").URL("/notfoo/bar").New(), false},
{nonresourceRequest("verb1").URL("/notfoo/baz").New(), false},
{nonresourceRequest("verb1").URL("/notfoo/bar/one").New(), false},
{nonresourceRequest("verb1").URL("/notfoo/baz/one").New(), false},
},
},
{
name: "star verb, exact nonresource",
rule: rbacv1helpers.NewRule("*").URLs("/foo", "/foo/bar/one").RuleOrDie(),
requestsToExpected: map[authorizer.AttributesRecord]bool{
nonresourceRequest("verb1").URL("/foo").New(): true,
nonresourceRequest("verb1").URL("/foo/bar").New(): false,
nonresourceRequest("verb1").URL("/foo/baz").New(): false,
nonresourceRequest("verb1").URL("/foo/bar/one").New(): true,
nonresourceRequest("verb1").URL("/foo/baz/one").New(): false,
nonresourceRequest("verb2").URL("/foo").New(): true,
nonresourceRequest("verb2").URL("/foo/bar").New(): false,
nonresourceRequest("verb2").URL("/foo/baz").New(): false,
nonresourceRequest("verb2").URL("/foo/bar/one").New(): true,
nonresourceRequest("verb2").URL("/foo/baz/one").New(): false,
requestsToExpected: []*requestToTest{
{nonresourceRequest("verb1").URL("/foo").New(), true},
{nonresourceRequest("verb1").URL("/foo/bar").New(), false},
{nonresourceRequest("verb1").URL("/foo/baz").New(), false},
{nonresourceRequest("verb1").URL("/foo/bar/one").New(), true},
{nonresourceRequest("verb1").URL("/foo/baz/one").New(), false},
{nonresourceRequest("verb2").URL("/foo").New(), true},
{nonresourceRequest("verb2").URL("/foo/bar").New(), false},
{nonresourceRequest("verb2").URL("/foo/baz").New(), false},
{nonresourceRequest("verb2").URL("/foo/bar/one").New(), true},
{nonresourceRequest("verb2").URL("/foo/baz/one").New(), false},
},
},
}
for _, tc := range tests {
for request, expected := range tc.requestsToExpected {
if e, a := expected, RuleAllows(request, &tc.rule); e != a {
t.Errorf("%q: expected %v, got %v for %v", tc.name, e, a, request)
for _, requestToTest := range tc.requestsToExpected {
if e, a := requestToTest.expected, RuleAllows(requestToTest.request, &tc.rule); e != a {
t.Errorf("%q: expected %v, got %v for %v", tc.name, e, a, requestToTest.request)
}
}
}