Skip to content

Commit

Permalink
add subjectaccessreviews resource
Browse files Browse the repository at this point in the history
  • Loading branch information
deads2k committed Aug 5, 2016
1 parent 5f3cc4a commit 32920b5
Show file tree
Hide file tree
Showing 36 changed files with 914 additions and 43 deletions.
13 changes: 11 additions & 2 deletions cmd/libs/go2idl/client-gen/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.")
Expand Down
1 change: 1 addition & 0 deletions cmd/libs/go2idl/go-to-protobuf/protobuf/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -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`,
Expand Down
20 changes: 20 additions & 0 deletions hack/make-rules/test-cmd.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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 #
#####################
Expand Down
2 changes: 1 addition & 1 deletion hack/make-rules/test-integration.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion hack/make-rules/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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:-}
Expand Down
2 changes: 1 addition & 1 deletion hack/update-codegen.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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" "$@"
Expand Down
2 changes: 1 addition & 1 deletion hack/update-swagger-spec.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
1 change: 1 addition & 0 deletions pkg/api/testapi/testapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
1 change: 1 addition & 0 deletions pkg/apis/authorization/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
18 changes: 17 additions & 1 deletion pkg/apis/authorization/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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.
Expand Down Expand Up @@ -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 {
Expand All @@ -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
}
1 change: 1 addition & 0 deletions pkg/apis/authorization/v1beta1/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
7 changes: 7 additions & 0 deletions pkg/apis/authorization/v1beta1/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 }
Expand Down
71 changes: 47 additions & 24 deletions pkg/apis/authorization/v1beta1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,45 +17,55 @@ 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
// spec.namespace means "in all namespaces". Self is a special case, because users should always be able
// 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.
// Having a namespace scoped resource makes it much easier to grant namespace scoped policy that includes permissions
// 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
Expand All @@ -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"`
}
Loading

0 comments on commit 32920b5

Please sign in to comment.