mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-24 12:15:52 +00:00
Merge pull request #108810 from enj/enj/i/create_token_duration
kubectl create token: use duration instead of expiration seconds
This commit is contained in:
commit
b383035ca3
@ -20,6 +20,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
@ -35,6 +36,7 @@ import (
|
|||||||
"k8s.io/kubectl/pkg/util"
|
"k8s.io/kubectl/pkg/util"
|
||||||
"k8s.io/kubectl/pkg/util/templates"
|
"k8s.io/kubectl/pkg/util/templates"
|
||||||
"k8s.io/kubectl/pkg/util/term"
|
"k8s.io/kubectl/pkg/util/term"
|
||||||
|
"k8s.io/utils/pointer"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TokenOptions is the data required to perform a token request operation.
|
// TokenOptions is the data required to perform a token request operation.
|
||||||
@ -57,8 +59,8 @@ type TokenOptions struct {
|
|||||||
// Audiences indicate the valid audiences for the requested token. If unset, defaults to the Kubernetes API server audiences.
|
// Audiences indicate the valid audiences for the requested token. If unset, defaults to the Kubernetes API server audiences.
|
||||||
Audiences []string
|
Audiences []string
|
||||||
|
|
||||||
// ExpirationSeconds is the requested token lifetime. Optional.
|
// Duration is the requested token lifetime. Optional.
|
||||||
ExpirationSeconds int64
|
Duration time.Duration
|
||||||
|
|
||||||
// CoreClient is the API client used to request the token. Required.
|
// CoreClient is the API client used to request the token. Required.
|
||||||
CoreClient corev1client.CoreV1Interface
|
CoreClient corev1client.CoreV1Interface
|
||||||
@ -78,7 +80,7 @@ var (
|
|||||||
kubectl create token myapp --namespace myns
|
kubectl create token myapp --namespace myns
|
||||||
|
|
||||||
# Request a token with a custom expiration
|
# Request a token with a custom expiration
|
||||||
kubectl create token myapp --expiration-seconds 600
|
kubectl create token myapp --duration 10m
|
||||||
|
|
||||||
# Request a token with a custom audience
|
# Request a token with a custom audience
|
||||||
kubectl create token myapp --audience https://example.com
|
kubectl create token myapp --audience https://example.com
|
||||||
@ -134,7 +136,7 @@ func NewCmdCreateToken(f cmdutil.Factory, ioStreams genericclioptions.IOStreams)
|
|||||||
|
|
||||||
cmd.Flags().StringArrayVar(&o.Audiences, "audience", o.Audiences, "Audience of the requested token. If unset, defaults to requesting a token for use with the Kubernetes API server. May be repeated to request a token valid for multiple audiences.")
|
cmd.Flags().StringArrayVar(&o.Audiences, "audience", o.Audiences, "Audience of the requested token. If unset, defaults to requesting a token for use with the Kubernetes API server. May be repeated to request a token valid for multiple audiences.")
|
||||||
|
|
||||||
cmd.Flags().Int64Var(&o.ExpirationSeconds, "expiration-seconds", o.ExpirationSeconds, "Requested lifetime of the issued token. The server may return a token with a longer or shorter lifetime.")
|
cmd.Flags().DurationVar(&o.Duration, "duration", o.Duration, "Requested lifetime of the issued token. The server may return a token with a longer or shorter lifetime.")
|
||||||
|
|
||||||
cmd.Flags().StringVar(&o.BoundObjectKind, "bound-object-kind", o.BoundObjectKind, "Kind of an object to bind the token to. "+
|
cmd.Flags().StringVar(&o.BoundObjectKind, "bound-object-kind", o.BoundObjectKind, "Kind of an object to bind the token to. "+
|
||||||
"Supported kinds are "+strings.Join(sets.StringKeySet(boundObjectKindToAPIVersion).List(), ", ")+". "+
|
"Supported kinds are "+strings.Join(sets.StringKeySet(boundObjectKindToAPIVersion).List(), ", ")+". "+
|
||||||
@ -192,8 +194,11 @@ func (o *TokenOptions) Validate() error {
|
|||||||
if len(o.Namespace) == 0 {
|
if len(o.Namespace) == 0 {
|
||||||
return fmt.Errorf("--namespace is required")
|
return fmt.Errorf("--namespace is required")
|
||||||
}
|
}
|
||||||
if o.ExpirationSeconds < 0 {
|
if o.Duration < 0 {
|
||||||
return fmt.Errorf("--expiration-seconds must be positive")
|
return fmt.Errorf("--duration must be positive")
|
||||||
|
}
|
||||||
|
if o.Duration%time.Second != 0 {
|
||||||
|
return fmt.Errorf("--duration cannot be expressed in units less than seconds")
|
||||||
}
|
}
|
||||||
for _, aud := range o.Audiences {
|
for _, aud := range o.Audiences {
|
||||||
if len(aud) == 0 {
|
if len(aud) == 0 {
|
||||||
@ -227,8 +232,8 @@ func (o *TokenOptions) Run() error {
|
|||||||
Audiences: o.Audiences,
|
Audiences: o.Audiences,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if o.ExpirationSeconds > 0 {
|
if o.Duration > 0 {
|
||||||
request.Spec.ExpirationSeconds = &o.ExpirationSeconds
|
request.Spec.ExpirationSeconds = pointer.Int64(int64(o.Duration / time.Second))
|
||||||
}
|
}
|
||||||
if len(o.BoundObjectKind) > 0 {
|
if len(o.BoundObjectKind) > 0 {
|
||||||
request.Spec.BoundObjectRef = &authenticationv1.BoundObjectReference{
|
request.Spec.BoundObjectRef = &authenticationv1.BoundObjectReference{
|
||||||
|
@ -22,8 +22,8 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
"k8s.io/utils/pointer"
|
"k8s.io/utils/pointer"
|
||||||
@ -44,14 +44,14 @@ func TestCreateToken(t *testing.T) {
|
|||||||
tests := []struct {
|
tests := []struct {
|
||||||
test string
|
test string
|
||||||
|
|
||||||
name string
|
name string
|
||||||
namespace string
|
namespace string
|
||||||
output string
|
output string
|
||||||
boundObjectKind string
|
boundObjectKind string
|
||||||
boundObjectName string
|
boundObjectName string
|
||||||
boundObjectUID string
|
boundObjectUID string
|
||||||
audiences []string
|
audiences []string
|
||||||
expirationSeconds int
|
duration time.Duration
|
||||||
|
|
||||||
serverResponseToken string
|
serverResponseToken string
|
||||||
serverResponseError string
|
serverResponseError string
|
||||||
@ -183,16 +183,22 @@ status:
|
|||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
test: "invalid expiration",
|
test: "invalid duration",
|
||||||
name: "mysa",
|
name: "mysa",
|
||||||
expirationSeconds: -1,
|
duration: -1,
|
||||||
expectStderr: `error: --expiration-seconds must be positive`,
|
expectStderr: `error: --duration must be positive`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: "valid expiration",
|
test: "invalid duration unit",
|
||||||
|
name: "mysa",
|
||||||
|
duration: time.Microsecond,
|
||||||
|
expectStderr: `error: --duration cannot be expressed in units less than seconds`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: "valid duration",
|
||||||
name: "mysa",
|
name: "mysa",
|
||||||
|
|
||||||
expirationSeconds: 1000,
|
duration: 1000 * time.Second,
|
||||||
|
|
||||||
expectRequestPath: "/api/v1/namespaces/test/serviceaccounts/mysa/token",
|
expectRequestPath: "/api/v1/namespaces/test/serviceaccounts/mysa/token",
|
||||||
expectTokenRequest: &authenticationv1.TokenRequest{
|
expectTokenRequest: &authenticationv1.TokenRequest{
|
||||||
@ -310,8 +316,8 @@ status:
|
|||||||
for _, aud := range test.audiences {
|
for _, aud := range test.audiences {
|
||||||
cmd.Flags().Set("audience", aud)
|
cmd.Flags().Set("audience", aud)
|
||||||
}
|
}
|
||||||
if test.expirationSeconds != 0 {
|
if test.duration != 0 {
|
||||||
cmd.Flags().Set("expiration-seconds", strconv.Itoa(test.expirationSeconds))
|
cmd.Flags().Set("duration", test.duration.String())
|
||||||
}
|
}
|
||||||
cmd.Run(cmd, []string{test.name})
|
cmd.Run(cmd, []string{test.name})
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user