From 57394ceda9972826730b7c7c68efbd6a9379ffa5 Mon Sep 17 00:00:00 2001 From: tennix Date: Wed, 29 Apr 2026 14:56:24 -0700 Subject: [PATCH] Allow FedRAMP deployments to avoid default initializer identities FedRAMP Gatekeeper can reject pods that fall back to the default service account. TidbInitializer creates a Job pod directly, so the CRD needs an explicit field that users can bind to a dedicated ServiceAccount without carrying operator-side patches. The initializer spec now exposes serviceAccountName and passes it through to the generated Job pod template. The CRD and OpenAPI schema are updated so users can configure the field through the v1 API. Constraint: FedRAMP block-default-service-account policy rejects implicit default service account usage Rejected: Hardcode tidb-initializer in the manager | forces one service account name on all users and keeps requiring operator code patches Confidence: high Scope-risk: narrow Directive: Keep this field as a pass-through to the Job pod spec; do not add defaulting here without checking backward compatibility Tested: go test ./pkg/manager/member Tested: cd pkg/apis && go test ./pingcap/v1alpha1 Tested: git diff --check --- docs/api-references/docs.md | 24 +++++++++++++++++++ manifests/crd.yaml | 2 ++ .../crd/v1/pingcap.com_tidbinitializers.yaml | 2 ++ .../pingcap/v1alpha1/openapi_generated.go | 7 ++++++ .../pingcap/v1alpha1/tidbinitializer_types.go | 4 ++++ pkg/manager/member/tidb_init_manager.go | 1 + pkg/manager/member/tidb_init_manager_test.go | 15 ++++++++++++ 7 files changed, 55 insertions(+) diff --git a/docs/api-references/docs.md b/docs/api-references/docs.md index b682eade719..76b36c2ff12 100644 --- a/docs/api-references/docs.md +++ b/docs/api-references/docs.md @@ -2650,6 +2650,18 @@ Kubernetes core/v1.PullPolicy +serviceAccountName
+ +string + + + +(Optional) +

ServiceAccountName is the name of the ServiceAccount to use to run TiDB initializer Pods.

+ + + + permitHost
string @@ -26326,6 +26338,18 @@ Kubernetes core/v1.PullPolicy +serviceAccountName
+ +string + + + +(Optional) +

ServiceAccountName is the name of the ServiceAccount to use to run TiDB initializer Pods.

+ + + + permitHost
string diff --git a/manifests/crd.yaml b/manifests/crd.yaml index 105f0d65dda..f42d380f2e8 100644 --- a/manifests/crd.yaml +++ b/manifests/crd.yaml @@ -57504,6 +57504,8 @@ spec: x-kubernetes-int-or-string: true type: object type: object + serviceAccountName: + type: string timezone: type: string tlsClientSecretName: diff --git a/manifests/crd/v1/pingcap.com_tidbinitializers.yaml b/manifests/crd/v1/pingcap.com_tidbinitializers.yaml index 13350bd2080..52acde8af87 100644 --- a/manifests/crd/v1/pingcap.com_tidbinitializers.yaml +++ b/manifests/crd/v1/pingcap.com_tidbinitializers.yaml @@ -158,6 +158,8 @@ spec: x-kubernetes-int-or-string: true type: object type: object + serviceAccountName: + type: string timezone: type: string tlsClientSecretName: diff --git a/pkg/apis/pingcap/v1alpha1/openapi_generated.go b/pkg/apis/pingcap/v1alpha1/openapi_generated.go index 2a54f34aa5f..5915d231e01 100644 --- a/pkg/apis/pingcap/v1alpha1/openapi_generated.go +++ b/pkg/apis/pingcap/v1alpha1/openapi_generated.go @@ -15676,6 +15676,13 @@ func schema_pkg_apis_pingcap_v1alpha1_TidbInitializerSpec(ref common.ReferenceCa }, }, }, + "serviceAccountName": { + SchemaProps: spec.SchemaProps{ + Description: "ServiceAccountName is the name of the ServiceAccount to use to run TiDB initializer Pods.", + Type: []string{"string"}, + Format: "", + }, + }, "permitHost": { SchemaProps: spec.SchemaProps{ Description: "permitHost is the host which will only be allowed to connect to the TiDB.", diff --git a/pkg/apis/pingcap/v1alpha1/tidbinitializer_types.go b/pkg/apis/pingcap/v1alpha1/tidbinitializer_types.go index edd4957555c..bd1f5188fa4 100644 --- a/pkg/apis/pingcap/v1alpha1/tidbinitializer_types.go +++ b/pkg/apis/pingcap/v1alpha1/tidbinitializer_types.go @@ -73,6 +73,10 @@ type TidbInitializerSpec struct { // +optional ImagePullSecrets []corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"` + // ServiceAccountName is the name of the ServiceAccount to use to run TiDB initializer Pods. + // +optional + ServiceAccountName string `json:"serviceAccountName,omitempty"` + // permitHost is the host which will only be allowed to connect to the TiDB. // +optional PermitHost *string `json:"permitHost,omitempty"` diff --git a/pkg/manager/member/tidb_init_manager.go b/pkg/manager/member/tidb_init_manager.go index 4b6ec4fdae9..3f3ed6e7a84 100644 --- a/pkg/manager/member/tidb_init_manager.go +++ b/pkg/manager/member/tidb_init_manager.go @@ -353,6 +353,7 @@ func (m *tidbInitManager) makeTiDBInitJob(ti *v1alpha1.TidbInitializer) (*batchv }, Spec: corev1.PodSpec{ ImagePullSecrets: ti.Spec.ImagePullSecrets, + ServiceAccountName: ti.Spec.ServiceAccountName, SecurityContext: ti.Spec.PodSecurityContext, AutomountServiceAccountToken: pointer.BoolPtr(false), InitContainers: []corev1.Container{ diff --git a/pkg/manager/member/tidb_init_manager_test.go b/pkg/manager/member/tidb_init_manager_test.go index 48c524f0d3a..203e527b540 100644 --- a/pkg/manager/member/tidb_init_manager_test.go +++ b/pkg/manager/member/tidb_init_manager_test.go @@ -143,6 +143,21 @@ func TestMakeTiDBInitJobDisablesServiceAccountTokenAutomount(t *testing.T) { g.Expect(*job.Spec.Template.Spec.AutomountServiceAccountToken).To(BeFalse()) } +func TestMakeTiDBInitJobUsesServiceAccountName(t *testing.T) { + g := NewGomegaWithT(t) + tim, _, indexers := newFakeTiDBInitManager() + ti := newTidbInitializerForTiDB() + ti.Spec.ServiceAccountName = "tidb-initializer" + tc := newTidbClusterForTiDB() + + err := indexers.tc.Add(tc) + g.Expect(err).NotTo(HaveOccurred()) + + job, err := tim.makeTiDBInitJob(ti) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(job.Spec.Template.Spec.ServiceAccountName).To(Equal("tidb-initializer")) +} + func newFakeTiDBInitManager() (*tidbInitManager, *tidbMemberManager, *fakeIndexers) { tmm, _, _, indexers := newFakeTiDBMemberManager() indexers.job = tmm.deps.KubeInformerFactory.Batch().V1().Jobs().Informer().GetIndexer()