Skip to content

Commit

Permalink
add selfsubjectrulesreview api
Browse files Browse the repository at this point in the history
  • Loading branch information
xilabao committed Sep 1, 2017
1 parent 6a845c6 commit f14c138
Show file tree
Hide file tree
Showing 28 changed files with 951 additions and 33 deletions.
4 changes: 2 additions & 2 deletions cmd/kube-apiserver/app/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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()
}
Expand Down
2 changes: 1 addition & 1 deletion federation/cmd/federation-apiserver/app/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/apis/authorization/install/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down
1 change: 1 addition & 0 deletions pkg/apis/authorization/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ var (

func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&SelfSubjectRulesReview{},
&SelfSubjectAccessReview{},
&SubjectAccessReview{},
&LocalSubjectAccessReview{},
Expand Down
71 changes: 71 additions & 0 deletions pkg/apis/authorization/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
4 changes: 4 additions & 0 deletions pkg/apis/authorization/validation/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
53 changes: 46 additions & 7 deletions pkg/auth/authorizer/abac/abac.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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) {
Expand All @@ -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 {
Expand Down Expand Up @@ -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{"*"}
}
Loading

0 comments on commit f14c138

Please sign in to comment.