Skip to content

Commit 2c019ac

Browse files
authored
Merge pull request #367 from huang195/fix/spire-agent-socket-mount
fix(injector): Mount spire-agent-socket into authbridge containers
2 parents ab722e2 + a644731 commit 2c019ac

2 files changed

Lines changed: 126 additions & 0 deletions

File tree

kagenti-operator/internal/webhook/injector/container_builder.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package injector
1818

1919
import (
2020
"fmt"
21+
"path"
2122
"strconv"
2223
"strings"
2324

@@ -123,6 +124,13 @@ func (b *ContainerBuilder) BuildEnvoyProxyContainerWithSpireOption(spireEnabled
123124
MountPath: "/etc/spiffe-helper",
124125
ReadOnly: true,
125126
},
127+
// SPIRE workload-API socket — bundled spiffe-helper dials it.
128+
// Path derived from SpiffeConfig.SocketPath (defaults.go).
129+
corev1.VolumeMount{
130+
Name: "spire-agent-socket",
131+
MountPath: spireSocketDir(b.cfg.Spiffe.SocketPath),
132+
ReadOnly: true,
133+
},
126134
)
127135
}
128136

@@ -187,6 +195,19 @@ func spireEnabledStr(b bool) string {
187195
return "false"
188196
}
189197

198+
// spireSocketDir returns the directory portion of the SPIRE workload-API
199+
// socket path (e.g. "unix:///spiffe-workload-api/spire-agent.sock" →
200+
// "/spiffe-workload-api"), suitable for use as a container mountPath.
201+
// Single source of truth: defaults.go's SpiffeConfig.SocketPath.
202+
func spireSocketDir(socketPath string) string {
203+
stripped := strings.TrimPrefix(socketPath, "unix://")
204+
dir := path.Dir(stripped)
205+
if dir == "." || dir == "/" {
206+
return ""
207+
}
208+
return dir
209+
}
210+
190211
// BuildProxySidecarContainer creates a combined authbridge container for proxy-sidecar mode.
191212
// Uses the authbridge image (authbridge-proxy + spiffe-helper bundled, no Envoy).
192213
// The app uses HTTP_PROXY env vars to route outbound traffic through the forward proxy.
@@ -235,6 +256,13 @@ func (b *ContainerBuilder) BuildProxySidecarContainerWithPorts(spireEnabled bool
235256
MountPath: "/etc/spiffe-helper",
236257
ReadOnly: true,
237258
},
259+
// SPIRE workload-API socket — bundled spiffe-helper dials it.
260+
// Path derived from SpiffeConfig.SocketPath (defaults.go).
261+
corev1.VolumeMount{
262+
Name: "spire-agent-socket",
263+
MountPath: spireSocketDir(b.cfg.Spiffe.SocketPath),
264+
ReadOnly: true,
265+
},
238266
)
239267
}
240268

