add selfsubjectrulesreview api

This commit is contained in:
xilabao
2017-07-14 11:24:27 +08:00
parent 6a845c67f0
commit f14c138438
28 changed files with 951 additions and 33 deletions

View File

@@ -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{"*"}
}

View File

@@ -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)