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
f14c1384
Commit
f14c1384
authored
Jul 14, 2017
by
xilabao
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add selfsubjectrulesreview api
parent
6a845c67
Hide whitespace changes
Inline
Side-by-side
Showing
28 changed files
with
951 additions
and
33 deletions
+951
-33
server.go
cmd/kube-apiserver/app/server.go
+2
-2
server.go
federation/cmd/federation-apiserver/app/server.go
+1
-1
install.go
pkg/apis/authorization/install/install.go
+1
-1
register.go
pkg/apis/authorization/register.go
+1
-0
types.go
pkg/apis/authorization/types.go
+71
-0
validation.go
pkg/apis/authorization/validation/validation.go
+4
-0
abac.go
pkg/auth/authorizer/abac/abac.go
+46
-7
abac_test.go
pkg/auth/authorizer/abac/abac_test.go
+200
-2
graph_builder.go
pkg/controller/garbagecollector/graph_builder.go
+1
-0
config.go
pkg/kubeapiserver/authorizer/config.go
+24
-14
config_test.go
pkg/kubeapiserver/authorizer/config_test.go
+1
-1
master.go
pkg/master/master.go
+1
-1
storage_authorization.go
pkg/registry/authorization/rest/storage_authorization.go
+9
-1
rest.go
pkg/registry/authorization/selfsubjectrulesreview/rest.go
+99
-0
rbac.go
plugin/pkg/auth/authorizer/rbac/rbac.go
+30
-0
register.go
staging/src/k8s.io/api/authorization/v1/register.go
+1
-0
types.go
staging/src/k8s.io/api/authorization/v1/types.go
+79
-0
register.go
staging/src/k8s.io/api/authorization/v1beta1/register.go
+1
-0
types.go
staging/src/k8s.io/api/authorization/v1beta1/types.go
+79
-0
interfaces.go
...s.io/apiserver/pkg/authorization/authorizer/interfaces.go
+6
-0
rule.go
...src/k8s.io/apiserver/pkg/authorization/authorizer/rule.go
+73
-0
builtin.go
.../apiserver/pkg/authorization/authorizerfactory/builtin.go
+22
-2
union.go
...ing/src/k8s.io/apiserver/pkg/authorization/union/union.go
+38
-0
union_test.go
...rc/k8s.io/apiserver/pkg/authorization/union/union_test.go
+142
-0
config.go
staging/src/k8s.io/apiserver/pkg/server/config.go
+3
-0
webhook.go
...k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook.go
+11
-0
node_test.go
test/integration/auth/node_test.go
+1
-1
etcd_storage_path_test.go
test/integration/etcd/etcd_storage_path_test.go
+4
-0
No files found.
cmd/kube-apiserver/app/server.go
View file @
f14c1384
...
...
@@ -441,7 +441,7 @@ func BuildGenericConfig(s *options.ServerRunOptions) (*genericapiserver.Config,
return
nil
,
nil
,
nil
,
nil
,
nil
,
fmt
.
Errorf
(
"invalid authentication config: %v"
,
err
)
}
genericConfig
.
Authorizer
,
err
=
BuildAuthorizer
(
s
,
sharedInformers
)
genericConfig
.
Authorizer
,
genericConfig
.
RuleResolver
,
err
=
BuildAuthorizer
(
s
,
sharedInformers
)
if
err
!=
nil
{
return
nil
,
nil
,
nil
,
nil
,
nil
,
fmt
.
Errorf
(
"invalid authorization config: %v"
,
err
)
}
...
...
@@ -542,7 +542,7 @@ func BuildAuthenticator(s *options.ServerRunOptions, storageFactory serverstorag
}
// BuildAuthorizer constructs the authorizer
func
BuildAuthorizer
(
s
*
options
.
ServerRunOptions
,
sharedInformers
informers
.
SharedInformerFactory
)
(
authorizer
.
Authorizer
,
error
)
{
func
BuildAuthorizer
(
s
*
options
.
ServerRunOptions
,
sharedInformers
informers
.
SharedInformerFactory
)
(
authorizer
.
Authorizer
,
authorizer
.
RuleResolver
,
error
)
{
authorizationConfig
:=
s
.
Authorization
.
ToAuthorizationConfig
(
sharedInformers
)
return
authorizationConfig
.
New
()
}
...
...
federation/cmd/federation-apiserver/app/server.go
View file @
f14c1384
...
...
@@ -190,7 +190,7 @@ func NonBlockingRun(s *options.ServerRunOptions, stopCh <-chan struct{}) error {
sharedInformers
:=
informers
.
NewSharedInformerFactory
(
client
,
10
*
time
.
Minute
)
authorizationConfig
:=
s
.
Authorization
.
ToAuthorizationConfig
(
sharedInformers
)
apiAuthorizer
,
err
:=
authorizationConfig
.
New
()
apiAuthorizer
,
_
,
err
:=
authorizationConfig
.
New
()
if
err
!=
nil
{
return
fmt
.
Errorf
(
"invalid Authorization Config: %v"
,
err
)
}
...
...
pkg/apis/authorization/install/install.go
View file @
f14c1384
...
...
@@ -39,7 +39,7 @@ func Install(groupFactoryRegistry announced.APIGroupFactoryRegistry, registry *r
&
announced
.
GroupMetaFactoryArgs
{
GroupName
:
authorization
.
GroupName
,
VersionPreferenceOrder
:
[]
string
{
v1
.
SchemeGroupVersion
.
Version
,
v1beta1
.
SchemeGroupVersion
.
Version
},
RootScopedKinds
:
sets
.
NewString
(
"SubjectAccessReview"
,
"SelfSubjectAccessReview"
),
RootScopedKinds
:
sets
.
NewString
(
"SubjectAccessReview"
,
"SelfSubjectAccessReview"
,
"SelfSubjectRulesReview"
),
AddInternalObjectsToScheme
:
authorization
.
AddToScheme
,
},
announced
.
VersionToSchemeFunc
{
...
...
pkg/apis/authorization/register.go
View file @
f14c1384
...
...
@@ -44,6 +44,7 @@ var (
func
addKnownTypes
(
scheme
*
runtime
.
Scheme
)
error
{
scheme
.
AddKnownTypes
(
SchemeGroupVersion
,
&
SelfSubjectRulesReview
{},
&
SelfSubjectAccessReview
{},
&
SubjectAccessReview
{},
&
LocalSubjectAccessReview
{},
...
...
pkg/apis/authorization/types.go
View file @
f14c1384
...
...
@@ -149,3 +149,74 @@ type SubjectAccessReviewStatus struct {
// For instance, RBAC can be missing a role, but enough roles are still present and bound to reason about the request.
EvaluationError
string
}
// +genclient
// +genclient:nonNamespaced
// +genclient:noVerbs
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// SelfSubjectRulesReview enumerates the set of actions the current user can perform within a namespace.
// The returned list of actions may be incomplete depending on the server's authorization mode,
// and any errors experienced during the evaluation. SelfSubjectRulesReview should be used by UIs to show/hide actions,
// or to quickly let an end user reason about their permissions. It should NOT Be used by external systems to
// drive authorization decisions as this raises confused deputy, cache lifetime/revocation, and correctness concerns.
// SubjectAccessReview, and LocalAccessReview are the correct way to defer authorization decisions to the API server.
type
SelfSubjectRulesReview
struct
{
metav1
.
TypeMeta
metav1
.
ObjectMeta
// Spec holds information about the request being evaluated.
Spec
SelfSubjectRulesReviewSpec
// Status is filled in by the server and indicates the set of actions a user can perform.
Status
SubjectRulesReviewStatus
}
type
SelfSubjectRulesReviewSpec
struct
{
// Namespace to evaluate rules for. Required.
Namespace
string
}
// SubjectRulesReviewStatus contains the result of a rules check. This check can be incomplete depending on
// the set of authorizers the server is configured with and any errors experienced during evaluation.
// Because authorization rules are additive, if a rule appears in a list it's safe to assume the subject has that permission,
// even if that list is incomplete.
type
SubjectRulesReviewStatus
struct
{
// ResourceRules 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.
ResourceRules
[]
ResourceRule
// NonResourceRules is the list of actions the subject is allowed to perform on non-resources.
// The list ordering isn't significant, may contain duplicates, and possibly be incomplete.
NonResourceRules
[]
NonResourceRule
// Incomplete is true when the rules returned by this call are incomplete. This is most commonly
// encountered when an authorizer, such as an external authorizer, doesn't support rules evaluation.
Incomplete
bool
// EvaluationError can appear in combination with Rules. It indicates an error occurred during
// rule evaluation, such as an authorizer that doesn't support rule evaluation, and that
// ResourceRules and/or NonResourceRules may be incomplete.
EvaluationError
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.
type
ResourceRule
struct
{
// Verb is a list of kubernetes resource API verbs, like: get, list, watch, create, update, delete, proxy. "*" means all.
Verbs
[]
string
// 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
[]
string
// Resources is a list of resources this rule applies to. ResourceAll represents all resources. "*" means all.
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
[]
string
}
// NonResourceRule holds information that describes a rule for the non-resource
type
NonResourceRule
struct
{
// Verb is a list of kubernetes non-resource API verbs, like: get, post, put, delete, patch, head, options. "*" means all.
Verbs
[]
string
// 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. "*" means all.
NonResourceURLs
[]
string
}
pkg/apis/authorization/validation/validation.go
View file @
f14c1384
...
...
@@ -50,6 +50,10 @@ func ValidateSelfSubjectAccessReviewSpec(spec authorizationapi.SelfSubjectAccess
return
allErrs
}
func
ValidateSelfSubjectRulesReview
(
review
*
authorizationapi
.
SelfSubjectRulesReview
)
field
.
ErrorList
{
return
field
.
ErrorList
{}
}
func
ValidateSubjectAccessReview
(
sar
*
authorizationapi
.
SubjectAccessReview
)
field
.
ErrorList
{
allErrs
:=
ValidateSubjectAccessReviewSpec
(
sar
.
Spec
,
field
.
NewPath
(
"spec"
))
if
!
apiequality
.
Semantic
.
DeepEqual
(
metav1
.
ObjectMeta
{},
sar
.
ObjectMeta
)
{
...
...
pkg/auth/authorizer/abac/abac.go
View file @
f14c1384
...
...
@@ -28,6 +28,7 @@ import (
"github.com/golang/glog"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/authentication/user"
"k8s.io/apiserver/pkg/authorization/authorizer"
api
"k8s.io/kubernetes/pkg/apis/abac"
_
"k8s.io/kubernetes/pkg/apis/abac/latest"
...
...
@@ -114,7 +115,7 @@ func NewFromFile(path string) (policyList, error) {
}
func
matches
(
p
api
.
Policy
,
a
authorizer
.
Attributes
)
bool
{
if
subjectMatches
(
p
,
a
)
{
if
subjectMatches
(
p
,
a
.
GetUser
()
)
{
if
verbMatches
(
p
,
a
)
{
// Resource and non-resource requests are mutually exclusive, at most one will match a policy
if
resourceMatches
(
p
,
a
)
{
...
...
@@ -129,15 +130,14 @@ func matches(p api.Policy, a authorizer.Attributes) bool {
}
// subjectMatches returns true if specified user and group properties in the policy match the attributes
func
subjectMatches
(
p
api
.
Policy
,
a
authorizer
.
Attributes
)
bool
{
func
subjectMatches
(
p
api
.
Policy
,
user
user
.
Info
)
bool
{
matched
:=
false
username
:=
""
groups
:=
[]
string
{}
if
user
:=
a
.
GetUser
();
user
!=
nil
{
username
=
user
.
GetName
()
groups
=
user
.
GetGroups
()
if
user
==
nil
{
return
false
}
username
:=
user
.
GetName
()
groups
:=
user
.
GetGroups
()
// If the policy specified a user, ensure it matches
if
len
(
p
.
Spec
.
User
)
>
0
{
...
...
@@ -232,3 +232,42 @@ func (pl policyList) Authorize(a authorizer.Attributes) (bool, string, error) {
// policy file, compared to other steps such as encoding/decoding.
// Then, add Caching only if needed.
}
func
(
pl
policyList
)
RulesFor
(
user
user
.
Info
,
namespace
string
)
([]
authorizer
.
ResourceRuleInfo
,
[]
authorizer
.
NonResourceRuleInfo
,
bool
,
error
)
{
var
(
resourceRules
[]
authorizer
.
ResourceRuleInfo
nonResourceRules
[]
authorizer
.
NonResourceRuleInfo
)
for
_
,
p
:=
range
pl
{
if
subjectMatches
(
*
p
,
user
)
{
if
p
.
Spec
.
Namespace
==
"*"
||
p
.
Spec
.
Namespace
==
namespace
{
if
len
(
p
.
Spec
.
Resource
)
>
0
{
r
:=
authorizer
.
DefaultResourceRuleInfo
{
Verbs
:
getVerbs
(
p
.
Spec
.
Readonly
),
APIGroups
:
[]
string
{
p
.
Spec
.
APIGroup
},
Resources
:
[]
string
{
p
.
Spec
.
Resource
},
}
var
resourceRule
authorizer
.
ResourceRuleInfo
=
&
r
resourceRules
=
append
(
resourceRules
,
resourceRule
)
}
if
len
(
p
.
Spec
.
NonResourcePath
)
>
0
{
r
:=
authorizer
.
DefaultNonResourceRuleInfo
{
Verbs
:
getVerbs
(
p
.
Spec
.
Readonly
),
NonResourceURLs
:
[]
string
{
p
.
Spec
.
NonResourcePath
},
}
var
nonResourceRule
authorizer
.
NonResourceRuleInfo
=
&
r
nonResourceRules
=
append
(
nonResourceRules
,
nonResourceRule
)
}
}
}
}
return
resourceRules
,
nonResourceRules
,
false
,
nil
}
func
getVerbs
(
isReadOnly
bool
)
[]
string
{
if
isReadOnly
{
return
[]
string
{
"get"
,
"list"
,
"watch"
}
}
return
[]
string
{
"*"
}
}
pkg/auth/authorizer/abac/abac_test.go
View file @
f14c1384
...
...
@@ -19,6 +19,7 @@ package abac
import
(
"io/ioutil"
"os"
"reflect"
"testing"
"k8s.io/apimachinery/pkg/runtime"
...
...
@@ -141,6 +142,203 @@ func TestAuthorizeV0(t *testing.T) {
}
}
func
getResourceRules
(
infos
[]
authorizer
.
ResourceRuleInfo
)
[]
authorizer
.
DefaultResourceRuleInfo
{
rules
:=
make
([]
authorizer
.
DefaultResourceRuleInfo
,
len
(
infos
))
for
i
,
info
:=
range
infos
{
rules
[
i
]
=
authorizer
.
DefaultResourceRuleInfo
{
Verbs
:
info
.
GetVerbs
(),
APIGroups
:
info
.
GetAPIGroups
(),
Resources
:
info
.
GetResources
(),
ResourceNames
:
info
.
GetResourceNames
(),
}
}
return
rules
}
func
getNonResourceRules
(
infos
[]
authorizer
.
NonResourceRuleInfo
)
[]
authorizer
.
DefaultNonResourceRuleInfo
{
rules
:=
make
([]
authorizer
.
DefaultNonResourceRuleInfo
,
len
(
infos
))
for
i
,
info
:=
range
infos
{
rules
[
i
]
=
authorizer
.
DefaultNonResourceRuleInfo
{
Verbs
:
info
.
GetVerbs
(),
NonResourceURLs
:
info
.
GetNonResourceURLs
(),
}
}
return
rules
}
func
TestRulesFor
(
t
*
testing
.
T
)
{
a
,
err
:=
newWithContents
(
t
,
`
{ "readonly": true, "resource": "events" }
{"user":"scheduler", "readonly": true, "resource": "pods" }
{"user":"scheduler", "resource": "bindings" }
{"user":"kubelet", "readonly": true, "resource": "pods" }
{"user":"kubelet", "resource": "events" }
{"user":"alice", "namespace": "projectCaribou"}
{"user":"bob", "readonly": true, "namespace": "projectCaribou"}
{"user":"bob", "readonly": true, "nonResourcePath": "*"}
{"group":"a", "resource": "bindings" }
{"group":"b", "readonly": true, "nonResourcePath": "*"}
`
)
if
err
!=
nil
{
t
.
Fatalf
(
"unable to read policy file: %v"
,
err
)
}
authenticatedGroup
:=
[]
string
{
user
.
AllAuthenticated
}
uScheduler
:=
user
.
DefaultInfo
{
Name
:
"scheduler"
,
UID
:
"uid1"
,
Groups
:
authenticatedGroup
}
uKubelet
:=
user
.
DefaultInfo
{
Name
:
"kubelet"
,
UID
:
"uid2"
,
Groups
:
[]
string
{
"a"
,
"b"
}}
uAlice
:=
user
.
DefaultInfo
{
Name
:
"alice"
,
UID
:
"uid3"
,
Groups
:
authenticatedGroup
}
uBob
:=
user
.
DefaultInfo
{
Name
:
"bob"
,
UID
:
"uid4"
,
Groups
:
authenticatedGroup
}
uChuck
:=
user
.
DefaultInfo
{
Name
:
"chuck"
,
UID
:
"uid5"
,
Groups
:
[]
string
{
"a"
,
"b"
}}
testCases
:=
[]
struct
{
User
user
.
DefaultInfo
Namespace
string
ExpectResourceRules
[]
authorizer
.
DefaultResourceRuleInfo
ExpectNonResourceRules
[]
authorizer
.
DefaultNonResourceRuleInfo
}{
{
User
:
uScheduler
,
Namespace
:
"ns1"
,
ExpectResourceRules
:
[]
authorizer
.
DefaultResourceRuleInfo
{
{
Verbs
:
[]
string
{
"get"
,
"list"
,
"watch"
},
APIGroups
:
[]
string
{
"*"
},
Resources
:
[]
string
{
"events"
},
},
{
Verbs
:
[]
string
{
"get"
,
"list"
,
"watch"
},
APIGroups
:
[]
string
{
"*"
},
Resources
:
[]
string
{
"pods"
},
},
{
Verbs
:
[]
string
{
"*"
},
APIGroups
:
[]
string
{
"*"
},
Resources
:
[]
string
{
"bindings"
},
},
},
ExpectNonResourceRules
:
[]
authorizer
.
DefaultNonResourceRuleInfo
{},
},
{
User
:
uKubelet
,
Namespace
:
"ns1"
,
ExpectResourceRules
:
[]
authorizer
.
DefaultResourceRuleInfo
{
{
Verbs
:
[]
string
{
"get"
,
"list"
,
"watch"
},
APIGroups
:
[]
string
{
"*"
},
Resources
:
[]
string
{
"pods"
},
},
{
Verbs
:
[]
string
{
"*"
},
APIGroups
:
[]
string
{
"*"
},
Resources
:
[]
string
{
"events"
},
},
{
Verbs
:
[]
string
{
"*"
},
APIGroups
:
[]
string
{
"*"
},
Resources
:
[]
string
{
"bindings"
},
},
{
Verbs
:
[]
string
{
"get"
,
"list"
,
"watch"
},
APIGroups
:
[]
string
{
"*"
},
Resources
:
[]
string
{
"*"
},
},
},
ExpectNonResourceRules
:
[]
authorizer
.
DefaultNonResourceRuleInfo
{
{
Verbs
:
[]
string
{
"get"
,
"list"
,
"watch"
},
NonResourceURLs
:
[]
string
{
"*"
},
},
},
},
{
User
:
uAlice
,
Namespace
:
"projectCaribou"
,
ExpectResourceRules
:
[]
authorizer
.
DefaultResourceRuleInfo
{
{
Verbs
:
[]
string
{
"get"
,
"list"
,
"watch"
},
APIGroups
:
[]
string
{
"*"
},
Resources
:
[]
string
{
"events"
},
},
{
Verbs
:
[]
string
{
"*"
},
APIGroups
:
[]
string
{
"*"
},
Resources
:
[]
string
{
"*"
},
},
},
ExpectNonResourceRules
:
[]
authorizer
.
DefaultNonResourceRuleInfo
{},
},
{
User
:
uBob
,
Namespace
:
"projectCaribou"
,
ExpectResourceRules
:
[]
authorizer
.
DefaultResourceRuleInfo
{
{
Verbs
:
[]
string
{
"get"
,
"list"
,
"watch"
},
APIGroups
:
[]
string
{
"*"
},
Resources
:
[]
string
{
"events"
},
},
{
Verbs
:
[]
string
{
"get"
,
"list"
,
"watch"
},
APIGroups
:
[]
string
{
"*"
},
Resources
:
[]
string
{
"*"
},
},
{
Verbs
:
[]
string
{
"get"
,
"list"
,
"watch"
},
APIGroups
:
[]
string
{
"*"
},
Resources
:
[]
string
{
"*"
},
},
},
ExpectNonResourceRules
:
[]
authorizer
.
DefaultNonResourceRuleInfo
{
{
Verbs
:
[]
string
{
"get"
,
"list"
,
"watch"
},
NonResourceURLs
:
[]
string
{
"*"
},
},
},
},
{
User
:
uChuck
,
Namespace
:
"ns1"
,
ExpectResourceRules
:
[]
authorizer
.
DefaultResourceRuleInfo
{
{
Verbs
:
[]
string
{
"*"
},
APIGroups
:
[]
string
{
"*"
},
Resources
:
[]
string
{
"bindings"
},
},
{
Verbs
:
[]
string
{
"get"
,
"list"
,
"watch"
},
APIGroups
:
[]
string
{
"*"
},
Resources
:
[]
string
{
"*"
},
},
},
ExpectNonResourceRules
:
[]
authorizer
.
DefaultNonResourceRuleInfo
{
{
Verbs
:
[]
string
{
"get"
,
"list"
,
"watch"
},
NonResourceURLs
:
[]
string
{
"*"
},
},
},
},
}
for
i
,
tc
:=
range
testCases
{
attr
:=
authorizer
.
AttributesRecord
{
User
:
&
tc
.
User
,
Namespace
:
tc
.
Namespace
,
}
resourceRules
,
nonResourceRules
,
_
,
_
:=
a
.
RulesFor
(
attr
.
GetUser
(),
attr
.
GetNamespace
())
actualResourceRules
:=
getResourceRules
(
resourceRules
)
if
!
reflect
.
DeepEqual
(
tc
.
ExpectResourceRules
,
actualResourceRules
)
{
t
.
Logf
(
"tc: %v -> attr %v"
,
tc
,
attr
)
t
.
Errorf
(
"%d: Expected:
\n
%#v
\n
but actual:
\n
%#v
\n
"
,
i
,
tc
.
ExpectResourceRules
,
actualResourceRules
)
}
actualNonResourceRules
:=
getNonResourceRules
(
nonResourceRules
)
if
!
reflect
.
DeepEqual
(
tc
.
ExpectNonResourceRules
,
actualNonResourceRules
)
{
t
.
Logf
(
"tc: %v -> attr %v"
,
tc
,
attr
)
t
.
Errorf
(
"%d: Expected:
\n
%#v
\n
but actual:
\n
%#v
\n
"
,
i
,
tc
.
ExpectNonResourceRules
,
actualNonResourceRules
)
}
}
}
func
TestAuthorizeV1beta1
(
t
*
testing
.
T
)
{
a
,
err
:=
newWithContents
(
t
,
`
...
...
@@ -609,7 +807,7 @@ func TestSubjectMatches(t *testing.T) {
attr
:=
authorizer
.
AttributesRecord
{
User
:
&
tc
.
User
,
}
actualMatch
:=
subjectMatches
(
*
policy
,
attr
)
actualMatch
:=
subjectMatches
(
*
policy
,
attr
.
GetUser
()
)
if
tc
.
ExpectMatch
!=
actualMatch
{
t
.
Errorf
(
"%v: Expected actorMatches=%v but actually got=%v"
,
k
,
tc
.
ExpectMatch
,
actualMatch
)
...
...
@@ -617,7 +815,7 @@ func TestSubjectMatches(t *testing.T) {
}
}
func
newWithContents
(
t
*
testing
.
T
,
contents
string
)
(
authorizer
.
Authorizer
,
error
)
{
func
newWithContents
(
t
*
testing
.
T
,
contents
string
)
(
policyList
,
error
)
{
f
,
err
:=
ioutil
.
TempFile
(
""
,
"abac_test"
)
if
err
!=
nil
{
t
.
Fatalf
(
"unexpected error creating policyfile: %v"
,
err
)
...
...
pkg/controller/garbagecollector/graph_builder.go
View file @
f14c1384
...
...
@@ -359,6 +359,7 @@ var ignoredResources = map[schema.GroupResource]struct{}{
{
Group
:
"authorization.k8s.io"
,
Resource
:
"subjectaccessreviews"
}
:
{},
{
Group
:
"authorization.k8s.io"
,
Resource
:
"selfsubjectaccessreviews"
}
:
{},
{
Group
:
"authorization.k8s.io"
,
Resource
:
"localsubjectaccessreviews"
}
:
{},
{
Group
:
"authorization.k8s.io"
,
Resource
:
"selfsubjectrulesreviews"
}
:
{},
{
Group
:
"apiregistration.k8s.io"
,
Resource
:
"apiservices"
}
:
{},
{
Group
:
"apiextensions.k8s.io"
,
Resource
:
"customresourcedefinitions"
}
:
{},
}
...
...
pkg/kubeapiserver/authorizer/config.go
View file @
f14c1384
...
...
@@ -56,17 +56,20 @@ type AuthorizationConfig struct {
// New returns the right sort of union of multiple authorizer.Authorizer objects
// based on the authorizationMode or an error.
func
(
config
AuthorizationConfig
)
New
()
(
authorizer
.
Authorizer
,
error
)
{
func
(
config
AuthorizationConfig
)
New
()
(
authorizer
.
Authorizer
,
authorizer
.
RuleResolver
,
error
)
{
if
len
(
config
.
AuthorizationModes
)
==
0
{
return
nil
,
errors
.
New
(
"At least one authorization mode should be passed"
)
return
nil
,
nil
,
errors
.
New
(
"At least one authorization mode should be passed"
)
}
var
authorizers
[]
authorizer
.
Authorizer
var
(
authorizers
[]
authorizer
.
Authorizer
ruleResolvers
[]
authorizer
.
RuleResolver
)
authorizerMap
:=
make
(
map
[
string
]
bool
)
for
_
,
authorizationMode
:=
range
config
.
AuthorizationModes
{
if
authorizerMap
[
authorizationMode
]
{
return
nil
,
fmt
.
Errorf
(
"Authorization mode %s specified more than once"
,
authorizationMode
)
return
nil
,
nil
,
fmt
.
Errorf
(
"Authorization mode %s specified more than once"
,
authorizationMode
)
}
// Keep cases in sync with constant list above.
switch
authorizationMode
{
...
...
@@ -81,29 +84,35 @@ func (config AuthorizationConfig) New() (authorizer.Authorizer, error) {
authorizers
=
append
(
authorizers
,
nodeAuthorizer
)
case
modes
.
ModeAlwaysAllow
:
authorizers
=
append
(
authorizers
,
authorizerfactory
.
NewAlwaysAllowAuthorizer
())
alwaysAllowAuthorizer
:=
authorizerfactory
.
NewAlwaysAllowAuthorizer
()
authorizers
=
append
(
authorizers
,
alwaysAllowAuthorizer
)
ruleResolvers
=
append
(
ruleResolvers
,
alwaysAllowAuthorizer
)
case
modes
.
ModeAlwaysDeny
:
authorizers
=
append
(
authorizers
,
authorizerfactory
.
NewAlwaysDenyAuthorizer
())
alwaysDenyAuthorizer
:=
authorizerfactory
.
NewAlwaysDenyAuthorizer
()
authorizers
=
append
(
authorizers
,
alwaysDenyAuthorizer
)
ruleResolvers
=
append
(
ruleResolvers
,
alwaysDenyAuthorizer
)
case
modes
.
ModeABAC
:
if
config
.
PolicyFile
==
""
{
return
nil
,
errors
.
New
(
"ABAC's authorization policy file not passed"
)
return
nil
,
nil
,
errors
.
New
(
"ABAC's authorization policy file not passed"
)
}
abacAuthorizer
,
err
:=
abac
.
NewFromFile
(
config
.
PolicyFile
)
if
err
!=
nil
{
return
nil
,
err
return
nil
,
nil
,
err
}
authorizers
=
append
(
authorizers
,
abacAuthorizer
)
ruleResolvers
=
append
(
ruleResolvers
,
abacAuthorizer
)
case
modes
.
ModeWebhook
:
if
config
.
WebhookConfigFile
==
""
{
return
nil
,
errors
.
New
(
"Webhook's configuration file not passed"
)
return
nil
,
nil
,
errors
.
New
(
"Webhook's configuration file not passed"
)
}
webhookAuthorizer
,
err
:=
webhook
.
New
(
config
.
WebhookConfigFile
,
config
.
WebhookCacheAuthorizedTTL
,
config
.
WebhookCacheUnauthorizedTTL
)
if
err
!=
nil
{
return
nil
,
err
return
nil
,
nil
,
err
}
authorizers
=
append
(
authorizers
,
webhookAuthorizer
)
ruleResolvers
=
append
(
ruleResolvers
,
webhookAuthorizer
)
case
modes
.
ModeRBAC
:
rbacAuthorizer
:=
rbac
.
New
(
&
rbac
.
RoleGetter
{
Lister
:
config
.
InformerFactory
.
Rbac
()
.
InternalVersion
()
.
Roles
()
.
Lister
()},
...
...
@@ -112,18 +121,19 @@ func (config AuthorizationConfig) New() (authorizer.Authorizer, error) {
&
rbac
.
ClusterRoleBindingLister
{
Lister
:
config
.
InformerFactory
.
Rbac
()
.
InternalVersion
()
.
ClusterRoleBindings
()
.
Lister
()},
)
authorizers
=
append
(
authorizers
,
rbacAuthorizer
)
ruleResolvers
=
append
(
ruleResolvers
,
rbacAuthorizer
)
default
:
return
nil
,
fmt
.
Errorf
(
"Unknown authorization mode %s specified"
,
authorizationMode
)
return
nil
,
nil
,
fmt
.
Errorf
(
"Unknown authorization mode %s specified"
,
authorizationMode
)
}
authorizerMap
[
authorizationMode
]
=
true
}
if
!
authorizerMap
[
modes
.
ModeABAC
]
&&
config
.
PolicyFile
!=
""
{
return
nil
,
errors
.
New
(
"Cannot specify --authorization-policy-file without mode ABAC"
)
return
nil
,
nil
,
errors
.
New
(
"Cannot specify --authorization-policy-file without mode ABAC"
)
}
if
!
authorizerMap
[
modes
.
ModeWebhook
]
&&
config
.
WebhookConfigFile
!=
""
{
return
nil
,
errors
.
New
(
"Cannot specify --authorization-webhook-config-file without mode Webhook"
)
return
nil
,
nil
,
errors
.
New
(
"Cannot specify --authorization-webhook-config-file without mode Webhook"
)
}
return
union
.
New
(
authorizers
...
),
nil
return
union
.
New
(
authorizers
...
),
union
.
NewRuleResolvers
(
ruleResolvers
...
),
nil
}
pkg/kubeapiserver/authorizer/config_test.go
View file @
f14c1384
...
...
@@ -91,7 +91,7 @@ func TestNew(t *testing.T) {
}
for
_
,
tt
:=
range
tests
{
_
,
err
:=
tt
.
config
.
New
()
_
,
_
,
err
:=
tt
.
config
.
New
()
if
tt
.
wantErr
&&
(
err
==
nil
)
{
t
.
Errorf
(
"New %s"
,
tt
.
msg
)
}
else
if
!
tt
.
wantErr
&&
(
err
!=
nil
)
{
...
...
pkg/master/master.go
View file @
f14c1384
...
...
@@ -256,7 +256,7 @@ func (c completedConfig) New(delegationTarget genericapiserver.DelegationTarget)
// handlers that we have.
restStorageProviders
:=
[]
RESTStorageProvider
{
authenticationrest
.
RESTStorageProvider
{
Authenticator
:
c
.
GenericConfig
.
Authenticator
},
authorizationrest
.
RESTStorageProvider
{
Authorizer
:
c
.
GenericConfig
.
Authorizer
},
authorizationrest
.
RESTStorageProvider
{
Authorizer
:
c
.
GenericConfig
.
Authorizer
,
RuleResolver
:
c
.
GenericConfig
.
RuleResolver
},
autoscalingrest
.
RESTStorageProvider
{},
batchrest
.
RESTStorageProvider
{},
certificatesrest
.
RESTStorageProvider
{},
...
...
pkg/registry/authorization/rest/storage_authorization.go
View file @
f14c1384
...
...
@@ -28,11 +28,13 @@ import (
"k8s.io/kubernetes/pkg/apis/authorization"
"k8s.io/kubernetes/pkg/registry/authorization/localsubjectaccessreview"
"k8s.io/kubernetes/pkg/registry/authorization/selfsubjectaccessreview"
"k8s.io/kubernetes/pkg/registry/authorization/selfsubjectrulesreview"
"k8s.io/kubernetes/pkg/registry/authorization/subjectaccessreview"
)
type
RESTStorageProvider
struct
{
Authorizer
authorizer
.
Authorizer
Authorizer
authorizer
.
Authorizer
RuleResolver
authorizer
.
RuleResolver
}
func
(
p
RESTStorageProvider
)
NewRESTStorage
(
apiResourceConfigSource
serverstorage
.
APIResourceConfigSource
,
restOptionsGetter
generic
.
RESTOptionsGetter
)
(
genericapiserver
.
APIGroupInfo
,
bool
)
{
...
...
@@ -70,6 +72,9 @@ func (p RESTStorageProvider) v1beta1Storage(apiResourceConfigSource serverstorag
if
apiResourceConfigSource
.
ResourceEnabled
(
version
.
WithResource
(
"localsubjectaccessreviews"
))
{
storage
[
"localsubjectaccessreviews"
]
=
localsubjectaccessreview
.
NewREST
(
p
.
Authorizer
)
}
if
apiResourceConfigSource
.
ResourceEnabled
(
version
.
WithResource
(
"selfsubjectrulesreviews"
))
{
storage
[
"selfsubjectrulesreviews"
]
=
selfsubjectrulesreview
.
NewREST
(
p
.
RuleResolver
)
}
return
storage
}
...
...
@@ -87,6 +92,9 @@ func (p RESTStorageProvider) v1Storage(apiResourceConfigSource serverstorage.API
if
apiResourceConfigSource
.
ResourceEnabled
(
version
.
WithResource
(
"localsubjectaccessreviews"
))
{
storage
[
"localsubjectaccessreviews"
]
=
localsubjectaccessreview
.
NewREST
(
p
.
Authorizer
)
}
if
apiResourceConfigSource
.
ResourceEnabled
(
version
.
WithResource
(
"selfsubjectrulesreviews"
))
{
storage
[
"selfsubjectrulesreviews"
]
=
selfsubjectrulesreview
.
NewREST
(
p
.
RuleResolver
)
}
return
storage
}
...
...
pkg/registry/authorization/selfsubjectrulesreview/rest.go
0 → 100644
View file @
f14c1384
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package
selfsubjectrulesreview
import
(
"fmt"
apierrors
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/authorization/authorizer"
genericapirequest
"k8s.io/apiserver/pkg/endpoints/request"
authorizationapi
"k8s.io/kubernetes/pkg/apis/authorization"
)
// REST implements a RESTStorage for selfsubjectrulesreview.
type
REST
struct
{
ruleResolver
authorizer
.
RuleResolver
}
// NewREST returns a RESTStorage object that will work against selfsubjectrulesreview.
func
NewREST
(
ruleResolver
authorizer
.
RuleResolver
)
*
REST
{
return
&
REST
{
ruleResolver
}
}
// New creates a new selfsubjectrulesreview object.
func
(
r
*
REST
)
New
()
runtime
.
Object
{
return
&
authorizationapi
.
SelfSubjectRulesReview
{}
}
// Create attempts to get self subject rules in specific namespace.
func
(
r
*
REST
)
Create
(
ctx
genericapirequest
.
Context
,
obj
runtime
.
Object
,
includeUninitialized
bool
)
(
runtime
.
Object
,
error
)
{
selfSRR
,
ok
:=
obj
.
(
*
authorizationapi
.
SelfSubjectRulesReview
)
if
!
ok
{
return
nil
,
apierrors
.
NewBadRequest
(
fmt
.
Sprintf
(
"not a SelfSubjectRulesReview: %#v"
,
obj
))
}
user
,
ok
:=
genericapirequest
.
UserFrom
(
ctx
)
if
!
ok
{
return
nil
,
apierrors
.
NewBadRequest
(
"no user present on request"
)
}
namespace
:=
selfSRR
.
Spec
.
Namespace
if
namespace
==
""
{
return
nil
,
apierrors
.
NewBadRequest
(
"no namespace on request"
)
}
resourceInfo
,
nonResourceInfo
,
incomplete
,
err
:=
r
.
ruleResolver
.
RulesFor
(
user
,
namespace
)
ret
:=
&
authorizationapi
.
SelfSubjectRulesReview
{
Status
:
authorizationapi
.
SubjectRulesReviewStatus
{
ResourceRules
:
getResourceRules
(
resourceInfo
),
NonResourceRules
:
getNonResourceRules
(
nonResourceInfo
),
Incomplete
:
incomplete
,
},
}
if
err
!=
nil
{
ret
.
Status
.
EvaluationError
=
err
.
Error
()
}
return
ret
,
nil
}
func
getResourceRules
(
infos
[]
authorizer
.
ResourceRuleInfo
)
[]
authorizationapi
.
ResourceRule
{
rules
:=
make
([]
authorizationapi
.
ResourceRule
,
len
(
infos
))
for
i
,
info
:=
range
infos
{
rules
[
i
]
=
authorizationapi
.
ResourceRule
{
Verbs
:
info
.
GetVerbs
(),
APIGroups
:
info
.
GetAPIGroups
(),
Resources
:
info
.
GetResources
(),
ResourceNames
:
info
.
GetResourceNames
(),
}
}
return
rules
}
func
getNonResourceRules
(
infos
[]
authorizer
.
NonResourceRuleInfo
)
[]
authorizationapi
.
NonResourceRule
{
rules
:=
make
([]
authorizationapi
.
NonResourceRule
,
len
(
infos
))
for
i
,
info
:=
range
infos
{
rules
[
i
]
=
authorizationapi
.
NonResourceRule
{
Verbs
:
info
.
GetVerbs
(),
NonResourceURLs
:
info
.
GetNonResourceURLs
(),
}
}
return
rules
}
plugin/pkg/auth/authorizer/rbac/rbac.go
View file @
f14c1384
...
...
@@ -123,6 +123,36 @@ func (r *RBACAuthorizer) Authorize(requestAttributes authorizer.Attributes) (boo
return
false
,
reason
,
nil
}
func
(
r
*
RBACAuthorizer
)
RulesFor
(
user
user
.
Info
,
namespace
string
)
([]
authorizer
.
ResourceRuleInfo
,
[]
authorizer
.
NonResourceRuleInfo
,
bool
,
error
)
{
var
(
resourceRules
[]
authorizer
.
ResourceRuleInfo
nonResourceRules
[]
authorizer
.
NonResourceRuleInfo
)
policyRules
,
err
:=
r
.
authorizationRuleResolver
.
RulesFor
(
user
,
namespace
)
for
_
,
policyRule
:=
range
policyRules
{
if
len
(
policyRule
.
Resources
)
>
0
{
r
:=
authorizer
.
DefaultResourceRuleInfo
{
Verbs
:
policyRule
.
Verbs
,
APIGroups
:
policyRule
.
APIGroups
,
Resources
:
policyRule
.
Resources
,
ResourceNames
:
policyRule
.
ResourceNames
,
}
var
resourceRule
authorizer
.
ResourceRuleInfo
=
&
r
resourceRules
=
append
(
resourceRules
,
resourceRule
)
}
if
len
(
policyRule
.
NonResourceURLs
)
>
0
{
r
:=
authorizer
.
DefaultNonResourceRuleInfo
{
Verbs
:
policyRule
.
Verbs
,
NonResourceURLs
:
policyRule
.
NonResourceURLs
,
}
var
nonResourceRule
authorizer
.
NonResourceRuleInfo
=
&
r
nonResourceRules
=
append
(
nonResourceRules
,
nonResourceRule
)
}
}
return
resourceRules
,
nonResourceRules
,
false
,
err
}
func
New
(
roles
rbacregistryvalidation
.
RoleGetter
,
roleBindings
rbacregistryvalidation
.
RoleBindingLister
,
clusterRoles
rbacregistryvalidation
.
ClusterRoleGetter
,
clusterRoleBindings
rbacregistryvalidation
.
ClusterRoleBindingLister
)
*
RBACAuthorizer
{
authorizer
:=
&
RBACAuthorizer
{
authorizationRuleResolver
:
rbacregistryvalidation
.
NewDefaultRuleResolver
(
...
...
staging/src/k8s.io/api/authorization/v1/register.go
View file @
f14c1384
...
...
@@ -44,6 +44,7 @@ var (
// Adds the list of known types to api.Scheme.
func
addKnownTypes
(
scheme
*
runtime
.
Scheme
)
error
{
scheme
.
AddKnownTypes
(
SchemeGroupVersion
,
&
SelfSubjectRulesReview
{},
&
SelfSubjectAccessReview
{},
&
SubjectAccessReview
{},
&
LocalSubjectAccessReview
{},
...
...
staging/src/k8s.io/api/authorization/v1/types.go
View file @
f14c1384
...
...
@@ -180,3 +180,82 @@ type SubjectAccessReviewStatus struct {
// +optional
EvaluationError
string
`json:"evaluationError,omitempty" protobuf:"bytes,3,opt,name=evaluationError"`
}
// +genclient
// +genclient:nonNamespaced
// +genclient:noVerbs
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// SelfSubjectRulesReview enumerates the set of actions the current user can perform within a namespace.
// The returned list of actions may be incomplete depending on the server's authorization mode,
// and any errors experienced during the evaluation. SelfSubjectRulesReview should be used by UIs to show/hide actions,
// or to quickly let an end user reason about their permissions. It should NOT Be used by external systems to
// drive authorization decisions as this raises confused deputy, cache lifetime/revocation, and correctness concerns.
// SubjectAccessReview, and LocalAccessReview are the correct way to defer authorization decisions to the API server.
type
SelfSubjectRulesReview
struct
{
metav1
.
TypeMeta
`json:",inline"`
// +optional
metav1
.
ObjectMeta
`json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
// Spec holds information about the request being evaluated.
Spec
SelfSubjectRulesReviewSpec
`json:"spec" protobuf:"bytes,2,opt,name=spec"`
// Status is filled in by the server and indicates the set of actions a user can perform.
// +optional
Status
SubjectRulesReviewStatus
`json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
}
type
SelfSubjectRulesReviewSpec
struct
{
// Namespace to evaluate rules for. Required.
Namespace
string
`json:"namespace,omitempty" protobuf:"bytes,1,opt,name=namespace"`
}
// SubjectRulesReviewStatus contains the result of a rules check. This check can be incomplete depending on
// the set of authorizers the server is configured with and any errors experienced during evaluation.
// Because authorization rules are additive, if a rule appears in a list it's safe to assume the subject has that permission,
// even if that list is incomplete.
type
SubjectRulesReviewStatus
struct
{
// ResourceRules 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.
ResourceRules
[]
ResourceRule
`json:"resourceRules" protobuf:"bytes,1,rep,name=resourceRules"`
// NonResourceRules is the list of actions the subject is allowed to perform on non-resources.
// The list ordering isn't significant, may contain duplicates, and possibly be incomplete.
NonResourceRules
[]
NonResourceRule
`json:"nonResourceRules" protobuf:"bytes,2,rep,name=nonResourceRules"`
// Incomplete is true when the rules returned by this call are incomplete. This is most commonly
// encountered when an authorizer, such as an external authorizer, doesn't support rules evaluation.
Incomplete
bool
`json:"incomplete" protobuf:"bytes,3,rep,name=incomplete"`
// EvaluationError can appear in combination with Rules. It indicates an error occurred during
// rule evaluation, such as an authorizer that doesn't support rule evaluation, and that
// ResourceRules and/or NonResourceRules may be incomplete.
// +optional
EvaluationError
string
`json:"evaluationError,omitempty" protobuf:"bytes,4,opt,name=evaluationError"`
}
// 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.
type
ResourceRule
struct
{
// Verb is a list of kubernetes resource API verbs, like: get, list, watch, create, update, delete, proxy. "*" means all.
Verbs
[]
string
`json:"verbs" protobuf:"bytes,1,rep,name=verbs"`
// 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.
// +optional
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.
// +optional
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.
// +optional
ResourceNames
[]
string
`json:"resourceNames,omitempty" protobuf:"bytes,4,rep,name=resourceNames"`
}
// NonResourceRule holds information that describes a rule for the non-resource
type
NonResourceRule
struct
{
// Verb is a list of kubernetes non-resource API verbs, like: get, post, put, delete, patch, head, options. "*" means all.
Verbs
[]
string
`json:"verbs" protobuf:"bytes,1,rep,name=verbs"`
// 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. "*" means all.
// +optional
NonResourceURLs
[]
string
`json:"nonResourceURLs,omitempty" protobuf:"bytes,2,rep,name=nonResourceURLs"`
}
staging/src/k8s.io/api/authorization/v1beta1/register.go
View file @
f14c1384
...
...
@@ -44,6 +44,7 @@ var (
// Adds the list of known types to api.Scheme.
func
addKnownTypes
(
scheme
*
runtime
.
Scheme
)
error
{
scheme
.
AddKnownTypes
(
SchemeGroupVersion
,
&
SelfSubjectRulesReview
{},
&
SelfSubjectAccessReview
{},
&
SubjectAccessReview
{},
&
LocalSubjectAccessReview
{},
...
...
staging/src/k8s.io/api/authorization/v1beta1/types.go
View file @
f14c1384
...
...
@@ -180,3 +180,82 @@ type SubjectAccessReviewStatus struct {
// +optional
EvaluationError
string
`json:"evaluationError,omitempty" protobuf:"bytes,3,opt,name=evaluationError"`
}
// +genclient
// +genclient:nonNamespaced
// +genclient:noVerbs
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// SelfSubjectRulesReview enumerates the set of actions the current user can perform within a namespace.
// The returned list of actions may be incomplete depending on the server's authorization mode,
// and any errors experienced during the evaluation. SelfSubjectRulesReview should be used by UIs to show/hide actions,
// or to quickly let an end user reason about their permissions. It should NOT Be used by external systems to
// drive authorization decisions as this raises confused deputy, cache lifetime/revocation, and correctness concerns.
// SubjectAccessReview, and LocalAccessReview are the correct way to defer authorization decisions to the API server.
type
SelfSubjectRulesReview
struct
{
metav1
.
TypeMeta
`json:",inline"`
// +optional
metav1
.
ObjectMeta
`json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
// Spec holds information about the request being evaluated.
Spec
SelfSubjectRulesReviewSpec
`json:"spec" protobuf:"bytes,2,opt,name=spec"`
// Status is filled in by the server and indicates the set of actions a user can perform.
// +optional
Status
SubjectRulesReviewStatus
`json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
}
type
SelfSubjectRulesReviewSpec
struct
{
// Namespace to evaluate rules for. Required.
Namespace
string
`json:"namespace,omitempty" protobuf:"bytes,1,opt,name=namespace"`
}
// SubjectRulesReviewStatus contains the result of a rules check. This check can be incomplete depending on
// the set of authorizers the server is configured with and any errors experienced during evaluation.
// Because authorization rules are additive, if a rule appears in a list it's safe to assume the subject has that permission,
// even if that list is incomplete.
type
SubjectRulesReviewStatus
struct
{
// ResourceRules 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.
ResourceRules
[]
ResourceRule
`json:"resourceRules" protobuf:"bytes,1,rep,name=resourceRules"`
// NonResourceRules is the list of actions the subject is allowed to perform on non-resources.
// The list ordering isn't significant, may contain duplicates, and possibly be incomplete.
NonResourceRules
[]
NonResourceRule
`json:"nonResourceRules" protobuf:"bytes,2,rep,name=nonResourceRules"`
// Incomplete is true when the rules returned by this call are incomplete. This is most commonly
// encountered when an authorizer, such as an external authorizer, doesn't support rules evaluation.
Incomplete
bool
`json:"incomplete" protobuf:"bytes,3,rep,name=incomplete"`
// EvaluationError can appear in combination with Rules. It indicates an error occurred during
// rule evaluation, such as an authorizer that doesn't support rule evaluation, and that
// ResourceRules and/or NonResourceRules may be incomplete.
// +optional
EvaluationError
string
`json:"evaluationError,omitempty" protobuf:"bytes,4,opt,name=evaluationError"`
}
// 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.
type
ResourceRule
struct
{
// Verb is a list of kubernetes resource API verbs, like: get, list, watch, create, update, delete, proxy. "*" means all.
Verbs
[]
string
`json:"verbs" protobuf:"bytes,1,rep,name=verbs"`
// 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.
// +optional
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.
// +optional
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.
// +optional
ResourceNames
[]
string
`json:"resourceNames,omitempty" protobuf:"bytes,4,rep,name=resourceNames"`
}
// NonResourceRule holds information that describes a rule for the non-resource
type
NonResourceRule
struct
{
// Verb is a list of kubernetes non-resource API verbs, like: get, post, put, delete, patch, head, options. "*" means all.
Verbs
[]
string
`json:"verbs" protobuf:"bytes,1,rep,name=verbs"`
// 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. "*" means all.
// +optional
NonResourceURLs
[]
string
`json:"nonResourceURLs,omitempty" protobuf:"bytes,2,rep,name=nonResourceURLs"`
}
staging/src/k8s.io/apiserver/pkg/authorization/authorizer/interfaces.go
View file @
f14c1384
...
...
@@ -76,6 +76,12 @@ func (f AuthorizerFunc) Authorize(a Attributes) (bool, string, error) {
return
f
(
a
)
}
// RuleResolver provides a mechanism for resolving the list of rules that apply to a given user within a namespace.
type
RuleResolver
interface
{
// RulesFor get the list of cluster wide rules, the list of rules in the specific namespace, incomplete status and errors.
RulesFor
(
user
user
.
Info
,
namespace
string
)
([]
ResourceRuleInfo
,
[]
NonResourceRuleInfo
,
bool
,
error
)
}
// RequestAttributesGetter provides a function that extracts Attributes from an http.Request
type
RequestAttributesGetter
interface
{
GetRequestAttributes
(
user
.
Info
,
*
http
.
Request
)
Attributes
...
...
staging/src/k8s.io/apiserver/pkg/authorization/authorizer/rule.go
0 → 100644
View file @
f14c1384
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package
authorizer
type
ResourceRuleInfo
interface
{
// GetVerbs returns a list of kubernetes resource API verbs.
GetVerbs
()
[]
string
// GetAPIGroups return the names of the APIGroup that contains the resources.
GetAPIGroups
()
[]
string
// GetResources return a list of resources the rule applies to.
GetResources
()
[]
string
// GetResourceNames return a white list of names that the rule applies to.
GetResourceNames
()
[]
string
}
// DefaultResourceRuleInfo holds information that describes a rule for the resource
type
DefaultResourceRuleInfo
struct
{
Verbs
[]
string
APIGroups
[]
string
Resources
[]
string
ResourceNames
[]
string
}
func
(
i
*
DefaultResourceRuleInfo
)
GetVerbs
()
[]
string
{
return
i
.
Verbs
}
func
(
i
*
DefaultResourceRuleInfo
)
GetAPIGroups
()
[]
string
{
return
i
.
APIGroups
}
func
(
i
*
DefaultResourceRuleInfo
)
GetResources
()
[]
string
{
return
i
.
Resources
}
func
(
i
*
DefaultResourceRuleInfo
)
GetResourceNames
()
[]
string
{
return
i
.
ResourceNames
}
type
NonResourceRuleInfo
interface
{
// GetVerbs returns a list of kubernetes resource API verbs.
GetVerbs
()
[]
string
// GetNonResourceURLs return a set of partial urls that a user should have access to.
GetNonResourceURLs
()
[]
string
}
// DefaultNonResourceRuleInfo holds information that describes a rule for the non-resource
type
DefaultNonResourceRuleInfo
struct
{
Verbs
[]
string
NonResourceURLs
[]
string
}
func
(
i
*
DefaultNonResourceRuleInfo
)
GetVerbs
()
[]
string
{
return
i
.
Verbs
}
func
(
i
*
DefaultNonResourceRuleInfo
)
GetNonResourceURLs
()
[]
string
{
return
i
.
NonResourceURLs
}
staging/src/k8s.io/apiserver/pkg/authorization/authorizerfactory/builtin.go
View file @
f14c1384
...
...
@@ -19,6 +19,7 @@ package authorizerfactory
import
(
"errors"
"k8s.io/apiserver/pkg/authentication/user"
"k8s.io/apiserver/pkg/authorization/authorizer"
)
...
...
@@ -31,7 +32,22 @@ func (alwaysAllowAuthorizer) Authorize(a authorizer.Attributes) (authorized bool
return
true
,
""
,
nil
}
func
NewAlwaysAllowAuthorizer
()
authorizer
.
Authorizer
{
func
(
alwaysAllowAuthorizer
)
RulesFor
(
user
user
.
Info
,
namespace
string
)
([]
authorizer
.
ResourceRuleInfo
,
[]
authorizer
.
NonResourceRuleInfo
,
bool
,
error
)
{
return
[]
authorizer
.
ResourceRuleInfo
{
&
authorizer
.
DefaultResourceRuleInfo
{
Verbs
:
[]
string
{
"*"
},
APIGroups
:
[]
string
{
"*"
},
Resources
:
[]
string
{
"*"
},
},
},
[]
authorizer
.
NonResourceRuleInfo
{
&
authorizer
.
DefaultNonResourceRuleInfo
{
Verbs
:
[]
string
{
"*"
},
NonResourceURLs
:
[]
string
{
"*"
},
},
},
false
,
nil
}
func
NewAlwaysAllowAuthorizer
()
*
alwaysAllowAuthorizer
{
return
new
(
alwaysAllowAuthorizer
)
}
...
...
@@ -44,7 +60,11 @@ func (alwaysDenyAuthorizer) Authorize(a authorizer.Attributes) (authorized bool,
return
false
,
"Everything is forbidden."
,
nil
}
func
NewAlwaysDenyAuthorizer
()
authorizer
.
Authorizer
{
func
(
alwaysDenyAuthorizer
)
RulesFor
(
user
user
.
Info
,
namespace
string
)
([]
authorizer
.
ResourceRuleInfo
,
[]
authorizer
.
NonResourceRuleInfo
,
bool
,
error
)
{
return
[]
authorizer
.
ResourceRuleInfo
{},
[]
authorizer
.
NonResourceRuleInfo
{},
false
,
nil
}
func
NewAlwaysDenyAuthorizer
()
*
alwaysDenyAuthorizer
{
return
new
(
alwaysDenyAuthorizer
)
}
...
...
staging/src/k8s.io/apiserver/pkg/authorization/union/union.go
View file @
f14c1384
...
...
@@ -20,6 +20,7 @@ import (
"strings"
utilerrors
"k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apiserver/pkg/authentication/user"
"k8s.io/apiserver/pkg/authorization/authorizer"
)
...
...
@@ -55,3 +56,40 @@ func (authzHandler unionAuthzHandler) Authorize(a authorizer.Attributes) (bool,
return
false
,
strings
.
Join
(
reasonlist
,
"
\n
"
),
utilerrors
.
NewAggregate
(
errlist
)
}
// unionAuthzRulesHandler authorizer against a chain of authorizer.RuleResolver
type
unionAuthzRulesHandler
[]
authorizer
.
RuleResolver
// NewRuleResolvers returns an authorizer that authorizes against a chain of authorizer.Authorizer objects
func
NewRuleResolvers
(
authorizationHandlers
...
authorizer
.
RuleResolver
)
authorizer
.
RuleResolver
{
return
unionAuthzRulesHandler
(
authorizationHandlers
)
}
// RulesFor against a chain of authorizer.RuleResolver objects and returns nil if successful and returns error if unsuccessful
func
(
authzHandler
unionAuthzRulesHandler
)
RulesFor
(
user
user
.
Info
,
namespace
string
)
([]
authorizer
.
ResourceRuleInfo
,
[]
authorizer
.
NonResourceRuleInfo
,
bool
,
error
)
{
var
(
errList
[]
error
resourceRulesList
[]
authorizer
.
ResourceRuleInfo
nonResourceRulesList
[]
authorizer
.
NonResourceRuleInfo
)
incompleteStatus
:=
false
for
_
,
currAuthzHandler
:=
range
authzHandler
{
resourceRules
,
nonResourceRules
,
incomplete
,
err
:=
currAuthzHandler
.
RulesFor
(
user
,
namespace
)
if
incomplete
==
true
{
incompleteStatus
=
true
}
if
err
!=
nil
{
errList
=
append
(
errList
,
err
)
}
if
len
(
resourceRules
)
>
0
{
resourceRulesList
=
append
(
resourceRulesList
,
resourceRules
...
)
}
if
len
(
nonResourceRules
)
>
0
{
nonResourceRulesList
=
append
(
nonResourceRulesList
,
nonResourceRules
...
)
}
}
return
resourceRulesList
,
nonResourceRulesList
,
incompleteStatus
,
utilerrors
.
NewAggregate
(
errList
)
}
staging/src/k8s.io/apiserver/pkg/authorization/union/union_test.go
View file @
f14c1384
...
...
@@ -18,8 +18,10 @@ package union
import
(
"fmt"
"reflect"
"testing"
"k8s.io/apiserver/pkg/authentication/user"
"k8s.io/apiserver/pkg/authorization/authorizer"
)
...
...
@@ -81,3 +83,143 @@ func TestAuthorizationError(t *testing.T) {
t
.
Errorf
(
"Expected error: %v"
,
err
)
}
}
type
mockAuthzRuleHandler
struct
{
resourceRules
[]
authorizer
.
ResourceRuleInfo
nonResourceRules
[]
authorizer
.
NonResourceRuleInfo
err
error
}
func
(
mock
*
mockAuthzRuleHandler
)
RulesFor
(
user
user
.
Info
,
namespace
string
)
([]
authorizer
.
ResourceRuleInfo
,
[]
authorizer
.
NonResourceRuleInfo
,
bool
,
error
)
{
if
mock
.
err
!=
nil
{
return
[]
authorizer
.
ResourceRuleInfo
{},
[]
authorizer
.
NonResourceRuleInfo
{},
false
,
mock
.
err
}
return
mock
.
resourceRules
,
mock
.
nonResourceRules
,
false
,
nil
}
func
TestAuthorizationResourceRules
(
t
*
testing
.
T
)
{
handler1
:=
&
mockAuthzRuleHandler
{
resourceRules
:
[]
authorizer
.
ResourceRuleInfo
{
&
authorizer
.
DefaultResourceRuleInfo
{
Verbs
:
[]
string
{
"*"
},
APIGroups
:
[]
string
{
"*"
},
Resources
:
[]
string
{
"bindings"
},
},
&
authorizer
.
DefaultResourceRuleInfo
{
Verbs
:
[]
string
{
"get"
,
"list"
,
"watch"
},
APIGroups
:
[]
string
{
"*"
},
Resources
:
[]
string
{
"*"
},
},
},
}
handler2
:=
&
mockAuthzRuleHandler
{
resourceRules
:
[]
authorizer
.
ResourceRuleInfo
{
&
authorizer
.
DefaultResourceRuleInfo
{
Verbs
:
[]
string
{
"*"
},
APIGroups
:
[]
string
{
"*"
},
Resources
:
[]
string
{
"events"
},
},
&
authorizer
.
DefaultResourceRuleInfo
{
Verbs
:
[]
string
{
"get"
},
APIGroups
:
[]
string
{
"*"
},
Resources
:
[]
string
{
"*"
},
ResourceNames
:
[]
string
{
"foo"
},
},
},
}
expected
:=
[]
authorizer
.
DefaultResourceRuleInfo
{
{
Verbs
:
[]
string
{
"*"
},
APIGroups
:
[]
string
{
"*"
},
Resources
:
[]
string
{
"bindings"
},
},
{
Verbs
:
[]
string
{
"get"
,
"list"
,
"watch"
},
APIGroups
:
[]
string
{
"*"
},
Resources
:
[]
string
{
"*"
},
},
{
Verbs
:
[]
string
{
"*"
},
APIGroups
:
[]
string
{
"*"
},
Resources
:
[]
string
{
"events"
},
},
{
Verbs
:
[]
string
{
"get"
},
APIGroups
:
[]
string
{
"*"
},
Resources
:
[]
string
{
"*"
},
ResourceNames
:
[]
string
{
"foo"
},
},
}
authzRulesHandler
:=
NewRuleResolvers
(
handler1
,
handler2
)
rules
,
_
,
_
,
_
:=
authzRulesHandler
.
RulesFor
(
nil
,
""
)
actual
:=
getResourceRules
(
rules
)
if
!
reflect
.
DeepEqual
(
expected
,
actual
)
{
t
.
Errorf
(
"Expected:
\n
%#v
\n
but actual:
\n
%#v
\n
"
,
expected
,
actual
)
}
}
func
TestAuthorizationNonResourceRules
(
t
*
testing
.
T
)
{
handler1
:=
&
mockAuthzRuleHandler
{
nonResourceRules
:
[]
authorizer
.
NonResourceRuleInfo
{
&
authorizer
.
DefaultNonResourceRuleInfo
{
Verbs
:
[]
string
{
"get"
},
NonResourceURLs
:
[]
string
{
"/api"
},
},
},
}
handler2
:=
&
mockAuthzRuleHandler
{
nonResourceRules
:
[]
authorizer
.
NonResourceRuleInfo
{
&
authorizer
.
DefaultNonResourceRuleInfo
{
Verbs
:
[]
string
{
"get"
},
NonResourceURLs
:
[]
string
{
"/api/*"
},
},
},
}
expected
:=
[]
authorizer
.
DefaultNonResourceRuleInfo
{
{
Verbs
:
[]
string
{
"get"
},
NonResourceURLs
:
[]
string
{
"/api"
},
},
{
Verbs
:
[]
string
{
"get"
},
NonResourceURLs
:
[]
string
{
"/api/*"
},
},
}
authzRulesHandler
:=
NewRuleResolvers
(
handler1
,
handler2
)
_
,
rules
,
_
,
_
:=
authzRulesHandler
.
RulesFor
(
nil
,
""
)
actual
:=
getNonResourceRules
(
rules
)
if
!
reflect
.
DeepEqual
(
expected
,
actual
)
{
t
.
Errorf
(
"Expected:
\n
%#v
\n
but actual:
\n
%#v
\n
"
,
expected
,
actual
)
}
}
func
getResourceRules
(
infos
[]
authorizer
.
ResourceRuleInfo
)
[]
authorizer
.
DefaultResourceRuleInfo
{
rules
:=
make
([]
authorizer
.
DefaultResourceRuleInfo
,
len
(
infos
))
for
i
,
info
:=
range
infos
{
rules
[
i
]
=
authorizer
.
DefaultResourceRuleInfo
{
Verbs
:
info
.
GetVerbs
(),
APIGroups
:
info
.
GetAPIGroups
(),
Resources
:
info
.
GetResources
(),
ResourceNames
:
info
.
GetResourceNames
(),
}
}
return
rules
}
func
getNonResourceRules
(
infos
[]
authorizer
.
NonResourceRuleInfo
)
[]
authorizer
.
DefaultNonResourceRuleInfo
{
rules
:=
make
([]
authorizer
.
DefaultNonResourceRuleInfo
,
len
(
infos
))
for
i
,
info
:=
range
infos
{
rules
[
i
]
=
authorizer
.
DefaultNonResourceRuleInfo
{
Verbs
:
info
.
GetVerbs
(),
NonResourceURLs
:
info
.
GetNonResourceURLs
(),
}
}
return
rules
}
staging/src/k8s.io/apiserver/pkg/server/config.go
View file @
f14c1384
...
...
@@ -87,6 +87,9 @@ type Config struct {
// Authorizer determines whether the subject is allowed to make the request based only
// on the RequestURI
Authorizer
authorizer
.
Authorizer
// RuleResolver is required to get the list of rules that apply to a given user
// in a given namespace
RuleResolver
authorizer
.
RuleResolver
// AdmissionControl performs deep inspection of a given request (including content)
// to set values and determine whether its allowed
AdmissionControl
admission
.
Interface
...
...
staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook.go
View file @
f14c1384
...
...
@@ -28,6 +28,7 @@ import (
"k8s.io/apimachinery/pkg/apimachinery/registered"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/cache"
"k8s.io/apiserver/pkg/authentication/user"
"k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/apiserver/pkg/util/webhook"
"k8s.io/client-go/kubernetes/scheme"
...
...
@@ -196,6 +197,16 @@ func (w *WebhookAuthorizer) Authorize(attr authorizer.Attributes) (authorized bo
return
r
.
Status
.
Allowed
,
r
.
Status
.
Reason
,
nil
}
//TODO: need to finish the method to get the rules when using webhook mode
func
(
w
*
WebhookAuthorizer
)
RulesFor
(
user
user
.
Info
,
namespace
string
)
([]
authorizer
.
ResourceRuleInfo
,
[]
authorizer
.
NonResourceRuleInfo
,
bool
,
error
)
{
var
(
resourceRules
[]
authorizer
.
ResourceRuleInfo
nonResourceRules
[]
authorizer
.
NonResourceRuleInfo
)
incomplete
:=
true
return
resourceRules
,
nonResourceRules
,
incomplete
,
fmt
.
Errorf
(
"webhook authorizer does not support user rule resolution"
)
}
func
convertToSARExtra
(
extra
map
[
string
][]
string
)
map
[
string
]
authorization
.
ExtraValue
{
if
extra
==
nil
{
return
nil
...
...
test/integration/auth/node_test.go
View file @
f14c1384
...
...
@@ -74,7 +74,7 @@ func TestNodeAuthorizer(t *testing.T) {
AuthorizationModes
:
[]
string
{
"Node"
,
"RBAC"
},
InformerFactory
:
informerFactory
,
}
nodeRBACAuthorizer
,
err
:=
authorizerConfig
.
New
()
nodeRBACAuthorizer
,
_
,
err
:=
authorizerConfig
.
New
()
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
...
...
test/integration/etcd/etcd_storage_path_test.go
View file @
f14c1384
...
...
@@ -394,6 +394,8 @@ var ephemeralWhiteList = createEphemeralWhiteList(
// k8s.io/kubernetes/pkg/apis/authorization/v1beta1
// SRR objects that are not stored in etcd
gvr
(
"authorization.k8s.io"
,
"v1beta1"
,
"selfsubjectrulesreviews"
),
// SAR objects that are not stored in etcd
gvr
(
"authorization.k8s.io"
,
"v1beta1"
,
"selfsubjectaccessreviews"
),
gvr
(
"authorization.k8s.io"
,
"v1beta1"
,
"localsubjectaccessreviews"
),
...
...
@@ -402,6 +404,8 @@ var ephemeralWhiteList = createEphemeralWhiteList(
// k8s.io/kubernetes/pkg/apis/authorization/v1
// SRR objects that are not stored in etcd
gvr
(
"authorization.k8s.io"
,
"v1"
,
"selfsubjectrulesreviews"
),
// SAR objects that are not stored in etcd
gvr
(
"authorization.k8s.io"
,
"v1"
,
"selfsubjectaccessreviews"
),
gvr
(
"authorization.k8s.io"
,
"v1"
,
"localsubjectaccessreviews"
),
...
...
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