Add Configurable Kubelet Address for SPIRE Agent (#709)

* Add kubeletAddress.mode configuration to spire-agent

Introduces new enum-based configuration for kubelet connection modes:
- auto (default): hostname for OpenShift, localhost otherwise
- localhost: SPIRE default behavior (127.0.0.1:10250)
- hostname: Connect via node hostname
- hostip: Connect via node IP
- custom: User-provided configuration

Deprecates kubeletConnectByHostname but maintains backward compatibility.

Signed-off-by: Oliver Bassett <[email protected]>

* Replace connect-by-hostname helper with mode resolution

Adds three new helpers:
- spire-agent.kubelet-address-mode: Determine mode with backward compat
- spire-agent.kubelet-address-mode-resolved: Resolve auto to actual mode
- spire-agent.should-set-node-name-env: Determine if node_name_env needed

Includes validation of enum values and maintains backward compatibility
by keeping the old connect-by-hostname helper as deprecated.

Signed-off-by: Oliver Bassett <[email protected]>

* Update daemonset to use KUBELET_ADDR env variable

- Sets KUBELET_ADDR from downward API for hostname/hostip modes
- Maintains MY_NODE_NAME for backward compatibility
- No env var set for localhost mode (SPIRE default)
- Custom mode allows user control via extraEnvVars
- Updates init container env to support both hostname and hostip modes

Signed-off-by: Oliver Bassett <[email protected]>

* Update workload attestor config and add validation

- Changes node_name_env from MY_NODE_NAME to KUBELET_ADDR
- Adds validation for kubeletAddress.mode enum
- Prevents using both old and new config simultaneously

Signed-off-by: Oliver Bassett <[email protected]>

* Improve documentation for custom mode

Clarifies that custom mode does not validate KUBELET_ADDR presence,
allowing for external secret injection and other advanced configuration
methods.

Signed-off-by: Oliver Bassett <[email protected]>

* Fix backward compatibility for kubeletConnectByHostname

Two critical fixes for backward compatibility:

1. Helper template priority: Reorder kubelet-address-mode helper to
   prioritize kubeletConnectByHostname when kubeletAddress.mode is
   'auto' or empty. This ensures deprecated config still works.

2. Type-safe validation: Convert kubeletConnectByHostname to string
   in validation and helper to handle both boolean and string types
   consistently. Original chart required string type.

3. Smart dual-config validation: Only fail when both configs are
   explicitly set to non-default values. Allow kubeletConnectByHostname
   with mode='auto' for backward compatibility.

Tested scenarios:
- kubeletConnectByHostname='true' maps to hostname mode
- kubeletConnectByHostname='false' maps to localhost mode
- Both set with mode='auto' allows backward compat to take priority
- Both set with different non-defaults triggers validation error
- OpenShift auto mode correctly resolves to hostname mode

Signed-off-by: Oliver Bassett <[email protected]>

* Use parentheses for DEPRECATED tag in values.yaml

Change [DEPRECATED] to (DEPRECATED) to avoid conflicts with automated
README generator which uses square brackets for special tags.

Signed-off-by: Oliver Bassett <[email protected]>

* Update generated README documentation

Regenerate README.md from values.yaml using documentation generator.
Includes new kubeletAddress.mode configuration and deprecation notice
for kubeletConnectByHostname.

Signed-off-by: Oliver Bassett <[email protected]>

* Remove MY_NODE_NAME environment variable

Remove MY_NODE_NAME as it is not used within the spire-agent chart.
Initially kept for backwards compatibility concerns, but confirmed
unnecessary after review.

The KUBELET_ADDR environment variable is sufficient for the workload
attestor configuration via node_name_env setting.

Addresses PR feedback: https://github.com/spiffe/helm-charts-hardened/pull/709#discussion_r1909855869

Signed-off-by: Oliver Bassett <[email protected]>

* Fix init container for custom kubelet address mode

Address PR #709 feedback by standardizing on KUBELET_ADDR environment
variable and passing extraEnvVars to init containers.

Changes:

1. Init container env variable:
   - Renamed NODE_NAME to KUBELET_ADDR for consistency
   - Made hostip check explicit with 'else if'
   - Passes extraEnvVars to init container for custom mode support

2. Init container script:
   - Updated URL construction to use KUBELET_ADDR for all modes
   - Added validation for custom mode: fails with clear error if
     KUBELET_ADDR is not set via extraEnvVars
   - hostname/hostip modes: Use KUBELET_ADDR from downward API
   - custom mode: Use KUBELET_ADDR from extraEnvVars with validation
   - localhost mode: Use hardcoded 'localhost'

3. Documentation updates:
   - Updated custom mode docs to explain extraEnvVars is passed to
     both main and init containers
   - Noted init container validation behavior
   - Updated extraEnvVars param docs to mention init containers

Testing verified:
- Template rendering for all modes (hostname, hostip, custom, localhost)
- Runtime validation: deployed custom mode without KUBELET_ADDR to kind
  cluster, init container correctly failed with clear error message

Addresses: https://github.com/spiffe/helm-charts-hardened/pull/709#discussion_r1909855869
Signed-off-by: Oliver Bassett <[email protected]>

* Update generated README for init container changes

Regenerate README.md to reflect that extraEnvVars is now passed
to both the main container and init containers.

Signed-off-by: Oliver Bassett <[email protected]>

---------

Signed-off-by: Oliver Bassett <[email protected]>
Co-authored-by: kfox1111 <[email protected]>
This commit is contained in:
Oliver Bassett
2026-01-21 16:47:55 -08:00
committed by GitHub
co-authored by kfox1111
parent 894cbb1089
commit 97c383b1cb
5 changed files with 117 additions and 18 deletions
@@ -114,14 +114,66 @@ Create the name of the service account to use
{{- print .Values.socketPath }}
{{- end }}
{{- define "spire-agent.connect-by-hostname" -}}
{{- if ne .Values.kubeletConnectByHostname "" }}
{{- if eq (.Values.kubeletConnectByHostname | toString) "true" }}
{{- printf "true" }}
{{- else }}
{{- printf "false" }}
{{/*
Determine the kubelet address mode (handles backward compatibility)
Returns: auto, localhost, hostname, hostip, or custom
Priority:
1. If kubeletAddress.mode is set to non-default (not auto/empty), use it
2. Else if kubeletConnectByHostname is set, use it (maps to hostname/localhost)
3. Else default to auto
*/}}
{{- define "spire-agent.kubelet-address-mode" -}}
{{- if and (hasKey .Values "kubeletAddress") (ne .Values.kubeletAddress.mode "") (ne .Values.kubeletAddress.mode "auto") }}
{{- if not (has .Values.kubeletAddress.mode (list "auto" "localhost" "hostname" "hostip" "custom")) }}
{{- fail (printf "kubeletAddress.mode must be one of [auto, localhost, hostname, hostip, custom], got: %s" .Values.kubeletAddress.mode) }}
{{- end }}
{{- else if (dig "openshift" false .Values.global) }}
{{- .Values.kubeletAddress.mode }}
{{- else if ne (.Values.kubeletConnectByHostname | toString) "" }}
{{- if eq (.Values.kubeletConnectByHostname | toString) "true" }}
{{- printf "hostname" }}
{{- else }}
{{- printf "localhost" }}
{{- end }}
{{- else }}
{{- printf "auto" }}
{{- end }}
{{- end }}
{{/*
Resolve auto mode to actual mode based on platform
Returns: localhost, hostname, hostip, or custom (never auto)
*/}}
{{- define "spire-agent.kubelet-address-mode-resolved" -}}
{{- $mode := include "spire-agent.kubelet-address-mode" . }}
{{- if eq $mode "auto" }}
{{- if (dig "openshift" false .Values.global) }}
{{- printf "hostname" }}
{{- else }}
{{- printf "localhost" }}
{{- end }}
{{- else }}
{{- $mode }}
{{- end }}
{{- end }}
{{/*
Check if node_name_env should be set in workload attestor config
Returns: "true" if we should set it, empty string otherwise
*/}}
{{- define "spire-agent.should-set-node-name-env" -}}
{{- $resolvedMode := include "spire-agent.kubelet-address-mode-resolved" . }}
{{- if or (eq $resolvedMode "hostname") (eq $resolvedMode "hostip") (eq $resolvedMode "custom") }}
{{- printf "true" }}
{{- end }}
{{- end }}
{{/*
DEPRECATED: Use spire-agent.kubelet-address-mode-resolved instead
Kept for backward compatibility
*/}}
{{- define "spire-agent.connect-by-hostname" -}}
{{- $resolvedMode := include "spire-agent.kubelet-address-mode-resolved" . }}
{{- if or (eq $resolvedMode "hostname") (eq $resolvedMode "hostip") }}
{{- printf "true" }}
{{- else }}
{{- printf "false" }}