Validate and populate metadata fields in token request

This commit is contained in:
Jordan Liggitt
2022-02-04 13:45:18 -05:00
parent 9b09612d1b
commit 19d71bb5d5
2 changed files with 156 additions and 21 deletions

View File

@@ -29,6 +29,7 @@ import (
"reflect"
"strconv"
"strings"
"sync"
"testing"
"time"
@@ -126,7 +127,11 @@ func TestServiceAccountTokenCreate(t *testing.T) {
instanceConfig, _, closeFn := framework.RunAnAPIServer(controlPlaneConfig)
defer closeFn()
cs, err := clientset.NewForConfig(instanceConfig.GenericAPIServer.LoopbackClientConfig)
warningHandler := &recordingWarningHandler{}
configWithWarningHandler := rest.CopyConfig(instanceConfig.GenericAPIServer.LoopbackClientConfig)
configWithWarningHandler.WarningHandler = warningHandler
cs, err := clientset.NewForConfig(configWithWarningHandler)
if err != nil {
t.Fatalf("err: %v", err)
}
@@ -182,16 +187,42 @@ func TestServiceAccountTokenCreate(t *testing.T) {
},
}
warningHandler.clear()
if resp, err := cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(context.TODO(), sa.Name, treq, metav1.CreateOptions{}); err == nil {
t.Fatalf("expected err creating token for nonexistant svcacct but got: %#v", resp)
}
warningHandler.assertEqual(t, nil)
sa, delSvcAcct := createDeleteSvcAcct(t, cs, sa)
defer delSvcAcct()
treqWithBadName := treq.DeepCopy()
treqWithBadName.Name = "invalid-name"
if resp, err := cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(context.TODO(), sa.Name, treqWithBadName, metav1.CreateOptions{}); err == nil || !strings.Contains(err.Error(), "must match the service account name") {
t.Fatalf("expected err creating token with mismatched name but got: %#v", resp)
}
treqWithBadNamespace := treq.DeepCopy()
treqWithBadNamespace.Namespace = "invalid-namespace"
if resp, err := cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(context.TODO(), sa.Name, treqWithBadNamespace, metav1.CreateOptions{}); err == nil || !strings.Contains(err.Error(), "must match the service account namespace") {
t.Fatalf("expected err creating token with mismatched namespace but got: %#v", resp)
}
warningHandler.clear()
treq, err = cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(context.TODO(), sa.Name, treq, metav1.CreateOptions{})
if err != nil {
t.Fatalf("err: %v", err)
}
warningHandler.assertEqual(t, nil)
if treq.Name != sa.Name {
t.Errorf("expected name=%s, got %s", sa.Name, treq.Name)
}
if treq.Namespace != sa.Namespace {
t.Errorf("expected namespace=%s, got %s", sa.Namespace, treq.Namespace)
}
if treq.CreationTimestamp.IsZero() {
t.Errorf("expected non-zero creation timestamp")
}
checkPayload(t, treq.Status.Token, `"system:serviceaccount:myns:test-svcacct"`, "sub")
checkPayload(t, treq.Status.Token, `["api"]`, "aud")
@@ -220,34 +251,44 @@ func TestServiceAccountTokenCreate(t *testing.T) {
},
}
warningHandler.clear()
if resp, err := cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(context.TODO(), sa.Name, treq, metav1.CreateOptions{}); err == nil {
t.Fatalf("expected err creating token for nonexistant svcacct but got: %#v", resp)
}
warningHandler.assertEqual(t, nil)
sa, del := createDeleteSvcAcct(t, cs, sa)
defer del()
warningHandler.clear()
if resp, err := cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(context.TODO(), sa.Name, treq, metav1.CreateOptions{}); err == nil {
t.Fatalf("expected err creating token bound to nonexistant pod but got: %#v", resp)
}
warningHandler.assertEqual(t, nil)
pod, delPod := createDeletePod(t, cs, pod)
defer delPod()
// right uid
treq.Spec.BoundObjectRef.UID = pod.UID
warningHandler.clear()
if _, err := cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(context.TODO(), sa.Name, treq, metav1.CreateOptions{}); err != nil {
t.Fatalf("err: %v", err)
}
warningHandler.assertEqual(t, nil)
// wrong uid
treq.Spec.BoundObjectRef.UID = wrongUID
warningHandler.clear()
if resp, err := cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(context.TODO(), sa.Name, treq, metav1.CreateOptions{}); err == nil {
t.Fatalf("expected err creating token bound to pod with wrong uid but got: %#v", resp)
}
warningHandler.assertEqual(t, nil)
// no uid
treq.Spec.BoundObjectRef.UID = noUID
warningHandler.clear()
treq, err = cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(context.TODO(), sa.Name, treq, metav1.CreateOptions{})
if err != nil {
t.Fatalf("err: %v", err)
}
warningHandler.assertEqual(t, nil)
checkPayload(t, treq.Status.Token, `"system:serviceaccount:myns:test-svcacct"`, "sub")
checkPayload(t, treq.Status.Token, `["api"]`, "aud")
@@ -283,34 +324,44 @@ func TestServiceAccountTokenCreate(t *testing.T) {
},
}
warningHandler.clear()
if resp, err := cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(context.TODO(), sa.Name, treq, metav1.CreateOptions{}); err == nil {
t.Fatalf("expected err creating token for nonexistant svcacct but got: %#v", resp)
}
warningHandler.assertEqual(t, nil)
sa, del := createDeleteSvcAcct(t, cs, sa)
defer del()
warningHandler.clear()
if resp, err := cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(context.TODO(), sa.Name, treq, metav1.CreateOptions{}); err == nil {
t.Fatalf("expected err creating token bound to nonexistant secret but got: %#v", resp)
}
warningHandler.assertEqual(t, nil)
secret, delSecret := createDeleteSecret(t, cs, secret)
defer delSecret()
// right uid
treq.Spec.BoundObjectRef.UID = secret.UID
warningHandler.clear()
if _, err := cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(context.TODO(), sa.Name, treq, metav1.CreateOptions{}); err != nil {
t.Fatalf("err: %v", err)
}
warningHandler.assertEqual(t, nil)
// wrong uid
treq.Spec.BoundObjectRef.UID = wrongUID
warningHandler.clear()
if resp, err := cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(context.TODO(), sa.Name, treq, metav1.CreateOptions{}); err == nil {
t.Fatalf("expected err creating token bound to secret with wrong uid but got: %#v", resp)
}
warningHandler.assertEqual(t, nil)
// no uid
treq.Spec.BoundObjectRef.UID = noUID
warningHandler.clear()
treq, err = cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(context.TODO(), sa.Name, treq, metav1.CreateOptions{})
if err != nil {
t.Fatalf("err: %v", err)
}
warningHandler.assertEqual(t, nil)
checkPayload(t, treq.Status.Token, `"system:serviceaccount:myns:test-svcacct"`, "sub")
checkPayload(t, treq.Status.Token, `["api"]`, "aud")
@@ -341,9 +392,11 @@ func TestServiceAccountTokenCreate(t *testing.T) {
_, del = createDeletePod(t, cs, otherpod)
defer del()
warningHandler.clear()
if resp, err := cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(context.TODO(), sa.Name, treq, metav1.CreateOptions{}); err == nil {
t.Fatalf("expected err but got: %#v", resp)
}
warningHandler.assertEqual(t, nil)
})
t.Run("expired token", func(t *testing.T) {
@@ -356,10 +409,12 @@ func TestServiceAccountTokenCreate(t *testing.T) {
sa, del := createDeleteSvcAcct(t, cs, sa)
defer del()
warningHandler.clear()
treq, err = cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(context.TODO(), sa.Name, treq, metav1.CreateOptions{})
if err != nil {
t.Fatalf("err: %v", err)
}
warningHandler.assertEqual(t, nil)
doTokenReview(t, cs, treq, false)
@@ -405,10 +460,12 @@ func TestServiceAccountTokenCreate(t *testing.T) {
defer delPod()
treq.Spec.BoundObjectRef.UID = pod.UID
warningHandler.clear()
treq, err = cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(context.TODO(), sa.Name, treq, metav1.CreateOptions{})
if err != nil {
t.Fatalf("err: %v", err)
}
warningHandler.assertEqual(t, nil)
doTokenReview(t, cs, treq, false)
@@ -459,10 +516,12 @@ func TestServiceAccountTokenCreate(t *testing.T) {
defer delPod()
treq.Spec.BoundObjectRef.UID = pod.UID
warningHandler.clear()
treq, err = cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(context.TODO(), sa.Name, treq, metav1.CreateOptions{})
if err != nil {
t.Fatalf("err: %v", err)
}
warningHandler.assertEqual(t, nil)
// Give some tolerance to avoid flakiness since we are using real time.
var leeway int64 = 10
@@ -499,10 +558,12 @@ func TestServiceAccountTokenCreate(t *testing.T) {
sa, del := createDeleteSvcAcct(t, cs, sa)
defer del()
warningHandler.clear()
treq, err = cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(context.TODO(), sa.Name, treq, metav1.CreateOptions{})
if err != nil {
t.Fatalf("err: %v", err)
}
warningHandler.assertEqual(t, nil)
doTokenReview(t, cs, treq, true)
})
@@ -515,10 +576,12 @@ func TestServiceAccountTokenCreate(t *testing.T) {
sa, del := createDeleteSvcAcct(t, cs, sa)
defer del()
warningHandler.clear()
treq, err = cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(context.TODO(), sa.Name, treq, metav1.CreateOptions{})
if err != nil {
t.Fatalf("err: %v", err)
}
warningHandler.assertEqual(t, nil)
checkPayload(t, treq.Status.Token, `["api"]`, "aud")
@@ -543,9 +606,11 @@ func TestServiceAccountTokenCreate(t *testing.T) {
defer originalDelPod()
treq.Spec.BoundObjectRef.UID = originalPod.UID
warningHandler.clear()
if treq, err = cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(context.TODO(), sa.Name, treq, metav1.CreateOptions{}); err != nil {
t.Fatalf("err: %v", err)
}
warningHandler.assertEqual(t, nil)
checkPayload(t, treq.Status.Token, `"system:serviceaccount:myns:test-svcacct"`, "sub")
checkPayload(t, treq.Status.Token, `["api"]`, "aud")
@@ -584,9 +649,11 @@ func TestServiceAccountTokenCreate(t *testing.T) {
defer originalDelSecret()
treq.Spec.BoundObjectRef.UID = originalSecret.UID
warningHandler.clear()
if treq, err = cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(context.TODO(), sa.Name, treq, metav1.CreateOptions{}); err != nil {
t.Fatalf("err: %v", err)
}
warningHandler.assertEqual(t, nil)
checkPayload(t, treq.Status.Token, `"system:serviceaccount:myns:test-svcacct"`, "sub")
checkPayload(t, treq.Status.Token, `["api"]`, "aud")
@@ -627,9 +694,11 @@ func TestServiceAccountTokenCreate(t *testing.T) {
defer originalDelSecret()
treq.Spec.BoundObjectRef.UID = originalSecret.UID
warningHandler.clear()
if treq, err = cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(context.TODO(), sa.Name, treq, metav1.CreateOptions{}); err != nil {
t.Fatalf("err: %v", err)
}
warningHandler.assertEqual(t, nil)
checkPayload(t, treq.Status.Token, `"system:serviceaccount:myns:test-svcacct"`, "sub")
checkPayload(t, treq.Status.Token, `["api"]`, "aud")
@@ -671,9 +740,11 @@ func TestServiceAccountTokenCreate(t *testing.T) {
defer originalDelSecret()
treq.Spec.BoundObjectRef.UID = originalSecret.UID
warningHandler.clear()
if treq, err = cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(context.TODO(), sa.Name, treq, metav1.CreateOptions{}); err != nil {
t.Fatalf("err: %v", err)
}
warningHandler.assertEqual(t, []string{fmt.Sprintf("requested expiration of %d seconds shortened to %d seconds", tooLongExpirationTime, maxExpirationSeconds)})
checkPayload(t, treq.Status.Token, `"system:serviceaccount:myns:test-svcacct"`, "sub")
checkPayload(t, treq.Status.Token, `["api"]`, "aud")
@@ -698,6 +769,7 @@ func TestServiceAccountTokenCreate(t *testing.T) {
defer del()
t.Log("get token")
warningHandler.clear()
tokenRequest, err := cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(
context.TODO(),
sa.Name,
@@ -709,6 +781,7 @@ func TestServiceAccountTokenCreate(t *testing.T) {
if err != nil {
t.Fatalf("unexpected error creating token: %v", err)
}
warningHandler.assertEqual(t, nil)
token := tokenRequest.Status.Token
if token == "" {
t.Fatal("no token")
@@ -972,3 +1045,29 @@ func (f *fakeIndexer) GetByKey(key string) (interface{}, bool, error) {
obj, err := f.get(namespace, name)
return obj, err == nil, err
}
type recordingWarningHandler struct {
warnings []string
sync.Mutex
}
func (r *recordingWarningHandler) HandleWarningHeader(code int, agent string, message string) {
r.Lock()
defer r.Unlock()
r.warnings = append(r.warnings, message)
}
func (r *recordingWarningHandler) clear() {
r.Lock()
defer r.Unlock()
r.warnings = nil
}
func (r *recordingWarningHandler) assertEqual(t *testing.T, expected []string) {
t.Helper()
r.Lock()
defer r.Unlock()
if !reflect.DeepEqual(r.warnings, expected) {
t.Errorf("expected\n\t%v\ngot\n\t%v", expected, r.warnings)
}
}