cmd/k8s-operator,k8s-operator: recorder custom service account

Allows configuring a custom service account for the recorder pods,
allowing the use of IRSA and other mechanisms for authing to write to
recorder buckets

Signed-off-by: Lee Briggs <lee@leebriggs.co.uk>
This commit is contained in:
Lee Briggs 2025-05-05 10:16:43 -07:00
parent b03a2a323b
commit d050cfc5c7
No known key found for this signature in database
GPG Key ID: A4D09B96FDFEB505
6 changed files with 65 additions and 28 deletions

View File

@ -1557,6 +1557,13 @@ spec:
May also be set in PodSecurityContext. If set in both SecurityContext and
PodSecurityContext, the value specified in SecurityContext takes precedence.
type: string
serviceAccountName:
description: |-
The service account to use for the Recorder's StatefulSet. If not set,
the operator will create a service account with the same name as the
Recorder resource.
https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#service-account
type: string
tolerations:
description: |-
Tolerations for Recorder Pods. By default, the operator does not apply

View File

@ -4552,6 +4552,13 @@ spec:
type: string
type: object
type: object
serviceAccountName:
description: |-
The service account to use for the Recorder's StatefulSet. If not set,
the operator will create a service account with the same name as the
Recorder resource.
https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#service-account
type: string
tolerations:
description: |-
Tolerations for Recorder Pods. By default, the operator does not apply

View File

@ -169,14 +169,17 @@ func (r *RecorderReconciler) maybeProvision(ctx context.Context, tsr *tsapi.Reco
}); err != nil {
return fmt.Errorf("error creating state Secret: %w", err)
}
sa := tsrServiceAccount(tsr, r.tsNamespace)
if _, err := createOrUpdate(ctx, r.Client, r.tsNamespace, sa, func(s *corev1.ServiceAccount) {
s.ObjectMeta.Labels = sa.ObjectMeta.Labels
s.ObjectMeta.Annotations = sa.ObjectMeta.Annotations
s.ObjectMeta.OwnerReferences = sa.ObjectMeta.OwnerReferences
}); err != nil {
return fmt.Errorf("error creating ServiceAccount: %w", err)
}
// Create the ServiceAccount only if the user hasn't specified a custom name
if tsr.Spec.StatefulSet.Pod.ServiceAccountName == "" {
sa := tsrServiceAccount(tsr, r.tsNamespace)
if _, err := createOrUpdate(ctx, r.Client, r.tsNamespace, sa, func(s *corev1.ServiceAccount) {
s.ObjectMeta.Labels = sa.ObjectMeta.Labels
s.ObjectMeta.Annotations = sa.ObjectMeta.Annotations
s.ObjectMeta.OwnerReferences = sa.ObjectMeta.OwnerReferences
}); err != nil {
return fmt.Errorf("error creating ServiceAccount: %w", err)
}
}
role := tsrRole(tsr, r.tsNamespace)
if _, err := createOrUpdate(ctx, r.Client, r.tsNamespace, role, func(r *rbacv1.Role) {
r.ObjectMeta.Labels = role.ObjectMeta.Labels

View File

@ -39,7 +39,13 @@ func tsrStatefulSet(tsr *tsapi.Recorder, namespace string) *appsv1.StatefulSet {
Annotations: tsr.Spec.StatefulSet.Pod.Annotations,
},
Spec: corev1.PodSpec{
ServiceAccountName: tsr.Name,
ServiceAccountName: func() string {
if tsr.Spec.StatefulSet.Pod.ServiceAccountName != "" {
return tsr.Spec.StatefulSet.Pod.ServiceAccountName
}
return tsr.Name
}(),
Affinity: tsr.Spec.StatefulSet.Pod.Affinity,
SecurityContext: tsr.Spec.StatefulSet.Pod.SecurityContext,
ImagePullSecrets: tsr.Spec.StatefulSet.Pod.ImagePullSecrets,
@ -144,25 +150,30 @@ func tsrRole(tsr *tsapi.Recorder, namespace string) *rbacv1.Role {
}
func tsrRoleBinding(tsr *tsapi.Recorder, namespace string) *rbacv1.RoleBinding {
return &rbacv1.RoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: tsr.Name,
Namespace: namespace,
Labels: labels("recorder", tsr.Name, nil),
OwnerReferences: tsrOwnerReference(tsr),
},
Subjects: []rbacv1.Subject{
{
Kind: "ServiceAccount",
Name: tsr.Name,
Namespace: namespace,
},
},
RoleRef: rbacv1.RoleRef{
Kind: "Role",
Name: tsr.Name,
},
}
saName := tsr.Spec.StatefulSet.Pod.ServiceAccountName
if saName == "" {
saName = tsr.Name
}
return &rbacv1.RoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: tsr.Name,
Namespace: namespace,
Labels: labels("recorder", tsr.Name, nil),
OwnerReferences: tsrOwnerReference(tsr),
},
Subjects: []rbacv1.Subject{
{
Kind: "ServiceAccount",
Name: saName,
Namespace: namespace,
},
},
RoleRef: rbacv1.RoleRef{
Kind: "Role",
Name: tsr.Name,
},
}
}
func tsrAuthSecret(tsr *tsapi.Recorder, namespace string, authKey string) *corev1.Secret {

View File

@ -726,6 +726,7 @@ _Appears in:_
| `imagePullSecrets` _[LocalObjectReference](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.3/#localobjectreference-v1-core) array_ | Image pull Secrets for Recorder Pods.<br />https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#PodSpec | | |
| `nodeSelector` _object (keys:string, values:string)_ | Node selector rules for Recorder Pods. By default, the operator does<br />not apply any node selector rules.<br />https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#scheduling | | |
| `tolerations` _[Toleration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.3/#toleration-v1-core) array_ | Tolerations for Recorder Pods. By default, the operator does not apply<br />any tolerations.<br />https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#scheduling | | |
| `serviceAccountName` _string_ | The service account to use for the Recorder's StatefulSet. If not set,<br />the operator will create a service account with the same name as the<br />Recorder resource.<br />https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#service-account | | |
#### RecorderSpec

View File

@ -94,6 +94,7 @@ type RecorderStatefulSet struct {
// Configuration for pods created by the Recorder's StatefulSet.
// +optional
Pod RecorderPod `json:"pod,omitempty"`
}
type RecorderPod struct {
@ -142,6 +143,13 @@ type RecorderPod struct {
// https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#scheduling
// +optional
Tolerations []corev1.Toleration `json:"tolerations,omitempty"`
// The service account to use for the Recorder's StatefulSet. If not set,
// the operator will create a service account with the same name as the
// Recorder resource.
// https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#service-account
// +optional
ServiceAccountName string `json:"serviceAccountName,omitempty"`
}
type RecorderContainer struct {