diff --git a/cmd/gitea-dynamic-runner/controller.go b/cmd/gitea-dynamic-runner/controller.go index 61fcb07..ed85907 100644 --- a/cmd/gitea-dynamic-runner/controller.go +++ b/cmd/gitea-dynamic-runner/controller.go @@ -41,6 +41,7 @@ type controllerConfig struct { FacadeListen, FacadeURL, FacadeSPIFFEID string CapabilityKey []byte PodNamespace, PodImage, PodServiceAccount, SPIRECluster, SPIREClass string + SPIREAgentID string PodExecutorUID, PodCapacity int OpenSandboxURL, OpenSandboxAPIKey, OpenSandboxPool string VMTimeout, VMCapacity int @@ -132,7 +133,8 @@ func runController(ctx context.Context) error { backend := podbackend.Backend{API: client, Config: podbackend.Config{ Namespace: config.PodNamespace, Image: config.PodImage, ServiceAccount: config.PodServiceAccount, 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) 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"), 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"), - 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), } if config.WorkloadAPIAddr == "" || config.FacadeURL == "" || config.FacadeSPIFFEID == "" { @@ -230,6 +232,9 @@ func loadControllerConfig() (controllerConfig, error) { if slices.Contains(selection, controller.PodWorker) && config.PodImage == "" { 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 config.OpenSandboxURL == "" { return controllerConfig{}, errors.New("OPENSANDBOX_API is required for vm-worker") diff --git a/cmd/gitea-dynamic-runner/controller_test.go b/cmd/gitea-dynamic-runner/controller_test.go index edb0d4d..9c1ebd3 100644 --- a/cmd/gitea-dynamic-runner/controller_test.go +++ b/cmd/gitea-dynamic-runner/controller_test.go @@ -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_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("SPIRE_AGENT_ID", "spiffe://ddupan.top/spire/agent/k8s_psat/homelab/node-uid") config, err := loadControllerConfig() if err != nil { diff --git a/internal/podbackend/backend.go b/internal/podbackend/backend.go index 8d27e4a..fb827ef 100644 --- a/internal/podbackend/backend.go +++ b/internal/podbackend/backend.go @@ -65,6 +65,7 @@ type Config struct { TrustDomain string SPIRECluster string SPIREClass string + SPIREAgentID string ExecutorUID int } @@ -134,12 +135,9 @@ func (b Backend) BindIdentity(ctx context.Context, executor *taskworker.Executor assignmentLabel: executor.Name, }, ClassName: b.Config.SPIREClass, - ParentID: fmt.Sprintf( - "spiffe://%s/spire/agent/k8s_psat/%s/pod/%s", - b.Config.TrustDomain, b.Config.SPIRECluster, executor.IdentityTarget, - ), + ParentID: b.Config.SPIREAgentID, 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 { - 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 nil diff --git a/internal/podbackend/backend_test.go b/internal/podbackend/backend_test.go index 17d64ca..e8ad748 100644 --- a/internal/podbackend/backend_test.go +++ b/internal/podbackend/backend_test.go @@ -46,7 +46,9 @@ func backend(api API) Backend { Namespace: "gitea-actions", Image: "zot/ci-executor:main", ServiceAccount: "gitea-task-executor", ExecutorArgs: []string{"executor"}, 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 { 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) } }