mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 03:41:45 +00:00
extend sa token if audience is apiserver (#105954)
Signed-off-by: Jyoti Mahapatra <jyotima@amazon.com>
This commit is contained in:
parent
7c2e612569
commit
a1b52fb17a
@ -20,6 +20,7 @@ import (
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||
"k8s.io/apiserver/pkg/registry/generic"
|
||||
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
|
||||
@ -64,6 +65,7 @@ func NewREST(optsGetter generic.RESTOptionsGetter, issuer token.TokenGenerator,
|
||||
secrets: secretStorage,
|
||||
issuer: issuer,
|
||||
auds: auds,
|
||||
audsSet: sets.NewString(auds...),
|
||||
maxExpirationSeconds: int64(max.Seconds()),
|
||||
extendExpiration: extendExpiration,
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
@ -46,6 +47,7 @@ type TokenREST struct {
|
||||
secrets getter
|
||||
issuer token.TokenGenerator
|
||||
auds authenticator.Audiences
|
||||
audsSet sets.String
|
||||
maxExpirationSeconds int64
|
||||
extendExpiration bool
|
||||
}
|
||||
@ -129,7 +131,7 @@ func (r *TokenREST) Create(ctx context.Context, name string, obj runtime.Object,
|
||||
// Only perform the extension when token is pod-bound.
|
||||
var warnAfter int64
|
||||
exp := out.Spec.ExpirationSeconds
|
||||
if r.extendExpiration && pod != nil && out.Spec.ExpirationSeconds == token.WarnOnlyBoundTokenExpirationSeconds {
|
||||
if r.extendExpiration && pod != nil && out.Spec.ExpirationSeconds == token.WarnOnlyBoundTokenExpirationSeconds && r.isKubeAudiences(out.Spec.Audiences) {
|
||||
warnAfter = exp
|
||||
exp = token.ExpirationExtensionSeconds
|
||||
}
|
||||
@ -176,3 +178,9 @@ func newContext(ctx context.Context, resource, name string, gvk schema.GroupVers
|
||||
}
|
||||
return genericapirequest.WithRequestInfo(ctx, &newInfo)
|
||||
}
|
||||
|
||||
// isKubeAudiences returns true if the tokenaudiences is a strict subset of apiserver audiences.
|
||||
func (r *TokenREST) isKubeAudiences(tokenAudience []string) bool {
|
||||
// tokenAudiences must be a strict subset of apiserver audiences
|
||||
return r.audsSet.HasAll(tokenAudience...)
|
||||
}
|
||||
|
@ -54,13 +54,17 @@ import (
|
||||
"k8s.io/kubernetes/test/integration/framework"
|
||||
)
|
||||
|
||||
// This key is for testing purposes only and is not considered secure.
|
||||
const ecdsaPrivateKey = `-----BEGIN EC PRIVATE KEY-----
|
||||
const (
|
||||
// This key is for testing purposes only and is not considered secure.
|
||||
ecdsaPrivateKey = `-----BEGIN EC PRIVATE KEY-----
|
||||
MHcCAQEEIEZmTmUhuanLjPA2CLquXivuwBDHTt5XYwgIr/kA1LtRoAoGCCqGSM49
|
||||
AwEHoUQDQgAEH6cuzP8XuD5wal6wf9M6xDljTOPLX2i8uIp/C/ASqiIGUeeKQtX0
|
||||
/IR3qCXyThP/dbCiHrF3v1cuhBOHY8CLVg==
|
||||
-----END EC PRIVATE KEY-----`
|
||||
|
||||
tokenExpirationSeconds = 60*60 + 7
|
||||
)
|
||||
|
||||
func TestServiceAccountTokenCreate(t *testing.T) {
|
||||
|
||||
// Build client config, clientset, and informers
|
||||
@ -382,7 +386,7 @@ func TestServiceAccountTokenCreate(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("expiration extended token", func(t *testing.T) {
|
||||
var requestExp int64 = 60*60 + 7
|
||||
var requestExp int64 = tokenExpirationSeconds
|
||||
treq := &authenticationv1.TokenRequest{
|
||||
Spec: authenticationv1.TokenRequestSpec{
|
||||
Audiences: []string{"api"},
|
||||
@ -435,6 +439,56 @@ func TestServiceAccountTokenCreate(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("extended expiration extended does not apply for other audiences", func(t *testing.T) {
|
||||
var requestExp int64 = tokenExpirationSeconds
|
||||
treq := &authenticationv1.TokenRequest{
|
||||
Spec: authenticationv1.TokenRequestSpec{
|
||||
Audiences: []string{"not-the-api", "api"},
|
||||
ExpirationSeconds: &requestExp,
|
||||
BoundObjectRef: &authenticationv1.BoundObjectReference{
|
||||
Kind: "Pod",
|
||||
APIVersion: "v1",
|
||||
Name: pod.Name,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
sa, del := createDeleteSvcAcct(t, cs, sa)
|
||||
defer del()
|
||||
pod, delPod := createDeletePod(t, cs, pod)
|
||||
defer delPod()
|
||||
treq.Spec.BoundObjectRef.UID = pod.UID
|
||||
|
||||
treq, err = cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(context.TODO(), sa.Name, treq, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
// Give some tolerance to avoid flakiness since we are using real time.
|
||||
var leeway int64 = 10
|
||||
actualExpiry := jwt.NewNumericDate(time.Now().Add(time.Duration(60*60) * time.Second))
|
||||
assumedExpiry := jwt.NewNumericDate(time.Now().Add(time.Duration(requestExp) * time.Second))
|
||||
|
||||
warnAfter := getSubObject(t, getPayload(t, treq.Status.Token), "kubernetes.io", "warnafter")
|
||||
if warnAfter != "null" {
|
||||
t.Errorf("warn after should be empty.Found: %s", warnAfter)
|
||||
}
|
||||
|
||||
exp, err := strconv.ParseInt(getSubObject(t, getPayload(t, treq.Status.Token), "exp"), 10, 64)
|
||||
if err != nil {
|
||||
t.Fatalf("error parsing exp: %v", err)
|
||||
}
|
||||
if exp < int64(actualExpiry)-leeway || exp > int64(actualExpiry)+leeway {
|
||||
t.Errorf("unexpected token exp %d, should within range of %d +- %d seconds", exp, actualExpiry, leeway)
|
||||
}
|
||||
|
||||
checkExpiration(t, treq, requestExp)
|
||||
expStatus := treq.Status.ExpirationTimestamp.Time.Unix()
|
||||
if expStatus < int64(assumedExpiry)-leeway {
|
||||
t.Errorf("unexpected expiration returned in tokenrequest status %d, should within range of %d +- %d seconds", expStatus, assumedExpiry, leeway)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("a token without an api audience is invalid", func(t *testing.T) {
|
||||
treq := &authenticationv1.TokenRequest{
|
||||
Spec: authenticationv1.TokenRequestSpec{
|
||||
|
Loading…
Reference in New Issue
Block a user