kagenti-operator/internal/webhook/injector/container_builder_test.go

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,3 +385,101 @@ func TestBuildProxySidecarContainer_SpireEnabled(t *testing.T) {
385385
t.Error("svid-output volume mount should be present when SPIRE is enabled")
386386
}
387387
}
388+
389+
// TestBuildEnvoyProxyContainer_SpireEnabled_HasSocketMount asserts that
390+
// the SPIRE workload-API socket volume is mounted into the envoy-proxy
391+
// container when SPIRE is on. The bundled spiffe-helper inside the
392+
// combined image dials this socket; without the mount it sits in a
393+
// silent dial-loop and never writes /opt/svid*.pem.
394+
func TestBuildEnvoyProxyContainer_SpireEnabled_HasSocketMount(t *testing.T) {
395+
cfg := config.CompiledDefaults()
396+
builder := NewContainerBuilder(cfg)
397+
container := builder.BuildEnvoyProxyContainerWithSpireOption(true)
398+
399+
// Derive the expected mount path from SpiffeConfig.SocketPath the
400+
// same way the production code does, so a future change to the
401+
// canonical SocketPath in defaults.go can't leave this test
402+
// asserting against a stale literal.
403+
wantPath := spireSocketDir(cfg.Spiffe.SocketPath)
404+
if wantPath == "" {
405+
t.Fatalf("spireSocketDir(%q) returned empty — defaults must declare a valid socket path", cfg.Spiffe.SocketPath)
406+
}
407+
408+
found := false
409+
for _, vm := range container.VolumeMounts {
410+
if vm.Name == "spire-agent-socket" {
411+
found = true
412+
if vm.MountPath != wantPath {
413+
t.Errorf("spire-agent-socket mount path = %q, want %q (derived from SpiffeConfig.SocketPath %q)",
414+
vm.MountPath, wantPath, cfg.Spiffe.SocketPath)
415+
}
416+
if !vm.ReadOnly {
417+
t.Error("spire-agent-socket mount should be read-only (CSI volume itself is read-only)")
418+
}
419+
break
420+
}
421+
}
422+
if !found {
423+
t.Error("envoy-proxy container missing spire-agent-socket mount when SPIRE is enabled — bundled spiffe-helper can't reach the workload API")
424+
}
425+
}
426+
427+
// TestBuildEnvoyProxyContainer_SpireDisabled_NoSocketMount: with SPIRE
428+
// off the socket mount must be absent — there's no spiffe-helper to
429+
// dial the socket, and mounting it would still try to schedule the
430+
// CSI volume.
431+
func TestBuildEnvoyProxyContainer_SpireDisabled_NoSocketMount(t *testing.T) {
432+
builder := NewContainerBuilder(config.CompiledDefaults())
433+
container := builder.BuildEnvoyProxyContainerWithSpireOption(false)
434+
435+
for _, vm := range container.VolumeMounts {
436+
if vm.Name == "spire-agent-socket" {
437+
t.Error("envoy-proxy container should NOT have spire-agent-socket mount when SPIRE is disabled")
438+
}
439+
}
440+
}
441+
442+
// TestBuildProxySidecarContainer_SpireEnabled_HasSocketMount: same as
443+
// the envoy-proxy variant but for the proxy-sidecar combined image.
444+
// The bundled spiffe-helper has the same workload-API requirement.
445+
func TestBuildProxySidecarContainer_SpireEnabled_HasSocketMount(t *testing.T) {
446+
cfg := config.CompiledDefaults()
447+
builder := NewContainerBuilder(cfg)
448+
container := builder.BuildProxySidecarContainer(true)
449+
450+
wantPath := spireSocketDir(cfg.Spiffe.SocketPath)
451+
if wantPath == "" {
452+
t.Fatalf("spireSocketDir(%q) returned empty — defaults must declare a valid socket path", cfg.Spiffe.SocketPath)
453+
}
454+
455+
found := false
456+
for _, vm := range container.VolumeMounts {
457+
if vm.Name == "spire-agent-socket" {
458+
found = true
459+
if vm.MountPath != wantPath {
460+
t.Errorf("spire-agent-socket mount path = %q, want %q (derived from SpiffeConfig.SocketPath %q)",
461+
vm.MountPath, wantPath, cfg.Spiffe.SocketPath)
462+
}
463+
if !vm.ReadOnly {
464+
t.Error("spire-agent-socket mount should be read-only (CSI volume itself is read-only)")
465+
}
466+
break
467+
}
468+
}
469+
if !found {
470+
t.Error("proxy-sidecar container missing spire-agent-socket mount when SPIRE is enabled — bundled spiffe-helper can't reach the workload API")
471+
}
472+
}
473+
474+
// TestBuildProxySidecarContainer_SpireDisabled_NoSocketMount mirrors
475+
// the envoy-proxy negative test for the proxy-sidecar variant.
476+
func TestBuildProxySidecarContainer_SpireDisabled_NoSocketMount(t *testing.T) {
477+
builder := NewContainerBuilder(config.CompiledDefaults())
478+
container := builder.BuildProxySidecarContainer(false)
479+
480+
for _, vm := range container.VolumeMounts {
481+
if vm.Name == "spire-agent-socket" {
482+
t.Error("proxy-sidecar container should NOT have spire-agent-socket mount when SPIRE is disabled")
483+
}
484+
}
485+
}

0 commit comments

Comments
 (0)