Skip to content

Commit cc5e3c3

Browse files
committed
Do not use existing auto-generated tokens
Kubernetes legacy ServiceAccount tokens will generate warnings on use and be garbage collected if not used for one year, starting with Kubernetes 1.30. Use an explicitly created token secret with a fixed name, based on the service account name. Signed-off-by: Max Gautier <mg@max.gautier.name>
1 parent cf6b7cd commit cc5e3c3

3 files changed

Lines changed: 21 additions & 56 deletions

File tree

util/clusterauth/clusterauth.go

Lines changed: 17 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const (
2323
ArgoCDManagerServiceAccount = "argocd-manager"
2424
ArgoCDManagerClusterRole = "argocd-manager-role"
2525
ArgoCDManagerClusterRoleBinding = "argocd-manager-role-binding"
26+
SATokenSecretSuffix = "-long-lived-token"
2627
)
2728

2829
// ArgoCDManagerPolicyRules are the policies to give argocd-manager
@@ -249,69 +250,34 @@ func GetServiceAccountBearerToken(clientset kubernetes.Interface, ns string, sa
249250
return string(secret.Data["token"]), nil
250251
}
251252

252-
// getOrCreateServiceAccountTokenSecret will check if a ServiceAccount
253-
// already has a kubernetes.io/service-account-token secret associated
254-
// with it or creates one if the ServiceAccount doesn't have one. This
255-
// was added to help add k8s v1.24+ clusters.
253+
// getOrCreateServiceAccountTokenSecret will create a
254+
// kubernetes.io/service-account-token secret associated with a
255+
// ServiceAccount named '<service account name>-long-lived-token', or
256+
// use the existing one with that name.
257+
// This was added to help add k8s v1.24+ clusters.
256258
func getOrCreateServiceAccountTokenSecret(clientset kubernetes.Interface, sa, ns string) (string, error) {
257-
// Wait for sa to have secret, but don't wait too
258-
// long for 1.24+ clusters
259-
var serviceAccount *corev1.ServiceAccount
260-
err := wait.PollUntilContextTimeout(context.Background(), 500*time.Millisecond, 30*time.Second, true, func(ctx context.Context) (bool, error) {
261-
ctx, cancel := context.WithTimeout(ctx, common.ClusterAuthRequestTimeout)
262-
defer cancel()
263-
var getErr error
264-
serviceAccount, getErr = clientset.CoreV1().ServiceAccounts(ns).Get(ctx, sa, metav1.GetOptions{})
265-
if getErr != nil {
266-
return false, fmt.Errorf("failed to get serviceaccount %q: %w", sa, getErr)
267-
}
268-
return true, nil
269-
})
270-
if err != nil && !wait.Interrupted(err) {
271-
return "", fmt.Errorf("failed to get serviceaccount token secret: %w", err)
272-
}
273-
if serviceAccount == nil {
274-
log.Errorf("Unexpected nil serviceaccount '%s/%s' with no error returned", ns, sa)
275-
return "", fmt.Errorf("failed to create serviceaccount token secret: nil serviceaccount returned for '%s/%s' with no error", ns, sa)
276-
}
277-
278-
outerCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
279-
defer cancel()
280-
for _, s := range serviceAccount.Secrets {
281-
innerCtx, cancel := context.WithTimeout(outerCtx, common.ClusterAuthRequestTimeout)
282-
defer cancel()
283-
existingSecret, err := clientset.CoreV1().Secrets(ns).Get(innerCtx, s.Name, metav1.GetOptions{})
284-
if err != nil {
285-
return "", fmt.Errorf("failed to retrieve secret %q: %w", s.Name, err)
286-
}
287-
if existingSecret.Type == corev1.SecretTypeServiceAccountToken {
288-
return existingSecret.Name, nil
289-
}
290-
}
291-
292-
return createServiceAccountToken(clientset, serviceAccount)
293-
}
294-
295-
func createServiceAccountToken(clientset kubernetes.Interface, serviceAccount *corev1.ServiceAccount) (string, error) {
296259
secret := &corev1.Secret{
297260
ObjectMeta: metav1.ObjectMeta{
298-
GenerateName: serviceAccount.Name + "-token-",
299-
Namespace: serviceAccount.Namespace,
261+
Name: sa + SATokenSecretSuffix,
262+
Namespace: ns,
300263
Annotations: map[string]string{
301-
corev1.ServiceAccountNameKey: serviceAccount.Name,
264+
corev1.ServiceAccountNameKey: sa,
302265
},
303266
},
304267
Type: corev1.SecretTypeServiceAccountToken,
305268
}
306269

307270
ctx, cancel := context.WithTimeout(context.Background(), common.ClusterAuthRequestTimeout)
308271
defer cancel()
309-
secret, err := clientset.CoreV1().Secrets(serviceAccount.Namespace).Create(ctx, secret, metav1.CreateOptions{})
310-
if err != nil {
311-
return "", fmt.Errorf("failed to create secret for serviceaccount %q: %w", serviceAccount.Name, err)
312-
}
272+
_, err := clientset.CoreV1().Secrets(ns).Create(ctx, secret, metav1.CreateOptions{})
313273

314-
log.Infof("Created bearer token secret for ServiceAccount %q", serviceAccount.Name)
274+
if apierr.IsAlreadyExists(err) {
275+
log.Infof("Using existing bearer token secret %q for ServiceAccount %q", secret.Name, sa)
276+
} else if err != nil {
277+
return "", fmt.Errorf("failed to create secret %q for serviceaccount %q: %w", secret.Name, sa, err)
278+
} else {
279+
log.Infof("Created bearer token secret %q for ServiceAccount %q", secret.Name, sa)
280+
}
315281

316282
return secret.Name, nil
317283
}

util/clusterauth/clusterauth_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ func Test_getOrCreateServiceAccountTokenSecret_NoSecretForSA(t *testing.T) {
280280

281281
got, err := getOrCreateServiceAccountTokenSecret(cs, ArgoCDManagerServiceAccount, ns.Name)
282282
require.NoError(t, err)
283-
assert.Contains(t, got, "argocd-manager-token-")
283+
assert.Equal(t, ArgoCDManagerServiceAccount+SATokenSecretSuffix, got)
284284

285285
obj, err := cs.Tracker().Get(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"},
286286
ns.Name, ArgoCDManagerServiceAccount)
@@ -331,7 +331,7 @@ func Test_getOrCreateServiceAccountTokenSecret_SAHasSecret(t *testing.T) {
331331

332332
got, err := getOrCreateServiceAccountTokenSecret(cs, ArgoCDManagerServiceAccount, ns.Name)
333333
require.NoError(t, err)
334-
assert.Equal(t, "sa-secret", got)
334+
assert.Equal(t, ArgoCDManagerServiceAccount+SATokenSecretSuffix, got)
335335

336336
obj, err := cs.Tracker().Get(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"},
337337
ns.Name, ArgoCDManagerServiceAccount)

util/clusterauth/testdata/argocd-manager-sa-token.yaml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,9 @@ metadata:
99
kubernetes.io/service-account.name: argocd-manager
1010
kubernetes.io/service-account.uid: 91dd37cf-8d92-11e9-a091-d65f2ae7fa8d
1111
creationTimestamp: "2019-06-13T04:30:24Z"
12-
generateName: argocd-manager-token-
13-
name: argocd-manager-token-tj79r
12+
name: argocd-manager-long-lived-token
1413
namespace: kube-system
1514
resourceVersion: "133010"
1615
selfLink: /api/v1/namespaces/kube-system/secrets/argocd-manager-token-tj79r
1716
uid: f657d67e-8d93-11e9-a091-d65f2ae7fa8d
18-
type: kubernetes.io/service-account-token
17+
type: kubernetes.io/service-account-token

0 commit comments

Comments
 (0)