KEP-3325: Promote SelfSubjectReview to Beta (#116274)
* Promote SelfSubjectReview to Beta Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com> * Fix whoami API Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com> * Fixes according to code review Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com> --------- Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com> Kubernetes-commit: c1431af4f83b2b06a581f23806ee12a0663fed3b
This commit is contained in:
parent
58a69e79d3
commit
ea55df59db
16
go.mod
16
go.mod
|
@ -30,11 +30,11 @@ require (
|
|||
github.com/stretchr/testify v1.8.1
|
||||
golang.org/x/sys v0.5.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
k8s.io/api v0.0.0-20230307055637-a9e2fb5f094f
|
||||
k8s.io/api v0.0.0-20230308234233-a4afee70a903
|
||||
k8s.io/apimachinery v0.0.0-20230303235435-f357b1fa74b7
|
||||
k8s.io/cli-runtime v0.0.0-20230307041416-a9210da26a77
|
||||
k8s.io/client-go v0.0.0-20230307074101-60e53732bb78
|
||||
k8s.io/component-base v0.0.0-20230304000900-3bf8af940f29
|
||||
k8s.io/cli-runtime v0.0.0-20230307162015-1076364b1950
|
||||
k8s.io/client-go v0.0.0-20230309033544-64e2c7ff167c
|
||||
k8s.io/component-base v0.0.0-20230308075123-cfc68dcaff73
|
||||
k8s.io/component-helpers v0.0.0-20230304001010-94a6fd9a7905
|
||||
k8s.io/klog/v2 v2.90.1
|
||||
k8s.io/kube-openapi v0.0.0-20230303024457-afdc3dddf62d
|
||||
|
@ -91,12 +91,12 @@ require (
|
|||
)
|
||||
|
||||
replace (
|
||||
k8s.io/api => k8s.io/api v0.0.0-20230307055637-a9e2fb5f094f
|
||||
k8s.io/api => k8s.io/api v0.0.0-20230308234233-a4afee70a903
|
||||
k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20230303235435-f357b1fa74b7
|
||||
k8s.io/cli-runtime => k8s.io/cli-runtime v0.0.0-20230307041416-a9210da26a77
|
||||
k8s.io/client-go => k8s.io/client-go v0.0.0-20230307074101-60e53732bb78
|
||||
k8s.io/cli-runtime => k8s.io/cli-runtime v0.0.0-20230307162015-1076364b1950
|
||||
k8s.io/client-go => k8s.io/client-go v0.0.0-20230309033544-64e2c7ff167c
|
||||
k8s.io/code-generator => k8s.io/code-generator v0.0.0-20230303235006-4400d5f574d7
|
||||
k8s.io/component-base => k8s.io/component-base v0.0.0-20230304000900-3bf8af940f29
|
||||
k8s.io/component-base => k8s.io/component-base v0.0.0-20230308075123-cfc68dcaff73
|
||||
k8s.io/component-helpers => k8s.io/component-helpers v0.0.0-20230304001010-94a6fd9a7905
|
||||
k8s.io/metrics => k8s.io/metrics v0.0.0-20230306121834-133605a72766
|
||||
)
|
||||
|
|
16
go.sum
16
go.sum
|
@ -531,16 +531,16 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
|
|||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
k8s.io/api v0.0.0-20230307055637-a9e2fb5f094f h1:kf7PdQ7o4kYpR8wNMDP5BBDX6zN+f7sNbrzz25aL7oE=
|
||||
k8s.io/api v0.0.0-20230307055637-a9e2fb5f094f/go.mod h1:esKbT+6XB9TZUHyxlJVQ3zUM0abhQZ81Ic68eirO+xM=
|
||||
k8s.io/api v0.0.0-20230308234233-a4afee70a903 h1:TmxUf1tDcGUHE8qZKLRWmn2nr2FypkwvqC2qviOUmQc=
|
||||
k8s.io/api v0.0.0-20230308234233-a4afee70a903/go.mod h1:esKbT+6XB9TZUHyxlJVQ3zUM0abhQZ81Ic68eirO+xM=
|
||||
k8s.io/apimachinery v0.0.0-20230303235435-f357b1fa74b7 h1:YN43Lvs3Pj9iQmuWGojeBiFdz1mkrxe0EZn7Ba3TMpQ=
|
||||
k8s.io/apimachinery v0.0.0-20230303235435-f357b1fa74b7/go.mod h1:jlJwObMa4oKAEOMnAeEaqeiM+Fwd/CbAwNyQ7OaEwS0=
|
||||
k8s.io/cli-runtime v0.0.0-20230307041416-a9210da26a77 h1:t+fWCmEVuJTApmS651BRSDqIOzfsw5EftlXXY/R7zqY=
|
||||
k8s.io/cli-runtime v0.0.0-20230307041416-a9210da26a77/go.mod h1:19C5E5NH5eRJBAD9wkz/TV0JUtO1/tGG1z+uTXwW58k=
|
||||
k8s.io/client-go v0.0.0-20230307074101-60e53732bb78 h1:sC/AUHGA0wfCxQQCzQLYZkyTCtWZf7cZN0nTFSbLlzw=
|
||||
k8s.io/client-go v0.0.0-20230307074101-60e53732bb78/go.mod h1:p2Qa5FMYfRFhtNUgj4FM9vYyVvKg8PfBqOpUwg4f4zY=
|
||||
k8s.io/component-base v0.0.0-20230304000900-3bf8af940f29 h1:26PuXs5/GsCX5EPltZN9KjZqkW/EwYHaebfNmIK3Wxc=
|
||||
k8s.io/component-base v0.0.0-20230304000900-3bf8af940f29/go.mod h1:1aFiUfjXiy45a88xJmd/nSkReVCoyShEHbGmWJQbp2Q=
|
||||
k8s.io/cli-runtime v0.0.0-20230307162015-1076364b1950 h1:e8AHvyKm96kzxrktgL7dPMY65BA5C2S30X3CPKHKO+E=
|
||||
k8s.io/cli-runtime v0.0.0-20230307162015-1076364b1950/go.mod h1:OBJKwPnOnWPdaZpa2ULBQaUf0b2p01bWWddPOpIxtyE=
|
||||
k8s.io/client-go v0.0.0-20230309033544-64e2c7ff167c h1:1IXuG9QQvPMR3GbYgBhOKre47MAIq+U41cWOGoAHpd8=
|
||||
k8s.io/client-go v0.0.0-20230309033544-64e2c7ff167c/go.mod h1:hjEB5iFHr17qVb6wnh6w2LQvO5DfoP6rzLN8NAE8K6U=
|
||||
k8s.io/component-base v0.0.0-20230308075123-cfc68dcaff73 h1:MEKvhkstqrRFmA9+qQlnkA/jPbZUH/VnMKiEfBeLbf8=
|
||||
k8s.io/component-base v0.0.0-20230308075123-cfc68dcaff73/go.mod h1:MB0hQ6Wy3OOZ/dr+sy5FwxCJhDJ4hszX743ar8dd2zE=
|
||||
k8s.io/component-helpers v0.0.0-20230304001010-94a6fd9a7905 h1:kHWUeYs8Mc9IQpqULpPd2j8G6cqqf/fz5wzvqcYCdSQ=
|
||||
k8s.io/component-helpers v0.0.0-20230304001010-94a6fd9a7905/go.mod h1:IrR1jWfgEwsQ2rBPvbuwL8bmskaLy5lDQ8mIPnPXcbA=
|
||||
k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw=
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
# See the OWNERS docs at https://go.k8s.io/owners
|
||||
|
||||
approvers:
|
||||
- sig-auth-authenticators-approvers
|
||||
- sig-auth-authorizers-approvers
|
||||
reviewers:
|
||||
- sig-auth-authenticators-reviewers
|
||||
- sig-auth-authorizers-reviewers
|
||||
labels:
|
||||
- sig/auth
|
||||
|
|
|
@ -22,7 +22,9 @@ import (
|
|||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
authenticationv1 "k8s.io/api/authentication/v1"
|
||||
authenticationv1alpha1 "k8s.io/api/authentication/v1alpha1"
|
||||
authenticationv1beta1 "k8s.io/api/authentication/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
@ -30,6 +32,7 @@ import (
|
|||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
"k8s.io/cli-runtime/pkg/printers"
|
||||
authenticationv1alpha1client "k8s.io/client-go/kubernetes/typed/authentication/v1alpha1"
|
||||
authenticationv1beta1client "k8s.io/client-go/kubernetes/typed/authentication/v1beta1"
|
||||
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
||||
"k8s.io/kubectl/pkg/scheme"
|
||||
"k8s.io/kubectl/pkg/util/templates"
|
||||
|
@ -71,7 +74,12 @@ func (flags *WhoAmIFlags) ToOptions(ctx context.Context, args []string) (*WhoAmI
|
|||
return nil, err
|
||||
}
|
||||
|
||||
w.authClient, err = authenticationv1alpha1client.NewForConfig(clientConfig)
|
||||
w.authV1alpha1Client, err = authenticationv1alpha1client.NewForConfig(clientConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
w.authV1beta1Client, err = authenticationv1beta1client.NewForConfig(clientConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -92,8 +100,10 @@ func (flags *WhoAmIFlags) ToOptions(ctx context.Context, args []string) (*WhoAmI
|
|||
// WhoAmIOptions is the start of the data required to perform the operation. As new fields are added,
|
||||
// add them here instead of referencing the cmd.Flags()
|
||||
type WhoAmIOptions struct {
|
||||
authClient authenticationv1alpha1client.AuthenticationV1alpha1Interface
|
||||
ctx context.Context
|
||||
authV1alpha1Client authenticationv1alpha1client.AuthenticationV1alpha1Interface
|
||||
authV1beta1Client authenticationv1beta1client.AuthenticationV1beta1Interface
|
||||
|
||||
ctx context.Context
|
||||
|
||||
resourcePrinterFunc printers.ResourcePrinterFunc
|
||||
|
||||
|
@ -142,7 +152,7 @@ func NewCmdWhoAmI(restClientGetter genericclioptions.RESTClientGetter, streams g
|
|||
var (
|
||||
notEnabledErr = fmt.Errorf(
|
||||
"the selfsubjectreviews API is not enabled in the cluster\n" +
|
||||
"enable APISelfSubjectReview feature gate and authentication.k8s.io/v1alpha1 API")
|
||||
"enable APISelfSubjectReview feature gate and authentication.k8s.io/v1alpha1 or authentication.k8s.io/v1beta1 API")
|
||||
|
||||
forbiddenErr = fmt.Errorf(
|
||||
"the selfsubjectreviews API is not enabled in the cluster or you do not have permission to call it")
|
||||
|
@ -150,8 +160,20 @@ var (
|
|||
|
||||
// Run prints all user attributes.
|
||||
func (o WhoAmIOptions) Run() error {
|
||||
sar := &authenticationv1alpha1.SelfSubjectReview{}
|
||||
response, err := o.authClient.SelfSubjectReviews().Create(context.TODO(), sar, metav1.CreateOptions{})
|
||||
var (
|
||||
res runtime.Object
|
||||
err error
|
||||
)
|
||||
|
||||
res, err = o.authV1beta1Client.
|
||||
SelfSubjectReviews().
|
||||
Create(context.TODO(), &authenticationv1beta1.SelfSubjectReview{}, metav1.CreateOptions{})
|
||||
if err != nil && errors.IsNotFound(err) {
|
||||
// Fallback to Alpha API if Beta is not enabled
|
||||
res, err = o.authV1alpha1Client.
|
||||
SelfSubjectReviews().
|
||||
Create(context.TODO(), &authenticationv1alpha1.SelfSubjectReview{}, metav1.CreateOptions{})
|
||||
}
|
||||
if err != nil {
|
||||
switch {
|
||||
case errors.IsForbidden(err):
|
||||
|
@ -162,25 +184,34 @@ func (o WhoAmIOptions) Run() error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
return o.resourcePrinterFunc(response, o.Out)
|
||||
return o.resourcePrinterFunc(res, o.Out)
|
||||
}
|
||||
|
||||
func getUserInfo(obj runtime.Object) (authenticationv1.UserInfo, error) {
|
||||
switch obj.(type) {
|
||||
case *authenticationv1alpha1.SelfSubjectReview:
|
||||
return obj.(*authenticationv1alpha1.SelfSubjectReview).Status.UserInfo, nil
|
||||
case *authenticationv1beta1.SelfSubjectReview:
|
||||
return obj.(*authenticationv1beta1.SelfSubjectReview).Status.UserInfo, nil
|
||||
default:
|
||||
return authenticationv1.UserInfo{}, fmt.Errorf("unexpected response type %T, expected SelfSubjectReview", obj)
|
||||
}
|
||||
}
|
||||
|
||||
func printTableSelfSubjectAccessReview(obj runtime.Object, out io.Writer) error {
|
||||
ssr, ok := obj.(*authenticationv1alpha1.SelfSubjectReview)
|
||||
if !ok {
|
||||
return fmt.Errorf("object is not SelfSubjectReview")
|
||||
ui, err := getUserInfo(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w := printers.GetNewTabWriter(out)
|
||||
defer w.Flush()
|
||||
|
||||
_, err := fmt.Fprintf(w, "ATTRIBUTE\tVALUE\n")
|
||||
_, err = fmt.Fprintf(w, "ATTRIBUTE\tVALUE\n")
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot write a header: %w", err)
|
||||
}
|
||||
|
||||
ui := ssr.Status.UserInfo
|
||||
|
||||
if ui.Username != "" {
|
||||
_, err := fmt.Fprintf(w, "Username\t%s\n", ui.Username)
|
||||
if err != nil {
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
|
||||
authenticationv1 "k8s.io/api/authentication/v1"
|
||||
authenticationv1alpha1 "k8s.io/api/authentication/v1alpha1"
|
||||
authenticationv1beta1 "k8s.io/api/authentication/v1beta1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
@ -37,10 +38,12 @@ import (
|
|||
|
||||
func TestWhoAmIRun(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
o *WhoAmIOptions
|
||||
args []string
|
||||
serverErr error
|
||||
name string
|
||||
o *WhoAmIOptions
|
||||
args []string
|
||||
serverErr error
|
||||
alphaDisabled bool
|
||||
betaDisabled bool
|
||||
|
||||
expectedError error
|
||||
expectedBodyStrings []string
|
||||
|
@ -70,6 +73,116 @@ func TestWhoAmIRun(t *testing.T) {
|
|||
expectedBodyStrings: []string{
|
||||
`{
|
||||
"kind": "SelfSubjectReview",
|
||||
"apiVersion": "authentication.k8s.io/v1beta1",
|
||||
"metadata": {
|
||||
"creationTimestamp": null
|
||||
},
|
||||
"status": {
|
||||
"userInfo": {
|
||||
"username": "jane.doe",
|
||||
"uid": "uniq-id",
|
||||
"groups": [
|
||||
"students",
|
||||
"teachers"
|
||||
],
|
||||
"extra": {
|
||||
"skills": [
|
||||
"reading",
|
||||
"learning"
|
||||
],
|
||||
"subjects": [
|
||||
"math",
|
||||
"sports"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "success test no alpha",
|
||||
o: &WhoAmIOptions{
|
||||
resourcePrinterFunc: printTableSelfSubjectAccessReview,
|
||||
},
|
||||
args: []string{},
|
||||
alphaDisabled: true,
|
||||
expectedBodyStrings: []string{
|
||||
`ATTRIBUTE VALUE`,
|
||||
`Username jane.doe`,
|
||||
`UID uniq-id`,
|
||||
`Groups [students teachers]`,
|
||||
`Extra: skills [reading learning]`,
|
||||
`Extra: subjects [math sports]`,
|
||||
``,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "JSON test no alpha",
|
||||
o: &WhoAmIOptions{
|
||||
resourcePrinterFunc: printers.NewTypeSetter(scheme.Scheme).ToPrinter(&printers.JSONPrinter{}).PrintObj,
|
||||
},
|
||||
args: []string{},
|
||||
alphaDisabled: true,
|
||||
expectedBodyStrings: []string{
|
||||
`{
|
||||
"kind": "SelfSubjectReview",
|
||||
"apiVersion": "authentication.k8s.io/v1beta1",
|
||||
"metadata": {
|
||||
"creationTimestamp": null
|
||||
},
|
||||
"status": {
|
||||
"userInfo": {
|
||||
"username": "jane.doe",
|
||||
"uid": "uniq-id",
|
||||
"groups": [
|
||||
"students",
|
||||
"teachers"
|
||||
],
|
||||
"extra": {
|
||||
"skills": [
|
||||
"reading",
|
||||
"learning"
|
||||
],
|
||||
"subjects": [
|
||||
"math",
|
||||
"sports"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "success test no beta",
|
||||
o: &WhoAmIOptions{
|
||||
resourcePrinterFunc: printTableSelfSubjectAccessReview,
|
||||
},
|
||||
args: []string{},
|
||||
betaDisabled: true,
|
||||
expectedBodyStrings: []string{
|
||||
`ATTRIBUTE VALUE`,
|
||||
`Username jane.doe`,
|
||||
`UID uniq-id`,
|
||||
`Groups [students teachers]`,
|
||||
`Extra: skills [reading learning]`,
|
||||
`Extra: subjects [math sports]`,
|
||||
``,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "JSON test no beta",
|
||||
o: &WhoAmIOptions{
|
||||
resourcePrinterFunc: printers.NewTypeSetter(scheme.Scheme).ToPrinter(&printers.JSONPrinter{}).PrintObj,
|
||||
},
|
||||
args: []string{},
|
||||
betaDisabled: true,
|
||||
expectedBodyStrings: []string{
|
||||
`{
|
||||
"kind": "SelfSubjectReview",
|
||||
"apiVersion": "authentication.k8s.io/v1alpha1",
|
||||
"metadata": {
|
||||
"creationTimestamp": null
|
||||
|
@ -98,6 +211,16 @@ func TestWhoAmIRun(t *testing.T) {
|
|||
`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "both API disabled",
|
||||
o: &WhoAmIOptions{
|
||||
resourcePrinterFunc: printTableSelfSubjectAccessReview,
|
||||
},
|
||||
args: []string{},
|
||||
betaDisabled: true,
|
||||
alphaDisabled: true,
|
||||
expectedError: notEnabledErr,
|
||||
},
|
||||
{
|
||||
name: "Forbidden error",
|
||||
o: &WhoAmIOptions{
|
||||
|
@ -150,22 +273,43 @@ func TestWhoAmIRun(t *testing.T) {
|
|||
return true, nil, test.serverErr
|
||||
}
|
||||
|
||||
res := &authenticationv1alpha1.SelfSubjectReview{
|
||||
Status: authenticationv1alpha1.SelfSubjectReviewStatus{
|
||||
UserInfo: authenticationv1.UserInfo{
|
||||
Username: "jane.doe",
|
||||
UID: "uniq-id",
|
||||
Groups: []string{"students", "teachers"},
|
||||
Extra: map[string]authenticationv1.ExtraValue{
|
||||
"subjects": {"math", "sports"},
|
||||
"skills": {"reading", "learning"},
|
||||
},
|
||||
},
|
||||
ui := authenticationv1.UserInfo{
|
||||
Username: "jane.doe",
|
||||
UID: "uniq-id",
|
||||
Groups: []string{"students", "teachers"},
|
||||
Extra: map[string]authenticationv1.ExtraValue{
|
||||
"subjects": {"math", "sports"},
|
||||
"skills": {"reading", "learning"},
|
||||
},
|
||||
}
|
||||
return true, res, nil
|
||||
|
||||
switch action.GetResource().GroupVersion().String() {
|
||||
case "authentication.k8s.io/v1alpha1":
|
||||
if test.alphaDisabled {
|
||||
return true, nil, errors.NewNotFound(corev1.Resource("selfsubjectreviews"), "foo")
|
||||
}
|
||||
res := &authenticationv1alpha1.SelfSubjectReview{
|
||||
Status: authenticationv1alpha1.SelfSubjectReviewStatus{
|
||||
UserInfo: ui,
|
||||
},
|
||||
}
|
||||
return true, res, nil
|
||||
case "authentication.k8s.io/v1beta1":
|
||||
if test.betaDisabled {
|
||||
return true, nil, errors.NewNotFound(corev1.Resource("selfsubjectreviews"), "foo")
|
||||
}
|
||||
res := &authenticationv1beta1.SelfSubjectReview{
|
||||
Status: authenticationv1beta1.SelfSubjectReviewStatus{
|
||||
UserInfo: ui,
|
||||
},
|
||||
}
|
||||
return true, res, nil
|
||||
default:
|
||||
return false, nil, fmt.Errorf("unknown API")
|
||||
}
|
||||
})
|
||||
test.o.authClient = fakeAuthClientSet.AuthenticationV1alpha1()
|
||||
test.o.authV1beta1Client = fakeAuthClientSet.AuthenticationV1beta1()
|
||||
test.o.authV1alpha1Client = fakeAuthClientSet.AuthenticationV1alpha1()
|
||||
|
||||
err := test.o.Run()
|
||||
switch {
|
||||
|
|
Loading…
Reference in New Issue