fix: 绑定 Pod 到真实 SPIRE agent

This commit is contained in:
2026-09-20 21:27:48 +00:00
parent a53483f2f0
commit 44909c2ee1
4 changed files with 16 additions and 10 deletions
+7 -2
View File
@@ -41,6 +41,7 @@ type controllerConfig struct {
FacadeListen, FacadeURL, FacadeSPIFFEID string FacadeListen, FacadeURL, FacadeSPIFFEID string
CapabilityKey []byte CapabilityKey []byte
PodNamespace, PodImage, PodServiceAccount, SPIRECluster, SPIREClass string PodNamespace, PodImage, PodServiceAccount, SPIRECluster, SPIREClass string
SPIREAgentID string
PodExecutorUID, PodCapacity int PodExecutorUID, PodCapacity int
OpenSandboxURL, OpenSandboxAPIKey, OpenSandboxPool string OpenSandboxURL, OpenSandboxAPIKey, OpenSandboxPool string
VMTimeout, VMCapacity int VMTimeout, VMCapacity int
@@ -132,7 +133,8 @@ func runController(ctx context.Context) error {
backend := podbackend.Backend{API: client, Config: podbackend.Config{ backend := podbackend.Backend{API: client, Config: podbackend.Config{
Namespace: config.PodNamespace, Image: config.PodImage, ServiceAccount: config.PodServiceAccount, Namespace: config.PodNamespace, Image: config.PodImage, ServiceAccount: config.PodServiceAccount,
ExecutorArgs: []string{"executor"}, TrustDomain: config.TrustDomain, ExecutorArgs: []string{"executor"}, TrustDomain: config.TrustDomain,
SPIRECluster: config.SPIRECluster, SPIREClass: config.SPIREClass, ExecutorUID: config.PodExecutorUID, SPIRECluster: config.SPIRECluster, SPIREClass: config.SPIREClass,
SPIREAgentID: config.SPIREAgentID, ExecutorUID: config.PodExecutorUID,
}} }}
component, err := workerComponent(ctx, workerJS, config, taskassignment.BackendPod, config.PodCapacity, taskworker.Worker{Backend: backend, Bootstrap: bootstrap}, registry) component, err := workerComponent(ctx, workerJS, config, taskassignment.BackendPod, config.PodCapacity, taskworker.Worker{Backend: backend, Bootstrap: bootstrap}, registry)
if err != nil { if err != nil {
@@ -221,7 +223,7 @@ func loadControllerConfig() (controllerConfig, error) {
NATSCA: os.Getenv("NATS_CA_FILE"), Stream: env("NATS_STREAM", "CI_RUNNER"), SubjectBase: env("NATS_SUBJECT_BASE", "ci.runner"), NATSCA: os.Getenv("NATS_CA_FILE"), Stream: env("NATS_STREAM", "CI_RUNNER"), SubjectBase: env("NATS_SUBJECT_BASE", "ci.runner"),
FacadeListen: env("RUNNER_FACADE_LISTEN", ":8443"), FacadeURL: os.Getenv("RUNNER_FACADE_URL"), FacadeSPIFFEID: os.Getenv("RUNNER_FACADE_SPIFFE_ID"), CapabilityKey: []byte(capabilityKey), FacadeListen: env("RUNNER_FACADE_LISTEN", ":8443"), FacadeURL: os.Getenv("RUNNER_FACADE_URL"), FacadeSPIFFEID: os.Getenv("RUNNER_FACADE_SPIFFE_ID"), CapabilityKey: []byte(capabilityKey),
PodNamespace: env("POD_NAMESPACE", "gitea-actions"), PodImage: os.Getenv("POD_EXECUTOR_IMAGE"), PodServiceAccount: env("POD_SERVICE_ACCOUNT", "gitea-task-executor"), PodNamespace: env("POD_NAMESPACE", "gitea-actions"), PodImage: os.Getenv("POD_EXECUTOR_IMAGE"), PodServiceAccount: env("POD_SERVICE_ACCOUNT", "gitea-task-executor"),
SPIRECluster: env("SPIRE_CLUSTER", "homelab"), SPIREClass: env("SPIRE_CLASS", "spire-mgmt-spire"), PodExecutorUID: envInt("POD_EXECUTOR_UID", 2000), PodCapacity: envInt("POD_CAPACITY", 4), SPIRECluster: env("SPIRE_CLUSTER", "homelab"), SPIREClass: env("SPIRE_CLASS", "spire-mgmt-spire"), SPIREAgentID: os.Getenv("SPIRE_AGENT_ID"), PodExecutorUID: envInt("POD_EXECUTOR_UID", 2000), PodCapacity: envInt("POD_CAPACITY", 4),
OpenSandboxURL: os.Getenv("OPENSANDBOX_API"), OpenSandboxPool: env("OPENSANDBOX_POOL", "ci-vm"), VMTimeout: envInt("VM_TIMEOUT_SECONDS", 14400), VMCapacity: envInt("VM_CAPACITY", 1), OpenSandboxURL: os.Getenv("OPENSANDBOX_API"), OpenSandboxPool: env("OPENSANDBOX_POOL", "ci-vm"), VMTimeout: envInt("VM_TIMEOUT_SECONDS", 14400), VMCapacity: envInt("VM_CAPACITY", 1),
} }
if config.WorkloadAPIAddr == "" || config.FacadeURL == "" || config.FacadeSPIFFEID == "" { if config.WorkloadAPIAddr == "" || config.FacadeURL == "" || config.FacadeSPIFFEID == "" {
@@ -230,6 +232,9 @@ func loadControllerConfig() (controllerConfig, error) {
if slices.Contains(selection, controller.PodWorker) && config.PodImage == "" { if slices.Contains(selection, controller.PodWorker) && config.PodImage == "" {
return controllerConfig{}, errors.New("POD_EXECUTOR_IMAGE is required for pod-worker") return controllerConfig{}, errors.New("POD_EXECUTOR_IMAGE is required for pod-worker")
} }
if slices.Contains(selection, controller.PodWorker) && config.SPIREAgentID == "" {
return controllerConfig{}, errors.New("SPIRE_AGENT_ID is required for pod-worker")
}
if slices.Contains(selection, controller.VMWorker) { if slices.Contains(selection, controller.VMWorker) {
if config.OpenSandboxURL == "" { if config.OpenSandboxURL == "" {
return controllerConfig{}, errors.New("OPENSANDBOX_API is required for vm-worker") return controllerConfig{}, errors.New("OPENSANDBOX_API is required for vm-worker")
@@ -28,6 +28,7 @@ func TestLoadControllerConfigUsesFileSecrets(t *testing.T) {
t.Setenv("RUNNER_FACADE_URL", "https://gitea-runner-facade.gitea-actions.svc:8443") t.Setenv("RUNNER_FACADE_URL", "https://gitea-runner-facade.gitea-actions.svc:8443")
t.Setenv("RUNNER_FACADE_SPIFFE_ID", "spiffe://ddupan.top/ns/gitea-actions/sa/gitea-dynamic-runner") t.Setenv("RUNNER_FACADE_SPIFFE_ID", "spiffe://ddupan.top/ns/gitea-actions/sa/gitea-dynamic-runner")
t.Setenv("POD_EXECUTOR_IMAGE", "zot.ddupan.top/ci/gitea-runner@sha256:abc") t.Setenv("POD_EXECUTOR_IMAGE", "zot.ddupan.top/ci/gitea-runner@sha256:abc")
t.Setenv("SPIRE_AGENT_ID", "spiffe://ddupan.top/spire/agent/k8s_psat/homelab/node-uid")
config, err := loadControllerConfig() config, err := loadControllerConfig()
if err != nil { if err != nil {
+4 -6
View File
@@ -65,6 +65,7 @@ type Config struct {
TrustDomain string TrustDomain string
SPIRECluster string SPIRECluster string
SPIREClass string SPIREClass string
SPIREAgentID string
ExecutorUID int ExecutorUID int
} }
@@ -134,12 +135,9 @@ func (b Backend) BindIdentity(ctx context.Context, executor *taskworker.Executor
assignmentLabel: executor.Name, assignmentLabel: executor.Name,
}, },
ClassName: b.Config.SPIREClass, ClassName: b.Config.SPIREClass,
ParentID: fmt.Sprintf( ParentID: b.Config.SPIREAgentID,
"spiffe://%s/spire/agent/k8s_psat/%s/pod/%s",
b.Config.TrustDomain, b.Config.SPIRECluster, executor.IdentityTarget,
),
SPIFFEID: identity.SPIFFEID, SPIFFEID: identity.SPIFFEID,
Selectors: []string{fmt.Sprintf("unix:uid:%d", b.Config.ExecutorUID)}, Selectors: []string{"k8s:pod-uid:" + executor.IdentityTarget},
}) })
} }
@@ -168,7 +166,7 @@ func (b Backend) Delete(ctx context.Context, executor *taskworker.Executor) erro
} }
func (b Backend) validate() error { func (b Backend) validate() error {
if b.API == nil || b.Config.Namespace == "" || b.Config.Image == "" || b.Config.ServiceAccount == "" || b.Config.TrustDomain == "" || b.Config.SPIRECluster == "" || b.Config.SPIREClass == "" || b.Config.ExecutorUID < 1 { if b.API == nil || b.Config.Namespace == "" || b.Config.Image == "" || b.Config.ServiceAccount == "" || b.Config.TrustDomain == "" || b.Config.SPIRECluster == "" || b.Config.SPIREClass == "" || b.Config.SPIREAgentID == "" || b.Config.ExecutorUID < 1 {
return errors.New("Pod API and complete executor/SPIRE configuration are required") return errors.New("Pod API and complete executor/SPIRE configuration are required")
} }
return nil return nil
+4 -2
View File
@@ -46,7 +46,9 @@ func backend(api API) Backend {
Namespace: "gitea-actions", Image: "zot/ci-executor:main", Namespace: "gitea-actions", Image: "zot/ci-executor:main",
ServiceAccount: "gitea-task-executor", ExecutorArgs: []string{"executor"}, ServiceAccount: "gitea-task-executor", ExecutorArgs: []string{"executor"},
TrustDomain: "ddupan.top", SPIRECluster: "homelab", TrustDomain: "ddupan.top", SPIRECluster: "homelab",
SPIREClass: "spire-mgmt-spire", ExecutorUID: 2000, SPIREClass: "spire-mgmt-spire",
SPIREAgentID: "spiffe://ddupan.top/spire/agent/k8s_psat/homelab/node-uid",
ExecutorUID: 2000,
}} }}
} }
@@ -101,7 +103,7 @@ func TestBindIdentityCreatesEntryPinnedToPodUID(t *testing.T) {
if err := backend(api).BindIdentity(context.Background(), executor, assignment().Identity); err != nil { if err := backend(api).BindIdentity(context.Background(), executor, assignment().Identity); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if api.entry.Name != executor.Name || api.entry.SPIFFEID != assignment().Identity.SPIFFEID || api.entry.ParentID != "spiffe://ddupan.top/spire/agent/k8s_psat/homelab/pod/pod-uid" || len(api.entry.Selectors) != 1 || api.entry.Selectors[0] != "unix:uid:2000" { if api.entry.Name != executor.Name || api.entry.SPIFFEID != assignment().Identity.SPIFFEID || api.entry.ParentID != "spiffe://ddupan.top/spire/agent/k8s_psat/homelab/node-uid" || len(api.entry.Selectors) != 1 || api.entry.Selectors[0] != "k8s:pod-uid:pod-uid" {
t.Fatalf("entry=%#v", api.entry) t.Fatalf("entry=%#v", api.entry)
} }
} }