mirror of https://github.com/k3s-io/k3s
Merge pull request #39729 from sttts/sttts-split-server-side-rbac-validation
Automatic merge from submit-queue Split out server-only code from api packages shared with the client Fixes staging/copy.sh.pull/6/head
commit
330c922706
|
@ -29,11 +29,9 @@ go_library(
|
||||||
deps = [
|
deps = [
|
||||||
"//pkg/api/resource:go_default_library",
|
"//pkg/api/resource:go_default_library",
|
||||||
"//pkg/fields:go_default_library",
|
"//pkg/fields:go_default_library",
|
||||||
"//pkg/genericapiserver/api/request:go_default_library",
|
|
||||||
"//pkg/util/intstr:go_default_library",
|
"//pkg/util/intstr:go_default_library",
|
||||||
"//pkg/util/labels:go_default_library",
|
"//pkg/util/labels:go_default_library",
|
||||||
"//pkg/util/rand:go_default_library",
|
"//pkg/util/rand:go_default_library",
|
||||||
"//pkg/util/uuid:go_default_library",
|
|
||||||
"//vendor:github.com/davecgh/go-spew/spew",
|
"//vendor:github.com/davecgh/go-spew/spew",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/api/meta",
|
"//vendor:k8s.io/apimachinery/pkg/api/meta",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||||
|
@ -88,8 +86,6 @@ go_test(
|
||||||
"//pkg/apis/batch/v2alpha1:go_default_library",
|
"//pkg/apis/batch/v2alpha1:go_default_library",
|
||||||
"//pkg/apis/extensions:go_default_library",
|
"//pkg/apis/extensions:go_default_library",
|
||||||
"//pkg/apis/extensions/v1beta1:go_default_library",
|
"//pkg/apis/extensions/v1beta1:go_default_library",
|
||||||
"//pkg/genericapiserver/api/request:go_default_library",
|
|
||||||
"//pkg/util/uuid:go_default_library",
|
|
||||||
"//vendor:github.com/davecgh/go-spew/spew",
|
"//vendor:github.com/davecgh/go-spew/spew",
|
||||||
"//vendor:github.com/gogo/protobuf/proto",
|
"//vendor:github.com/gogo/protobuf/proto",
|
||||||
"//vendor:github.com/golang/protobuf/proto",
|
"//vendor:github.com/golang/protobuf/proto",
|
||||||
|
|
|
@ -22,23 +22,8 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/conversion"
|
"k8s.io/apimachinery/pkg/conversion"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request"
|
|
||||||
"k8s.io/kubernetes/pkg/util/uuid"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// FillObjectMetaSystemFields populates fields that are managed by the system on ObjectMeta.
|
|
||||||
func FillObjectMetaSystemFields(ctx genericapirequest.Context, meta *ObjectMeta) {
|
|
||||||
meta.CreationTimestamp = metav1.Now()
|
|
||||||
// allows admission controllers to assign a UID earlier in the request processing
|
|
||||||
// to support tracking resources pending creation.
|
|
||||||
uid, found := genericapirequest.UIDFrom(ctx)
|
|
||||||
if !found {
|
|
||||||
uid = uuid.NewUUID()
|
|
||||||
}
|
|
||||||
meta.UID = uid
|
|
||||||
meta.SelfLink = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasObjectMetaSystemFieldValues returns true if fields that are managed by the system on ObjectMeta have values.
|
// HasObjectMetaSystemFieldValues returns true if fields that are managed by the system on ObjectMeta have values.
|
||||||
func HasObjectMetaSystemFieldValues(meta *ObjectMeta) bool {
|
func HasObjectMetaSystemFieldValues(meta *ObjectMeta) bool {
|
||||||
return !meta.CreationTimestamp.Time.IsZero() ||
|
return !meta.CreationTimestamp.Time.IsZero() ||
|
||||||
|
|
|
@ -28,45 +28,10 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request"
|
|
||||||
"k8s.io/kubernetes/pkg/util/uuid"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ meta.Object = &api.ObjectMeta{}
|
var _ meta.Object = &api.ObjectMeta{}
|
||||||
|
|
||||||
// TestFillObjectMetaSystemFields validates that system populated fields are set on an object
|
|
||||||
func TestFillObjectMetaSystemFields(t *testing.T) {
|
|
||||||
ctx := genericapirequest.NewDefaultContext()
|
|
||||||
resource := api.ObjectMeta{}
|
|
||||||
api.FillObjectMetaSystemFields(ctx, &resource)
|
|
||||||
if resource.CreationTimestamp.Time.IsZero() {
|
|
||||||
t.Errorf("resource.CreationTimestamp is zero")
|
|
||||||
} else if len(resource.UID) == 0 {
|
|
||||||
t.Errorf("resource.UID missing")
|
|
||||||
}
|
|
||||||
// verify we can inject a UID
|
|
||||||
uid := uuid.NewUUID()
|
|
||||||
ctx = genericapirequest.WithUID(ctx, uid)
|
|
||||||
resource = api.ObjectMeta{}
|
|
||||||
api.FillObjectMetaSystemFields(ctx, &resource)
|
|
||||||
if resource.UID != uid {
|
|
||||||
t.Errorf("resource.UID expected: %v, actual: %v", uid, resource.UID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestHasObjectMetaSystemFieldValues validates that true is returned if and only if all fields are populated
|
|
||||||
func TestHasObjectMetaSystemFieldValues(t *testing.T) {
|
|
||||||
ctx := genericapirequest.NewDefaultContext()
|
|
||||||
resource := api.ObjectMeta{}
|
|
||||||
if api.HasObjectMetaSystemFieldValues(&resource) {
|
|
||||||
t.Errorf("the resource does not have all fields yet populated, but incorrectly reports it does")
|
|
||||||
}
|
|
||||||
api.FillObjectMetaSystemFields(ctx, &resource)
|
|
||||||
if !api.HasObjectMetaSystemFieldValues(&resource) {
|
|
||||||
t.Errorf("the resource does have all fields populated, but incorrectly reports it does not")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getObjectMetaAndOwnerReferences() (objectMeta api.ObjectMeta, metaOwnerReferences []metav1.OwnerReference) {
|
func getObjectMetaAndOwnerReferences() (objectMeta api.ObjectMeta, metaOwnerReferences []metav1.OwnerReference) {
|
||||||
fuzz.New().NilChance(.5).NumElements(1, 5).Fuzz(&objectMeta)
|
fuzz.New().NilChance(.5).NumElements(1, 5).Fuzz(&objectMeta)
|
||||||
references := objectMeta.OwnerReferences
|
references := objectMeta.OwnerReferences
|
||||||
|
|
|
@ -21,7 +21,6 @@ import (
|
||||||
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/kubernetes/pkg/api/resource"
|
"k8s.io/kubernetes/pkg/api/resource"
|
||||||
genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Returns string version of ResourceName.
|
// Returns string version of ResourceName.
|
||||||
|
@ -228,13 +227,3 @@ func PodRequestsAndLimits(pod *Pod) (reqs map[ResourceName]resource.Quantity, li
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidNamespace returns false if the namespace on the context differs from the resource. If the resource has no namespace, it is set to the value in the context.
|
|
||||||
// TODO(sttts): move into pkg/genericapiserver/api
|
|
||||||
func ValidNamespace(ctx genericapirequest.Context, resource *ObjectMeta) bool {
|
|
||||||
ns, ok := genericapirequest.NamespaceFrom(ctx)
|
|
||||||
if len(resource.Namespace) == 0 {
|
|
||||||
resource.Namespace = ns
|
|
||||||
}
|
|
||||||
return ns == resource.Namespace && ok
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ licenses(["notice"])
|
||||||
load(
|
load(
|
||||||
"@io_bazel_rules_go//go:def.bzl",
|
"@io_bazel_rules_go//go:def.bzl",
|
||||||
"go_library",
|
"go_library",
|
||||||
|
"go_test",
|
||||||
)
|
)
|
||||||
|
|
||||||
go_library(
|
go_library(
|
||||||
|
@ -14,6 +15,7 @@ go_library(
|
||||||
"delete.go",
|
"delete.go",
|
||||||
"doc.go",
|
"doc.go",
|
||||||
"export.go",
|
"export.go",
|
||||||
|
"meta.go",
|
||||||
"rest.go",
|
"rest.go",
|
||||||
"types.go",
|
"types.go",
|
||||||
"update.go",
|
"update.go",
|
||||||
|
@ -25,6 +27,7 @@ go_library(
|
||||||
"//pkg/api/validation/genericvalidation:go_default_library",
|
"//pkg/api/validation/genericvalidation:go_default_library",
|
||||||
"//pkg/api/validation/path:go_default_library",
|
"//pkg/api/validation/path:go_default_library",
|
||||||
"//pkg/genericapiserver/api/request:go_default_library",
|
"//pkg/genericapiserver/api/request:go_default_library",
|
||||||
|
"//pkg/util/uuid:go_default_library",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/api/meta",
|
"//vendor:k8s.io/apimachinery/pkg/api/meta",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||||
|
@ -49,3 +52,15 @@ filegroup(
|
||||||
],
|
],
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
go_test(
|
||||||
|
name = "go_default_test",
|
||||||
|
srcs = ["meta_test.go"],
|
||||||
|
library = ":go_default_library",
|
||||||
|
tags = ["automanaged"],
|
||||||
|
deps = [
|
||||||
|
"//pkg/api:go_default_library",
|
||||||
|
"//pkg/genericapiserver/api/request:go_default_library",
|
||||||
|
"//pkg/util/uuid:go_default_library",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
|
@ -23,7 +23,7 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/errors"
|
"k8s.io/kubernetes/pkg/api/errors"
|
||||||
"k8s.io/kubernetes/pkg/api/validation/genericvalidation"
|
"k8s.io/kubernetes/pkg/api/validation/genericvalidation"
|
||||||
path "k8s.io/kubernetes/pkg/api/validation/path"
|
"k8s.io/kubernetes/pkg/api/validation/path"
|
||||||
genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request"
|
genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ func BeforeCreate(strategy RESTCreateStrategy, ctx genericapirequest.Context, ob
|
||||||
}
|
}
|
||||||
|
|
||||||
if strategy.NamespaceScoped() {
|
if strategy.NamespaceScoped() {
|
||||||
if !api.ValidNamespace(ctx, objectMeta) {
|
if !ValidNamespace(ctx, objectMeta) {
|
||||||
return errors.NewBadRequest("the namespace of the provided object does not match the namespace sent on the request")
|
return errors.NewBadRequest("the namespace of the provided object does not match the namespace sent on the request")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -70,7 +70,7 @@ func BeforeCreate(strategy RESTCreateStrategy, ctx genericapirequest.Context, ob
|
||||||
objectMeta.DeletionTimestamp = nil
|
objectMeta.DeletionTimestamp = nil
|
||||||
objectMeta.DeletionGracePeriodSeconds = nil
|
objectMeta.DeletionGracePeriodSeconds = nil
|
||||||
strategy.PrepareForCreate(ctx, obj)
|
strategy.PrepareForCreate(ctx, obj)
|
||||||
api.FillObjectMetaSystemFields(ctx, objectMeta)
|
FillObjectMetaSystemFields(ctx, objectMeta)
|
||||||
api.GenerateName(strategy, objectMeta)
|
api.GenerateName(strategy, objectMeta)
|
||||||
|
|
||||||
// ClusterName is ignored and should not be saved
|
// ClusterName is ignored and should not be saved
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
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 rest
|
||||||
|
|
||||||
|
import (
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request"
|
||||||
|
"k8s.io/kubernetes/pkg/util/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FillObjectMetaSystemFields populates fields that are managed by the system on ObjectMeta.
|
||||||
|
func FillObjectMetaSystemFields(ctx genericapirequest.Context, meta *api.ObjectMeta) {
|
||||||
|
meta.CreationTimestamp = metav1.Now()
|
||||||
|
// allows admission controllers to assign a UID earlier in the request processing
|
||||||
|
// to support tracking resources pending creation.
|
||||||
|
uid, found := genericapirequest.UIDFrom(ctx)
|
||||||
|
if !found {
|
||||||
|
uid = uuid.NewUUID()
|
||||||
|
}
|
||||||
|
meta.UID = uid
|
||||||
|
meta.SelfLink = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidNamespace returns false if the namespace on the context differs from the resource. If the resource has no namespace, it is set to the value in the context.
|
||||||
|
// TODO(sttts): move into pkg/genericapiserver/api
|
||||||
|
func ValidNamespace(ctx genericapirequest.Context, resource *api.ObjectMeta) bool {
|
||||||
|
ns, ok := genericapirequest.NamespaceFrom(ctx)
|
||||||
|
if len(resource.Namespace) == 0 {
|
||||||
|
resource.Namespace = ns
|
||||||
|
}
|
||||||
|
return ns == resource.Namespace && ok
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
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 rest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request"
|
||||||
|
"k8s.io/kubernetes/pkg/util/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestFillObjectMetaSystemFields validates that system populated fields are set on an object
|
||||||
|
func TestFillObjectMetaSystemFields(t *testing.T) {
|
||||||
|
ctx := genericapirequest.NewDefaultContext()
|
||||||
|
resource := api.ObjectMeta{}
|
||||||
|
FillObjectMetaSystemFields(ctx, &resource)
|
||||||
|
if resource.CreationTimestamp.Time.IsZero() {
|
||||||
|
t.Errorf("resource.CreationTimestamp is zero")
|
||||||
|
} else if len(resource.UID) == 0 {
|
||||||
|
t.Errorf("resource.UID missing")
|
||||||
|
}
|
||||||
|
// verify we can inject a UID
|
||||||
|
uid := uuid.NewUUID()
|
||||||
|
ctx = genericapirequest.WithUID(ctx, uid)
|
||||||
|
resource = api.ObjectMeta{}
|
||||||
|
FillObjectMetaSystemFields(ctx, &resource)
|
||||||
|
if resource.UID != uid {
|
||||||
|
t.Errorf("resource.UID expected: %v, actual: %v", uid, resource.UID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestHasObjectMetaSystemFieldValues validates that true is returned if and only if all fields are populated
|
||||||
|
func TestHasObjectMetaSystemFieldValues(t *testing.T) {
|
||||||
|
ctx := genericapirequest.NewDefaultContext()
|
||||||
|
resource := api.ObjectMeta{}
|
||||||
|
if api.HasObjectMetaSystemFieldValues(&resource) {
|
||||||
|
t.Errorf("the resource does not have all fields yet populated, but incorrectly reports it does")
|
||||||
|
}
|
||||||
|
FillObjectMetaSystemFields(ctx, &resource)
|
||||||
|
if !api.HasObjectMetaSystemFieldValues(&resource) {
|
||||||
|
t.Errorf("the resource does have all fields populated, but incorrectly reports it does not")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestValidNamespace validates that namespace rules are enforced on a resource prior to create or update
|
||||||
|
func TestValidNamespace(t *testing.T) {
|
||||||
|
ctx := genericapirequest.NewDefaultContext()
|
||||||
|
namespace, _ := genericapirequest.NamespaceFrom(ctx)
|
||||||
|
resource := api.ReplicationController{}
|
||||||
|
if !ValidNamespace(ctx, &resource.ObjectMeta) {
|
||||||
|
t.Fatalf("expected success")
|
||||||
|
}
|
||||||
|
if namespace != resource.Namespace {
|
||||||
|
t.Fatalf("expected resource to have the default namespace assigned during validation")
|
||||||
|
}
|
||||||
|
resource = api.ReplicationController{ObjectMeta: api.ObjectMeta{Namespace: "other"}}
|
||||||
|
if ValidNamespace(ctx, &resource.ObjectMeta) {
|
||||||
|
t.Fatalf("Expected error that resource and context errors do not match because resource has different namespace")
|
||||||
|
}
|
||||||
|
ctx = genericapirequest.NewContext()
|
||||||
|
if ValidNamespace(ctx, &resource.ObjectMeta) {
|
||||||
|
t.Fatalf("Expected error that resource and context errors do not match since context has no namespace")
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = genericapirequest.NewContext()
|
||||||
|
ns := genericapirequest.NamespaceValue(ctx)
|
||||||
|
if ns != "" {
|
||||||
|
t.Fatalf("Expected the empty string")
|
||||||
|
}
|
||||||
|
}
|
|
@ -81,7 +81,7 @@ func BeforeUpdate(strategy RESTUpdateStrategy, ctx genericapirequest.Context, ob
|
||||||
return kerr
|
return kerr
|
||||||
}
|
}
|
||||||
if strategy.NamespaceScoped() {
|
if strategy.NamespaceScoped() {
|
||||||
if !api.ValidNamespace(ctx, objectMeta) {
|
if !ValidNamespace(ctx, objectMeta) {
|
||||||
return errors.NewBadRequest("the namespace of the provided object does not match the namespace sent on the request")
|
return errors.NewBadRequest("the namespace of the provided object does not match the namespace sent on the request")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -22,7 +22,6 @@ go_library(
|
||||||
"//vendor:k8s.io/apimachinery/pkg/conversion",
|
"//vendor:k8s.io/apimachinery/pkg/conversion",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
|
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
|
||||||
"//vendor:k8s.io/apiserver/pkg/authentication/user",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -19,10 +19,13 @@ package v0
|
||||||
import (
|
import (
|
||||||
"k8s.io/apimachinery/pkg/conversion"
|
"k8s.io/apimachinery/pkg/conversion"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apiserver/pkg/authentication/user"
|
|
||||||
api "k8s.io/kubernetes/pkg/apis/abac"
|
api "k8s.io/kubernetes/pkg/apis/abac"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// allAuthenticated matches k8s.io/apiserver/pkg/authentication/user.AllAuthenticated,
|
||||||
|
// but we don't want an client library (which must include types), depending on a server library
|
||||||
|
const allAuthenticated = "system:authenticated"
|
||||||
|
|
||||||
func addConversionFuncs(scheme *runtime.Scheme) error {
|
func addConversionFuncs(scheme *runtime.Scheme) error {
|
||||||
return scheme.AddConversionFuncs(
|
return scheme.AddConversionFuncs(
|
||||||
func(in *Policy, out *api.Policy, s conversion.Scope) error {
|
func(in *Policy, out *api.Policy, s conversion.Scope) error {
|
||||||
|
@ -35,11 +38,11 @@ func addConversionFuncs(scheme *runtime.Scheme) error {
|
||||||
|
|
||||||
// In v0, unspecified user and group matches all authenticated subjects
|
// In v0, unspecified user and group matches all authenticated subjects
|
||||||
if len(in.User) == 0 && len(in.Group) == 0 {
|
if len(in.User) == 0 && len(in.Group) == 0 {
|
||||||
out.Spec.Group = user.AllAuthenticated
|
out.Spec.Group = allAuthenticated
|
||||||
}
|
}
|
||||||
// In v0, user or group of * matches all authenticated subjects
|
// In v0, user or group of * matches all authenticated subjects
|
||||||
if in.User == "*" || in.Group == "*" {
|
if in.User == "*" || in.Group == "*" {
|
||||||
out.Spec.Group = user.AllAuthenticated
|
out.Spec.Group = allAuthenticated
|
||||||
out.Spec.User = ""
|
out.Spec.User = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,6 @@ go_library(
|
||||||
"//vendor:k8s.io/apimachinery/pkg/conversion",
|
"//vendor:k8s.io/apimachinery/pkg/conversion",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
|
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
|
||||||
"//vendor:k8s.io/apiserver/pkg/authentication/user",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -19,10 +19,13 @@ package v1beta1
|
||||||
import (
|
import (
|
||||||
"k8s.io/apimachinery/pkg/conversion"
|
"k8s.io/apimachinery/pkg/conversion"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apiserver/pkg/authentication/user"
|
|
||||||
api "k8s.io/kubernetes/pkg/apis/abac"
|
api "k8s.io/kubernetes/pkg/apis/abac"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// allAuthenticated matches k8s.io/apiserver/pkg/authentication/user.AllAuthenticated,
|
||||||
|
// but we don't want an client library (which must include types), depending on a server library
|
||||||
|
const allAuthenticated = "system:authenticated"
|
||||||
|
|
||||||
func addConversionFuncs(scheme *runtime.Scheme) error {
|
func addConversionFuncs(scheme *runtime.Scheme) error {
|
||||||
return scheme.AddConversionFuncs(
|
return scheme.AddConversionFuncs(
|
||||||
func(in *Policy, out *api.Policy, s conversion.Scope) error {
|
func(in *Policy, out *api.Policy, s conversion.Scope) error {
|
||||||
|
@ -33,7 +36,7 @@ func addConversionFuncs(scheme *runtime.Scheme) error {
|
||||||
|
|
||||||
// In v1beta1, * user or group maps to all authenticated subjects
|
// In v1beta1, * user or group maps to all authenticated subjects
|
||||||
if in.Spec.User == "*" || in.Spec.Group == "*" {
|
if in.Spec.User == "*" || in.Spec.Group == "*" {
|
||||||
out.Spec.Group = user.AllAuthenticated
|
out.Spec.Group = allAuthenticated
|
||||||
out.Spec.User = ""
|
out.Spec.User = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,41 +10,25 @@ load(
|
||||||
|
|
||||||
go_library(
|
go_library(
|
||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
srcs = [
|
srcs = ["validation.go"],
|
||||||
"policy_comparator.go",
|
|
||||||
"rulevalidation.go",
|
|
||||||
"validation.go",
|
|
||||||
],
|
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
deps = [
|
deps = [
|
||||||
"//pkg/api/errors:go_default_library",
|
|
||||||
"//pkg/api/validation:go_default_library",
|
"//pkg/api/validation:go_default_library",
|
||||||
"//pkg/api/validation/path:go_default_library",
|
"//pkg/api/validation/path:go_default_library",
|
||||||
"//pkg/apis/rbac:go_default_library",
|
"//pkg/apis/rbac:go_default_library",
|
||||||
"//pkg/genericapiserver/api/request:go_default_library",
|
|
||||||
"//pkg/serviceaccount:go_default_library",
|
|
||||||
"//vendor:github.com/golang/glog",
|
|
||||||
"//vendor:k8s.io/apimachinery/pkg/util/errors",
|
|
||||||
"//vendor:k8s.io/apimachinery/pkg/util/validation/field",
|
"//vendor:k8s.io/apimachinery/pkg/util/validation/field",
|
||||||
"//vendor:k8s.io/apiserver/pkg/authentication/user",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
go_test(
|
go_test(
|
||||||
name = "go_default_test",
|
name = "go_default_test",
|
||||||
srcs = [
|
srcs = ["validation_test.go"],
|
||||||
"policy_comparator_test.go",
|
|
||||||
"rulevalidation_test.go",
|
|
||||||
"validation_test.go",
|
|
||||||
],
|
|
||||||
library = ":go_default_library",
|
library = ":go_default_library",
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
deps = [
|
deps = [
|
||||||
"//pkg/api:go_default_library",
|
"//pkg/api:go_default_library",
|
||||||
"//pkg/apis/rbac:go_default_library",
|
"//pkg/apis/rbac:go_default_library",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/util/diff",
|
|
||||||
"//vendor:k8s.io/apimachinery/pkg/util/validation/field",
|
"//vendor:k8s.io/apimachinery/pkg/util/validation/field",
|
||||||
"//vendor:k8s.io/apiserver/pkg/authentication/user",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
api "k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -293,31 +293,6 @@ func TestValidateRoleBindingUpdate(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNonResourceURLCovers(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
owner string
|
|
||||||
requested string
|
|
||||||
want bool
|
|
||||||
}{
|
|
||||||
{"*", "/api", true},
|
|
||||||
{"/api", "/api", true},
|
|
||||||
{"/apis", "/api", false},
|
|
||||||
{"/api/v1", "/api", false},
|
|
||||||
{"/api/v1", "/api/v1", true},
|
|
||||||
{"/api/*", "/api/v1", true},
|
|
||||||
{"/api/*", "/api", false},
|
|
||||||
{"/api/*/*", "/api/v1", false},
|
|
||||||
{"/*/v1/*", "/api/v1", false},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range tests {
|
|
||||||
got := nonResourceURLCovers(tc.owner, tc.requested)
|
|
||||||
if got != tc.want {
|
|
||||||
t.Errorf("nonResourceURLCovers(%q, %q): want=(%t), got=(%t)", tc.owner, tc.requested, tc.want, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type ValidateRoleTest struct {
|
type ValidateRoleTest struct {
|
||||||
role rbac.Role
|
role rbac.Role
|
||||||
wantErr bool
|
wantErr bool
|
||||||
|
|
|
@ -43,33 +43,6 @@ func TestNamespaceContext(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestValidNamespace validates that namespace rules are enforced on a resource prior to create or update
|
|
||||||
func TestValidNamespace(t *testing.T) {
|
|
||||||
ctx := genericapirequest.NewDefaultContext()
|
|
||||||
namespace, _ := genericapirequest.NamespaceFrom(ctx)
|
|
||||||
resource := api.ReplicationController{}
|
|
||||||
if !api.ValidNamespace(ctx, &resource.ObjectMeta) {
|
|
||||||
t.Fatalf("expected success")
|
|
||||||
}
|
|
||||||
if namespace != resource.Namespace {
|
|
||||||
t.Fatalf("expected resource to have the default namespace assigned during validation")
|
|
||||||
}
|
|
||||||
resource = api.ReplicationController{ObjectMeta: api.ObjectMeta{Namespace: "other"}}
|
|
||||||
if api.ValidNamespace(ctx, &resource.ObjectMeta) {
|
|
||||||
t.Fatalf("Expected error that resource and context errors do not match because resource has different namespace")
|
|
||||||
}
|
|
||||||
ctx = genericapirequest.NewContext()
|
|
||||||
if api.ValidNamespace(ctx, &resource.ObjectMeta) {
|
|
||||||
t.Fatalf("Expected error that resource and context errors do not match since context has no namespace")
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx = genericapirequest.NewContext()
|
|
||||||
ns := genericapirequest.NamespaceValue(ctx)
|
|
||||||
if ns != "" {
|
|
||||||
t.Fatalf("Expected the empty string")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//TestUserContext validates that a userinfo can be get/set on a context object
|
//TestUserContext validates that a userinfo can be get/set on a context object
|
||||||
func TestUserContext(t *testing.T) {
|
func TestUserContext(t *testing.T) {
|
||||||
ctx := genericapirequest.NewContext()
|
ctx := genericapirequest.NewContext()
|
||||||
|
|
|
@ -381,7 +381,7 @@ func (rs *REST) Update(ctx genericapirequest.Context, name string, objInfo rest.
|
||||||
}
|
}
|
||||||
|
|
||||||
service := obj.(*api.Service)
|
service := obj.(*api.Service)
|
||||||
if !api.ValidNamespace(ctx, &service.ObjectMeta) {
|
if !rest.ValidNamespace(ctx, &service.ObjectMeta) {
|
||||||
return nil, false, errors.NewConflict(api.Resource("services"), service.Namespace, fmt.Errorf("Service.Namespace does not match the provided context"))
|
return nil, false, errors.NewConflict(api.Resource("services"), service.Namespace, fmt.Errorf("Service.Namespace does not match the provided context"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ filegroup(
|
||||||
"//pkg/registry/rbac/rest:all-srcs",
|
"//pkg/registry/rbac/rest:all-srcs",
|
||||||
"//pkg/registry/rbac/role:all-srcs",
|
"//pkg/registry/rbac/role:all-srcs",
|
||||||
"//pkg/registry/rbac/rolebinding:all-srcs",
|
"//pkg/registry/rbac/rolebinding:all-srcs",
|
||||||
|
"//pkg/registry/rbac/validation:all-srcs",
|
||||||
],
|
],
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
)
|
)
|
||||||
|
|
|
@ -15,9 +15,9 @@ go_library(
|
||||||
"//pkg/api/errors:go_default_library",
|
"//pkg/api/errors:go_default_library",
|
||||||
"//pkg/api/rest:go_default_library",
|
"//pkg/api/rest:go_default_library",
|
||||||
"//pkg/apis/rbac:go_default_library",
|
"//pkg/apis/rbac:go_default_library",
|
||||||
"//pkg/apis/rbac/validation:go_default_library",
|
|
||||||
"//pkg/genericapiserver/api/request:go_default_library",
|
"//pkg/genericapiserver/api/request:go_default_library",
|
||||||
"//pkg/registry/rbac:go_default_library",
|
"//pkg/registry/rbac:go_default_library",
|
||||||
|
"//pkg/registry/rbac/validation:go_default_library",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -22,9 +22,9 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/api/errors"
|
"k8s.io/kubernetes/pkg/api/errors"
|
||||||
"k8s.io/kubernetes/pkg/api/rest"
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||||
"k8s.io/kubernetes/pkg/apis/rbac/validation"
|
|
||||||
genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request"
|
genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request"
|
||||||
rbacregistry "k8s.io/kubernetes/pkg/registry/rbac"
|
rbacregistry "k8s.io/kubernetes/pkg/registry/rbac"
|
||||||
|
rbacregistryvalidation "k8s.io/kubernetes/pkg/registry/rbac/validation"
|
||||||
)
|
)
|
||||||
|
|
||||||
var groupResource = rbac.Resource("clusterroles")
|
var groupResource = rbac.Resource("clusterroles")
|
||||||
|
@ -32,10 +32,10 @@ var groupResource = rbac.Resource("clusterroles")
|
||||||
type Storage struct {
|
type Storage struct {
|
||||||
rest.StandardStorage
|
rest.StandardStorage
|
||||||
|
|
||||||
ruleResolver validation.AuthorizationRuleResolver
|
ruleResolver rbacregistryvalidation.AuthorizationRuleResolver
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStorage(s rest.StandardStorage, ruleResolver validation.AuthorizationRuleResolver) *Storage {
|
func NewStorage(s rest.StandardStorage, ruleResolver rbacregistryvalidation.AuthorizationRuleResolver) *Storage {
|
||||||
return &Storage{s, ruleResolver}
|
return &Storage{s, ruleResolver}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ func (s *Storage) Create(ctx genericapirequest.Context, obj runtime.Object) (run
|
||||||
|
|
||||||
clusterRole := obj.(*rbac.ClusterRole)
|
clusterRole := obj.(*rbac.ClusterRole)
|
||||||
rules := clusterRole.Rules
|
rules := clusterRole.Rules
|
||||||
if err := validation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
|
if err := rbacregistryvalidation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
|
||||||
return nil, errors.NewForbidden(groupResource, clusterRole.Name, err)
|
return nil, errors.NewForbidden(groupResource, clusterRole.Name, err)
|
||||||
}
|
}
|
||||||
return s.StandardStorage.Create(ctx, obj)
|
return s.StandardStorage.Create(ctx, obj)
|
||||||
|
@ -61,7 +61,7 @@ func (s *Storage) Update(ctx genericapirequest.Context, name string, obj rest.Up
|
||||||
clusterRole := obj.(*rbac.ClusterRole)
|
clusterRole := obj.(*rbac.ClusterRole)
|
||||||
|
|
||||||
rules := clusterRole.Rules
|
rules := clusterRole.Rules
|
||||||
if err := validation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
|
if err := rbacregistryvalidation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
|
||||||
return nil, errors.NewForbidden(groupResource, clusterRole.Name, err)
|
return nil, errors.NewForbidden(groupResource, clusterRole.Name, err)
|
||||||
}
|
}
|
||||||
return obj, nil
|
return obj, nil
|
||||||
|
|
|
@ -15,9 +15,9 @@ go_library(
|
||||||
"//pkg/api/errors:go_default_library",
|
"//pkg/api/errors:go_default_library",
|
||||||
"//pkg/api/rest:go_default_library",
|
"//pkg/api/rest:go_default_library",
|
||||||
"//pkg/apis/rbac:go_default_library",
|
"//pkg/apis/rbac:go_default_library",
|
||||||
"//pkg/apis/rbac/validation:go_default_library",
|
|
||||||
"//pkg/genericapiserver/api/request:go_default_library",
|
"//pkg/genericapiserver/api/request:go_default_library",
|
||||||
"//pkg/registry/rbac:go_default_library",
|
"//pkg/registry/rbac:go_default_library",
|
||||||
|
"//pkg/registry/rbac/validation:go_default_library",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||||
"//vendor:k8s.io/apiserver/pkg/authorization/authorizer",
|
"//vendor:k8s.io/apiserver/pkg/authorization/authorizer",
|
||||||
],
|
],
|
||||||
|
|
|
@ -23,9 +23,9 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/api/errors"
|
"k8s.io/kubernetes/pkg/api/errors"
|
||||||
"k8s.io/kubernetes/pkg/api/rest"
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||||
"k8s.io/kubernetes/pkg/apis/rbac/validation"
|
|
||||||
genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request"
|
genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request"
|
||||||
rbacregistry "k8s.io/kubernetes/pkg/registry/rbac"
|
rbacregistry "k8s.io/kubernetes/pkg/registry/rbac"
|
||||||
|
rbacregistryvalidation "k8s.io/kubernetes/pkg/registry/rbac/validation"
|
||||||
)
|
)
|
||||||
|
|
||||||
var groupResource = rbac.Resource("clusterrolebindings")
|
var groupResource = rbac.Resource("clusterrolebindings")
|
||||||
|
@ -35,10 +35,10 @@ type Storage struct {
|
||||||
|
|
||||||
authorizer authorizer.Authorizer
|
authorizer authorizer.Authorizer
|
||||||
|
|
||||||
ruleResolver validation.AuthorizationRuleResolver
|
ruleResolver rbacregistryvalidation.AuthorizationRuleResolver
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStorage(s rest.StandardStorage, authorizer authorizer.Authorizer, ruleResolver validation.AuthorizationRuleResolver) *Storage {
|
func NewStorage(s rest.StandardStorage, authorizer authorizer.Authorizer, ruleResolver rbacregistryvalidation.AuthorizationRuleResolver) *Storage {
|
||||||
return &Storage{s, authorizer, ruleResolver}
|
return &Storage{s, authorizer, ruleResolver}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ func (s *Storage) Create(ctx genericapirequest.Context, obj runtime.Object) (run
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := validation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
|
if err := rbacregistryvalidation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
|
||||||
return nil, errors.NewForbidden(groupResource, clusterRoleBinding.Name, err)
|
return nil, errors.NewForbidden(groupResource, clusterRoleBinding.Name, err)
|
||||||
}
|
}
|
||||||
return s.StandardStorage.Create(ctx, obj)
|
return s.StandardStorage.Create(ctx, obj)
|
||||||
|
@ -80,7 +80,7 @@ func (s *Storage) Update(ctx genericapirequest.Context, name string, obj rest.Up
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := validation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
|
if err := rbacregistryvalidation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
|
||||||
return nil, errors.NewForbidden(groupResource, clusterRoleBinding.Name, err)
|
return nil, errors.NewForbidden(groupResource, clusterRoleBinding.Name, err)
|
||||||
}
|
}
|
||||||
return obj, nil
|
return obj, nil
|
||||||
|
|
|
@ -16,7 +16,6 @@ go_library(
|
||||||
"//pkg/api/rest:go_default_library",
|
"//pkg/api/rest:go_default_library",
|
||||||
"//pkg/apis/rbac:go_default_library",
|
"//pkg/apis/rbac:go_default_library",
|
||||||
"//pkg/apis/rbac/v1alpha1:go_default_library",
|
"//pkg/apis/rbac/v1alpha1:go_default_library",
|
||||||
"//pkg/apis/rbac/validation:go_default_library",
|
|
||||||
"//pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion:go_default_library",
|
"//pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion:go_default_library",
|
||||||
"//pkg/genericapiserver:go_default_library",
|
"//pkg/genericapiserver:go_default_library",
|
||||||
"//pkg/registry/generic:go_default_library",
|
"//pkg/registry/generic:go_default_library",
|
||||||
|
@ -32,6 +31,7 @@ go_library(
|
||||||
"//pkg/registry/rbac/rolebinding:go_default_library",
|
"//pkg/registry/rbac/rolebinding:go_default_library",
|
||||||
"//pkg/registry/rbac/rolebinding/etcd:go_default_library",
|
"//pkg/registry/rbac/rolebinding/etcd:go_default_library",
|
||||||
"//pkg/registry/rbac/rolebinding/policybased:go_default_library",
|
"//pkg/registry/rbac/rolebinding/policybased:go_default_library",
|
||||||
|
"//pkg/registry/rbac/validation:go_default_library",
|
||||||
"//plugin/pkg/auth/authorizer/rbac/bootstrappolicy:go_default_library",
|
"//plugin/pkg/auth/authorizer/rbac/bootstrappolicy:go_default_library",
|
||||||
"//vendor:github.com/golang/glog",
|
"//vendor:github.com/golang/glog",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/util/runtime",
|
"//vendor:k8s.io/apimachinery/pkg/util/runtime",
|
||||||
|
|
|
@ -30,7 +30,6 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/api/rest"
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||||
rbacapiv1alpha1 "k8s.io/kubernetes/pkg/apis/rbac/v1alpha1"
|
rbacapiv1alpha1 "k8s.io/kubernetes/pkg/apis/rbac/v1alpha1"
|
||||||
rbacvalidation "k8s.io/kubernetes/pkg/apis/rbac/validation"
|
|
||||||
rbacclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion"
|
rbacclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion"
|
||||||
"k8s.io/kubernetes/pkg/genericapiserver"
|
"k8s.io/kubernetes/pkg/genericapiserver"
|
||||||
"k8s.io/kubernetes/pkg/registry/generic"
|
"k8s.io/kubernetes/pkg/registry/generic"
|
||||||
|
@ -46,6 +45,7 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/registry/rbac/rolebinding"
|
"k8s.io/kubernetes/pkg/registry/rbac/rolebinding"
|
||||||
rolebindingetcd "k8s.io/kubernetes/pkg/registry/rbac/rolebinding/etcd"
|
rolebindingetcd "k8s.io/kubernetes/pkg/registry/rbac/rolebinding/etcd"
|
||||||
rolebindingpolicybased "k8s.io/kubernetes/pkg/registry/rbac/rolebinding/policybased"
|
rolebindingpolicybased "k8s.io/kubernetes/pkg/registry/rbac/rolebinding/policybased"
|
||||||
|
rbacregistryvalidation "k8s.io/kubernetes/pkg/registry/rbac/validation"
|
||||||
"k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac/bootstrappolicy"
|
"k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac/bootstrappolicy"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ func (p RESTStorageProvider) v1alpha1Storage(apiResourceConfigSource genericapis
|
||||||
|
|
||||||
once := new(sync.Once)
|
once := new(sync.Once)
|
||||||
var (
|
var (
|
||||||
authorizationRuleResolver rbacvalidation.AuthorizationRuleResolver
|
authorizationRuleResolver rbacregistryvalidation.AuthorizationRuleResolver
|
||||||
rolesStorage rest.StandardStorage
|
rolesStorage rest.StandardStorage
|
||||||
roleBindingsStorage rest.StandardStorage
|
roleBindingsStorage rest.StandardStorage
|
||||||
clusterRolesStorage rest.StandardStorage
|
clusterRolesStorage rest.StandardStorage
|
||||||
|
@ -85,7 +85,7 @@ func (p RESTStorageProvider) v1alpha1Storage(apiResourceConfigSource genericapis
|
||||||
clusterRolesStorage = clusterroleetcd.NewREST(restOptionsGetter)
|
clusterRolesStorage = clusterroleetcd.NewREST(restOptionsGetter)
|
||||||
clusterRoleBindingsStorage = clusterrolebindingetcd.NewREST(restOptionsGetter)
|
clusterRoleBindingsStorage = clusterrolebindingetcd.NewREST(restOptionsGetter)
|
||||||
|
|
||||||
authorizationRuleResolver = rbacvalidation.NewDefaultRuleResolver(
|
authorizationRuleResolver = rbacregistryvalidation.NewDefaultRuleResolver(
|
||||||
role.AuthorizerAdapter{Registry: role.NewRegistry(rolesStorage)},
|
role.AuthorizerAdapter{Registry: role.NewRegistry(rolesStorage)},
|
||||||
rolebinding.AuthorizerAdapter{Registry: rolebinding.NewRegistry(roleBindingsStorage)},
|
rolebinding.AuthorizerAdapter{Registry: rolebinding.NewRegistry(roleBindingsStorage)},
|
||||||
clusterrole.AuthorizerAdapter{Registry: clusterrole.NewRegistry(clusterRolesStorage)},
|
clusterrole.AuthorizerAdapter{Registry: clusterrole.NewRegistry(clusterRolesStorage)},
|
||||||
|
|
|
@ -15,9 +15,9 @@ go_library(
|
||||||
"//pkg/api/errors:go_default_library",
|
"//pkg/api/errors:go_default_library",
|
||||||
"//pkg/api/rest:go_default_library",
|
"//pkg/api/rest:go_default_library",
|
||||||
"//pkg/apis/rbac:go_default_library",
|
"//pkg/apis/rbac:go_default_library",
|
||||||
"//pkg/apis/rbac/validation:go_default_library",
|
|
||||||
"//pkg/genericapiserver/api/request:go_default_library",
|
"//pkg/genericapiserver/api/request:go_default_library",
|
||||||
"//pkg/registry/rbac:go_default_library",
|
"//pkg/registry/rbac:go_default_library",
|
||||||
|
"//pkg/registry/rbac/validation:go_default_library",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -22,9 +22,9 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/api/errors"
|
"k8s.io/kubernetes/pkg/api/errors"
|
||||||
"k8s.io/kubernetes/pkg/api/rest"
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||||
"k8s.io/kubernetes/pkg/apis/rbac/validation"
|
|
||||||
genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request"
|
genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request"
|
||||||
rbacregistry "k8s.io/kubernetes/pkg/registry/rbac"
|
rbacregistry "k8s.io/kubernetes/pkg/registry/rbac"
|
||||||
|
rbacregistryvalidation "k8s.io/kubernetes/pkg/registry/rbac/validation"
|
||||||
)
|
)
|
||||||
|
|
||||||
var groupResource = rbac.Resource("roles")
|
var groupResource = rbac.Resource("roles")
|
||||||
|
@ -32,10 +32,10 @@ var groupResource = rbac.Resource("roles")
|
||||||
type Storage struct {
|
type Storage struct {
|
||||||
rest.StandardStorage
|
rest.StandardStorage
|
||||||
|
|
||||||
ruleResolver validation.AuthorizationRuleResolver
|
ruleResolver rbacregistryvalidation.AuthorizationRuleResolver
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStorage(s rest.StandardStorage, ruleResolver validation.AuthorizationRuleResolver) *Storage {
|
func NewStorage(s rest.StandardStorage, ruleResolver rbacregistryvalidation.AuthorizationRuleResolver) *Storage {
|
||||||
return &Storage{s, ruleResolver}
|
return &Storage{s, ruleResolver}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ func (s *Storage) Create(ctx genericapirequest.Context, obj runtime.Object) (run
|
||||||
|
|
||||||
role := obj.(*rbac.Role)
|
role := obj.(*rbac.Role)
|
||||||
rules := role.Rules
|
rules := role.Rules
|
||||||
if err := validation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
|
if err := rbacregistryvalidation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
|
||||||
return nil, errors.NewForbidden(groupResource, role.Name, err)
|
return nil, errors.NewForbidden(groupResource, role.Name, err)
|
||||||
}
|
}
|
||||||
return s.StandardStorage.Create(ctx, obj)
|
return s.StandardStorage.Create(ctx, obj)
|
||||||
|
@ -61,7 +61,7 @@ func (s *Storage) Update(ctx genericapirequest.Context, name string, obj rest.Up
|
||||||
role := obj.(*rbac.Role)
|
role := obj.(*rbac.Role)
|
||||||
|
|
||||||
rules := role.Rules
|
rules := role.Rules
|
||||||
if err := validation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
|
if err := rbacregistryvalidation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
|
||||||
return nil, errors.NewForbidden(groupResource, role.Name, err)
|
return nil, errors.NewForbidden(groupResource, role.Name, err)
|
||||||
}
|
}
|
||||||
return obj, nil
|
return obj, nil
|
||||||
|
|
|
@ -15,9 +15,9 @@ go_library(
|
||||||
"//pkg/api/errors:go_default_library",
|
"//pkg/api/errors:go_default_library",
|
||||||
"//pkg/api/rest:go_default_library",
|
"//pkg/api/rest:go_default_library",
|
||||||
"//pkg/apis/rbac:go_default_library",
|
"//pkg/apis/rbac:go_default_library",
|
||||||
"//pkg/apis/rbac/validation:go_default_library",
|
|
||||||
"//pkg/genericapiserver/api/request:go_default_library",
|
"//pkg/genericapiserver/api/request:go_default_library",
|
||||||
"//pkg/registry/rbac:go_default_library",
|
"//pkg/registry/rbac:go_default_library",
|
||||||
|
"//pkg/registry/rbac/validation:go_default_library",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||||
"//vendor:k8s.io/apiserver/pkg/authorization/authorizer",
|
"//vendor:k8s.io/apiserver/pkg/authorization/authorizer",
|
||||||
],
|
],
|
||||||
|
|
|
@ -23,9 +23,9 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/api/errors"
|
"k8s.io/kubernetes/pkg/api/errors"
|
||||||
"k8s.io/kubernetes/pkg/api/rest"
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||||
"k8s.io/kubernetes/pkg/apis/rbac/validation"
|
|
||||||
genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request"
|
genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request"
|
||||||
rbacregistry "k8s.io/kubernetes/pkg/registry/rbac"
|
rbacregistry "k8s.io/kubernetes/pkg/registry/rbac"
|
||||||
|
rbacregistryvalidation "k8s.io/kubernetes/pkg/registry/rbac/validation"
|
||||||
)
|
)
|
||||||
|
|
||||||
var groupResource = rbac.Resource("rolebindings")
|
var groupResource = rbac.Resource("rolebindings")
|
||||||
|
@ -35,10 +35,10 @@ type Storage struct {
|
||||||
|
|
||||||
authorizer authorizer.Authorizer
|
authorizer authorizer.Authorizer
|
||||||
|
|
||||||
ruleResolver validation.AuthorizationRuleResolver
|
ruleResolver rbacregistryvalidation.AuthorizationRuleResolver
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStorage(s rest.StandardStorage, authorizer authorizer.Authorizer, ruleResolver validation.AuthorizationRuleResolver) *Storage {
|
func NewStorage(s rest.StandardStorage, authorizer authorizer.Authorizer, ruleResolver rbacregistryvalidation.AuthorizationRuleResolver) *Storage {
|
||||||
return &Storage{s, authorizer, ruleResolver}
|
return &Storage{s, authorizer, ruleResolver}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ func (s *Storage) Create(ctx genericapirequest.Context, obj runtime.Object) (run
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := validation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
|
if err := rbacregistryvalidation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
|
||||||
return nil, errors.NewForbidden(groupResource, roleBinding.Name, err)
|
return nil, errors.NewForbidden(groupResource, roleBinding.Name, err)
|
||||||
}
|
}
|
||||||
return s.StandardStorage.Create(ctx, obj)
|
return s.StandardStorage.Create(ctx, obj)
|
||||||
|
@ -80,7 +80,7 @@ func (s *Storage) Update(ctx genericapirequest.Context, name string, obj rest.Up
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := validation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
|
if err := rbacregistryvalidation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
|
||||||
return nil, errors.NewForbidden(groupResource, roleBinding.Name, err)
|
return nil, errors.NewForbidden(groupResource, roleBinding.Name, err)
|
||||||
}
|
}
|
||||||
return obj, nil
|
return obj, nil
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
package(default_visibility = ["//visibility:public"])
|
||||||
|
|
||||||
|
licenses(["notice"])
|
||||||
|
|
||||||
|
load(
|
||||||
|
"@io_bazel_rules_go//go:def.bzl",
|
||||||
|
"go_library",
|
||||||
|
"go_test",
|
||||||
|
)
|
||||||
|
|
||||||
|
go_test(
|
||||||
|
name = "go_default_test",
|
||||||
|
srcs = [
|
||||||
|
"policy_comparator_test.go",
|
||||||
|
"rule_test.go",
|
||||||
|
],
|
||||||
|
library = ":go_default_library",
|
||||||
|
tags = ["automanaged"],
|
||||||
|
deps = [
|
||||||
|
"//pkg/api:go_default_library",
|
||||||
|
"//pkg/apis/rbac:go_default_library",
|
||||||
|
"//vendor:k8s.io/apimachinery/pkg/util/diff",
|
||||||
|
"//vendor:k8s.io/apiserver/pkg/authentication/user",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
go_library(
|
||||||
|
name = "go_default_library",
|
||||||
|
srcs = [
|
||||||
|
"policy_comparator.go",
|
||||||
|
"rule.go",
|
||||||
|
],
|
||||||
|
tags = ["automanaged"],
|
||||||
|
deps = [
|
||||||
|
"//pkg/api/errors:go_default_library",
|
||||||
|
"//pkg/apis/rbac:go_default_library",
|
||||||
|
"//pkg/genericapiserver/api/request:go_default_library",
|
||||||
|
"//pkg/serviceaccount:go_default_library",
|
||||||
|
"//vendor:github.com/golang/glog",
|
||||||
|
"//vendor:k8s.io/apimachinery/pkg/util/errors",
|
||||||
|
"//vendor:k8s.io/apiserver/pkg/authentication/user",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "package-srcs",
|
||||||
|
srcs = glob(["**"]),
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:private"],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "all-srcs",
|
||||||
|
srcs = [":package-srcs"],
|
||||||
|
tags = ["automanaged"],
|
||||||
|
)
|
|
@ -400,3 +400,28 @@ func rulesMatch(expectedRules, actualRules []rbac.PolicyRule) bool {
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNonResourceURLCovers(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
owner string
|
||||||
|
requested string
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{"*", "/api", true},
|
||||||
|
{"/api", "/api", true},
|
||||||
|
{"/apis", "/api", false},
|
||||||
|
{"/api/v1", "/api", false},
|
||||||
|
{"/api/v1", "/api/v1", true},
|
||||||
|
{"/api/*", "/api/v1", true},
|
||||||
|
{"/api/*", "/api", false},
|
||||||
|
{"/api/*/*", "/api/v1", false},
|
||||||
|
{"/*/v1/*", "/api/v1", false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
got := nonResourceURLCovers(tc.owner, tc.requested)
|
||||||
|
if got != tc.want {
|
||||||
|
t.Errorf("nonResourceURLCovers(%q, %q): want=(%t), got=(%t)", tc.owner, tc.requested, tc.want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,7 +17,7 @@ go_library(
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
deps = [
|
deps = [
|
||||||
"//pkg/apis/rbac:go_default_library",
|
"//pkg/apis/rbac:go_default_library",
|
||||||
"//pkg/apis/rbac/validation:go_default_library",
|
"//pkg/registry/rbac/validation:go_default_library",
|
||||||
"//vendor:github.com/golang/glog",
|
"//vendor:github.com/golang/glog",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/util/errors",
|
"//vendor:k8s.io/apimachinery/pkg/util/errors",
|
||||||
"//vendor:k8s.io/apiserver/pkg/authentication/user",
|
"//vendor:k8s.io/apiserver/pkg/authentication/user",
|
||||||
|
@ -36,7 +36,7 @@ go_test(
|
||||||
deps = [
|
deps = [
|
||||||
"//pkg/api:go_default_library",
|
"//pkg/api:go_default_library",
|
||||||
"//pkg/apis/rbac:go_default_library",
|
"//pkg/apis/rbac:go_default_library",
|
||||||
"//pkg/apis/rbac/validation:go_default_library",
|
"//pkg/registry/rbac/validation:go_default_library",
|
||||||
"//vendor:k8s.io/apiserver/pkg/authentication/user",
|
"//vendor:k8s.io/apiserver/pkg/authentication/user",
|
||||||
"//vendor:k8s.io/apiserver/pkg/authorization/authorizer",
|
"//vendor:k8s.io/apiserver/pkg/authorization/authorizer",
|
||||||
],
|
],
|
||||||
|
|
|
@ -37,7 +37,7 @@ go_test(
|
||||||
"//pkg/apis/rbac:go_default_library",
|
"//pkg/apis/rbac:go_default_library",
|
||||||
"//pkg/apis/rbac/install:go_default_library",
|
"//pkg/apis/rbac/install:go_default_library",
|
||||||
"//pkg/apis/rbac/v1alpha1:go_default_library",
|
"//pkg/apis/rbac/v1alpha1:go_default_library",
|
||||||
"//pkg/apis/rbac/validation:go_default_library",
|
"//pkg/registry/rbac/validation:go_default_library",
|
||||||
"//plugin/pkg/auth/authorizer/rbac/bootstrappolicy:go_default_library",
|
"//plugin/pkg/auth/authorizer/rbac/bootstrappolicy:go_default_library",
|
||||||
"//vendor:github.com/ghodss/yaml",
|
"//vendor:github.com/ghodss/yaml",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/api/meta",
|
"//vendor:k8s.io/apimachinery/pkg/api/meta",
|
||||||
|
|
|
@ -32,10 +32,10 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
_ "k8s.io/kubernetes/pkg/api/install"
|
_ "k8s.io/kubernetes/pkg/api/install"
|
||||||
"k8s.io/kubernetes/pkg/api/v1"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
rbac "k8s.io/kubernetes/pkg/apis/rbac"
|
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||||
_ "k8s.io/kubernetes/pkg/apis/rbac/install"
|
_ "k8s.io/kubernetes/pkg/apis/rbac/install"
|
||||||
rbacv1alpha1 "k8s.io/kubernetes/pkg/apis/rbac/v1alpha1"
|
rbacv1alpha1 "k8s.io/kubernetes/pkg/apis/rbac/v1alpha1"
|
||||||
rbacvalidation "k8s.io/kubernetes/pkg/apis/rbac/validation"
|
rbacregistryvalidation "k8s.io/kubernetes/pkg/registry/rbac/validation"
|
||||||
"k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac/bootstrappolicy"
|
"k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac/bootstrappolicy"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -67,13 +67,13 @@ func getSemanticRoles(roles []rbac.ClusterRole) semanticRoles {
|
||||||
func TestCovers(t *testing.T) {
|
func TestCovers(t *testing.T) {
|
||||||
semanticRoles := getSemanticRoles(bootstrappolicy.ClusterRoles())
|
semanticRoles := getSemanticRoles(bootstrappolicy.ClusterRoles())
|
||||||
|
|
||||||
if covers, miss := rbacvalidation.Covers(semanticRoles.admin.Rules, semanticRoles.edit.Rules); !covers {
|
if covers, miss := rbacregistryvalidation.Covers(semanticRoles.admin.Rules, semanticRoles.edit.Rules); !covers {
|
||||||
t.Errorf("failed to cover: %#v", miss)
|
t.Errorf("failed to cover: %#v", miss)
|
||||||
}
|
}
|
||||||
if covers, miss := rbacvalidation.Covers(semanticRoles.admin.Rules, semanticRoles.view.Rules); !covers {
|
if covers, miss := rbacregistryvalidation.Covers(semanticRoles.admin.Rules, semanticRoles.view.Rules); !covers {
|
||||||
t.Errorf("failed to cover: %#v", miss)
|
t.Errorf("failed to cover: %#v", miss)
|
||||||
}
|
}
|
||||||
if covers, miss := rbacvalidation.Covers(semanticRoles.edit.Rules, semanticRoles.view.Rules); !covers {
|
if covers, miss := rbacregistryvalidation.Covers(semanticRoles.edit.Rules, semanticRoles.view.Rules); !covers {
|
||||||
t.Errorf("failed to cover: %#v", miss)
|
t.Errorf("failed to cover: %#v", miss)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,17 +91,17 @@ func TestAdminEditRelationship(t *testing.T) {
|
||||||
|
|
||||||
// confirm that the edit role doesn't already have extra powers
|
// confirm that the edit role doesn't already have extra powers
|
||||||
for _, rule := range additionalAdminPowers {
|
for _, rule := range additionalAdminPowers {
|
||||||
if covers, _ := rbacvalidation.Covers(semanticRoles.edit.Rules, []rbac.PolicyRule{rule}); covers {
|
if covers, _ := rbacregistryvalidation.Covers(semanticRoles.edit.Rules, []rbac.PolicyRule{rule}); covers {
|
||||||
t.Errorf("edit has extra powers: %#v", rule)
|
t.Errorf("edit has extra powers: %#v", rule)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
semanticRoles.edit.Rules = append(semanticRoles.edit.Rules, additionalAdminPowers...)
|
semanticRoles.edit.Rules = append(semanticRoles.edit.Rules, additionalAdminPowers...)
|
||||||
|
|
||||||
// at this point, we should have a two way covers relationship
|
// at this point, we should have a two way covers relationship
|
||||||
if covers, miss := rbacvalidation.Covers(semanticRoles.admin.Rules, semanticRoles.edit.Rules); !covers {
|
if covers, miss := rbacregistryvalidation.Covers(semanticRoles.admin.Rules, semanticRoles.edit.Rules); !covers {
|
||||||
t.Errorf("admin has lost rules for: %#v", miss)
|
t.Errorf("admin has lost rules for: %#v", miss)
|
||||||
}
|
}
|
||||||
if covers, miss := rbacvalidation.Covers(semanticRoles.edit.Rules, semanticRoles.admin.Rules); !covers {
|
if covers, miss := rbacregistryvalidation.Covers(semanticRoles.edit.Rules, semanticRoles.admin.Rules); !covers {
|
||||||
t.Errorf("edit is missing rules for: %#v\nIf these should only be admin powers, add them to the list. Otherwise, add them to the edit role.", miss)
|
t.Errorf("edit is missing rules for: %#v\nIf these should only be admin powers, add them to the list. Otherwise, add them to the edit role.", miss)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -136,17 +136,17 @@ func TestEditViewRelationship(t *testing.T) {
|
||||||
|
|
||||||
// confirm that the view role doesn't already have extra powers
|
// confirm that the view role doesn't already have extra powers
|
||||||
for _, rule := range viewEscalatingNamespaceResources {
|
for _, rule := range viewEscalatingNamespaceResources {
|
||||||
if covers, _ := rbacvalidation.Covers(semanticRoles.view.Rules, []rbac.PolicyRule{rule}); covers {
|
if covers, _ := rbacregistryvalidation.Covers(semanticRoles.view.Rules, []rbac.PolicyRule{rule}); covers {
|
||||||
t.Errorf("view has extra powers: %#v", rule)
|
t.Errorf("view has extra powers: %#v", rule)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
semanticRoles.view.Rules = append(semanticRoles.view.Rules, viewEscalatingNamespaceResources...)
|
semanticRoles.view.Rules = append(semanticRoles.view.Rules, viewEscalatingNamespaceResources...)
|
||||||
|
|
||||||
// at this point, we should have a two way covers relationship
|
// at this point, we should have a two way covers relationship
|
||||||
if covers, miss := rbacvalidation.Covers(semanticRoles.edit.Rules, semanticRoles.view.Rules); !covers {
|
if covers, miss := rbacregistryvalidation.Covers(semanticRoles.edit.Rules, semanticRoles.view.Rules); !covers {
|
||||||
t.Errorf("edit has lost rules for: %#v", miss)
|
t.Errorf("edit has lost rules for: %#v", miss)
|
||||||
}
|
}
|
||||||
if covers, miss := rbacvalidation.Covers(semanticRoles.view.Rules, semanticRoles.edit.Rules); !covers {
|
if covers, miss := rbacregistryvalidation.Covers(semanticRoles.view.Rules, semanticRoles.edit.Rules); !covers {
|
||||||
t.Errorf("view is missing rules for: %#v\nIf these are escalating powers, add them to the list. Otherwise, add them to the view role.", miss)
|
t.Errorf("view is missing rules for: %#v\nIf these are escalating powers, add them to the list. Otherwise, add them to the view role.", miss)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ import (
|
||||||
"k8s.io/apiserver/pkg/authentication/user"
|
"k8s.io/apiserver/pkg/authentication/user"
|
||||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||||
"k8s.io/kubernetes/pkg/apis/rbac/validation"
|
rbacregistryvalidation "k8s.io/kubernetes/pkg/registry/rbac/validation"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RequestToRuleMapper interface {
|
type RequestToRuleMapper interface {
|
||||||
|
@ -55,9 +55,9 @@ func (r *RBACAuthorizer) Authorize(requestAttributes authorizer.Attributes) (boo
|
||||||
return false, reason, nil
|
return false, reason, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(roles validation.RoleGetter, roleBindings validation.RoleBindingLister, clusterRoles validation.ClusterRoleGetter, clusterRoleBindings validation.ClusterRoleBindingLister) *RBACAuthorizer {
|
func New(roles rbacregistryvalidation.RoleGetter, roleBindings rbacregistryvalidation.RoleBindingLister, clusterRoles rbacregistryvalidation.ClusterRoleGetter, clusterRoleBindings rbacregistryvalidation.ClusterRoleBindingLister) *RBACAuthorizer {
|
||||||
authorizer := &RBACAuthorizer{
|
authorizer := &RBACAuthorizer{
|
||||||
authorizationRuleResolver: validation.NewDefaultRuleResolver(
|
authorizationRuleResolver: rbacregistryvalidation.NewDefaultRuleResolver(
|
||||||
roles, roleBindings, clusterRoles, clusterRoleBindings,
|
roles, roleBindings, clusterRoles, clusterRoleBindings,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ import (
|
||||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||||
"k8s.io/kubernetes/pkg/apis/rbac/validation"
|
rbacregistryvalidation "k8s.io/kubernetes/pkg/registry/rbac/validation"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newRule(verbs, apiGroups, resources, nonResourceURLs string) rbac.PolicyRule {
|
func newRule(verbs, apiGroups, resources, nonResourceURLs string) rbac.PolicyRule {
|
||||||
|
@ -219,7 +219,7 @@ func TestAuthorizer(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for i, tt := range tests {
|
for i, tt := range tests {
|
||||||
ruleResolver, _ := validation.NewTestRuleResolver(tt.roles, tt.roleBindings, tt.clusterRoles, tt.clusterRoleBindings)
|
ruleResolver, _ := rbacregistryvalidation.NewTestRuleResolver(tt.roles, tt.roleBindings, tt.clusterRoles, tt.clusterRoleBindings)
|
||||||
a := RBACAuthorizer{ruleResolver}
|
a := RBACAuthorizer{ruleResolver}
|
||||||
for _, attr := range tt.shouldPass {
|
for _, attr := range tt.shouldPass {
|
||||||
if authorized, _, _ := a.Authorize(attr); !authorized {
|
if authorized, _, _ := a.Authorize(attr); !authorized {
|
||||||
|
|
|
@ -22,7 +22,7 @@ import (
|
||||||
"k8s.io/apiserver/pkg/authentication/user"
|
"k8s.io/apiserver/pkg/authentication/user"
|
||||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||||
"k8s.io/kubernetes/pkg/apis/rbac/validation"
|
rbacregistryvalidation "k8s.io/kubernetes/pkg/registry/rbac/validation"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RoleToRuleMapper interface {
|
type RoleToRuleMapper interface {
|
||||||
|
@ -34,17 +34,17 @@ type RoleToRuleMapper interface {
|
||||||
type SubjectAccessEvaluator struct {
|
type SubjectAccessEvaluator struct {
|
||||||
superUser string
|
superUser string
|
||||||
|
|
||||||
roleBindingLister validation.RoleBindingLister
|
roleBindingLister rbacregistryvalidation.RoleBindingLister
|
||||||
clusterRoleBindingLister validation.ClusterRoleBindingLister
|
clusterRoleBindingLister rbacregistryvalidation.ClusterRoleBindingLister
|
||||||
roleToRuleMapper RoleToRuleMapper
|
roleToRuleMapper RoleToRuleMapper
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSubjectAccessEvaluator(roles validation.RoleGetter, roleBindings validation.RoleBindingLister, clusterRoles validation.ClusterRoleGetter, clusterRoleBindings validation.ClusterRoleBindingLister, superUser string) *SubjectAccessEvaluator {
|
func NewSubjectAccessEvaluator(roles rbacregistryvalidation.RoleGetter, roleBindings rbacregistryvalidation.RoleBindingLister, clusterRoles rbacregistryvalidation.ClusterRoleGetter, clusterRoleBindings rbacregistryvalidation.ClusterRoleBindingLister, superUser string) *SubjectAccessEvaluator {
|
||||||
subjectLocator := &SubjectAccessEvaluator{
|
subjectLocator := &SubjectAccessEvaluator{
|
||||||
superUser: superUser,
|
superUser: superUser,
|
||||||
roleBindingLister: roleBindings,
|
roleBindingLister: roleBindings,
|
||||||
clusterRoleBindingLister: clusterRoleBindings,
|
clusterRoleBindingLister: clusterRoleBindings,
|
||||||
roleToRuleMapper: validation.NewDefaultRuleResolver(
|
roleToRuleMapper: rbacregistryvalidation.NewDefaultRuleResolver(
|
||||||
roles, roleBindings, clusterRoles, clusterRoleBindings,
|
roles, roleBindings, clusterRoles, clusterRoleBindings,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ import (
|
||||||
"k8s.io/apiserver/pkg/authentication/user"
|
"k8s.io/apiserver/pkg/authentication/user"
|
||||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||||
"k8s.io/kubernetes/pkg/apis/rbac/validation"
|
rbacregistryvalidation "k8s.io/kubernetes/pkg/registry/rbac/validation"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSubjectLocator(t *testing.T) {
|
func TestSubjectLocator(t *testing.T) {
|
||||||
|
@ -136,7 +136,7 @@ func TestSubjectLocator(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
ruleResolver, lister := validation.NewTestRuleResolver(tt.roles, tt.roleBindings, tt.clusterRoles, tt.clusterRoleBindings)
|
ruleResolver, lister := rbacregistryvalidation.NewTestRuleResolver(tt.roles, tt.roleBindings, tt.clusterRoles, tt.clusterRoleBindings)
|
||||||
a := SubjectAccessEvaluator{tt.superUser, lister, lister, ruleResolver}
|
a := SubjectAccessEvaluator{tt.superUser, lister, lister, ruleResolver}
|
||||||
for i, action := range tt.actionsToSubjects {
|
for i, action := range tt.actionsToSubjects {
|
||||||
actualSubjects, err := a.AllowedSubjects(action.action)
|
actualSubjects, err := a.AllowedSubjects(action.action)
|
||||||
|
|
Loading…
Reference in New Issue