lock LegacyServiceAccountTokenNoAutoGeneration

This commit is contained in:
Shihang Zhang
2022-12-15 14:36:18 -08:00
parent 093c5964f7
commit 4fd09a06d6
5 changed files with 32 additions and 506 deletions

View File

@@ -30,7 +30,6 @@ import (
v1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/wait"
serviceaccountapiserver "k8s.io/apiserver/pkg/authentication/serviceaccount"
"k8s.io/apiserver/pkg/authorization/authorizer"
@@ -96,105 +95,6 @@ func TestServiceAccountAutoCreate(t *testing.T) {
}
}
func TestServiceAccountTokenAutoCreate(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, kubefeatures.LegacyServiceAccountTokenNoAutoGeneration, false)()
c, _, stopFunc, err := startServiceAccountTestServerAndWaitForCaches(t)
defer stopFunc()
if err != nil {
t.Fatalf("failed to setup ServiceAccounts server: %v", err)
}
ns := "test-service-account-token-creation"
name := "my-service-account"
// Create namespace
_, err = c.CoreV1().Namespaces().Create(context.TODO(), &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: ns}}, metav1.CreateOptions{})
if err != nil {
t.Fatalf("could not create namespace: %v", err)
}
// Create service account
_, err = c.CoreV1().ServiceAccounts(ns).Create(context.TODO(), &v1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: name}}, metav1.CreateOptions{})
if err != nil {
t.Fatalf("Service Account not created: %v", err)
}
// Get token
token1Name, token1, err := getReferencedServiceAccountToken(c, ns, name, true)
if err != nil {
t.Fatal(err)
}
// Delete token
err = c.CoreV1().Secrets(ns).Delete(context.TODO(), token1Name, metav1.DeleteOptions{})
if err != nil {
t.Fatalf("Could not delete token: %v", err)
}
// Get recreated token
token2Name, token2, err := getReferencedServiceAccountToken(c, ns, name, true)
if err != nil {
t.Fatal(err)
}
if token1Name == token2Name {
t.Fatalf("Expected new auto-created token name")
}
if token1 == token2 {
t.Fatalf("Expected new auto-created token value")
}
// Trigger creation of a new referenced token
serviceAccount, err := c.CoreV1().ServiceAccounts(ns).Get(context.TODO(), name, metav1.GetOptions{})
if err != nil {
t.Fatal(err)
}
serviceAccount.Secrets = []v1.ObjectReference{}
_, err = c.CoreV1().ServiceAccounts(ns).Update(context.TODO(), serviceAccount, metav1.UpdateOptions{})
if err != nil {
t.Fatal(err)
}
// Get rotated token
token3Name, token3, err := getReferencedServiceAccountToken(c, ns, name, true)
if err != nil {
t.Fatal(err)
}
if token3Name == token2Name {
t.Fatalf("Expected new auto-created token name")
}
if token3 == token2 {
t.Fatalf("Expected new auto-created token value")
}
// Delete service account
err = c.CoreV1().ServiceAccounts(ns).Delete(context.TODO(), name, metav1.DeleteOptions{})
if err != nil {
t.Fatal(err)
}
// Wait for tokens to be deleted
tokensToCleanup := sets.NewString(token1Name, token2Name, token3Name)
err = wait.Poll(time.Second, 10*time.Second, func() (bool, error) {
// Get all secrets in the namespace
secrets, err := c.CoreV1().Secrets(ns).List(context.TODO(), metav1.ListOptions{})
// Retrieval errors should fail
if err != nil {
return false, err
}
for _, s := range secrets.Items {
if tokensToCleanup.Has(s.Name) {
// Still waiting for tokens to be cleaned up
return false, nil
}
}
// All clean
return true, nil
})
if err != nil {
t.Fatalf("Error waiting for tokens to be deleted: %v", err)
}
}
func TestServiceAccountTokenAutoMount(t *testing.T) {
c, _, stopFunc, err := startServiceAccountTestServerAndWaitForCaches(t)
defer stopFunc()
@@ -315,7 +215,6 @@ func TestServiceAccountTokenAuthentication(t *testing.T) {
}
func TestLegacyServiceAccountTokenTracking(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, kubefeatures.LegacyServiceAccountTokenNoAutoGeneration, false)()
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, kubefeatures.LegacyServiceAccountTokenTracking, true)()
c, config, stopFunc, err := startServiceAccountTestServerAndWaitForCaches(t)
defer stopFunc()
@@ -339,8 +238,13 @@ func TestLegacyServiceAccountTokenTracking(t *testing.T) {
t.Fatalf("Secret not created: %v", err)
}
autoSecretName, autoSecretTokenData, err := getReferencedServiceAccountToken(c, myns, readOnlyServiceAccountName, true)
// manually craft an auto created token
autoSecretName := "auto-token"
autoSecret, err := createServiceAccountToken(c, mysa, myns, autoSecretName)
if err != nil {
t.Fatalf("Secret not created: %v", err)
}
if err := addReferencedServiceAccountToken(c, myns, readOnlyServiceAccountName, autoSecret); err != nil {
t.Fatal(err)
}
@@ -359,7 +263,7 @@ func TestLegacyServiceAccountTokenTracking(t *testing.T) {
{
name: "auto created legacy token",
secretName: autoSecretName,
secretTokenData: autoSecretTokenData,
secretTokenData: string(autoSecret.Data[v1.ServiceAccountTokenKey]),
expectWarning: true,
},
}
@@ -494,7 +398,6 @@ func startServiceAccountTestServerAndWaitForCaches(t *testing.T) (clientset.Inte
rootClientset,
serviceaccountcontroller.TokensControllerOptions{
TokenGenerator: tokenGenerator,
AutoGenerate: !utilfeature.DefaultFeatureGate.Enabled(kubefeatures.LegacyServiceAccountTokenNoAutoGeneration),
},
)
if err != nil {
@@ -573,58 +476,22 @@ func createServiceAccountToken(c clientset.Interface, sa *v1.ServiceAccount, ns
return secret, nil
}
func getReferencedServiceAccountToken(c clientset.Interface, ns string, name string, shouldWait bool) (string, string, error) {
tokenName := ""
token := ""
findToken := func() (bool, error) {
user, err := c.CoreV1().ServiceAccounts(ns).Get(context.TODO(), name, metav1.GetOptions{})
if apierrors.IsNotFound(err) {
return false, nil
}
if err != nil {
return false, err
}
for _, ref := range user.Secrets {
secret, err := c.CoreV1().Secrets(ns).Get(context.TODO(), ref.Name, metav1.GetOptions{})
if apierrors.IsNotFound(err) {
continue
}
if err != nil {
return false, err
}
if secret.Type != v1.SecretTypeServiceAccountToken {
continue
}
name := secret.Annotations[v1.ServiceAccountNameKey]
uid := secret.Annotations[v1.ServiceAccountUIDKey]
tokenData := secret.Data[v1.ServiceAccountTokenKey]
if name == user.Name && uid == string(user.UID) && len(tokenData) > 0 {
tokenName = secret.Name
token = string(tokenData)
return true, nil
}
}
return false, nil
func addReferencedServiceAccountToken(c clientset.Interface, ns string, name string, secret *v1.Secret) error {
sa, err := c.CoreV1().ServiceAccounts(ns).Get(context.TODO(), name, metav1.GetOptions{})
if err != nil {
return err
}
if shouldWait {
err := wait.Poll(time.Second, 10*time.Second, findToken)
if err != nil {
return "", "", err
}
} else {
ok, err := findToken()
if err != nil {
return "", "", err
}
if !ok {
return "", "", fmt.Errorf("No token found for %s/%s", ns, name)
}
sa.Secrets = append(sa.Secrets, v1.ObjectReference{
APIVersion: secret.APIVersion,
Kind: secret.Kind,
Namespace: secret.Namespace,
Name: secret.Name,
ResourceVersion: secret.ResourceVersion,
})
if _, err = c.CoreV1().ServiceAccounts(ns).Update(context.TODO(), sa, metav1.UpdateOptions{}); err != nil {
return err
}
return tokenName, token, nil
return nil
}
type testOperation func() error