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
@@ -25,6 +25,16 @@
{{- if hasPrefix (.Values.socketPath | dir | clean) (.Values.sockets.hostBasePath | clean) }}
{{- fail "The sockets.hostBasePath can not be located under the socketPath directory" }}
{{- end }}
{{- /* Validate kubeletAddress.mode */ -}}
{{- if and (hasKey .Values "kubeletAddress") (ne .Values.kubeletAddress.mode "") }}
{{- 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 }}
{{- end }}
{{- /* Prevent using both old and new config */ -}}
{{- if and (ne (.Values.kubeletConnectByHostname | toString) "") (and (hasKey .Values "kubeletAddress") (ne .Values.kubeletAddress.mode "") (ne .Values.kubeletAddress.mode "auto")) }}
{{- fail "Both kubeletConnectByHostname (deprecated) and kubeletAddress.mode are set. Please use only kubeletAddress.mode." }}
{{- end }}
{{- end }}
{{- define "spire-agent.yaml-config" -}}
agent:
@@ -149,8 +159,8 @@ plugins:
disable_container_selectors: {{ eq .Values.workloadAttestors.k8s.disableContainerSelectors true}}
use_new_container_locator: {{ eq .Values.workloadAttestors.k8s.useNewContainerLocator true }}
verbose_container_locator_logs: {{ eq .Values.workloadAttestors.k8s.verboseContainerLocatorLogs true }}
{{- if eq (include "spire-agent.connect-by-hostname" .) "true" }}
node_name_env: "MY_NODE_NAME"
{{- if eq (include "spire-agent.should-set-node-name-env" .) "true" }}
node_name_env: "KUBELET_ADDR"
{{- end }}
{{- end }}