cmd/k8s-operator: support workload identity federation
The feature is currently in private alpha, so requires a tailnet feature
flag. Initially focuses on supporting the operator's own auth, because the
operator is the only device we maintain that uses static long-lived
credentials. All other operator-created devices use single-use auth keys.
Testing steps:
* Create a cluster with an API server accessible over public internet
* kubectl get --raw /.well-known/openid-configuration | jq '.issuer'
* Create a federated OAuth client in the Tailscale admin console with:
* The issuer from the previous step
* Subject claim `system:serviceaccount:tailscale:operator`
* Write scopes services, devices:core, auth_keys
* Tag tag:k8s-operator
* Allow the Tailscale control plane to get the public portion of
the ServiceAccount token signing key without authentication:
* kubectl create clusterrolebinding oidc-discovery \
--clusterrole=system:service-account-issuer-discovery \
--group=system:unauthenticated
* helm install --set oauth.clientId=... --set oauth.audience=...
Updates #17457
Change-Id: Ib29c85ba97b093c70b002f4f41793ffc02e6c6e9
Signed-off-by: Tom Proctor <tomhjp@users.noreply.github.com>
This commit is contained in:
@@ -34,7 +34,9 @@ spec:
|
||||
securityContext:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- if or .Values.oauth.clientSecret .Values.oauth.audience }}
|
||||
volumes:
|
||||
{{- if .Values.oauth.clientSecret }}
|
||||
- name: oauth
|
||||
{{- with .Values.oauthSecretVolume }}
|
||||
{{- toYaml . | nindent 10 }}
|
||||
@@ -42,6 +44,17 @@ spec:
|
||||
secret:
|
||||
secretName: operator-oauth
|
||||
{{- end }}
|
||||
{{- else }}
|
||||
- name: oidc-jwt
|
||||
projected:
|
||||
defaultMode: 420
|
||||
sources:
|
||||
- serviceAccountToken:
|
||||
audience: {{ .Values.oauth.audience }}
|
||||
expirationSeconds: 3600
|
||||
path: token
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: operator
|
||||
{{- with .Values.operatorConfig.securityContext }}
|
||||
@@ -72,10 +85,15 @@ spec:
|
||||
value: {{ .Values.loginServer }}
|
||||
- name: OPERATOR_INGRESS_CLASS_NAME
|
||||
value: {{ .Values.ingressClass.name }}
|
||||
{{- if .Values.oauth.clientSecret }}
|
||||
- name: CLIENT_ID_FILE
|
||||
value: /oauth/client_id
|
||||
- name: CLIENT_SECRET_FILE
|
||||
value: /oauth/client_secret
|
||||
{{- else if .Values.oauth.audience }}
|
||||
- name: CLIENT_ID
|
||||
value: {{ .Values.oauth.clientId }}
|
||||
{{- end }}
|
||||
{{- $proxyTag := printf ":%s" ( .Values.proxyConfig.image.tag | default .Chart.AppVersion )}}
|
||||
- name: PROXY_IMAGE
|
||||
value: {{ coalesce .Values.proxyConfig.image.repo .Values.proxyConfig.image.repository }}{{- if .Values.proxyConfig.image.digest -}}{{ printf "@%s" .Values.proxyConfig.image.digest}}{{- else -}}{{ printf "%s" $proxyTag }}{{- end }}
|
||||
@@ -100,10 +118,18 @@ spec:
|
||||
{{- with .Values.operatorConfig.extraEnv }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if or .Values.oauth.clientSecret .Values.oauth.audience }}
|
||||
volumeMounts:
|
||||
{{- if .Values.oauth.clientSecret }}
|
||||
- name: oauth
|
||||
mountPath: /oauth
|
||||
readOnly: true
|
||||
{{- else }}
|
||||
- name: oidc-jwt
|
||||
mountPath: /var/run/secrets/tailscale/serviceaccount
|
||||
readOnly: true
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- with .Values.operatorConfig.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
|
||||
Reference in New Issue
Block a user