Create SA token for mc remote access (#9122)

Create SA token for mc remote access

As of Kubernetes v1.24, ServiceAccount secrets are no longer
automatically generated. The multicluster `link` requires a token
associated with the 'linkerd-service-mirror-remote-access-default'
ServiceAccount in order to create a kubeconfig that can be used to
create remote clients.

Since tokens are no longer generated when a ServiceAccount is created,
linking clusters is not currently possible in Kubernetes v1.24. This
change introduces a new Secret object, whose type is a "service account
secret", and whose associated ServiceAccount is our remote access SA.

By creating the Secret manually (and associating it with our SA through
annotations), a token will be created by the relevant k8s controllers.
As a result of manually creating a secret, versions smaller than v1.24
will now have two tokens created for the ServiceAccount.

Signed-off-by: Matei David <matei@buoyant.io>
Co-authored-by: Alejandro Pedraza <alejandro@buoyant.io>
This commit is contained in:
Matei David 2022-08-10 18:39:20 +01:00 committed by GitHub
parent 4bc680a878
commit 0864c74e66
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 72 additions and 15 deletions

View File

@ -36,6 +36,18 @@ metadata:
annotations:
{{ include "partials.annotations.created-by" $ }}
---
apiVersion: v1
kind: Secret
metadata:
name: {{.}}-token
{{ include "partials.namespace" $ }}
labels:
linkerd.io/extension: multicluster
annotations:
kubernetes.io/service-account.name: {{.}}
{{ include "partials.annotations.created-by" $ }}
type: kubernetes.io/service-account-token
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:

View File

@ -109,25 +109,17 @@ A full list of configurable values can be found at https://github.com/linkerd/li
return err
}
var secretName string
for _, s := range sa.Secrets {
if strings.HasPrefix(s.Name, fmt.Sprintf("%s-token", sa.Name)) {
secretName = s.Name
break
}
listOpts := metav1.ListOptions{
FieldSelector: fmt.Sprintf("type=%s", corev1.SecretTypeServiceAccountToken),
}
if secretName == "" {
return fmt.Errorf("could not find service account token secret for %s", sa.Name)
}
secret, err := k.CoreV1().Secrets(opts.namespace).Get(cmd.Context(), secretName, metav1.GetOptions{})
secrets, err := k.CoreV1().Secrets(opts.namespace).List(cmd.Context(), listOpts)
if err != nil {
return err
}
token, ok := secret.Data[tokenKey]
if !ok {
return fmt.Errorf("could not find the token data in the service account secret")
token, err := extractSAToken(secrets.Items, sa.Name)
if err != nil {
return err
}
context, ok := config.Contexts[config.CurrentContext]
@ -141,7 +133,7 @@ A full list of configurable values can be found at https://github.com/linkerd/li
}
config.AuthInfos = map[string]*api.AuthInfo{
opts.serviceAccountName: {
Token: string(token),
Token: token,
},
}
@ -435,3 +427,19 @@ func extractGatewayPort(gateway *corev1.Service) (uint32, error) {
}
return 0, fmt.Errorf("gateway service %s has no gateway port named %s", gateway.Name, k8s.GatewayPortName)
}
func extractSAToken(secrets []corev1.Secret, saName string) (string, error) {
for _, secret := range secrets {
boundSA := secret.Annotations[saNameAnnotationKey]
if saName == boundSA {
token, ok := secret.Data[tokenKey]
if !ok {
return "", fmt.Errorf("could not find the token data in service account secret %s", secret.Name)
}
return string(token), nil
}
}
return "", fmt.Errorf("could not find service account token secret for %s", saName)
}

View File

@ -22,6 +22,7 @@ const (
helmMulticlusterLinkDefaultChartName = "linkerd-multicluster-link"
tokenKey = "token"
saNameAnnotationKey = "kubernetes.io/service-account.name"
defaultServiceAccountName = "linkerd-service-mirror-remote-access-default"
)

View File

@ -232,6 +232,18 @@ metadata:
annotations:
linkerd.io/created-by: linkerd/helm linkerdVersionValue
---
apiVersion: v1
kind: Secret
metadata:
name: linkerd-service-mirror-remote-access-default-token
namespace: linkerd-multicluster
labels:
linkerd.io/extension: multicluster
annotations:
kubernetes.io/service-account.name: linkerd-service-mirror-remote-access-default
linkerd.io/created-by: linkerd/helm linkerdVersionValue
type: kubernetes.io/service-account-token
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:

View File

@ -300,6 +300,18 @@ metadata:
annotations:
linkerd.io/created-by: linkerd/helm linkerdVersionValue
---
apiVersion: v1
kind: Secret
metadata:
name: linkerd-service-mirror-remote-access-default-token
namespace: linkerd-multicluster
labels:
linkerd.io/extension: multicluster
annotations:
kubernetes.io/service-account.name: linkerd-service-mirror-remote-access-default
linkerd.io/created-by: linkerd/helm linkerdVersionValue
type: kubernetes.io/service-account-token
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:

View File

@ -263,6 +263,18 @@ metadata:
annotations:
linkerd.io/created-by: linkerd/helm linkerdVersionValue
---
apiVersion: v1
kind: Secret
metadata:
name: linkerd-service-mirror-remote-access-default-token
namespace: linkerd-multicluster
labels:
linkerd.io/extension: multicluster
annotations:
kubernetes.io/service-account.name: linkerd-service-mirror-remote-access-default
linkerd.io/created-by: linkerd/helm linkerdVersionValue
type: kubernetes.io/service-account-token
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata: