Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
b4fb2526
Unverified
Commit
b4fb2526
authored
Jan 19, 2018
by
Jordan Liggitt
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
return reason for allowed rbac authorizations
includes the binding, role, and subject that allowed a request so audit can make use of it
parent
f9bb978a
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
83 additions
and
19 deletions
+83
-19
rule.go
pkg/registry/rbac/validation/rule.go
+66
-15
rule_test.go
pkg/registry/rbac/validation/rule_test.go
+12
-1
rbac.go
plugin/pkg/auth/authorizer/rbac/rbac.go
+5
-3
No files found.
pkg/registry/rbac/validation/rule.go
View file @
b4fb2526
...
@@ -42,7 +42,7 @@ type AuthorizationRuleResolver interface {
...
@@ -42,7 +42,7 @@ type AuthorizationRuleResolver interface {
// VisitRulesFor invokes visitor() with each rule that applies to a given user in a given namespace, and each error encountered resolving those rules.
// VisitRulesFor invokes visitor() with each rule that applies to a given user in a given namespace, and each error encountered resolving those rules.
// If visitor() returns false, visiting is short-circuited.
// If visitor() returns false, visiting is short-circuited.
VisitRulesFor
(
user
user
.
Info
,
namespace
string
,
visitor
func
(
rule
*
rbac
.
PolicyRule
,
err
error
)
bool
)
VisitRulesFor
(
user
user
.
Info
,
namespace
string
,
visitor
func
(
source
fmt
.
Stringer
,
rule
*
rbac
.
PolicyRule
,
err
error
)
bool
)
}
}
// ConfirmNoEscalation determines if the roles for a given user in a given namespace encompass the provided role.
// ConfirmNoEscalation determines if the roles for a given user in a given namespace encompass the provided role.
...
@@ -107,7 +107,7 @@ type ruleAccumulator struct {
...
@@ -107,7 +107,7 @@ type ruleAccumulator struct {
errors
[]
error
errors
[]
error
}
}
func
(
r
*
ruleAccumulator
)
visit
(
rule
*
rbac
.
PolicyRule
,
err
error
)
bool
{
func
(
r
*
ruleAccumulator
)
visit
(
source
fmt
.
Stringer
,
rule
*
rbac
.
PolicyRule
,
err
error
)
bool
{
if
rule
!=
nil
{
if
rule
!=
nil
{
r
.
rules
=
append
(
r
.
rules
,
*
rule
)
r
.
rules
=
append
(
r
.
rules
,
*
rule
)
}
}
...
@@ -117,25 +117,69 @@ func (r *ruleAccumulator) visit(rule *rbac.PolicyRule, err error) bool {
...
@@ -117,25 +117,69 @@ func (r *ruleAccumulator) visit(rule *rbac.PolicyRule, err error) bool {
return
true
return
true
}
}
func
(
r
*
DefaultRuleResolver
)
VisitRulesFor
(
user
user
.
Info
,
namespace
string
,
visitor
func
(
rule
*
rbac
.
PolicyRule
,
err
error
)
bool
)
{
func
describeSubject
(
s
*
rbac
.
Subject
,
bindingNamespace
string
)
string
{
switch
s
.
Kind
{
case
rbac
.
ServiceAccountKind
:
if
len
(
s
.
Namespace
)
>
0
{
return
fmt
.
Sprintf
(
"%s %q"
,
s
.
Kind
,
s
.
Name
+
"/"
+
s
.
Namespace
)
}
return
fmt
.
Sprintf
(
"%s %q"
,
s
.
Kind
,
s
.
Name
+
"/"
+
bindingNamespace
)
default
:
return
fmt
.
Sprintf
(
"%s %q"
,
s
.
Kind
,
s
.
Name
)
}
}
type
clusterRoleBindingDescriber
struct
{
binding
*
rbac
.
ClusterRoleBinding
subject
*
rbac
.
Subject
}
func
(
d
*
clusterRoleBindingDescriber
)
String
()
string
{
return
fmt
.
Sprintf
(
"ClusterRoleBinding %q of %s %q to %s"
,
d
.
binding
.
Name
,
d
.
binding
.
RoleRef
.
Kind
,
d
.
binding
.
RoleRef
.
Name
,
describeSubject
(
d
.
subject
,
""
),
)
}
type
roleBindingDescriber
struct
{
binding
*
rbac
.
RoleBinding
subject
*
rbac
.
Subject
}
func
(
d
*
roleBindingDescriber
)
String
()
string
{
return
fmt
.
Sprintf
(
"RoleBinding %q of %s %q to %s"
,
d
.
binding
.
Name
+
"/"
+
d
.
binding
.
Namespace
,
d
.
binding
.
RoleRef
.
Kind
,
d
.
binding
.
RoleRef
.
Name
,
describeSubject
(
d
.
subject
,
d
.
binding
.
Namespace
),
)
}
func
(
r
*
DefaultRuleResolver
)
VisitRulesFor
(
user
user
.
Info
,
namespace
string
,
visitor
func
(
source
fmt
.
Stringer
,
rule
*
rbac
.
PolicyRule
,
err
error
)
bool
)
{
if
clusterRoleBindings
,
err
:=
r
.
clusterRoleBindingLister
.
ListClusterRoleBindings
();
err
!=
nil
{
if
clusterRoleBindings
,
err
:=
r
.
clusterRoleBindingLister
.
ListClusterRoleBindings
();
err
!=
nil
{
if
!
visitor
(
nil
,
err
)
{
if
!
visitor
(
nil
,
nil
,
err
)
{
return
return
}
}
}
else
{
}
else
{
sourceDescriber
:=
&
clusterRoleBindingDescriber
{}
for
_
,
clusterRoleBinding
:=
range
clusterRoleBindings
{
for
_
,
clusterRoleBinding
:=
range
clusterRoleBindings
{
if
!
appliesTo
(
user
,
clusterRoleBinding
.
Subjects
,
""
)
{
subjectIndex
,
applies
:=
appliesTo
(
user
,
clusterRoleBinding
.
Subjects
,
""
)
if
!
applies
{
continue
continue
}
}
rules
,
err
:=
r
.
GetRoleReferenceRules
(
clusterRoleBinding
.
RoleRef
,
""
)
rules
,
err
:=
r
.
GetRoleReferenceRules
(
clusterRoleBinding
.
RoleRef
,
""
)
if
err
!=
nil
{
if
err
!=
nil
{
if
!
visitor
(
nil
,
err
)
{
if
!
visitor
(
nil
,
nil
,
err
)
{
return
return
}
}
continue
continue
}
}
sourceDescriber
.
binding
=
clusterRoleBinding
sourceDescriber
.
subject
=
&
clusterRoleBinding
.
Subjects
[
subjectIndex
]
for
i
:=
range
rules
{
for
i
:=
range
rules
{
if
!
visitor
(
&
rules
[
i
],
nil
)
{
if
!
visitor
(
sourceDescriber
,
&
rules
[
i
],
nil
)
{
return
return
}
}
}
}
...
@@ -144,23 +188,27 @@ func (r *DefaultRuleResolver) VisitRulesFor(user user.Info, namespace string, vi
...
@@ -144,23 +188,27 @@ func (r *DefaultRuleResolver) VisitRulesFor(user user.Info, namespace string, vi
if
len
(
namespace
)
>
0
{
if
len
(
namespace
)
>
0
{
if
roleBindings
,
err
:=
r
.
roleBindingLister
.
ListRoleBindings
(
namespace
);
err
!=
nil
{
if
roleBindings
,
err
:=
r
.
roleBindingLister
.
ListRoleBindings
(
namespace
);
err
!=
nil
{
if
!
visitor
(
nil
,
err
)
{
if
!
visitor
(
nil
,
nil
,
err
)
{
return
return
}
}
}
else
{
}
else
{
sourceDescriber
:=
&
roleBindingDescriber
{}
for
_
,
roleBinding
:=
range
roleBindings
{
for
_
,
roleBinding
:=
range
roleBindings
{
if
!
appliesTo
(
user
,
roleBinding
.
Subjects
,
namespace
)
{
subjectIndex
,
applies
:=
appliesTo
(
user
,
roleBinding
.
Subjects
,
namespace
)
if
!
applies
{
continue
continue
}
}
rules
,
err
:=
r
.
GetRoleReferenceRules
(
roleBinding
.
RoleRef
,
namespace
)
rules
,
err
:=
r
.
GetRoleReferenceRules
(
roleBinding
.
RoleRef
,
namespace
)
if
err
!=
nil
{
if
err
!=
nil
{
if
!
visitor
(
nil
,
err
)
{
if
!
visitor
(
nil
,
nil
,
err
)
{
return
return
}
}
continue
continue
}
}
sourceDescriber
.
binding
=
roleBinding
sourceDescriber
.
subject
=
&
roleBinding
.
Subjects
[
subjectIndex
]
for
i
:=
range
rules
{
for
i
:=
range
rules
{
if
!
visitor
(
&
rules
[
i
],
nil
)
{
if
!
visitor
(
sourceDescriber
,
&
rules
[
i
],
nil
)
{
return
return
}
}
}
}
...
@@ -190,13 +238,16 @@ func (r *DefaultRuleResolver) GetRoleReferenceRules(roleRef rbac.RoleRef, bindin
...
@@ -190,13 +238,16 @@ func (r *DefaultRuleResolver) GetRoleReferenceRules(roleRef rbac.RoleRef, bindin
return
nil
,
fmt
.
Errorf
(
"unsupported role reference kind: %q"
,
kind
)
return
nil
,
fmt
.
Errorf
(
"unsupported role reference kind: %q"
,
kind
)
}
}
}
}
func
appliesTo
(
user
user
.
Info
,
bindingSubjects
[]
rbac
.
Subject
,
namespace
string
)
bool
{
for
_
,
bindingSubject
:=
range
bindingSubjects
{
// appliesTo returns whether any of the bindingSubjects applies to the specified subject,
// and if true, the index of the first subject that applies
func
appliesTo
(
user
user
.
Info
,
bindingSubjects
[]
rbac
.
Subject
,
namespace
string
)
(
int
,
bool
)
{
for
i
,
bindingSubject
:=
range
bindingSubjects
{
if
appliesToUser
(
user
,
bindingSubject
,
namespace
)
{
if
appliesToUser
(
user
,
bindingSubject
,
namespace
)
{
return
true
return
i
,
true
}
}
}
}
return
false
return
0
,
false
}
}
func
appliesToUser
(
user
user
.
Info
,
subject
rbac
.
Subject
,
namespace
string
)
bool
{
func
appliesToUser
(
user
user
.
Info
,
subject
rbac
.
Subject
,
namespace
string
)
bool
{
...
...
pkg/registry/rbac/validation/rule_test.go
View file @
b4fb2526
...
@@ -168,6 +168,7 @@ func TestAppliesTo(t *testing.T) {
...
@@ -168,6 +168,7 @@ func TestAppliesTo(t *testing.T) {
user
user
.
Info
user
user
.
Info
namespace
string
namespace
string
appliesTo
bool
appliesTo
bool
index
int
testCase
string
testCase
string
}{
}{
{
{
...
@@ -176,6 +177,7 @@ func TestAppliesTo(t *testing.T) {
...
@@ -176,6 +177,7 @@ func TestAppliesTo(t *testing.T) {
},
},
user
:
&
user
.
DefaultInfo
{
Name
:
"foobar"
},
user
:
&
user
.
DefaultInfo
{
Name
:
"foobar"
},
appliesTo
:
true
,
appliesTo
:
true
,
index
:
0
,
testCase
:
"single subject that matches username"
,
testCase
:
"single subject that matches username"
,
},
},
{
{
...
@@ -185,6 +187,7 @@ func TestAppliesTo(t *testing.T) {
...
@@ -185,6 +187,7 @@ func TestAppliesTo(t *testing.T) {
},
},
user
:
&
user
.
DefaultInfo
{
Name
:
"foobar"
},
user
:
&
user
.
DefaultInfo
{
Name
:
"foobar"
},
appliesTo
:
true
,
appliesTo
:
true
,
index
:
1
,
testCase
:
"multiple subjects, one that matches username"
,
testCase
:
"multiple subjects, one that matches username"
,
},
},
{
{
...
@@ -203,6 +206,7 @@ func TestAppliesTo(t *testing.T) {
...
@@ -203,6 +206,7 @@ func TestAppliesTo(t *testing.T) {
},
},
user
:
&
user
.
DefaultInfo
{
Name
:
"zimzam"
,
Groups
:
[]
string
{
"foobar"
}},
user
:
&
user
.
DefaultInfo
{
Name
:
"zimzam"
,
Groups
:
[]
string
{
"foobar"
}},
appliesTo
:
true
,
appliesTo
:
true
,
index
:
1
,
testCase
:
"multiple subjects, one that match group"
,
testCase
:
"multiple subjects, one that match group"
,
},
},
{
{
...
@@ -213,6 +217,7 @@ func TestAppliesTo(t *testing.T) {
...
@@ -213,6 +217,7 @@ func TestAppliesTo(t *testing.T) {
user
:
&
user
.
DefaultInfo
{
Name
:
"zimzam"
,
Groups
:
[]
string
{
"foobar"
}},
user
:
&
user
.
DefaultInfo
{
Name
:
"zimzam"
,
Groups
:
[]
string
{
"foobar"
}},
namespace
:
"namespace1"
,
namespace
:
"namespace1"
,
appliesTo
:
true
,
appliesTo
:
true
,
index
:
1
,
testCase
:
"multiple subjects, one that match group, should ignore namespace"
,
testCase
:
"multiple subjects, one that match group, should ignore namespace"
,
},
},
{
{
...
@@ -224,6 +229,7 @@ func TestAppliesTo(t *testing.T) {
...
@@ -224,6 +229,7 @@ func TestAppliesTo(t *testing.T) {
user
:
&
user
.
DefaultInfo
{
Name
:
"system:serviceaccount:kube-system:default"
},
user
:
&
user
.
DefaultInfo
{
Name
:
"system:serviceaccount:kube-system:default"
},
namespace
:
"default"
,
namespace
:
"default"
,
appliesTo
:
true
,
appliesTo
:
true
,
index
:
2
,
testCase
:
"multiple subjects with a service account that matches"
,
testCase
:
"multiple subjects with a service account that matches"
,
},
},
{
{
...
@@ -243,6 +249,7 @@ func TestAppliesTo(t *testing.T) {
...
@@ -243,6 +249,7 @@ func TestAppliesTo(t *testing.T) {
user
:
&
user
.
DefaultInfo
{
Name
:
"foobar"
,
Groups
:
[]
string
{
user
.
AllAuthenticated
}},
user
:
&
user
.
DefaultInfo
{
Name
:
"foobar"
,
Groups
:
[]
string
{
user
.
AllAuthenticated
}},
namespace
:
"default"
,
namespace
:
"default"
,
appliesTo
:
true
,
appliesTo
:
true
,
index
:
0
,
testCase
:
"binding to all authenticated and unauthenticated subjects matches authenticated user"
,
testCase
:
"binding to all authenticated and unauthenticated subjects matches authenticated user"
,
},
},
{
{
...
@@ -253,14 +260,18 @@ func TestAppliesTo(t *testing.T) {
...
@@ -253,14 +260,18 @@ func TestAppliesTo(t *testing.T) {
user
:
&
user
.
DefaultInfo
{
Name
:
"system:anonymous"
,
Groups
:
[]
string
{
user
.
AllUnauthenticated
}},
user
:
&
user
.
DefaultInfo
{
Name
:
"system:anonymous"
,
Groups
:
[]
string
{
user
.
AllUnauthenticated
}},
namespace
:
"default"
,
namespace
:
"default"
,
appliesTo
:
true
,
appliesTo
:
true
,
index
:
1
,
testCase
:
"binding to all authenticated and unauthenticated subjects matches anonymous user"
,
testCase
:
"binding to all authenticated and unauthenticated subjects matches anonymous user"
,
},
},
}
}
for
_
,
tc
:=
range
tests
{
for
_
,
tc
:=
range
tests
{
got
:=
appliesTo
(
tc
.
user
,
tc
.
subjects
,
tc
.
namespace
)
got
Index
,
got
:=
appliesTo
(
tc
.
user
,
tc
.
subjects
,
tc
.
namespace
)
if
got
!=
tc
.
appliesTo
{
if
got
!=
tc
.
appliesTo
{
t
.
Errorf
(
"case %q want appliesTo=%t, got appliesTo=%t"
,
tc
.
testCase
,
tc
.
appliesTo
,
got
)
t
.
Errorf
(
"case %q want appliesTo=%t, got appliesTo=%t"
,
tc
.
testCase
,
tc
.
appliesTo
,
got
)
}
}
if
gotIndex
!=
tc
.
index
{
t
.
Errorf
(
"case %q want index %d, got %d"
,
tc
.
testCase
,
tc
.
index
,
gotIndex
)
}
}
}
}
}
plugin/pkg/auth/authorizer/rbac/rbac.go
View file @
b4fb2526
...
@@ -43,7 +43,7 @@ type RequestToRuleMapper interface {
...
@@ -43,7 +43,7 @@ type RequestToRuleMapper interface {
// VisitRulesFor invokes visitor() with each rule that applies to a given user in a given namespace,
// VisitRulesFor invokes visitor() with each rule that applies to a given user in a given namespace,
// and each error encountered resolving those rules. Rule may be nil if err is non-nil.
// and each error encountered resolving those rules. Rule may be nil if err is non-nil.
// If visitor() returns false, visiting is short-circuited.
// If visitor() returns false, visiting is short-circuited.
VisitRulesFor
(
user
user
.
Info
,
namespace
string
,
visitor
func
(
rule
*
rbac
.
PolicyRule
,
err
error
)
bool
)
VisitRulesFor
(
user
user
.
Info
,
namespace
string
,
visitor
func
(
source
fmt
.
Stringer
,
rule
*
rbac
.
PolicyRule
,
err
error
)
bool
)
}
}
type
RBACAuthorizer
struct
{
type
RBACAuthorizer
struct
{
...
@@ -55,12 +55,14 @@ type authorizingVisitor struct {
...
@@ -55,12 +55,14 @@ type authorizingVisitor struct {
requestAttributes
authorizer
.
Attributes
requestAttributes
authorizer
.
Attributes
allowed
bool
allowed
bool
reason
string
errors
[]
error
errors
[]
error
}
}
func
(
v
*
authorizingVisitor
)
visit
(
rule
*
rbac
.
PolicyRule
,
err
error
)
bool
{
func
(
v
*
authorizingVisitor
)
visit
(
source
fmt
.
Stringer
,
rule
*
rbac
.
PolicyRule
,
err
error
)
bool
{
if
rule
!=
nil
&&
RuleAllows
(
v
.
requestAttributes
,
rule
)
{
if
rule
!=
nil
&&
RuleAllows
(
v
.
requestAttributes
,
rule
)
{
v
.
allowed
=
true
v
.
allowed
=
true
v
.
reason
=
fmt
.
Sprintf
(
"allowed by %s"
,
source
.
String
())
return
false
return
false
}
}
if
err
!=
nil
{
if
err
!=
nil
{
...
@@ -74,7 +76,7 @@ func (r *RBACAuthorizer) Authorize(requestAttributes authorizer.Attributes) (aut
...
@@ -74,7 +76,7 @@ func (r *RBACAuthorizer) Authorize(requestAttributes authorizer.Attributes) (aut
r
.
authorizationRuleResolver
.
VisitRulesFor
(
requestAttributes
.
GetUser
(),
requestAttributes
.
GetNamespace
(),
ruleCheckingVisitor
.
visit
)
r
.
authorizationRuleResolver
.
VisitRulesFor
(
requestAttributes
.
GetUser
(),
requestAttributes
.
GetNamespace
(),
ruleCheckingVisitor
.
visit
)
if
ruleCheckingVisitor
.
allowed
{
if
ruleCheckingVisitor
.
allowed
{
return
authorizer
.
DecisionAllow
,
""
,
nil
return
authorizer
.
DecisionAllow
,
ruleCheckingVisitor
.
reason
,
nil
}
}
// Build a detailed log of the denial.
// Build a detailed log of the denial.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment