From 32bf28daed422d8dd4a7c67dcc9d1c5c5c31b301 Mon Sep 17 00:00:00 2001 From: Mike Danese Date: Fri, 23 Feb 2018 11:40:43 -0800 Subject: [PATCH] integration: refactor, cleanup, and add more tests for TokenRequest --- test/integration/auth/svcaccttoken_test.go | 290 ++++++++++++++------- 1 file changed, 196 insertions(+), 94 deletions(-) diff --git a/test/integration/auth/svcaccttoken_test.go b/test/integration/auth/svcaccttoken_test.go index ac9fe62bd49..0bccbcc5283 100644 --- a/test/integration/auth/svcaccttoken_test.go +++ b/test/integration/auth/svcaccttoken_test.go @@ -25,6 +25,7 @@ import ( authenticationv1 "k8s.io/api/authentication/v1" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" "k8s.io/apiserver/pkg/authorization/authorizerfactory" utilfeature "k8s.io/apiserver/pkg/util/feature" utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing" @@ -63,103 +64,162 @@ func TestServiceAccountTokenCreate(t *testing.T) { t.Fatalf("err: %v", err) } - sa := &v1.ServiceAccount{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test", - Namespace: "default", - }, - } - - tr1 := &authenticationv1.TokenRequest{ - Spec: authenticationv1.TokenRequestSpec{ - Audiences: []string{"aud"}, - }, - } - - _, err = cs.CoreV1().ServiceAccounts(sa.Namespace).Create(sa) - if err != nil { - t.Fatalf("err: %v", err) - } - tr1, err = cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(sa.Name, tr1) - if err != nil { - t.Fatalf("err: %v", err) - } - - checkPayload(t, tr1.Status.Token, `"system:serviceaccount:default:test"`, "sub") - checkPayload(t, tr1.Status.Token, `["aud"]`, "aud") - checkPayload(t, tr1.Status.Token, "null", "kubernetes.io", "pod") - checkPayload(t, tr1.Status.Token, "null", "kubernetes.io", "secret") - checkPayload(t, tr1.Status.Token, `"default"`, "kubernetes.io", "namespace") - checkPayload(t, tr1.Status.Token, `"test"`, "kubernetes.io", "serviceaccount", "name") - - pod := &v1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-pod", - Namespace: sa.Namespace, - }, - Spec: v1.PodSpec{ - ServiceAccountName: sa.Name, - Containers: []v1.Container{{Name: "test-container", Image: "nginx"}}, - }, - } - _, err = cs.CoreV1().Pods(pod.Namespace).Create(pod) - if err != nil { - t.Fatalf("err: %v", err) - } - - tr2 := &authenticationv1.TokenRequest{ - Spec: authenticationv1.TokenRequestSpec{ - Audiences: []string{"aud"}, - BoundObjectRef: &authenticationv1.BoundObjectReference{ - Kind: "Pod", - APIVersion: "v1", - Name: pod.Name, + var ( + sa = &v1.ServiceAccount{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-svcacct", + Namespace: "myns", }, - }, - } - tr2, err = cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(sa.Name, tr2) - if err != nil { - t.Fatalf("err: %v", err) - } - - checkPayload(t, tr2.Status.Token, `"system:serviceaccount:default:test"`, "sub") - checkPayload(t, tr2.Status.Token, `["aud"]`, "aud") - checkPayload(t, tr2.Status.Token, `"test-pod"`, "kubernetes.io", "pod", "name") - checkPayload(t, tr2.Status.Token, "null", "kubernetes.io", "secret") - checkPayload(t, tr2.Status.Token, `"default"`, "kubernetes.io", "namespace") - checkPayload(t, tr2.Status.Token, `"test"`, "kubernetes.io", "serviceaccount", "name") - - secret := &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-secret", - Namespace: sa.Namespace, - }, - } - _, err = cs.CoreV1().Secrets(secret.Namespace).Create(secret) - if err != nil { - t.Fatalf("err: %v", err) - } - tr3 := &authenticationv1.TokenRequest{ - Spec: authenticationv1.TokenRequestSpec{ - Audiences: []string{"aud"}, - BoundObjectRef: &authenticationv1.BoundObjectReference{ - Kind: "Secret", - APIVersion: "v1", - Name: secret.Name, + } + pod = &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-pod", + Namespace: sa.Namespace, }, - }, - } - tr3, err = cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(sa.Name, tr3) - if err != nil { - t.Fatalf("err: %v", err) - } + Spec: v1.PodSpec{ + ServiceAccountName: sa.Name, + Containers: []v1.Container{{Name: "test-container", Image: "nginx"}}, + }, + } + secret = &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-secret", + Namespace: sa.Namespace, + }, + } - checkPayload(t, tr2.Status.Token, `"system:serviceaccount:default:test"`, "sub") - checkPayload(t, tr2.Status.Token, `["aud"]`, "aud") - checkPayload(t, tr2.Status.Token, `"test-pod"`, "kubernetes.io", "pod", "name") - checkPayload(t, tr2.Status.Token, `null`, "kubernetes.io", "secret") - checkPayload(t, tr2.Status.Token, `"default"`, "kubernetes.io", "namespace") - checkPayload(t, tr2.Status.Token, `"test"`, "kubernetes.io", "serviceaccount", "name") + one = int64(1) + wrongUID = types.UID("wrong") + noUID = types.UID("") + ) + + t.Run("bound to service account", func(t *testing.T) { + treq := &authenticationv1.TokenRequest{ + Spec: authenticationv1.TokenRequestSpec{ + Audiences: []string{"api"}, + ExpirationSeconds: &one, + }, + } + + if resp, err := cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(sa.Name, treq); err == nil { + t.Fatalf("expected err creating token for nonexistant svcacct but got: %#v", resp) + } + sa, del := createDeleteSvcAcct(t, cs, sa) + defer del() + + treq, err = cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(sa.Name, treq) + if err != nil { + t.Fatalf("err: %v", err) + } + + checkPayload(t, treq.Status.Token, `"system:serviceaccount:myns:test-svcacct"`, "sub") + checkPayload(t, treq.Status.Token, `["api"]`, "aud") + checkPayload(t, treq.Status.Token, "null", "kubernetes.io", "pod") + checkPayload(t, treq.Status.Token, "null", "kubernetes.io", "secret") + checkPayload(t, treq.Status.Token, `"myns"`, "kubernetes.io", "namespace") + checkPayload(t, treq.Status.Token, `"test-svcacct"`, "kubernetes.io", "serviceaccount", "name") + }) + + t.Run("bound to service account and pod", func(t *testing.T) { + treq := &authenticationv1.TokenRequest{ + Spec: authenticationv1.TokenRequestSpec{ + Audiences: []string{"api"}, + ExpirationSeconds: &one, + BoundObjectRef: &authenticationv1.BoundObjectReference{ + Kind: "Pod", + APIVersion: "v1", + Name: pod.Name, + }, + }, + } + + if resp, err := cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(sa.Name, treq); err == nil { + t.Fatalf("expected err creating token for nonexistant svcacct but got: %#v", resp) + } + sa, del := createDeleteSvcAcct(t, cs, sa) + defer del() + + if resp, err := cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(sa.Name, treq); err == nil { + t.Fatalf("expected err creating token bound to nonexistant pod but got: %#v", resp) + } + pod, del := createDeletePod(t, cs, pod) + defer del() + + // right uid + treq.Spec.BoundObjectRef.UID = pod.UID + if _, err := cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(sa.Name, treq); err != nil { + t.Fatalf("err: %v", err) + } + // wrong uid + treq.Spec.BoundObjectRef.UID = wrongUID + if resp, err := cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(sa.Name, treq); err == nil { + t.Fatalf("expected err creating token bound to pod with wrong uid but got: %#v", resp) + } + // no uid + treq.Spec.BoundObjectRef.UID = noUID + treq, err = cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(sa.Name, treq) + if err != nil { + t.Fatalf("err: %v", err) + } + + checkPayload(t, treq.Status.Token, `"system:serviceaccount:myns:test-svcacct"`, "sub") + checkPayload(t, treq.Status.Token, `["api"]`, "aud") + checkPayload(t, treq.Status.Token, `"test-pod"`, "kubernetes.io", "pod", "name") + checkPayload(t, treq.Status.Token, "null", "kubernetes.io", "secret") + checkPayload(t, treq.Status.Token, `"myns"`, "kubernetes.io", "namespace") + checkPayload(t, treq.Status.Token, `"test-svcacct"`, "kubernetes.io", "serviceaccount", "name") + }) + + t.Run("bound to service account and secret", func(t *testing.T) { + treq := &authenticationv1.TokenRequest{ + Spec: authenticationv1.TokenRequestSpec{ + Audiences: []string{"api"}, + ExpirationSeconds: &one, + BoundObjectRef: &authenticationv1.BoundObjectReference{ + Kind: "Secret", + APIVersion: "v1", + Name: secret.Name, + UID: secret.UID, + }, + }, + } + + if resp, err := cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(sa.Name, treq); err == nil { + t.Fatalf("expected err creating token for nonexistant svcacct but got: %#v", resp) + } + sa, del := createDeleteSvcAcct(t, cs, sa) + defer del() + + if resp, err := cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(sa.Name, treq); err == nil { + t.Fatalf("expected err creating token bound to nonexistant secret but got: %#v", resp) + } + secret, del := createDeleteSecret(t, cs, secret) + defer del() + + // right uid + treq.Spec.BoundObjectRef.UID = secret.UID + if _, err := cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(sa.Name, treq); err != nil { + t.Fatalf("err: %v", err) + } + // wrong uid + treq.Spec.BoundObjectRef.UID = wrongUID + if resp, err := cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(sa.Name, treq); err == nil { + t.Fatalf("expected err creating token bound to secret with wrong uid but got: %#v", resp) + } + // no uid + treq.Spec.BoundObjectRef.UID = noUID + treq, err = cs.CoreV1().ServiceAccounts(sa.Namespace).CreateToken(sa.Name, treq) + if err != nil { + t.Fatalf("err: %v", err) + } + + checkPayload(t, treq.Status.Token, `"system:serviceaccount:myns:test-svcacct"`, "sub") + checkPayload(t, treq.Status.Token, `["api"]`, "aud") + checkPayload(t, treq.Status.Token, `null`, "kubernetes.io", "pod") + checkPayload(t, treq.Status.Token, `"test-secret"`, "kubernetes.io", "secret", "name") + checkPayload(t, treq.Status.Token, `"myns"`, "kubernetes.io", "namespace") + checkPayload(t, treq.Status.Token, `"test-svcacct"`, "kubernetes.io", "serviceaccount", "name") + }) } func checkPayload(t *testing.T, tok string, want string, parts ...string) { @@ -199,3 +259,45 @@ func getPayload(t *testing.T, b string) string { } return string(payload) } + +func createDeleteSvcAcct(t *testing.T, cs clientset.Interface, sa *v1.ServiceAccount) (*v1.ServiceAccount, func()) { + t.Helper() + sa, err := cs.CoreV1().ServiceAccounts(sa.Namespace).Create(sa) + if err != nil { + t.Fatalf("err: %v", err) + } + return sa, func() { + t.Helper() + if err := cs.CoreV1().ServiceAccounts(sa.Namespace).Delete(sa.Name, nil); err != nil { + t.Fatalf("err: %v", err) + } + } +} + +func createDeletePod(t *testing.T, cs clientset.Interface, pod *v1.Pod) (*v1.Pod, func()) { + t.Helper() + pod, err := cs.CoreV1().Pods(pod.Namespace).Create(pod) + if err != nil { + t.Fatalf("err: %v", err) + } + return pod, func() { + t.Helper() + if err := cs.CoreV1().Pods(pod.Namespace).Delete(pod.Name, nil); err != nil { + t.Fatalf("err: %v", err) + } + } +} + +func createDeleteSecret(t *testing.T, cs clientset.Interface, sec *v1.Secret) (*v1.Secret, func()) { + t.Helper() + sec, err := cs.CoreV1().Secrets(sec.Namespace).Create(sec) + if err != nil { + t.Fatalf("err: %v", err) + } + return sec, func() { + t.Helper() + if err := cs.CoreV1().Secrets(sec.Namespace).Delete(sec.Name, nil); err != nil { + t.Fatalf("err: %v", err) + } + } +}