spiffe / helm-charts-hardened

Apache License 2.0
19 stars 32 forks source link

Enable the SPIRE agent socket path to be set in the Helm values file #399

Closed gary-archer closed 3 months ago

gary-archer commented 3 months ago

Great to see this project that enables everyone to keep up to date with the latest SPIRE components and best practices. It enabled me to build some nice end-to-end demo solutions for REST API use cases. But I had one issue that worked fine in the older Helm chart but no longer works in the new chart.

SPIRE AGENT SOCKET PATH

I want to express a socket path like this in the Helm values.yaml file:

global:
  spire:
    clusterName: mycluster
    trustDomain: mytrustdomain
    caSubject ...

spire-agent:
  socketPath: '/var/run/secrets/workload-spiffe-uds/socket'

In the previous Helm chart it resulted in a SPIRE agent config map with this entry:

{
"socket_path": "/var/run/secrets/workload-spiffe-uds/socket",
}

And the SPIRE agent daemonset getting a volume mount entry like this:

volumeMounts:
- name: spire-agent-socket-dir
   mountPath: /var/run/secrets/workload-spiffe-uds

In the current SPIRE agent chart:

SERVICE MESH INTEGRATION

My motivation is to integrate with a service mesh (Istio in my case, which requires the above path):

So for example, a REST API might:

CURRENT WORKAROUND

I can use helm template and update the above two paths and all of the above use cases work perfectly end-to-end.

OTHER APPROACHES?

If I am doing something unsupported or non-standard then any alternative suggestions would be appreciated. If required I could provide further info or a small demo setup.

kfox1111 commented 3 months ago

Great to see this project that enables everyone to keep up to date with the latest SPIRE components and best practices. It enabled me to build some nice end-to-end demo solutions for REST API use cases. But I had one issue that worked fine in the older Helm chart but no longer works in the new chart.

❤️

SPIRE AGENT SOCKET PATH

I want to express a socket path like this in the Helm values.yaml file:

global:
  spire:
    clusterName: mycluster
    trustDomain: mytrustdomain
    caSubject ...

spire-agent:
  socketPath: '/var/run/secrets/workload-spiffe-uds/socket'

We had problems with different workloads expecting the name of the socket to be different in each application, leading to one person changing the name to 'socket' to fix one thing, and it break other things that can get installed. We added a section here: https://github.com/spiffe/helm-charts-hardened/blob/main/charts/spire/charts/spire-agent/values.yaml#L253

That causes symlinks to multiple names to be created to reduce the need to ever set socketPath, and support multiple apps at once that expect different names. You could probably try unsetting your custom socketPath entirely and see if it works for you out of the box. 'socket' is in the list by default.

gary-archer commented 3 months ago

Ah - that is very neat and fixes my problems elegantly so I will close this issue. An initial SPIRE / Istio Helm base setup took me a little time to figure out so I will post here in case useful to others.

SPIRE

I run the default commands:

helm upgrade --install -n spire-server spire-crds spire-crds --repo https://spiffe.github.io/helm-charts-hardened/ --create-namespace --version 0.4.0

helm upgrade --install -n spire-server spire spire --repo https://spiffe.github.io/helm-charts-hardened/ --values=helm-values.yaml --version 0.21.0

This is my initial values file, though I am still learning about options and of course many aspects like root CAs could be refined further. I specify the Istio socket name of workload-socket:

global:
  spire:
    clusterName: workload-identities
    trustDomain: examplecluster.internal.com
    caSubject:
      country: SE
      organization: examplecluster.internal.com
      commonName: examplecluster.internal.com

spire-server:
  controllerManager:
    identities:
      clusterSPIFFEIDs:

        default:
          enabled: false
        oidc-discovery-provider:
          enabled: false
        test-keys:
          enabled: false

        default-spiffe-id:
          spiffeIDTemplate: "spiffe://{{ .TrustDomain }}/ns/{{ .PodMeta.Namespace }}/sa/{{ .PodSpec.ServiceAccountName }}"
          podSelector:
            matchLabels:
              spire-managed-identity: "true"

        dns-spiffe-id:
          spiffeIDTemplate: "spiffe://{{ .TrustDomain }}/ns/{{ .PodMeta.Namespace }}/sa/{{ .PodSpec.ServiceAccountName }}"
          podSelector:
            matchLabels:
              spire-managed-dns-identity: "true"
          dnsNameTemplates: 
          - "{{ .PodMeta.Labels.dnsIdentity }}"

socketAlternate:
  names:
    - workload-socket

spiffe-oidc-discovery-provider:
  enabled: false

ISTIO

I run the default commands:

helm upgrade --install istio-base istio/base -n istio-system --create-namespace --version 1.22.3
helm upgrade --install istiod istio/istiod -n istio-system --values=istiod-helm-values.yaml --version 1.22.3
helm upgrade --install istio-ingressgateway istio/gateway -n istio-system --values=gateway-helm-values.yaml --version 1.22.3

Where this is the istiod values file that mounts the CSI driver into Istio sidecars:

defaults:
  meshConfig:
    trustDomain: examplecluster.internal.com

  sidecarInjectorWebhook:
    templates:
      spire: |
        spec:
          volumes:
            - name: workload-socket
              csi:
                driver: "csi.spiffe.io"
                readOnly: true
      spire-gw: |
        spec:
          volumes:
            - name: workload-socket
              emptyDir: null
              csi:
                driver: "csi.spiffe.io"
                readOnly: true
          initContainers:
          - name: wait-for-spire-socket
            image: busybox:1.28
            volumeMounts:
              - name: workload-socket
                mountPath: /var/run/secrets/workload-spiffe-uds
                readOnly: true
            env:
              - name: CHECK_FILE
                value: /var/run/secrets/workload-spiffe-uds/socket
            command:
              - sh
              - "-c"
              - |-
                echo "$(date -Iseconds)" Waiting for: $${CHECK_FILE}
                while [[ ! -e $${CHECK_FILE} && ! -L $${CHECK_FILE} ]] ; do
                  echo "$(date -Iseconds)" File does not exist: $${CHECK_FILE}
                  sleep 15
                done
                ls -l $${CHECK_FILE}

And this is the gateway values file:

defaults:
  labels:
    spire-managed-identity: 'true'

  podAnnotations:
    inject.istio.io/templates: 'gateway,spire-gw'

This command then shows a SPIRE identity registered for the Istio gateway:

kubectl -n spire-server exec -t spire-server-0 -- ./bin/spire-server entry show
kfox1111 commented 3 months ago

Very cool. Thanks for sharing. :)