mirror of https://github.com/k3s-io/k3s.git
add subjectaccessreviews resource
parent
5f3cc4a941
commit
32920b5617
|
@ -32,8 +32,17 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
test = flag.BoolP("test", "t", false, "set this flag to generate the client code for the testdata")
|
||||
inputVersions = flag.StringSlice("input", []string{"api/", "extensions/", "autoscaling/", "authentication/", "batch/", "rbac/", "certificates/"}, "group/versions that client-gen will generate clients for. At most one version per group is allowed. Specified in the format \"group1/version1,group2/version2...\". Default to \"api/,extensions/,autoscaling/,batch/,rbac/\"")
|
||||
test = flag.BoolP("test", "t", false, "set this flag to generate the client code for the testdata")
|
||||
inputVersions = flag.StringSlice("input", []string{
|
||||
"api/",
|
||||
"authentication/",
|
||||
"authorization/",
|
||||
"autoscaling/",
|
||||
"batch/",
|
||||
"certificates/",
|
||||
"extensions/",
|
||||
"rbac/",
|
||||
}, "group/versions that client-gen will generate clients for. At most one version per group is allowed. Specified in the format \"group1/version1,group2/version2...\". Default to \"api/,extensions/,autoscaling/,batch/,rbac/\"")
|
||||
includedTypesOverrides = flag.StringSlice("included-types-overrides", []string{}, "list of group/version/type for which client should be generated. By default, client is generated for all types which have genclient=true in types.go. This overrides that. For each groupVersion in this list, only the types mentioned here will be included. The default check of genclient=true will be used for other group versions.")
|
||||
basePath = flag.String("input-base", "k8s.io/kubernetes/pkg/apis", "base path to look for the api group. Default to \"k8s.io/kubernetes/pkg/apis\"")
|
||||
clientsetName = flag.StringP("clientset-name", "n", "internalclientset", "the name of the generated clientset package.")
|
||||
|
|
|
@ -69,6 +69,7 @@ func New() *Generator {
|
|||
`k8s.io/kubernetes/pkg/apis/policy/v1alpha1`,
|
||||
`k8s.io/kubernetes/pkg/apis/extensions/v1beta1`,
|
||||
`k8s.io/kubernetes/pkg/apis/autoscaling/v1`,
|
||||
`k8s.io/kubernetes/pkg/apis/authorization/v1beta1`,
|
||||
`k8s.io/kubernetes/pkg/apis/batch/v1`,
|
||||
`k8s.io/kubernetes/pkg/apis/batch/v2alpha1`,
|
||||
`k8s.io/kubernetes/pkg/apis/apps/v1alpha1`,
|
||||
|
|
|
@ -2328,6 +2328,26 @@ __EOF__
|
|||
kubectl create -f test/fixtures/pkg/kubectl/cmd/create/tokenreview.json --validate=false
|
||||
|
||||
|
||||
|
||||
########################
|
||||
# authorization.k8s.io #
|
||||
########################
|
||||
|
||||
# check remote authorization endpoint, kubectl doesn't actually display the returned object so this isn't super useful
|
||||
# but it proves that works
|
||||
kubectl create -f test/fixtures/pkg/kubectl/cmd/create/sar.json --validate=false
|
||||
|
||||
SAR_RESULT_FILE="${KUBE_TEMP}/sar-result.json"
|
||||
curl -k -H "Content-Type:" http://localhost:8080/apis/authorization.k8s.io/v1beta1/subjectaccessreviews -XPOST -d @test/fixtures/pkg/kubectl/cmd/create/sar.json > "${SAR_RESULT_FILE}"
|
||||
if grep -q '"allowed": true' "${SAR_RESULT_FILE}"; then
|
||||
kube::log::status "\"authorization.k8s.io/subjectaccessreviews\" returns as expected: $(cat "${SAR_RESULT_FILE}")"
|
||||
else
|
||||
kube::log::status "\"authorization.k8s.io/subjectaccessreviews\" does not return as expected: $(cat "${SAR_RESULT_FILE}")"
|
||||
exit 1
|
||||
fi
|
||||
rm "${SAR_RESULT_FILE}"
|
||||
|
||||
|
||||
#####################
|
||||
# Retrieve multiple #
|
||||
#####################
|
||||
|
|
|
@ -27,7 +27,7 @@ source "${KUBE_ROOT}/hack/lib/init.sh"
|
|||
# KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1,extensions/v1beta1"}
|
||||
# FIXME: due to current implementation of a test client (see: pkg/api/testapi/testapi.go)
|
||||
# ONLY the last version is tested in each group.
|
||||
KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1,autoscaling/v1,batch/v1,apps/v1alpha1,policy/v1alpha1,extensions/v1beta1,rbac.authorization.k8s.io/v1alpha1,certificates/v1alpha1"}
|
||||
KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1,authorization.k8s.io/v1beta1,autoscaling/v1,batch/v1,apps/v1alpha1,policy/v1alpha1,extensions/v1beta1,rbac.authorization.k8s.io/v1alpha1,certificates/v1alpha1"}
|
||||
|
||||
# Give integration tests longer to run
|
||||
# TODO: allow a larger value to be passed in
|
||||
|
|
|
@ -60,7 +60,7 @@ KUBE_GOVERALLS_BIN=${KUBE_GOVERALLS_BIN:-}
|
|||
# "v1,compute/v1alpha1,experimental/v1alpha2;v1,compute/v2,experimental/v1alpha3"
|
||||
# FIXME: due to current implementation of a test client (see: pkg/api/testapi/testapi.go)
|
||||
# ONLY the last version is tested in each group.
|
||||
KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1,autoscaling/v1,authentication.k8s.io/v1beta1,batch/v1,batch/v2alpha1,extensions/v1beta1,apps/v1alpha1,federation/v1beta1,policy/v1alpha1,rbac.authorization.k8s.io/v1alpha1,certificates/v1alpha1"}
|
||||
KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1,apps/v1alpha1,authentication.k8s.io/v1beta1,authorization.k8s.io/v1beta1,autoscaling/v1,batch/v1,batch/v2alpha1,certificates/v1alpha1,extensions/v1beta1,federation/v1beta1,policy/v1alpha1,rbac.authorization.k8s.io/v1alpha1"}
|
||||
# once we have multiple group supports
|
||||
# Create a junit-style XML test report in this directory if set.
|
||||
KUBE_JUNIT_REPORT_DIR=${KUBE_JUNIT_REPORT_DIR:-}
|
||||
|
|
|
@ -39,7 +39,7 @@ setgen=$(kube::util::find-binary "set-gen")
|
|||
# update- and verify- scripts.
|
||||
${clientgen} "$@"
|
||||
${clientgen} -t "$@"
|
||||
${clientgen} --clientset-name="release_1_4" --input="api/v1,extensions/v1beta1,autoscaling/v1,batch/v1"
|
||||
${clientgen} --clientset-name="release_1_4" --input="api/v1,authorization/v1beta1,autoscaling/v1,batch/v1,extensions/v1beta1"
|
||||
# Clientgen for federation clientset.
|
||||
${clientgen} --clientset-name=federation_internalclientset --clientset-path=k8s.io/kubernetes/federation/client/clientset_generated --input="../../federation/apis/federation/","api/","extensions/" --included-types-overrides="api/Service,api/Namespace,extensions/ReplicaSet,api/Secret" "$@"
|
||||
${clientgen} --clientset-name=federation_release_1_4 --clientset-path=k8s.io/kubernetes/federation/client/clientset_generated --input="../../federation/apis/federation/v1beta1","api/v1","extensions/v1beta1" --included-types-overrides="api/v1/Service,api/v1/Namespace,extensions/v1beta1/ReplicaSet,api/v1/Secret" "$@"
|
||||
|
|
|
@ -74,7 +74,7 @@ APISERVER_PID=$!
|
|||
kube::util::wait_for_url "http://127.0.0.1:${API_PORT}/healthz" "apiserver: "
|
||||
|
||||
SWAGGER_API_PATH="http://127.0.0.1:${API_PORT}/swaggerapi/"
|
||||
DEFAULT_GROUP_VERSIONS="v1 authentication.k8s.io/v1beta1 autoscaling/v1 batch/v1 batch/v2alpha1 extensions/v1beta1 apps/v1alpha1 policy/v1alpha1 rbac.authorization.k8s.io/v1alpha1 certificates/v1alpha1"
|
||||
DEFAULT_GROUP_VERSIONS="v1 apps/v1alpha1 authentication.k8s.io/v1beta1 authorization.k8s.io/v1beta1 autoscaling/v1 batch/v1 batch/v2alpha1 extensions/v1beta1 certificates/v1alpha1 policy/v1alpha1 rbac.authorization.k8s.io/v1alpha1"
|
||||
VERSIONS=${VERSIONS:-$DEFAULT_GROUP_VERSIONS}
|
||||
|
||||
kube::log::status "Updating " ${SWAGGER_ROOT_DIR}
|
||||
|
|
|
@ -43,6 +43,7 @@ import (
|
|||
_ "k8s.io/kubernetes/pkg/api/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/apps/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/authentication/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/authorization/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/autoscaling/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/batch/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/certificates/install"
|
||||
|
|
|
@ -16,4 +16,5 @@ limitations under the License.
|
|||
|
||||
// +k8s:deepcopy-gen=package,register
|
||||
|
||||
// +groupName=authorization.k8s.io
|
||||
package authorization // import "k8s.io/kubernetes/pkg/apis/authorization"
|
||||
|
|
|
@ -17,13 +17,19 @@ limitations under the License.
|
|||
package authorization
|
||||
|
||||
import (
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
)
|
||||
|
||||
// +genclient=true
|
||||
// +nonNamespaced=true
|
||||
// +noMethods=true
|
||||
|
||||
// SubjectAccessReview checks whether or not a user or group can perform an action. Not filling in a
|
||||
// spec.namespace means "in all namespaces".
|
||||
type SubjectAccessReview struct {
|
||||
unversioned.TypeMeta
|
||||
api.ObjectMeta
|
||||
|
||||
// Spec holds information about the request being evaluated
|
||||
Spec SubjectAccessReviewSpec
|
||||
|
@ -37,6 +43,7 @@ type SubjectAccessReview struct {
|
|||
// to check whether they can perform an action
|
||||
type SelfSubjectAccessReview struct {
|
||||
unversioned.TypeMeta
|
||||
api.ObjectMeta
|
||||
|
||||
// Spec holds information about the request being evaluated.
|
||||
Spec SelfSubjectAccessReviewSpec
|
||||
|
@ -50,6 +57,7 @@ type SelfSubjectAccessReview struct {
|
|||
// checking.
|
||||
type LocalSubjectAccessReview struct {
|
||||
unversioned.TypeMeta
|
||||
api.ObjectMeta
|
||||
|
||||
// Spec holds information about the request being evaluated. spec.namespace must be equal to the namespace
|
||||
// you made the request against. If empty, it is defaulted.
|
||||
|
@ -103,9 +111,13 @@ type SubjectAccessReviewSpec struct {
|
|||
Groups []string
|
||||
// Extra corresponds to the user.Info.GetExtra() method from the authenticator. Since that is input to the authorizer
|
||||
// it needs a reflection here.
|
||||
Extra map[string][]string
|
||||
Extra map[string]ExtraValue
|
||||
}
|
||||
|
||||
// ExtraValue masks the value so protobuf can generate
|
||||
// +protobuf.nullable=true
|
||||
type ExtraValue []string
|
||||
|
||||
// SelfSubjectAccessReviewSpec is a description of the access request. Exactly one of ResourceAttributes
|
||||
// and NonResourceAttributes must be set
|
||||
type SelfSubjectAccessReviewSpec struct {
|
||||
|
@ -121,4 +133,8 @@ type SubjectAccessReviewStatus struct {
|
|||
Allowed bool
|
||||
// Reason is optional. It indicates why a request was allowed or denied.
|
||||
Reason string
|
||||
// EvaluationError is an indication that some error occurred during the authorization check.
|
||||
// It is entirely possible to get an error and be able to continue determine authorization status in spite of it.
|
||||
// For instance, RBAC can be missing a role, but enough roles are still present and bound to reason about the request.
|
||||
EvaluationError string
|
||||
}
|
||||
|
|
|
@ -17,4 +17,5 @@ limitations under the License.
|
|||
// +k8s:deepcopy-gen=package,register
|
||||
// +k8s:conversion-gen=k8s.io/kubernetes/pkg/apis/authorization
|
||||
|
||||
// +groupName=authorization.k8s.io
|
||||
package v1beta1 // import "k8s.io/kubernetes/pkg/apis/authorization/v1beta1"
|
||||
|
|
|
@ -18,7 +18,9 @@ package v1beta1
|
|||
|
||||
import (
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
versionedwatch "k8s.io/kubernetes/pkg/watch/versioned"
|
||||
)
|
||||
|
||||
// GroupName is the group name use in this package
|
||||
|
@ -37,10 +39,15 @@ func AddToScheme(scheme *runtime.Scheme) {
|
|||
// Adds the list of known types to api.Scheme.
|
||||
func addKnownTypes(scheme *runtime.Scheme) {
|
||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||
&v1.ListOptions{},
|
||||
&v1.DeleteOptions{},
|
||||
|
||||
&SelfSubjectAccessReview{},
|
||||
&SubjectAccessReview{},
|
||||
&LocalSubjectAccessReview{},
|
||||
)
|
||||
|
||||
versionedwatch.AddToGroupVersion(scheme, SchemeGroupVersion)
|
||||
}
|
||||
|
||||
func (obj *LocalSubjectAccessReview) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
|
||||
|
|
|
@ -17,18 +17,26 @@ limitations under the License.
|
|||
package v1beta1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
)
|
||||
|
||||
// +genclient=true
|
||||
// +nonNamespaced=true
|
||||
// +noMethods=true
|
||||
|
||||
// SubjectAccessReview checks whether or not a user or group can perform an action.
|
||||
type SubjectAccessReview struct {
|
||||
unversioned.TypeMeta `json:",inline"`
|
||||
v1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
|
||||
// Spec holds information about the request being evaluated
|
||||
Spec SubjectAccessReviewSpec `json:"spec"`
|
||||
Spec SubjectAccessReviewSpec `json:"spec" protobuf:"bytes,2,opt,name=spec"`
|
||||
|
||||
// Status is filled in by the server and indicates whether the request is allowed or not
|
||||
Status SubjectAccessReviewStatus `json:"status,omitempty"`
|
||||
Status SubjectAccessReviewStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
|
||||
}
|
||||
|
||||
// SelfSubjectAccessReview checks whether or the current user can perform an action. Not filling in a
|
||||
|
@ -36,12 +44,13 @@ type SubjectAccessReview struct {
|
|||
// to check whether they can perform an action
|
||||
type SelfSubjectAccessReview struct {
|
||||
unversioned.TypeMeta `json:",inline"`
|
||||
v1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
|
||||
// Spec holds information about the request being evaluated. user and groups must be empty
|
||||
Spec SelfSubjectAccessReviewSpec `json:"spec"`
|
||||
Spec SelfSubjectAccessReviewSpec `json:"spec" protobuf:"bytes,2,opt,name=spec"`
|
||||
|
||||
// Status is filled in by the server and indicates whether the request is allowed or not
|
||||
Status SubjectAccessReviewStatus `json:"status,omitempty"`
|
||||
Status SubjectAccessReviewStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
|
||||
}
|
||||
|
||||
// LocalSubjectAccessReview checks whether or not a user or group can perform an action in a given namespace.
|
||||
|
@ -49,13 +58,14 @@ type SelfSubjectAccessReview struct {
|
|||
// checking.
|
||||
type LocalSubjectAccessReview struct {
|
||||
unversioned.TypeMeta `json:",inline"`
|
||||
v1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
|
||||
// Spec holds information about the request being evaluated. spec.namespace must be equal to the namespace
|
||||
// you made the request against. If empty, it is defaulted.
|
||||
Spec SubjectAccessReviewSpec `json:"spec"`
|
||||
Spec SubjectAccessReviewSpec `json:"spec" protobuf:"bytes,2,opt,name=spec"`
|
||||
|
||||
// Status is filled in by the server and indicates whether the request is allowed or not
|
||||
Status SubjectAccessReviewStatus `json:"status,omitempty"`
|
||||
Status SubjectAccessReviewStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
|
||||
}
|
||||
|
||||
// ResourceAttributes includes the authorization attributes available for resource requests to the Authorizer interface
|
||||
|
@ -64,60 +74,73 @@ type ResourceAttributes struct {
|
|||
// "" (empty) is defaulted for LocalSubjectAccessReviews
|
||||
// "" (empty) is empty for cluster-scoped resources
|
||||
// "" (empty) means "all" for namespace scoped resources from a SubjectAccessReview or SelfSubjectAccessReview
|
||||
Namespace string `json:"namespace,omitempty"`
|
||||
Namespace string `json:"namespace,omitempty" protobuf:"bytes,1,opt,name=namespace"`
|
||||
// Verb is a kubernetes resource API verb, like: get, list, watch, create, update, delete, proxy. "*" means all.
|
||||
Verb string `json:"verb,omitempty"`
|
||||
Verb string `json:"verb,omitempty" protobuf:"bytes,2,opt,name=verb"`
|
||||
// Group is the API Group of the Resource. "*" means all.
|
||||
Group string `json:"group,omitempty"`
|
||||
Group string `json:"group,omitempty" protobuf:"bytes,3,opt,name=group"`
|
||||
// Version is the API Version of the Resource. "*" means all.
|
||||
Version string `json:"version,omitempty"`
|
||||
Version string `json:"version,omitempty" protobuf:"bytes,4,opt,name=version"`
|
||||
// Resource is one of the existing resource types. "*" means all.
|
||||
Resource string `json:"resource,omitempty"`
|
||||
Resource string `json:"resource,omitempty" protobuf:"bytes,5,opt,name=resource"`
|
||||
// Subresource is one of the existing resource types. "" means none.
|
||||
Subresource string `json:"subresource,omitempty"`
|
||||
Subresource string `json:"subresource,omitempty" protobuf:"bytes,6,opt,name=subresource"`
|
||||
// Name is the name of the resource being requested for a "get" or deleted for a "delete". "" (empty) means all.
|
||||
Name string `json:"name,omitempty"`
|
||||
Name string `json:"name,omitempty" protobuf:"bytes,7,opt,name=name"`
|
||||
}
|
||||
|
||||
// NonResourceAttributes includes the authorization attributes available for non-resource requests to the Authorizer interface
|
||||
type NonResourceAttributes struct {
|
||||
// Path is the URL path of the request
|
||||
Path string `json:"path,omitempty"`
|
||||
Path string `json:"path,omitempty" protobuf:"bytes,1,opt,name=path"`
|
||||
// Verb is the standard HTTP verb
|
||||
Verb string `json:"verb,omitempty"`
|
||||
Verb string `json:"verb,omitempty" protobuf:"bytes,2,opt,name=verb"`
|
||||
}
|
||||
|
||||
// SubjectAccessReviewSpec is a description of the access request. Exactly one of ResourceAuthorizationAttributes
|
||||
// and NonResourceAuthorizationAttributes must be set
|
||||
type SubjectAccessReviewSpec struct {
|
||||
// ResourceAuthorizationAttributes describes information for a resource access request
|
||||
ResourceAttributes *ResourceAttributes `json:"resourceAttributes,omitempty"`
|
||||
ResourceAttributes *ResourceAttributes `json:"resourceAttributes,omitempty" protobuf:"bytes,1,opt,name=resourceAttributes"`
|
||||
// NonResourceAttributes describes information for a non-resource access request
|
||||
NonResourceAttributes *NonResourceAttributes `json:"nonResourceAttributes,omitempty"`
|
||||
NonResourceAttributes *NonResourceAttributes `json:"nonResourceAttributes,omitempty" protobuf:"bytes,2,opt,name=nonResourceAttributes"`
|
||||
|
||||
// User is the user you're testing for.
|
||||
// If you specify "User" but not "Group", then is it interpreted as "What if User were not a member of any groups
|
||||
User string `json:"user,omitempty"`
|
||||
User string `json:"user,omitempty" protobuf:"bytes,3,opt,name=verb"`
|
||||
// Groups is the groups you're testing for.
|
||||
Groups []string `json:"group,omitempty"`
|
||||
Groups []string `json:"group,omitempty" protobuf:"bytes,4,rep,name=group"`
|
||||
// Extra corresponds to the user.Info.GetExtra() method from the authenticator. Since that is input to the authorizer
|
||||
// it needs a reflection here.
|
||||
Extra map[string][]string `json:"extra,omitempty"`
|
||||
Extra map[string]ExtraValue `json:"extra,omitempty" protobuf:"bytes,5,rep,name=extra"`
|
||||
}
|
||||
|
||||
// ExtraValue masks the value so protobuf can generate
|
||||
// +protobuf.nullable=true
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
type ExtraValue []string
|
||||
|
||||
func (t ExtraValue) String() string {
|
||||
return fmt.Sprintf("%v", []string(t))
|
||||
}
|
||||
|
||||
// SelfSubjectAccessReviewSpec is a description of the access request. Exactly one of ResourceAuthorizationAttributes
|
||||
// and NonResourceAuthorizationAttributes must be set
|
||||
type SelfSubjectAccessReviewSpec struct {
|
||||
// ResourceAuthorizationAttributes describes information for a resource access request
|
||||
ResourceAttributes *ResourceAttributes `json:"resourceAttributes,omitempty"`
|
||||
ResourceAttributes *ResourceAttributes `json:"resourceAttributes,omitempty" protobuf:"bytes,1,opt,name=resourceAttributes"`
|
||||
// NonResourceAttributes describes information for a non-resource access request
|
||||
NonResourceAttributes *NonResourceAttributes `json:"nonResourceAttributes,omitempty"`
|
||||
NonResourceAttributes *NonResourceAttributes `json:"nonResourceAttributes,omitempty" protobuf:"bytes,2,opt,name=nonResourceAttributes"`
|
||||
}
|
||||
|
||||
// SubjectAccessReviewStatus
|
||||
type SubjectAccessReviewStatus struct {
|
||||
// Allowed is required. True if the action would be allowed, false otherwise.
|
||||
Allowed bool `json:"allowed"`
|
||||
Allowed bool `json:"allowed" protobuf:"varint,1,opt,name=allowed"`
|
||||
// Reason is optional. It indicates why a request was allowed or denied.
|
||||
Reason string `json:"reason,omitempty"`
|
||||
Reason string `json:"reason,omitempty" protobuf:"bytes,2,opt,name=reason"`
|
||||
// EvaluationError is an indication that some error occurred during the authorization check.
|
||||
// It is entirely possible to get an error and be able to continue determine authorization status in spite of it.
|
||||
// For instance, RBAC can be missing a role, but enough roles are still present and bound to reason about the request.
|
||||
EvaluationError string `json:"evaluationError,omitempty" protobuf:"bytes,3,opt,name=evaluationError"`
|
||||
}
|
||||
|
|
|
@ -54,6 +54,10 @@ func autoConvert_v1beta1_LocalSubjectAccessReview_To_authorization_LocalSubjectA
|
|||
if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO: Inefficient conversion - can we improve it?
|
||||
if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := Convert_v1beta1_SubjectAccessReviewSpec_To_authorization_SubjectAccessReviewSpec(&in.Spec, &out.Spec, s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -71,6 +75,10 @@ func autoConvert_authorization_LocalSubjectAccessReview_To_v1beta1_LocalSubjectA
|
|||
if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO: Inefficient conversion - can we improve it?
|
||||
if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := Convert_authorization_SubjectAccessReviewSpec_To_v1beta1_SubjectAccessReviewSpec(&in.Spec, &out.Spec, s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -138,6 +146,10 @@ func autoConvert_v1beta1_SelfSubjectAccessReview_To_authorization_SelfSubjectAcc
|
|||
if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO: Inefficient conversion - can we improve it?
|
||||
if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := Convert_v1beta1_SelfSubjectAccessReviewSpec_To_authorization_SelfSubjectAccessReviewSpec(&in.Spec, &out.Spec, s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -155,6 +167,10 @@ func autoConvert_authorization_SelfSubjectAccessReview_To_v1beta1_SelfSubjectAcc
|
|||
if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO: Inefficient conversion - can we improve it?
|
||||
if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := Convert_authorization_SelfSubjectAccessReviewSpec_To_v1beta1_SelfSubjectAccessReviewSpec(&in.Spec, &out.Spec, s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -224,6 +240,10 @@ func autoConvert_v1beta1_SubjectAccessReview_To_authorization_SubjectAccessRevie
|
|||
if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO: Inefficient conversion - can we improve it?
|
||||
if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := Convert_v1beta1_SubjectAccessReviewSpec_To_authorization_SubjectAccessReviewSpec(&in.Spec, &out.Spec, s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -241,6 +261,10 @@ func autoConvert_authorization_SubjectAccessReview_To_v1beta1_SubjectAccessRevie
|
|||
if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO: Inefficient conversion - can we improve it?
|
||||
if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := Convert_authorization_SubjectAccessReviewSpec_To_v1beta1_SubjectAccessReviewSpec(&in.Spec, &out.Spec, s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -275,7 +299,20 @@ func autoConvert_v1beta1_SubjectAccessReviewSpec_To_authorization_SubjectAccessR
|
|||
}
|
||||
out.User = in.User
|
||||
out.Groups = in.Groups
|
||||
out.Extra = in.Extra
|
||||
if in.Extra != nil {
|
||||
in, out := &in.Extra, &out.Extra
|
||||
*out = make(map[string]authorization.ExtraValue, len(*in))
|
||||
for key, val := range *in {
|
||||
newVal := new(authorization.ExtraValue)
|
||||
// TODO: Inefficient conversion - can we improve it?
|
||||
if err := s.Convert(&val, newVal, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
(*out)[key] = *newVal
|
||||
}
|
||||
} else {
|
||||
out.Extra = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -304,7 +341,20 @@ func autoConvert_authorization_SubjectAccessReviewSpec_To_v1beta1_SubjectAccessR
|
|||
}
|
||||
out.User = in.User
|
||||
out.Groups = in.Groups
|
||||
out.Extra = in.Extra
|
||||
if in.Extra != nil {
|
||||
in, out := &in.Extra, &out.Extra
|
||||
*out = make(map[string]ExtraValue, len(*in))
|
||||
for key, val := range *in {
|
||||
newVal := new(ExtraValue)
|
||||
// TODO: Inefficient conversion - can we improve it?
|
||||
if err := s.Convert(&val, newVal, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
(*out)[key] = *newVal
|
||||
}
|
||||
} else {
|
||||
out.Extra = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -315,6 +365,7 @@ func Convert_authorization_SubjectAccessReviewSpec_To_v1beta1_SubjectAccessRevie
|
|||
func autoConvert_v1beta1_SubjectAccessReviewStatus_To_authorization_SubjectAccessReviewStatus(in *SubjectAccessReviewStatus, out *authorization.SubjectAccessReviewStatus, s conversion.Scope) error {
|
||||
out.Allowed = in.Allowed
|
||||
out.Reason = in.Reason
|
||||
out.EvaluationError = in.EvaluationError
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -325,6 +376,7 @@ func Convert_v1beta1_SubjectAccessReviewStatus_To_authorization_SubjectAccessRev
|
|||
func autoConvert_authorization_SubjectAccessReviewStatus_To_v1beta1_SubjectAccessReviewStatus(in *authorization.SubjectAccessReviewStatus, out *SubjectAccessReviewStatus, s conversion.Scope) error {
|
||||
out.Allowed = in.Allowed
|
||||
out.Reason = in.Reason
|
||||
out.EvaluationError = in.EvaluationError
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ package v1beta1
|
|||
|
||||
import (
|
||||
api "k8s.io/kubernetes/pkg/api"
|
||||
v1 "k8s.io/kubernetes/pkg/api/v1"
|
||||
conversion "k8s.io/kubernetes/pkg/conversion"
|
||||
reflect "reflect"
|
||||
)
|
||||
|
@ -47,6 +48,9 @@ func DeepCopy_v1beta1_LocalSubjectAccessReview(in interface{}, out interface{},
|
|||
in := in.(*LocalSubjectAccessReview)
|
||||
out := out.(*LocalSubjectAccessReview)
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if err := v1.DeepCopy_v1_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := DeepCopy_v1beta1_SubjectAccessReviewSpec(&in.Spec, &out.Spec, c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -85,6 +89,9 @@ func DeepCopy_v1beta1_SelfSubjectAccessReview(in interface{}, out interface{}, c
|
|||
in := in.(*SelfSubjectAccessReview)
|
||||
out := out.(*SelfSubjectAccessReview)
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if err := v1.DeepCopy_v1_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := DeepCopy_v1beta1_SelfSubjectAccessReviewSpec(&in.Spec, &out.Spec, c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -120,6 +127,9 @@ func DeepCopy_v1beta1_SubjectAccessReview(in interface{}, out interface{}, c *co
|
|||
in := in.(*SubjectAccessReview)
|
||||
out := out.(*SubjectAccessReview)
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if err := v1.DeepCopy_v1_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := DeepCopy_v1beta1_SubjectAccessReviewSpec(&in.Spec, &out.Spec, c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -156,12 +166,12 @@ func DeepCopy_v1beta1_SubjectAccessReviewSpec(in interface{}, out interface{}, c
|
|||
}
|
||||
if in.Extra != nil {
|
||||
in, out := &in.Extra, &out.Extra
|
||||
*out = make(map[string][]string)
|
||||
*out = make(map[string]ExtraValue)
|
||||
for key, val := range *in {
|
||||
if newVal, err := c.DeepCopy(&val); err != nil {
|
||||
return err
|
||||
} else {
|
||||
(*out)[key] = *newVal.(*[]string)
|
||||
(*out)[key] = *newVal.(*ExtraValue)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -177,6 +187,7 @@ func DeepCopy_v1beta1_SubjectAccessReviewStatus(in interface{}, out interface{},
|
|||
out := out.(*SubjectAccessReviewStatus)
|
||||
out.Allowed = in.Allowed
|
||||
out.Reason = in.Reason
|
||||
out.EvaluationError = in.EvaluationError
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||
package validation
|
||||
|
||||
import (
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
authorizationapi "k8s.io/kubernetes/pkg/apis/authorization"
|
||||
"k8s.io/kubernetes/pkg/util/validation/field"
|
||||
)
|
||||
|
@ -50,15 +51,24 @@ func ValidateSelfSubjectAccessReviewSpec(spec authorizationapi.SelfSubjectAccess
|
|||
|
||||
func ValidateSubjectAccessReview(sar *authorizationapi.SubjectAccessReview) field.ErrorList {
|
||||
allErrs := ValidateSubjectAccessReviewSpec(sar.Spec, field.NewPath("spec"))
|
||||
if !api.Semantic.DeepEqual(api.ObjectMeta{}, sar.ObjectMeta) {
|
||||
allErrs = append(allErrs, field.Invalid(field.NewPath("metadata"), sar.ObjectMeta, `must be empty`))
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func ValidateSelfSubjectAccessReview(sar *authorizationapi.SelfSubjectAccessReview) field.ErrorList {
|
||||
allErrs := ValidateSelfSubjectAccessReviewSpec(sar.Spec, field.NewPath("spec"))
|
||||
if !api.Semantic.DeepEqual(api.ObjectMeta{}, sar.ObjectMeta) {
|
||||
allErrs = append(allErrs, field.Invalid(field.NewPath("metadata"), sar.ObjectMeta, `must be empty`))
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func ValidateLocalSubjectAccessReview(sar *authorizationapi.LocalSubjectAccessReview) field.ErrorList {
|
||||
allErrs := ValidateSubjectAccessReviewSpec(sar.Spec, field.NewPath("spec"))
|
||||
if !api.Semantic.DeepEqual(api.ObjectMeta{}, sar.ObjectMeta) {
|
||||
allErrs = append(allErrs, field.Invalid(field.NewPath("metadata"), sar.ObjectMeta, `must be empty`))
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
|
|
@ -47,6 +47,9 @@ func DeepCopy_authorization_LocalSubjectAccessReview(in interface{}, out interfa
|
|||
in := in.(*LocalSubjectAccessReview)
|
||||
out := out.(*LocalSubjectAccessReview)
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if err := api.DeepCopy_api_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := DeepCopy_authorization_SubjectAccessReviewSpec(&in.Spec, &out.Spec, c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -85,6 +88,9 @@ func DeepCopy_authorization_SelfSubjectAccessReview(in interface{}, out interfac
|
|||
in := in.(*SelfSubjectAccessReview)
|
||||
out := out.(*SelfSubjectAccessReview)
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if err := api.DeepCopy_api_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := DeepCopy_authorization_SelfSubjectAccessReviewSpec(&in.Spec, &out.Spec, c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -120,6 +126,9 @@ func DeepCopy_authorization_SubjectAccessReview(in interface{}, out interface{},
|
|||
in := in.(*SubjectAccessReview)
|
||||
out := out.(*SubjectAccessReview)
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if err := api.DeepCopy_api_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := DeepCopy_authorization_SubjectAccessReviewSpec(&in.Spec, &out.Spec, c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -156,12 +165,12 @@ func DeepCopy_authorization_SubjectAccessReviewSpec(in interface{}, out interfac
|
|||
}
|
||||
if in.Extra != nil {
|
||||
in, out := &in.Extra, &out.Extra
|
||||
*out = make(map[string][]string)
|
||||
*out = make(map[string]ExtraValue)
|
||||
for key, val := range *in {
|
||||
if newVal, err := c.DeepCopy(&val); err != nil {
|
||||
return err
|
||||
} else {
|
||||
(*out)[key] = *newVal.(*[]string)
|
||||
(*out)[key] = *newVal.(*ExtraValue)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -177,6 +186,7 @@ func DeepCopy_authorization_SubjectAccessReviewStatus(in interface{}, out interf
|
|||
out := out.(*SubjectAccessReviewStatus)
|
||||
out.Allowed = in.Allowed
|
||||
out.Reason = in.Reason
|
||||
out.EvaluationError = in.EvaluationError
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
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 fake
|
||||
|
||||
import (
|
||||
authorizationapi "k8s.io/kubernetes/pkg/apis/authorization"
|
||||
|
||||
"k8s.io/kubernetes/pkg/client/testing/core"
|
||||
)
|
||||
|
||||
func (c *FakeSubjectAccessReviews) Create(sar *authorizationapi.SubjectAccessReview) (result *authorizationapi.SubjectAccessReview, err error) {
|
||||
obj, err := c.Fake.Invokes(core.NewRootCreateAction(authorizationapi.SchemeGroupVersion.WithResource("subjectaccessreviews"), sar), &authorizationapi.SubjectAccessReview{})
|
||||
return obj.(*authorizationapi.SubjectAccessReview), err
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
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 unversioned
|
||||
|
||||
import (
|
||||
authorizationapi "k8s.io/kubernetes/pkg/apis/authorization"
|
||||
)
|
||||
|
||||
// The PodExpansion interface allows manually adding extra methods to the PodInterface.
|
||||
type SubjectAccessReviewExpansion interface {
|
||||
Create(sar *authorizationapi.SubjectAccessReview) (result *authorizationapi.SubjectAccessReview, err error)
|
||||
}
|
||||
|
||||
func (c *subjectAccessReviews) Create(sar *authorizationapi.SubjectAccessReview) (result *authorizationapi.SubjectAccessReview, err error) {
|
||||
result = &authorizationapi.SubjectAccessReview{}
|
||||
err = c.client.Post().
|
||||
Resource("subjectaccessreviews").
|
||||
Body(sar).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
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 fake
|
||||
|
||||
import (
|
||||
authorizationapi "k8s.io/kubernetes/pkg/apis/authorization/v1beta1"
|
||||
|
||||
"k8s.io/kubernetes/pkg/client/testing/core"
|
||||
)
|
||||
|
||||
func (c *FakeSubjectAccessReviews) Create(sar *authorizationapi.SubjectAccessReview) (result *authorizationapi.SubjectAccessReview, err error) {
|
||||
obj, err := c.Fake.Invokes(core.NewRootCreateAction(authorizationapi.SchemeGroupVersion.WithResource("subjectaccessreviews"), sar), &authorizationapi.SubjectAccessReview{})
|
||||
return obj.(*authorizationapi.SubjectAccessReview), err
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
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 (
|
||||
authorizationapi "k8s.io/kubernetes/pkg/apis/authorization/v1beta1"
|
||||
)
|
||||
|
||||
// The PodExpansion interface allows manually adding extra methods to the PodInterface.
|
||||
type SubjectAccessReviewExpansion interface {
|
||||
Create(sar *authorizationapi.SubjectAccessReview) (result *authorizationapi.SubjectAccessReview, err error)
|
||||
}
|
||||
|
||||
func (c *subjectAccessReviews) Create(sar *authorizationapi.SubjectAccessReview) (result *authorizationapi.SubjectAccessReview, err error) {
|
||||
result = &authorizationapi.SubjectAccessReview{}
|
||||
err = c.client.Post().
|
||||
Resource("subjectaccessreviews").
|
||||
Body(sar).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
|
@ -19,6 +19,7 @@ package internalclientset
|
|||
import (
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
unversionedauthentication "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/authentication/unversioned"
|
||||
unversionedauthorization "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/authorization/unversioned"
|
||||
unversionedautoscaling "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/autoscaling/unversioned"
|
||||
unversionedbatch "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/batch/unversioned"
|
||||
unversionedcore "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/unversioned"
|
||||
|
@ -47,6 +48,11 @@ func FromUnversionedClient(c *unversioned.Client) *internalclientset.Clientset {
|
|||
} else {
|
||||
clientset.BatchClient = unversionedbatch.New(nil)
|
||||
}
|
||||
if c != nil && c.AuthorizationClient != nil {
|
||||
clientset.AuthorizationClient = unversionedauthorization.New(c.AuthorizationClient.RESTClient)
|
||||
} else {
|
||||
clientset.AuthorizationClient = unversionedauthorization.New(nil)
|
||||
}
|
||||
if c != nil && c.AutoscalingClient != nil {
|
||||
clientset.AutoscalingClient = unversionedautoscaling.New(c.AutoscalingClient.RESTClient)
|
||||
} else {
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
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 unversioned
|
||||
|
||||
import (
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||
"k8s.io/kubernetes/pkg/apis/authorization"
|
||||
"k8s.io/kubernetes/pkg/client/restclient"
|
||||
)
|
||||
|
||||
type AuthorizationInterface interface {
|
||||
SubjectAccessReviewsInterface
|
||||
}
|
||||
|
||||
// AuthorizationClient is used to interact with Kubernetes authorization features.
|
||||
type AuthorizationClient struct {
|
||||
*restclient.RESTClient
|
||||
}
|
||||
|
||||
func (c *AuthorizationClient) SubjectAccessReviews() SubjectAccessReviewInterface {
|
||||
return newSubjectAccessReviews(c)
|
||||
}
|
||||
|
||||
func NewAuthorization(c *restclient.Config) (*AuthorizationClient, error) {
|
||||
config := *c
|
||||
if err := setAuthorizationDefaults(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client, err := restclient.RESTClientFor(&config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &AuthorizationClient{client}, nil
|
||||
}
|
||||
|
||||
func NewAuthorizationOrDie(c *restclient.Config) *AuthorizationClient {
|
||||
client, err := NewAuthorization(c)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return client
|
||||
}
|
||||
|
||||
func setAuthorizationDefaults(config *restclient.Config) error {
|
||||
// if authorization group is not registered, return an error
|
||||
g, err := registered.Group(authorization.GroupName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config.APIPath = defaultAPIPath
|
||||
if config.UserAgent == "" {
|
||||
config.UserAgent = restclient.DefaultKubernetesUserAgent()
|
||||
}
|
||||
// TODO: Unconditionally set the config.Version, until we fix the config.
|
||||
//if config.Version == "" {
|
||||
copyGroupVersion := g.GroupVersion
|
||||
config.GroupVersion = ©GroupVersion
|
||||
//}
|
||||
|
||||
config.NegotiatedSerializer = api.Codecs
|
||||
return nil
|
||||
}
|
|
@ -45,6 +45,7 @@ type Interface interface {
|
|||
ComponentStatusesInterface
|
||||
ConfigMapsNamespacer
|
||||
Apps() AppsInterface
|
||||
Authorization() AuthorizationInterface
|
||||
Autoscaling() AutoscalingInterface
|
||||
Authentication() AuthenticationInterface
|
||||
Batch() BatchInterface
|
||||
|
@ -120,6 +121,7 @@ func (c *Client) ConfigMaps(namespace string) ConfigMapsInterface {
|
|||
// Client is the implementation of a Kubernetes client.
|
||||
type Client struct {
|
||||
*restclient.RESTClient
|
||||
*AuthorizationClient
|
||||
*AutoscalingClient
|
||||
*AuthenticationClient
|
||||
*BatchClient
|
||||
|
@ -153,6 +155,10 @@ func IsTimeout(err error) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (c *Client) Authorization() AuthorizationInterface {
|
||||
return c.AuthorizationClient
|
||||
}
|
||||
|
||||
func (c *Client) Autoscaling() AutoscalingInterface {
|
||||
return c.AutoscalingClient
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||
"k8s.io/kubernetes/pkg/apis/apps"
|
||||
"k8s.io/kubernetes/pkg/apis/authentication"
|
||||
"k8s.io/kubernetes/pkg/apis/authorization"
|
||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||
"k8s.io/kubernetes/pkg/apis/batch"
|
||||
"k8s.io/kubernetes/pkg/apis/certificates"
|
||||
|
@ -63,6 +64,15 @@ func New(c *restclient.Config) (*Client, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
var authorizationClient *AuthorizationClient
|
||||
if registered.IsRegistered(authorization.GroupName) {
|
||||
authorizationConfig := *c
|
||||
authorizationClient, err = NewAuthorization(&authorizationConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var autoscalingClient *AutoscalingClient
|
||||
if registered.IsRegistered(autoscaling.GroupName) {
|
||||
autoscalingConfig := *c
|
||||
|
@ -137,6 +147,7 @@ func New(c *restclient.Config) (*Client, error) {
|
|||
RESTClient: client,
|
||||
AppsClient: appsClient,
|
||||
AuthenticationClient: authenticationClient,
|
||||
AuthorizationClient: authorizationClient,
|
||||
AutoscalingClient: autoscalingClient,
|
||||
BatchClient: batchClient,
|
||||
CertificatesClient: certsClient,
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
Copyright 2015 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 unversioned
|
||||
|
||||
import (
|
||||
"k8s.io/kubernetes/pkg/apis/authorization"
|
||||
)
|
||||
|
||||
type SubjectAccessReviewsInterface interface {
|
||||
SubjectAccessReviews() SubjectAccessReviewInterface
|
||||
}
|
||||
|
||||
type SubjectAccessReviewInterface interface {
|
||||
Create(subjectAccessReview *authorization.SubjectAccessReview) (*authorization.SubjectAccessReview, error)
|
||||
}
|
||||
|
||||
type subjectAccessReviews struct {
|
||||
client *AuthorizationClient
|
||||
}
|
||||
|
||||
func newSubjectAccessReviews(c *AuthorizationClient) *subjectAccessReviews {
|
||||
return &subjectAccessReviews{
|
||||
client: c,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *subjectAccessReviews) Create(subjectAccessReview *authorization.SubjectAccessReview) (result *authorization.SubjectAccessReview, err error) {
|
||||
result = &authorization.SubjectAccessReview{}
|
||||
err = c.client.Post().Resource("subjectAccessReviews").Body(subjectAccessReview).Do().Into(result)
|
||||
return
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
Copyright 2015 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 testclient
|
||||
|
||||
import (
|
||||
"k8s.io/kubernetes/pkg/apis/authorization"
|
||||
)
|
||||
|
||||
// FakeSubjectAccessReviews implements SubjectAccessReviewInterface. Meant to be embedded into a struct to get a default
|
||||
// implementation. This makes faking out just the methods you want to test easier.
|
||||
type FakeSubjectAccessReviews struct {
|
||||
Fake *FakeAuthorization
|
||||
}
|
||||
|
||||
func (c *FakeSubjectAccessReviews) Create(a *authorization.SubjectAccessReview) (*authorization.SubjectAccessReview, error) {
|
||||
obj, err := c.Fake.Invokes(NewRootCreateAction("subjectaccessreviews", a), a)
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return obj.(*authorization.SubjectAccessReview), err
|
||||
}
|
|
@ -281,6 +281,10 @@ func (c *Fake) Apps() client.AppsInterface {
|
|||
return &FakeApps{c}
|
||||
}
|
||||
|
||||
func (c *Fake) Authorization() client.AuthorizationInterface {
|
||||
return &FakeAuthorization{c}
|
||||
}
|
||||
|
||||
func (c *Fake) Autoscaling() client.AutoscalingInterface {
|
||||
return &FakeAutoscaling{c}
|
||||
}
|
||||
|
@ -344,6 +348,19 @@ func (c *FakeApps) PetSets(namespace string) client.PetSetInterface {
|
|||
return &FakePetSets{Fake: c, Namespace: namespace}
|
||||
}
|
||||
|
||||
// NewSimpleFakeAuthorization returns a client that will respond with the provided objects
|
||||
func NewSimpleFakeAuthorization(objects ...runtime.Object) *FakeAuthorization {
|
||||
return &FakeAuthorization{Fake: NewSimpleFake(objects...)}
|
||||
}
|
||||
|
||||
type FakeAuthorization struct {
|
||||
*Fake
|
||||
}
|
||||
|
||||
func (c *FakeAuthorization) SubjectAccessReviews() client.SubjectAccessReviewInterface {
|
||||
return &FakeSubjectAccessReviews{Fake: c}
|
||||
}
|
||||
|
||||
// NewSimpleFakeAutoscaling returns a client that will respond with the provided objects
|
||||
func NewSimpleFakeAutoscaling(objects ...runtime.Object) *FakeAutoscaling {
|
||||
return &FakeAutoscaling{Fake: NewSimpleFake(objects...)}
|
||||
|
|
|
@ -503,11 +503,12 @@ func monitorFor(p *Propagator, clientPool dynamic.ClientPool, resource unversion
|
|||
}
|
||||
|
||||
var ignoredResources = map[unversioned.GroupVersionResource]struct{}{
|
||||
unversioned.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "replicationcontrollers"}: {},
|
||||
unversioned.GroupVersionResource{Group: "", Version: "v1", Resource: "bindings"}: {},
|
||||
unversioned.GroupVersionResource{Group: "", Version: "v1", Resource: "componentstatuses"}: {},
|
||||
unversioned.GroupVersionResource{Group: "", Version: "v1", Resource: "events"}: {},
|
||||
unversioned.GroupVersionResource{Group: "authentication.k8s.io", Version: "v1beta1", Resource: "tokenreviews"}: {},
|
||||
unversioned.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "replicationcontrollers"}: {},
|
||||
unversioned.GroupVersionResource{Group: "", Version: "v1", Resource: "bindings"}: {},
|
||||
unversioned.GroupVersionResource{Group: "", Version: "v1", Resource: "componentstatuses"}: {},
|
||||
unversioned.GroupVersionResource{Group: "", Version: "v1", Resource: "events"}: {},
|
||||
unversioned.GroupVersionResource{Group: "authentication.k8s.io", Version: "v1beta1", Resource: "tokenreviews"}: {},
|
||||
unversioned.GroupVersionResource{Group: "authorization.k8s.io", Version: "v1beta1", Resource: "subjectaccessreviews"}: {},
|
||||
}
|
||||
|
||||
func NewGarbageCollector(clientPool dynamic.ClientPool, resources []unversioned.GroupVersionResource) (*GarbageCollector, error) {
|
||||
|
|
|
@ -35,6 +35,8 @@ import (
|
|||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||
appsapi "k8s.io/kubernetes/pkg/apis/apps/v1alpha1"
|
||||
authenticationv1beta1 "k8s.io/kubernetes/pkg/apis/authentication/v1beta1"
|
||||
"k8s.io/kubernetes/pkg/apis/authorization"
|
||||
authorizationapiv1beta1 "k8s.io/kubernetes/pkg/apis/authorization/v1beta1"
|
||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||
autoscalingapiv1 "k8s.io/kubernetes/pkg/apis/autoscaling/v1"
|
||||
"k8s.io/kubernetes/pkg/apis/batch"
|
||||
|
@ -202,6 +204,7 @@ func New(c *Config) (*Master, error) {
|
|||
c.RESTStorageProviders[policy.GroupName] = PolicyRESTStorageProvider{}
|
||||
c.RESTStorageProviders[rbac.GroupName] = RBACRESTStorageProvider{AuthorizerRBACSuperUser: c.AuthorizerRBACSuperUser}
|
||||
c.RESTStorageProviders[authenticationv1beta1.GroupName] = AuthenticationRESTStorageProvider{Authenticator: c.Authenticator}
|
||||
c.RESTStorageProviders[authorization.GroupName] = AuthorizationRESTStorageProvider{Authorizer: c.Authorizer}
|
||||
m.InstallAPIs(c)
|
||||
|
||||
// TODO: Attempt clean shutdown?
|
||||
|
@ -762,6 +765,7 @@ func DefaultAPIResourceConfigSource() *genericapiserver.ResourceConfig {
|
|||
policyapiv1alpha1.SchemeGroupVersion,
|
||||
rbacapi.SchemeGroupVersion,
|
||||
certificatesapiv1alpha1.SchemeGroupVersion,
|
||||
authorizationapiv1beta1.SchemeGroupVersion,
|
||||
)
|
||||
|
||||
// all extensions resources except these are disabled by default
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
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 master
|
||||
|
||||
import (
|
||||
"k8s.io/kubernetes/pkg/api/rest"
|
||||
"k8s.io/kubernetes/pkg/apis/authorization"
|
||||
authorizationv1beta1 "k8s.io/kubernetes/pkg/apis/authorization/v1beta1"
|
||||
"k8s.io/kubernetes/pkg/auth/authorizer"
|
||||
"k8s.io/kubernetes/pkg/genericapiserver"
|
||||
"k8s.io/kubernetes/pkg/registry/authorization/subjectaccessreview"
|
||||
)
|
||||
|
||||
type AuthorizationRESTStorageProvider struct {
|
||||
Authorizer authorizer.Authorizer
|
||||
}
|
||||
|
||||
var _ RESTStorageProvider = &AuthorizationRESTStorageProvider{}
|
||||
|
||||
func (p AuthorizationRESTStorageProvider) NewRESTStorage(apiResourceConfigSource genericapiserver.APIResourceConfigSource, restOptionsGetter RESTOptionsGetter) (genericapiserver.APIGroupInfo, bool) {
|
||||
if p.Authorizer == nil {
|
||||
return genericapiserver.APIGroupInfo{}, false
|
||||
}
|
||||
|
||||
apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(authorization.GroupName)
|
||||
|
||||
if apiResourceConfigSource.AnyResourcesForVersionEnabled(authorizationv1beta1.SchemeGroupVersion) {
|
||||
apiGroupInfo.VersionedResourcesStorageMap[authorizationv1beta1.SchemeGroupVersion.Version] = p.v1beta1Storage(apiResourceConfigSource, restOptionsGetter)
|
||||
apiGroupInfo.GroupMeta.GroupVersion = authorizationv1beta1.SchemeGroupVersion
|
||||
}
|
||||
|
||||
return apiGroupInfo, true
|
||||
}
|
||||
|
||||
func (p AuthorizationRESTStorageProvider) v1beta1Storage(apiResourceConfigSource genericapiserver.APIResourceConfigSource, restOptionsGetter RESTOptionsGetter) map[string]rest.Storage {
|
||||
version := authorizationv1beta1.SchemeGroupVersion
|
||||
|
||||
storage := map[string]rest.Storage{}
|
||||
if apiResourceConfigSource.ResourceEnabled(version.WithResource("subjectaccessreviews")) {
|
||||
storage["subjectaccessreviews"] = subjectaccessreview.NewREST(p.Authorizer)
|
||||
}
|
||||
|
||||
return storage
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
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 subjectaccessreview
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
kapi "k8s.io/kubernetes/pkg/api"
|
||||
kapierrors "k8s.io/kubernetes/pkg/api/errors"
|
||||
authorizationapi "k8s.io/kubernetes/pkg/apis/authorization"
|
||||
authorizationvalidation "k8s.io/kubernetes/pkg/apis/authorization/validation"
|
||||
"k8s.io/kubernetes/pkg/auth/authorizer"
|
||||
"k8s.io/kubernetes/pkg/auth/user"
|
||||
authorizationutil "k8s.io/kubernetes/pkg/registry/authorization/util"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
type REST struct {
|
||||
authorizer authorizer.Authorizer
|
||||
}
|
||||
|
||||
func NewREST(authorizer authorizer.Authorizer) *REST {
|
||||
return &REST{authorizer}
|
||||
}
|
||||
|
||||
func (r *REST) New() runtime.Object {
|
||||
return &authorizationapi.SubjectAccessReview{}
|
||||
}
|
||||
|
||||
func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) {
|
||||
subjectAccessReview, ok := obj.(*authorizationapi.SubjectAccessReview)
|
||||
if !ok {
|
||||
return nil, kapierrors.NewBadRequest(fmt.Sprintf("not a SubjectAccessReview: %#v", obj))
|
||||
}
|
||||
if errs := authorizationvalidation.ValidateSubjectAccessReview(subjectAccessReview); len(errs) > 0 {
|
||||
return nil, kapierrors.NewInvalid(authorizationapi.Kind(subjectAccessReview.Kind), "", errs)
|
||||
}
|
||||
|
||||
userToCheck := &user.DefaultInfo{
|
||||
Name: subjectAccessReview.Spec.User,
|
||||
Groups: subjectAccessReview.Spec.Groups,
|
||||
Extra: convertToUserInfoExtra(subjectAccessReview.Spec.Extra),
|
||||
}
|
||||
|
||||
var authorizationAttributes authorizer.AttributesRecord
|
||||
if subjectAccessReview.Spec.ResourceAttributes != nil {
|
||||
authorizationAttributes = authorizationutil.ResourceAttributesFrom(userToCheck, *subjectAccessReview.Spec.ResourceAttributes)
|
||||
} else {
|
||||
authorizationAttributes = authorizationutil.NonResourceAttributesFrom(userToCheck, *subjectAccessReview.Spec.NonResourceAttributes)
|
||||
}
|
||||
|
||||
allowed, reason, evaluationErr := r.authorizer.Authorize(authorizationAttributes)
|
||||
|
||||
subjectAccessReview.Status = authorizationapi.SubjectAccessReviewStatus{
|
||||
Allowed: allowed,
|
||||
Reason: reason,
|
||||
}
|
||||
if evaluationErr != nil {
|
||||
subjectAccessReview.Status.EvaluationError = evaluationErr.Error()
|
||||
}
|
||||
|
||||
return subjectAccessReview, nil
|
||||
}
|
||||
|
||||
func convertToUserInfoExtra(extra map[string]authorizationapi.ExtraValue) map[string][]string {
|
||||
if extra == nil {
|
||||
return nil
|
||||
}
|
||||
ret := map[string][]string{}
|
||||
for k, v := range extra {
|
||||
ret[k] = []string(v)
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
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 util
|
||||
|
||||
import (
|
||||
authorizationapi "k8s.io/kubernetes/pkg/apis/authorization"
|
||||
"k8s.io/kubernetes/pkg/auth/authorizer"
|
||||
"k8s.io/kubernetes/pkg/auth/user"
|
||||
)
|
||||
|
||||
// ResourceAttributesFrom combines the API object information and the user.Info from the context to build a full authorizer.AttributesRecord for resource access
|
||||
func ResourceAttributesFrom(user user.Info, in authorizationapi.ResourceAttributes) authorizer.AttributesRecord {
|
||||
return authorizer.AttributesRecord{
|
||||
User: user,
|
||||
Verb: in.Verb,
|
||||
Namespace: in.Namespace,
|
||||
APIGroup: in.Group,
|
||||
Resource: in.Resource,
|
||||
ResourceRequest: true,
|
||||
}
|
||||
}
|
||||
|
||||
// NonResourceAttributesFrom combines the API object information and the user.Info from the context to build a full authorizer.AttributesRecord for non resource access
|
||||
func NonResourceAttributesFrom(user user.Info, in authorizationapi.NonResourceAttributes) authorizer.AttributesRecord {
|
||||
return authorizer.AttributesRecord{
|
||||
User: user,
|
||||
ResourceRequest: false,
|
||||
Path: in.Path,
|
||||
}
|
||||
}
|
|
@ -133,7 +133,7 @@ func (w *WebhookAuthorizer) Authorize(attr authorizer.Attributes) (authorized bo
|
|||
r.Spec = v1beta1.SubjectAccessReviewSpec{
|
||||
User: user.GetName(),
|
||||
Groups: user.GetGroups(),
|
||||
Extra: user.GetExtra(),
|
||||
Extra: convertToSARExtra(user.GetExtra()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -186,3 +186,15 @@ func (w *WebhookAuthorizer) Authorize(attr authorizer.Attributes) (authorized bo
|
|||
}
|
||||
return r.Status.Allowed, r.Status.Reason, nil
|
||||
}
|
||||
|
||||
func convertToSARExtra(extra map[string][]string) map[string]v1beta1.ExtraValue {
|
||||
if extra == nil {
|
||||
return nil
|
||||
}
|
||||
ret := map[string]v1beta1.ExtraValue{}
|
||||
for k, v := range extra {
|
||||
ret[k] = v1beta1.ExtraValue(v)
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"apiVersion": "authorization.k8s.io/v1beta1",
|
||||
"kind": "SubjectAccessReview",
|
||||
"spec": {
|
||||
"user": "bob",
|
||||
"groups": [
|
||||
"the-group"
|
||||
],
|
||||
"resourceAttributes": {
|
||||
"namespace": "ns",
|
||||
"verb": "create",
|
||||
"group": "autoscaling",
|
||||
"resource": "horizontalpodautoscalers"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,159 @@
|
|||
// +build integration,!no-etcd
|
||||
|
||||
/*
|
||||
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 auth
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
authorizationapi "k8s.io/kubernetes/pkg/apis/authorization"
|
||||
"k8s.io/kubernetes/pkg/auth/authenticator"
|
||||
"k8s.io/kubernetes/pkg/auth/authorizer"
|
||||
"k8s.io/kubernetes/pkg/auth/user"
|
||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
"k8s.io/kubernetes/pkg/client/restclient"
|
||||
"k8s.io/kubernetes/pkg/master"
|
||||
"k8s.io/kubernetes/plugin/pkg/admission/admit"
|
||||
"k8s.io/kubernetes/test/integration/framework"
|
||||
)
|
||||
|
||||
// Inject into master an authorizer that uses user info.
|
||||
// TODO(etune): remove this test once a more comprehensive built-in authorizer is implemented.
|
||||
type sarAuthorizer struct{}
|
||||
|
||||
func (sarAuthorizer) Authorize(a authorizer.Attributes) (bool, string, error) {
|
||||
if a.GetUser().GetName() == "dave" {
|
||||
return false, "no", errors.New("I'm sorry, Dave")
|
||||
}
|
||||
|
||||
return true, "you're not dave", nil
|
||||
}
|
||||
|
||||
func alwaysAlice(req *http.Request) (user.Info, bool, error) {
|
||||
return &user.DefaultInfo{
|
||||
Name: "alice",
|
||||
}, true, nil
|
||||
}
|
||||
|
||||
func TestSubjectAccessReview(t *testing.T) {
|
||||
// Set up a master
|
||||
var m *master.Master
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
m.Handler.ServeHTTP(w, req)
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
masterConfig := framework.NewIntegrationTestMasterConfig()
|
||||
masterConfig.Authenticator = authenticator.RequestFunc(alwaysAlice)
|
||||
masterConfig.Authorizer = sarAuthorizer{}
|
||||
masterConfig.AdmissionControl = admit.NewAlwaysAdmit()
|
||||
m, err := master.New(masterConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("error in bringing up the master: %v", err)
|
||||
}
|
||||
|
||||
clientset := clientset.NewForConfigOrDie(&restclient.Config{Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: testapi.Default.GroupVersion()}})
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
sar *authorizationapi.SubjectAccessReview
|
||||
expectedError string
|
||||
expectedStatus authorizationapi.SubjectAccessReviewStatus
|
||||
}{
|
||||
{
|
||||
name: "simple allow",
|
||||
sar: &authorizationapi.SubjectAccessReview{
|
||||
Spec: authorizationapi.SubjectAccessReviewSpec{
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{
|
||||
Verb: "list",
|
||||
Group: api.GroupName,
|
||||
Version: "v1",
|
||||
Resource: "pods",
|
||||
},
|
||||
User: "alice",
|
||||
},
|
||||
},
|
||||
expectedStatus: authorizationapi.SubjectAccessReviewStatus{
|
||||
Allowed: true,
|
||||
Reason: "you're not dave",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "simple deny",
|
||||
sar: &authorizationapi.SubjectAccessReview{
|
||||
Spec: authorizationapi.SubjectAccessReviewSpec{
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{
|
||||
Verb: "list",
|
||||
Group: api.GroupName,
|
||||
Version: "v1",
|
||||
Resource: "pods",
|
||||
},
|
||||
User: "dave",
|
||||
},
|
||||
},
|
||||
expectedStatus: authorizationapi.SubjectAccessReviewStatus{
|
||||
Allowed: false,
|
||||
Reason: "no",
|
||||
EvaluationError: "I'm sorry, Dave",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "simple error",
|
||||
sar: &authorizationapi.SubjectAccessReview{
|
||||
Spec: authorizationapi.SubjectAccessReviewSpec{
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{
|
||||
Verb: "list",
|
||||
Group: api.GroupName,
|
||||
Version: "v1",
|
||||
Resource: "pods",
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedError: "at least one of user or group must be specified",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
response, err := clientset.Authorization().SubjectAccessReviews().Create(test.sar)
|
||||
switch {
|
||||
case err == nil && len(test.expectedError) == 0:
|
||||
|
||||
case err != nil && strings.Contains(err.Error(), test.expectedError):
|
||||
continue
|
||||
|
||||
case err != nil && len(test.expectedError) != 0:
|
||||
t.Errorf("%s: unexpected error: %v", test.name, err)
|
||||
continue
|
||||
default:
|
||||
t.Errorf("%s: expected %v, got %v", test.name, test.expectedError, err)
|
||||
continue
|
||||
}
|
||||
if response.Status != test.expectedStatus {
|
||||
t.Errorf("%s: expected %v, got %v", test.name, test.expectedStatus, response.Status)
|
||||
continue
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue