From 742ef34484d2aca04279dc865a839997a10a3cd8 Mon Sep 17 00:00:00 2001 From: Jordan Liggitt Date: Mon, 19 Dec 2016 09:25:51 -0500 Subject: [PATCH] Convert user/group * to match authenticated users only in ABAC --- hack/.linted_packages | 1 + pkg/apis/abac/v0/BUILD | 2 + pkg/apis/abac/v0/conversion.go | 10 +- pkg/apis/abac/v0/conversion_test.go | 21 +- pkg/apis/abac/v1beta1/BUILD | 18 ++ pkg/apis/abac/v1beta1/conversion.go | 43 ++++ pkg/apis/abac/v1beta1/conversion_test.go | 64 +++++ pkg/apis/abac/v1beta1/register.go | 6 +- pkg/auth/authorizer/abac/abac_test.go | 233 +++++++++++++----- .../authorizer/abac/example_policy_file.jsonl | 3 +- test/integration/auth/auth_test.go | 3 +- test/test_owners.csv | 1 + 12 files changed, 332 insertions(+), 73 deletions(-) create mode 100644 pkg/apis/abac/v1beta1/conversion.go create mode 100644 pkg/apis/abac/v1beta1/conversion_test.go diff --git a/hack/.linted_packages b/hack/.linted_packages index 6740498cb50..6221bbdc4e7 100644 --- a/hack/.linted_packages +++ b/hack/.linted_packages @@ -75,6 +75,7 @@ pkg/api/v1 pkg/api/v1/service pkg/apimachinery pkg/apis/abac/v0 +pkg/apis/abac/v1beta1 pkg/apis/apps/install pkg/apis/authentication.k8s.io/install pkg/apis/authentication/install diff --git a/pkg/apis/abac/v0/BUILD b/pkg/apis/abac/v0/BUILD index 5c3a5b36d51..168f41656d2 100644 --- a/pkg/apis/abac/v0/BUILD +++ b/pkg/apis/abac/v0/BUILD @@ -19,6 +19,7 @@ go_library( deps = [ "//pkg/apis/abac:go_default_library", "//pkg/apis/meta/v1:go_default_library", + "//pkg/auth/user:go_default_library", "//pkg/conversion:go_default_library", "//pkg/runtime:go_default_library", "//pkg/runtime/schema:go_default_library", @@ -32,5 +33,6 @@ go_test( deps = [ "//pkg/apis/abac:go_default_library", "//pkg/apis/abac/v0:go_default_library", + "//pkg/auth/user:go_default_library", ], ) diff --git a/pkg/apis/abac/v0/conversion.go b/pkg/apis/abac/v0/conversion.go index 2d17f05c22b..722b9df100e 100644 --- a/pkg/apis/abac/v0/conversion.go +++ b/pkg/apis/abac/v0/conversion.go @@ -18,6 +18,7 @@ package v0 import ( api "k8s.io/kubernetes/pkg/apis/abac" + "k8s.io/kubernetes/pkg/auth/user" "k8s.io/kubernetes/pkg/conversion" "k8s.io/kubernetes/pkg/runtime" ) @@ -32,9 +33,14 @@ func addConversionFuncs(scheme *runtime.Scheme) error { out.Spec.Resource = in.Resource out.Spec.Readonly = in.Readonly - // In v0, unspecified user and group matches all subjects + // In v0, unspecified user and group matches all authenticated subjects if len(in.User) == 0 && len(in.Group) == 0 { - out.Spec.User = "*" + out.Spec.Group = user.AllAuthenticated + } + // In v0, user or group of * matches all authenticated subjects + if in.User == "*" || in.Group == "*" { + out.Spec.Group = user.AllAuthenticated + out.Spec.User = "" } // In v0, leaving namespace empty matches all namespaces diff --git a/pkg/apis/abac/v0/conversion_test.go b/pkg/apis/abac/v0/conversion_test.go index 30a433b5e35..ff260d7bcc8 100644 --- a/pkg/apis/abac/v0/conversion_test.go +++ b/pkg/apis/abac/v0/conversion_test.go @@ -22,9 +22,10 @@ import ( api "k8s.io/kubernetes/pkg/apis/abac" "k8s.io/kubernetes/pkg/apis/abac/v0" + "k8s.io/kubernetes/pkg/auth/user" ) -func TestConversion(t *testing.T) { +func TestV0Conversion(t *testing.T) { testcases := map[string]struct { old *v0.Policy expected *api.Policy @@ -32,7 +33,7 @@ func TestConversion(t *testing.T) { // a completely empty policy rule allows everything to all users "empty": { old: &v0.Policy{}, - expected: &api.Policy{Spec: api.PolicySpec{User: "*", Readonly: false, NonResourcePath: "*", Namespace: "*", Resource: "*", APIGroup: "*"}}, + expected: &api.Policy{Spec: api.PolicySpec{Group: user.AllAuthenticated, Readonly: false, NonResourcePath: "*", Namespace: "*", Resource: "*", APIGroup: "*"}}, }, // specifying a user is preserved @@ -47,22 +48,32 @@ func TestConversion(t *testing.T) { expected: &api.Policy{Spec: api.PolicySpec{Group: "mygroup", Readonly: false, NonResourcePath: "*", Namespace: "*", Resource: "*", APIGroup: "*"}}, }, + // specifying * for user or group maps to all authenticated subjects + "* user": { + old: &v0.Policy{User: "*"}, + expected: &api.Policy{Spec: api.PolicySpec{Group: user.AllAuthenticated, Readonly: false, NonResourcePath: "*", Namespace: "*", Resource: "*", APIGroup: "*"}}, + }, + "* group": { + old: &v0.Policy{Group: "*"}, + expected: &api.Policy{Spec: api.PolicySpec{Group: user.AllAuthenticated, Readonly: false, NonResourcePath: "*", Namespace: "*", Resource: "*", APIGroup: "*"}}, + }, + // specifying a namespace removes the * match on non-resource path "namespace": { old: &v0.Policy{Namespace: "myns"}, - expected: &api.Policy{Spec: api.PolicySpec{User: "*", Readonly: false, NonResourcePath: "", Namespace: "myns", Resource: "*", APIGroup: "*"}}, + expected: &api.Policy{Spec: api.PolicySpec{Group: user.AllAuthenticated, Readonly: false, NonResourcePath: "", Namespace: "myns", Resource: "*", APIGroup: "*"}}, }, // specifying a resource removes the * match on non-resource path "resource": { old: &v0.Policy{Resource: "myresource"}, - expected: &api.Policy{Spec: api.PolicySpec{User: "*", Readonly: false, NonResourcePath: "", Namespace: "*", Resource: "myresource", APIGroup: "*"}}, + expected: &api.Policy{Spec: api.PolicySpec{Group: user.AllAuthenticated, Readonly: false, NonResourcePath: "", Namespace: "*", Resource: "myresource", APIGroup: "*"}}, }, // specifying a namespace+resource removes the * match on non-resource path "namespace+resource": { old: &v0.Policy{Namespace: "myns", Resource: "myresource"}, - expected: &api.Policy{Spec: api.PolicySpec{User: "*", Readonly: false, NonResourcePath: "", Namespace: "myns", Resource: "myresource", APIGroup: "*"}}, + expected: &api.Policy{Spec: api.PolicySpec{Group: user.AllAuthenticated, Readonly: false, NonResourcePath: "", Namespace: "myns", Resource: "myresource", APIGroup: "*"}}, }, } for k, tc := range testcases { diff --git a/pkg/apis/abac/v1beta1/BUILD b/pkg/apis/abac/v1beta1/BUILD index ba190284f9b..657dc2c05ce 100644 --- a/pkg/apis/abac/v1beta1/BUILD +++ b/pkg/apis/abac/v1beta1/BUILD @@ -5,19 +5,37 @@ licenses(["notice"]) load( "@io_bazel_rules_go//go:def.bzl", "go_library", + "go_test", ) go_library( name = "go_default_library", srcs = [ + "conversion.go", + "doc.go", "register.go", "types.go", + "zz_generated.conversion.go", + "zz_generated.deepcopy.go", ], tags = ["automanaged"], deps = [ "//pkg/apis/abac:go_default_library", "//pkg/apis/meta/v1:go_default_library", + "//pkg/auth/user:go_default_library", + "//pkg/conversion:go_default_library", "//pkg/runtime:go_default_library", "//pkg/runtime/schema:go_default_library", ], ) + +go_test( + name = "go_default_xtest", + srcs = ["conversion_test.go"], + tags = ["automanaged"], + deps = [ + "//pkg/apis/abac:go_default_library", + "//pkg/apis/abac/v1beta1:go_default_library", + "//pkg/auth/user:go_default_library", + ], +) diff --git a/pkg/apis/abac/v1beta1/conversion.go b/pkg/apis/abac/v1beta1/conversion.go new file mode 100644 index 00000000000..6186314ae98 --- /dev/null +++ b/pkg/apis/abac/v1beta1/conversion.go @@ -0,0 +1,43 @@ +/* +Copyright 2016 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 v1beta1 + +import ( + api "k8s.io/kubernetes/pkg/apis/abac" + "k8s.io/kubernetes/pkg/auth/user" + "k8s.io/kubernetes/pkg/conversion" + "k8s.io/kubernetes/pkg/runtime" +) + +func addConversionFuncs(scheme *runtime.Scheme) error { + return scheme.AddConversionFuncs( + func(in *Policy, out *api.Policy, s conversion.Scope) error { + // Begin by copying all fields + if err := autoConvert_v1beta1_Policy_To_abac_Policy(in, out, s); err != nil { + return err + } + + // In v1beta1, * user or group maps to all authenticated subjects + if in.Spec.User == "*" || in.Spec.Group == "*" { + out.Spec.Group = user.AllAuthenticated + out.Spec.User = "" + } + + return nil + }, + ) +} diff --git a/pkg/apis/abac/v1beta1/conversion_test.go b/pkg/apis/abac/v1beta1/conversion_test.go new file mode 100644 index 00000000000..430e833e143 --- /dev/null +++ b/pkg/apis/abac/v1beta1/conversion_test.go @@ -0,0 +1,64 @@ +/* +Copyright 2016 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 v1beta1_test + +import ( + "reflect" + "testing" + + api "k8s.io/kubernetes/pkg/apis/abac" + "k8s.io/kubernetes/pkg/apis/abac/v1beta1" + "k8s.io/kubernetes/pkg/auth/user" +) + +func TestV1Beta1Conversion(t *testing.T) { + testcases := map[string]struct { + old *v1beta1.Policy + expected *api.Policy + }{ + // specifying a user is preserved + "user": { + old: &v1beta1.Policy{Spec: v1beta1.PolicySpec{User: "bob"}}, + expected: &api.Policy{Spec: api.PolicySpec{User: "bob"}}, + }, + + // specifying a group is preserved + "group": { + old: &v1beta1.Policy{Spec: v1beta1.PolicySpec{Group: "mygroup"}}, + expected: &api.Policy{Spec: api.PolicySpec{Group: "mygroup"}}, + }, + + // specifying * for user or group maps to all authenticated subjects + "* user": { + old: &v1beta1.Policy{Spec: v1beta1.PolicySpec{User: "*"}}, + expected: &api.Policy{Spec: api.PolicySpec{Group: user.AllAuthenticated}}, + }, + "* group": { + old: &v1beta1.Policy{Spec: v1beta1.PolicySpec{Group: "*"}}, + expected: &api.Policy{Spec: api.PolicySpec{Group: user.AllAuthenticated}}, + }, + } + for k, tc := range testcases { + internal := &api.Policy{} + if err := api.Scheme.Convert(tc.old, internal, nil); err != nil { + t.Errorf("%s: unexpected error: %v", k, err) + } + if !reflect.DeepEqual(internal, tc.expected) { + t.Errorf("%s: expected\n\t%#v, got \n\t%#v", k, tc.expected, internal) + } + } +} diff --git a/pkg/apis/abac/v1beta1/register.go b/pkg/apis/abac/v1beta1/register.go index 38e87c7f7c6..693e3086392 100644 --- a/pkg/apis/abac/v1beta1/register.go +++ b/pkg/apis/abac/v1beta1/register.go @@ -33,10 +33,14 @@ func init() { // Programmer error. panic(err) } + if err := addConversionFuncs(api.Scheme); err != nil { + // Programmer error. + panic(err) + } } var ( - SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addConversionFuncs) AddToScheme = SchemeBuilder.AddToScheme ) diff --git a/pkg/auth/authorizer/abac/abac_test.go b/pkg/auth/authorizer/abac/abac_test.go index 05d09aa51c8..7942ad2594e 100644 --- a/pkg/auth/authorizer/abac/abac_test.go +++ b/pkg/auth/authorizer/abac/abac_test.go @@ -73,9 +73,11 @@ func TestAuthorizeV0(t *testing.T) { t.Fatalf("unable to read policy file: %v", err) } - uScheduler := user.DefaultInfo{Name: "scheduler", UID: "uid1"} - uAlice := user.DefaultInfo{Name: "alice", UID: "uid3"} - uChuck := user.DefaultInfo{Name: "chuck", UID: "uid5"} + authenticatedGroup := []string{user.AllAuthenticated} + + uScheduler := user.DefaultInfo{Name: "scheduler", UID: "uid1", Groups: authenticatedGroup} + uAlice := user.DefaultInfo{Name: "alice", UID: "uid3", Groups: authenticatedGroup} + uChuck := user.DefaultInfo{Name: "chuck", UID: "uid5", Groups: authenticatedGroup} testCases := []struct { User user.DefaultInfo @@ -163,12 +165,14 @@ func TestAuthorizeV1beta1(t *testing.T) { t.Fatalf("unable to read policy file: %v", err) } - uScheduler := user.DefaultInfo{Name: "scheduler", UID: "uid1"} - uAlice := user.DefaultInfo{Name: "alice", UID: "uid3"} - uChuck := user.DefaultInfo{Name: "chuck", UID: "uid5"} - uDebbie := user.DefaultInfo{Name: "debbie", UID: "uid6"} - uNoResource := user.DefaultInfo{Name: "noresource", UID: "uid7"} - uAPIGroup := user.DefaultInfo{Name: "apigroupuser", UID: "uid8"} + authenticatedGroup := []string{user.AllAuthenticated} + + uScheduler := user.DefaultInfo{Name: "scheduler", UID: "uid1", Groups: authenticatedGroup} + uAlice := user.DefaultInfo{Name: "alice", UID: "uid3", Groups: authenticatedGroup} + uChuck := user.DefaultInfo{Name: "chuck", UID: "uid5", Groups: authenticatedGroup} + uDebbie := user.DefaultInfo{Name: "debbie", UID: "uid6", Groups: authenticatedGroup} + uNoResource := user.DefaultInfo{Name: "noresource", UID: "uid7", Groups: authenticatedGroup} + uAPIGroup := user.DefaultInfo{Name: "apigroupuser", UID: "uid8", Groups: authenticatedGroup} testCases := []struct { User user.DefaultInfo @@ -263,16 +267,32 @@ func TestSubjectMatches(t *testing.T) { Policy runtime.Object ExpectMatch bool }{ - "v0 empty policy matches unauthed user": { - User: user.DefaultInfo{}, + "v0 empty policy does not match unauthed user": { + User: user.DefaultInfo{Name: "system:anonymous", Groups: []string{"system:unauthenticated"}}, Policy: &v0.Policy{ User: "", Group: "", }, - ExpectMatch: true, + ExpectMatch: false, + }, + "v0 * user policy does not match unauthed user": { + User: user.DefaultInfo{Name: "system:anonymous", Groups: []string{"system:unauthenticated"}}, + Policy: &v0.Policy{ + User: "*", + Group: "", + }, + ExpectMatch: false, + }, + "v0 * group policy does not match unauthed user": { + User: user.DefaultInfo{Name: "system:anonymous", Groups: []string{"system:unauthenticated"}}, + Policy: &v0.Policy{ + User: "", + Group: "*", + }, + ExpectMatch: false, }, "v0 empty policy matches authed user": { - User: user.DefaultInfo{Name: "Foo"}, + User: user.DefaultInfo{Name: "Foo", Groups: []string{user.AllAuthenticated}}, Policy: &v0.Policy{ User: "", Group: "", @@ -280,7 +300,7 @@ func TestSubjectMatches(t *testing.T) { ExpectMatch: true, }, "v0 empty policy matches authed user with groups": { - User: user.DefaultInfo{Name: "Foo", Groups: []string{"a", "b"}}, + User: user.DefaultInfo{Name: "Foo", Groups: []string{"a", "b", user.AllAuthenticated}}, Policy: &v0.Policy{ User: "", Group: "", @@ -289,7 +309,7 @@ func TestSubjectMatches(t *testing.T) { }, "v0 user policy does not match unauthed user": { - User: user.DefaultInfo{}, + User: user.DefaultInfo{Name: "system:anonymous", Groups: []string{"system:unauthenticated"}}, Policy: &v0.Policy{ User: "Foo", Group: "", @@ -297,7 +317,7 @@ func TestSubjectMatches(t *testing.T) { ExpectMatch: false, }, "v0 user policy does not match different user": { - User: user.DefaultInfo{Name: "Bar"}, + User: user.DefaultInfo{Name: "Bar", Groups: []string{user.AllAuthenticated}}, Policy: &v0.Policy{ User: "Foo", Group: "", @@ -305,7 +325,7 @@ func TestSubjectMatches(t *testing.T) { ExpectMatch: false, }, "v0 user policy is case-sensitive": { - User: user.DefaultInfo{Name: "foo"}, + User: user.DefaultInfo{Name: "foo", Groups: []string{user.AllAuthenticated}}, Policy: &v0.Policy{ User: "Foo", Group: "", @@ -313,7 +333,7 @@ func TestSubjectMatches(t *testing.T) { ExpectMatch: false, }, "v0 user policy does not match substring": { - User: user.DefaultInfo{Name: "FooBar"}, + User: user.DefaultInfo{Name: "FooBar", Groups: []string{user.AllAuthenticated}}, Policy: &v0.Policy{ User: "Foo", Group: "", @@ -321,7 +341,7 @@ func TestSubjectMatches(t *testing.T) { ExpectMatch: false, }, "v0 user policy matches username": { - User: user.DefaultInfo{Name: "Foo"}, + User: user.DefaultInfo{Name: "Foo", Groups: []string{user.AllAuthenticated}}, Policy: &v0.Policy{ User: "Foo", Group: "", @@ -330,7 +350,7 @@ func TestSubjectMatches(t *testing.T) { }, "v0 group policy does not match unauthed user": { - User: user.DefaultInfo{}, + User: user.DefaultInfo{Name: "system:anonymous", Groups: []string{"system:unauthenticated"}}, Policy: &v0.Policy{ User: "", Group: "Foo", @@ -338,7 +358,7 @@ func TestSubjectMatches(t *testing.T) { ExpectMatch: false, }, "v0 group policy does not match user in different group": { - User: user.DefaultInfo{Name: "FooBar", Groups: []string{"B"}}, + User: user.DefaultInfo{Name: "FooBar", Groups: []string{"B", user.AllAuthenticated}}, Policy: &v0.Policy{ User: "", Group: "A", @@ -346,7 +366,7 @@ func TestSubjectMatches(t *testing.T) { ExpectMatch: false, }, "v0 group policy is case-sensitive": { - User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "B", "C"}}, + User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "B", "C", user.AllAuthenticated}}, Policy: &v0.Policy{ User: "", Group: "b", @@ -354,7 +374,7 @@ func TestSubjectMatches(t *testing.T) { ExpectMatch: false, }, "v0 group policy does not match substring": { - User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "BBB", "C"}}, + User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "BBB", "C", user.AllAuthenticated}}, Policy: &v0.Policy{ User: "", Group: "B", @@ -362,7 +382,7 @@ func TestSubjectMatches(t *testing.T) { ExpectMatch: false, }, "v0 group policy matches user in group": { - User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "B", "C"}}, + User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "B", "C", user.AllAuthenticated}}, Policy: &v0.Policy{ User: "", Group: "B", @@ -371,7 +391,7 @@ func TestSubjectMatches(t *testing.T) { }, "v0 user and group policy requires user match": { - User: user.DefaultInfo{Name: "Bar", Groups: []string{"A", "B", "C"}}, + User: user.DefaultInfo{Name: "Bar", Groups: []string{"A", "B", "C", user.AllAuthenticated}}, Policy: &v0.Policy{ User: "Foo", Group: "B", @@ -379,7 +399,7 @@ func TestSubjectMatches(t *testing.T) { ExpectMatch: false, }, "v0 user and group policy requires group match": { - User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "B", "C"}}, + User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "B", "C", user.AllAuthenticated}}, Policy: &v0.Policy{ User: "Foo", Group: "D", @@ -387,7 +407,7 @@ func TestSubjectMatches(t *testing.T) { ExpectMatch: false, }, "v0 user and group policy matches": { - User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "B", "C"}}, + User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "B", "C", user.AllAuthenticated}}, Policy: &v0.Policy{ User: "Foo", Group: "B", @@ -396,7 +416,7 @@ func TestSubjectMatches(t *testing.T) { }, "v1 empty policy does not match unauthed user": { - User: user.DefaultInfo{}, + User: user.DefaultInfo{Name: "system:anonymous", Groups: []string{"system:unauthenticated"}}, Policy: &v1beta1.Policy{ Spec: v1beta1.PolicySpec{ User: "", @@ -405,8 +425,28 @@ func TestSubjectMatches(t *testing.T) { }, ExpectMatch: false, }, + "v1 * user policy does not match unauthed user": { + User: user.DefaultInfo{Name: "system:anonymous", Groups: []string{"system:unauthenticated"}}, + Policy: &v1beta1.Policy{ + Spec: v1beta1.PolicySpec{ + User: "*", + Group: "", + }, + }, + ExpectMatch: false, + }, + "v1 * group policy does not match unauthed user": { + User: user.DefaultInfo{Name: "system:anonymous", Groups: []string{"system:unauthenticated"}}, + Policy: &v1beta1.Policy{ + Spec: v1beta1.PolicySpec{ + User: "", + Group: "*", + }, + }, + ExpectMatch: false, + }, "v1 empty policy does not match authed user": { - User: user.DefaultInfo{Name: "Foo"}, + User: user.DefaultInfo{Name: "Foo", Groups: []string{user.AllAuthenticated}}, Policy: &v1beta1.Policy{ Spec: v1beta1.PolicySpec{ User: "", @@ -416,7 +456,7 @@ func TestSubjectMatches(t *testing.T) { ExpectMatch: false, }, "v1 empty policy does not match authed user with groups": { - User: user.DefaultInfo{Name: "Foo", Groups: []string{"a", "b"}}, + User: user.DefaultInfo{Name: "Foo", Groups: []string{"a", "b", user.AllAuthenticated}}, Policy: &v1beta1.Policy{ Spec: v1beta1.PolicySpec{ User: "", @@ -427,7 +467,7 @@ func TestSubjectMatches(t *testing.T) { }, "v1 user policy does not match unauthed user": { - User: user.DefaultInfo{}, + User: user.DefaultInfo{Name: "system:anonymous", Groups: []string{"system:unauthenticated"}}, Policy: &v1beta1.Policy{ Spec: v1beta1.PolicySpec{ User: "Foo", @@ -437,7 +477,7 @@ func TestSubjectMatches(t *testing.T) { ExpectMatch: false, }, "v1 user policy does not match different user": { - User: user.DefaultInfo{Name: "Bar"}, + User: user.DefaultInfo{Name: "Bar", Groups: []string{user.AllAuthenticated}}, Policy: &v1beta1.Policy{ Spec: v1beta1.PolicySpec{ User: "Foo", @@ -447,7 +487,7 @@ func TestSubjectMatches(t *testing.T) { ExpectMatch: false, }, "v1 user policy is case-sensitive": { - User: user.DefaultInfo{Name: "foo"}, + User: user.DefaultInfo{Name: "foo", Groups: []string{user.AllAuthenticated}}, Policy: &v1beta1.Policy{ Spec: v1beta1.PolicySpec{ User: "Foo", @@ -457,7 +497,7 @@ func TestSubjectMatches(t *testing.T) { ExpectMatch: false, }, "v1 user policy does not match substring": { - User: user.DefaultInfo{Name: "FooBar"}, + User: user.DefaultInfo{Name: "FooBar", Groups: []string{user.AllAuthenticated}}, Policy: &v1beta1.Policy{ Spec: v1beta1.PolicySpec{ User: "Foo", @@ -467,7 +507,7 @@ func TestSubjectMatches(t *testing.T) { ExpectMatch: false, }, "v1 user policy matches username": { - User: user.DefaultInfo{Name: "Foo"}, + User: user.DefaultInfo{Name: "Foo", Groups: []string{user.AllAuthenticated}}, Policy: &v1beta1.Policy{ Spec: v1beta1.PolicySpec{ User: "Foo", @@ -478,7 +518,7 @@ func TestSubjectMatches(t *testing.T) { }, "v1 group policy does not match unauthed user": { - User: user.DefaultInfo{}, + User: user.DefaultInfo{Name: "system:anonymous", Groups: []string{"system:unauthenticated"}}, Policy: &v1beta1.Policy{ Spec: v1beta1.PolicySpec{ User: "", @@ -488,7 +528,7 @@ func TestSubjectMatches(t *testing.T) { ExpectMatch: false, }, "v1 group policy does not match user in different group": { - User: user.DefaultInfo{Name: "FooBar", Groups: []string{"B"}}, + User: user.DefaultInfo{Name: "FooBar", Groups: []string{"B", user.AllAuthenticated}}, Policy: &v1beta1.Policy{ Spec: v1beta1.PolicySpec{ User: "", @@ -498,7 +538,7 @@ func TestSubjectMatches(t *testing.T) { ExpectMatch: false, }, "v1 group policy is case-sensitive": { - User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "B", "C"}}, + User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "B", "C", user.AllAuthenticated}}, Policy: &v1beta1.Policy{ Spec: v1beta1.PolicySpec{ User: "", @@ -508,7 +548,7 @@ func TestSubjectMatches(t *testing.T) { ExpectMatch: false, }, "v1 group policy does not match substring": { - User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "BBB", "C"}}, + User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "BBB", "C", user.AllAuthenticated}}, Policy: &v1beta1.Policy{ Spec: v1beta1.PolicySpec{ User: "", @@ -518,7 +558,7 @@ func TestSubjectMatches(t *testing.T) { ExpectMatch: false, }, "v1 group policy matches user in group": { - User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "B", "C"}}, + User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "B", "C", user.AllAuthenticated}}, Policy: &v1beta1.Policy{ Spec: v1beta1.PolicySpec{ User: "", @@ -529,7 +569,7 @@ func TestSubjectMatches(t *testing.T) { }, "v1 user and group policy requires user match": { - User: user.DefaultInfo{Name: "Bar", Groups: []string{"A", "B", "C"}}, + User: user.DefaultInfo{Name: "Bar", Groups: []string{"A", "B", "C", user.AllAuthenticated}}, Policy: &v1beta1.Policy{ Spec: v1beta1.PolicySpec{ User: "Foo", @@ -539,7 +579,7 @@ func TestSubjectMatches(t *testing.T) { ExpectMatch: false, }, "v1 user and group policy requires group match": { - User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "B", "C"}}, + User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "B", "C", user.AllAuthenticated}}, Policy: &v1beta1.Policy{ Spec: v1beta1.PolicySpec{ User: "Foo", @@ -549,7 +589,7 @@ func TestSubjectMatches(t *testing.T) { ExpectMatch: false, }, "v1 user and group policy matches": { - User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "B", "C"}}, + User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "B", "C", user.AllAuthenticated}}, Policy: &v1beta1.Policy{ Spec: v1beta1.PolicySpec{ User: "Foo", @@ -600,20 +640,18 @@ func TestPolicy(t *testing.T) { matches bool name string }{ - // v0 - { - policy: &v0.Policy{}, - attr: authorizer.AttributesRecord{}, - matches: true, - name: "v0 null", - }, - // v0 mismatches { policy: &v0.Policy{ Readonly: true, }, - attr: authorizer.AttributesRecord{}, + attr: authorizer.AttributesRecord{ + User: &user.DefaultInfo{ + Name: "foo", + Groups: []string{user.AllAuthenticated}, + }, + Verb: "create", + }, matches: false, name: "v0 read-only mismatch", }, @@ -623,7 +661,8 @@ func TestPolicy(t *testing.T) { }, attr: authorizer.AttributesRecord{ User: &user.DefaultInfo{ - Name: "bar", + Name: "bar", + Groups: []string{user.AllAuthenticated}, }, }, matches: false, @@ -634,6 +673,10 @@ func TestPolicy(t *testing.T) { Resource: "foo", }, attr: authorizer.AttributesRecord{ + User: &user.DefaultInfo{ + Name: "foo", + Groups: []string{user.AllAuthenticated}, + }, Resource: "bar", ResourceRequest: true, }, @@ -648,7 +691,8 @@ func TestPolicy(t *testing.T) { }, attr: authorizer.AttributesRecord{ User: &user.DefaultInfo{ - Name: "foo", + Name: "foo", + Groups: []string{user.AllAuthenticated}, }, Resource: "foo", Namespace: "foo", @@ -660,8 +704,14 @@ func TestPolicy(t *testing.T) { // v0 matches { - policy: &v0.Policy{}, - attr: authorizer.AttributesRecord{ResourceRequest: true}, + policy: &v0.Policy{}, + attr: authorizer.AttributesRecord{ + User: &user.DefaultInfo{ + Name: "foo", + Groups: []string{user.AllAuthenticated}, + }, + ResourceRequest: true, + }, matches: true, name: "v0 null resource", }, @@ -670,6 +720,10 @@ func TestPolicy(t *testing.T) { Readonly: true, }, attr: authorizer.AttributesRecord{ + User: &user.DefaultInfo{ + Name: "foo", + Groups: []string{user.AllAuthenticated}, + }, Verb: "get", }, matches: true, @@ -681,7 +735,8 @@ func TestPolicy(t *testing.T) { }, attr: authorizer.AttributesRecord{ User: &user.DefaultInfo{ - Name: "foo", + Name: "foo", + Groups: []string{user.AllAuthenticated}, }, }, matches: true, @@ -692,6 +747,10 @@ func TestPolicy(t *testing.T) { Resource: "foo", }, attr: authorizer.AttributesRecord{ + User: &user.DefaultInfo{ + Name: "foo", + Groups: []string{user.AllAuthenticated}, + }, Resource: "foo", ResourceRequest: true, }, @@ -703,6 +762,10 @@ func TestPolicy(t *testing.T) { { policy: &v1beta1.Policy{}, attr: authorizer.AttributesRecord{ + User: &user.DefaultInfo{ + Name: "foo", + Groups: []string{user.AllAuthenticated}, + }, ResourceRequest: true, }, matches: false, @@ -716,7 +779,8 @@ func TestPolicy(t *testing.T) { }, attr: authorizer.AttributesRecord{ User: &user.DefaultInfo{ - Name: "bar", + Name: "bar", + Groups: []string{user.AllAuthenticated}, }, ResourceRequest: true, }, @@ -731,6 +795,10 @@ func TestPolicy(t *testing.T) { }, }, attr: authorizer.AttributesRecord{ + User: &user.DefaultInfo{ + Name: "foo", + Groups: []string{user.AllAuthenticated}, + }, ResourceRequest: true, }, matches: false, @@ -744,6 +812,10 @@ func TestPolicy(t *testing.T) { }, }, attr: authorizer.AttributesRecord{ + User: &user.DefaultInfo{ + Name: "foo", + Groups: []string{user.AllAuthenticated}, + }, Resource: "bar", ResourceRequest: true, }, @@ -760,7 +832,8 @@ func TestPolicy(t *testing.T) { }, attr: authorizer.AttributesRecord{ User: &user.DefaultInfo{ - Name: "foo", + Name: "foo", + Groups: []string{user.AllAuthenticated}, }, Namespace: "bar", Resource: "baz", @@ -777,6 +850,10 @@ func TestPolicy(t *testing.T) { }, }, attr: authorizer.AttributesRecord{ + User: &user.DefaultInfo{ + Name: "foo", + Groups: []string{user.AllAuthenticated}, + }, Path: "/api2", ResourceRequest: false, }, @@ -791,6 +868,10 @@ func TestPolicy(t *testing.T) { }, }, attr: authorizer.AttributesRecord{ + User: &user.DefaultInfo{ + Name: "foo", + Groups: []string{user.AllAuthenticated}, + }, Path: "/api2/foo", ResourceRequest: false, }, @@ -807,7 +888,8 @@ func TestPolicy(t *testing.T) { }, attr: authorizer.AttributesRecord{ User: &user.DefaultInfo{ - Name: "foo", + Name: "foo", + Groups: []string{user.AllAuthenticated}, }, ResourceRequest: true, }, @@ -821,6 +903,10 @@ func TestPolicy(t *testing.T) { }, }, attr: authorizer.AttributesRecord{ + User: &user.DefaultInfo{ + Name: "foo", + Groups: []string{user.AllAuthenticated}, + }, ResourceRequest: true, }, matches: true, @@ -835,7 +921,7 @@ func TestPolicy(t *testing.T) { attr: authorizer.AttributesRecord{ User: &user.DefaultInfo{ Name: "foo", - Groups: []string{"bar"}, + Groups: []string{"bar", user.AllAuthenticated}, }, ResourceRequest: true, }, @@ -851,7 +937,7 @@ func TestPolicy(t *testing.T) { attr: authorizer.AttributesRecord{ User: &user.DefaultInfo{ Name: "foo", - Groups: []string{"bar"}, + Groups: []string{"bar", user.AllAuthenticated}, }, ResourceRequest: true, }, @@ -866,6 +952,10 @@ func TestPolicy(t *testing.T) { }, }, attr: authorizer.AttributesRecord{ + User: &user.DefaultInfo{ + Name: "foo", + Groups: []string{user.AllAuthenticated}, + }, Verb: "get", ResourceRequest: true, }, @@ -880,6 +970,10 @@ func TestPolicy(t *testing.T) { }, }, attr: authorizer.AttributesRecord{ + User: &user.DefaultInfo{ + Name: "foo", + Groups: []string{user.AllAuthenticated}, + }, Resource: "foo", ResourceRequest: true, }, @@ -896,7 +990,8 @@ func TestPolicy(t *testing.T) { }, attr: authorizer.AttributesRecord{ User: &user.DefaultInfo{ - Name: "foo", + Name: "foo", + Groups: []string{user.AllAuthenticated}, }, Namespace: "bar", Resource: "baz", @@ -913,6 +1008,10 @@ func TestPolicy(t *testing.T) { }, }, attr: authorizer.AttributesRecord{ + User: &user.DefaultInfo{ + Name: "foo", + Groups: []string{user.AllAuthenticated}, + }, Path: "/api", ResourceRequest: false, }, @@ -927,6 +1026,10 @@ func TestPolicy(t *testing.T) { }, }, attr: authorizer.AttributesRecord{ + User: &user.DefaultInfo{ + Name: "foo", + Groups: []string{user.AllAuthenticated}, + }, Path: "/api", ResourceRequest: false, }, @@ -941,6 +1044,10 @@ func TestPolicy(t *testing.T) { }, }, attr: authorizer.AttributesRecord{ + User: &user.DefaultInfo{ + Name: "foo", + Groups: []string{user.AllAuthenticated}, + }, Path: "/api/foo", ResourceRequest: false, }, diff --git a/pkg/auth/authorizer/abac/example_policy_file.jsonl b/pkg/auth/authorizer/abac/example_policy_file.jsonl index 755145a1d7d..10a9c289965 100644 --- a/pkg/auth/authorizer/abac/example_policy_file.jsonl +++ b/pkg/auth/authorizer/abac/example_policy_file.jsonl @@ -1,4 +1,5 @@ -{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user":"*", "nonResourcePath": "*", "readonly": true}} +{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"group":"system:authenticated", "nonResourcePath": "*", "readonly": true}} +{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user":"system:unauthenticated", "nonResourcePath": "*", "readonly": true}} {"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user":"admin", "namespace": "*", "resource": "*", "apiGroup": "*" }} {"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user":"scheduler", "namespace": "*", "resource": "pods", "readonly": true }} {"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user":"scheduler", "namespace": "*", "resource": "bindings" }} diff --git a/test/integration/auth/auth_test.go b/test/integration/auth/auth_test.go index abda5bfca03..35aaa126cd1 100644 --- a/test/integration/auth/auth_test.go +++ b/test/integration/auth/auth_test.go @@ -46,6 +46,7 @@ import ( "k8s.io/kubernetes/pkg/auth/authenticator/bearertoken" "k8s.io/kubernetes/pkg/auth/authorizer" "k8s.io/kubernetes/pkg/auth/authorizer/abac" + "k8s.io/kubernetes/pkg/auth/group" "k8s.io/kubernetes/pkg/auth/user" "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/v1" apiserverauthorizer "k8s.io/kubernetes/pkg/genericapiserver/authorizer" @@ -67,7 +68,7 @@ func getTestTokenAuth() authenticator.Request { tokenAuthenticator := tokentest.New() tokenAuthenticator.Tokens[AliceToken] = &user.DefaultInfo{Name: "alice", UID: "1"} tokenAuthenticator.Tokens[BobToken] = &user.DefaultInfo{Name: "bob", UID: "2"} - return bearertoken.New(tokenAuthenticator) + return group.NewGroupAdder(bearertoken.New(tokenAuthenticator), []string{user.AllAuthenticated}) } func getTestWebhookTokenAuth(serverURL string) (authenticator.Request, error) { diff --git a/test/test_owners.csv b/test/test_owners.csv index eec5f606589..55076013a08 100644 --- a/test/test_owners.csv +++ b/test/test_owners.csv @@ -559,6 +559,7 @@ k8s.io/kubernetes/pkg/apimachinery,gmarek,1 k8s.io/kubernetes/pkg/apimachinery/announced,kargakis,1 k8s.io/kubernetes/pkg/apimachinery/registered,jlowdermilk,1 k8s.io/kubernetes/pkg/apis/abac/v0,liggitt,0 +k8s.io/kubernetes/pkg/apis/abac/v1beta1,liggitt,0 k8s.io/kubernetes/pkg/apis/apps/validation,derekwaynecarr,1 k8s.io/kubernetes/pkg/apis/authorization/validation,erictune,0 k8s.io/kubernetes/pkg/apis/autoscaling/v1,yarntime,0