|
| 1 | +--- |
| 2 | +weight: 10 |
| 3 | +title: SPIRE |
| 4 | +--- |
| 5 | + |
| 6 | +# Alauda Build of SPIRE |
| 7 | + |
| 8 | +SPIRE (the SPIFFE Runtime Environment) is a toolchain for establishing trust between software systems across a wide variety of hosting platforms. SPIRE exposes the [SPIFFE](https://spiffe.io/) (Secure Production Identity Framework for Everyone) API, which allows workloads to securely authenticate each other without the need for shared secrets or hardcoded credentials. |
| 9 | + |
| 10 | +In the Alauda Container Platform (ACP), SPIRE is provided as a cluster plugin to enhance workload security by providing cryptographically verifiable identities (SVIDs) for all workloads. |
| 11 | + |
| 12 | +## Core Components |
| 13 | + |
| 14 | +The SPIRE plugin includes several components to manage identities: |
| 15 | + |
| 16 | +- **SPIRE Server**: The central authority that manages trust and issues identities. |
| 17 | +- **SPIRE Agent**: Runs on every node and delivers identities to local workloads. |
| 18 | +- **SPIFFE CSI Driver**: A Container Storage Interface driver that mounts SVIDs as volumes into Pods. |
| 19 | +- **SPIRE Controller Manager**: Automates the registration of Kubernetes workloads. |
| 20 | +- **OIDC Discovery Provider**: Exposes an OIDC discovery document for SPIRE's trust domain. |
| 21 | + |
| 22 | +## Workflow |
| 23 | + |
| 24 | +The SPIRE plugin operates based on a zero-trust model. The following high-level workflow describes how identities are established and delivered: |
| 25 | + |
| 26 | +1. **Deployment**: The SPIRE Server, Agent, and CSI Driver are deployed as cluster plugins. |
| 27 | +2. **Node Attestation**: When a node starts, the SPIRE Agent connects to the SPIRE Server and identifies the node (e.g., using Kubernetes node labels and security tokens). |
| 28 | +3. **Agent SVID Issuance**: The SPIRE Server evaluates the node's identity against its policies and issues an **Agent SVID** and a Trust Bundle (CA Certificate) to the Agent. |
| 29 | +4. **Workload Request**: A workload (such as a Pod) starts on the node and requests a secure identity from the local SPIRE Agent's Workload API (exposed via the SPIFFE CSI Driver). |
| 30 | +5. **Workload Attestation**: The SPIRE Agent gathers metadata about the workload (e.g., namespace, service account, labels) and sends it to the SPIRE Server. |
| 31 | +6. **Workload SVID Issuance**: The SPIRE Server verifies the workload information against its registration entries and issues a **Workload SVID**. |
| 32 | +7. **SVID Delivery**: The SPIRE Agent receives the SVID and delivers it to the workload. The SPIFFE CSI Driver mounts this identity as a volume into the Pod. |
| 33 | +8. **Secure Communication**: The workload now has a cryptographically verifiable identity and can use it to perform mTLS-authenticated communication with other SPIFFE-aware services. |
| 34 | + |
| 35 | +## Installation |
| 36 | + |
| 37 | +### Prerequisites |
| 38 | + |
| 39 | +- A running Alauda Container Platform cluster. |
| 40 | +- An available **StorageClass** in the cluster for persistent storage. |
| 41 | +- Sufficient resources for the SPIRE stack. |
| 42 | + |
| 43 | +### Install via Console |
| 44 | + |
| 45 | +1. Log in to the ACP console and navigate to **Administrator**. |
| 46 | +2. Click **Marketplace** > **Cluster Plugins**. |
| 47 | +3. Select the target cluster in the top navigation bar. |
| 48 | +4. Search for **Alauda Build of SPIRE** and click to view its details. |
| 49 | +5. Click **Install**. |
| 50 | +6. In the configuration step, update the following parameters: |
| 51 | + - **Cluster Name**: The unique identifier for your cluster (e.g., `dce-cluster`). |
| 52 | + - **Trust Domain**: The trust domain name (e.g., `example.org`). |
| 53 | + - **Common Name**: The common name for the SPIRE CA. |
| 54 | + - **Storage Class**: Select an available storage class for SPIRE Server data storage. |
| 55 | +7. Click **Confirm** to complete the installation. |
| 56 | + |
| 57 | +## Usage |
| 58 | + |
| 59 | +### Using SPIFFE IDs in Workloads |
| 60 | + |
| 61 | +Once SPIRE is installed, workloads can obtain their SVIDs using the SPIFFE CSI Driver. |
| 62 | + |
| 63 | +1. **Enable SPIFFE for a Pod**: Add the SPIFFE CSI volume to your Pod specification. |
| 64 | + |
| 65 | + ```yaml |
| 66 | + apiVersion: v1 |
| 67 | + kind: Pod |
| 68 | + metadata: |
| 69 | + name: example-workload |
| 70 | + spec: |
| 71 | + containers: |
| 72 | + - name: app |
| 73 | + image: alpine |
| 74 | + volumeMounts: |
| 75 | + - name: spiffe-workload-api |
| 76 | + mountPath: /run/spiffe.io/public |
| 77 | + readOnly: true |
| 78 | + volumes: |
| 79 | + - name: spiffe-workload-api |
| 80 | + csi: |
| 81 | + driver: 'csi.spiffe.io' |
| 82 | + readOnly: true |
| 83 | + ``` |
| 84 | +
|
| 85 | +2. **Workload Authentication**: Your application can now use the SPIFFE Workload API at `/run/spiffe.io/public` to retrieve its identity and certificates. |
| 86 | + |
| 87 | +### Workload Registration |
| 88 | + |
| 89 | +By default, the **SPIRE Controller Manager** automatically creates SPIRE entries for Kubernetes workloads based on their labels or service accounts. You can customize this behavior using annotations on your workloads. |
| 90 | + |
| 91 | +### End-to-End Implementation Example |
| 92 | + |
| 93 | +The following example demonstrates a complete SPIRE deployment showing how to set up mutual TLS (mTLS) authentication between workloads using SPIFFE identities. |
| 94 | + |
| 95 | +<Steps> |
| 96 | + |
| 97 | +### Implementation Goals and Architecture |
| 98 | + |
| 99 | +This example shows how to: |
| 100 | + |
| 101 | +- Deploy SPIRE Server and Agent in a single Kubernetes cluster |
| 102 | +- Complete Node Attestation using k8s_psat |
| 103 | +- Automatically issue SPIFFE IDs and X.509 SVIDs for example workloads |
| 104 | +- Verify that authorized workloads can successfully obtain identities while unauthorized workloads cannot |
| 105 | + |
| 106 | +The architecture consists of: |
| 107 | + |
| 108 | +- **Server Workload**: SPIFFE ID `spiffe://example.org/ns/example/sa/server-sa`, retrieves certificates via Workload API, enables mTLS trusting only specific Client SPIFFE ID |
| 109 | +- **Client Workload**: SPIFFE ID `spiffe://example.org/ns/example/sa/client-sa`, retrieves certificates via Workload API, accesses Server using mTLS |
| 110 | +- Both communicate with **SPIRE Agent** which talks to **SPIRE Server** |
| 111 | + |
| 112 | +### Prerequisites |
| 113 | + |
| 114 | +Before starting, ensure you have: |
| 115 | + |
| 116 | +- A running Kubernetes cluster with storage component deployed |
| 117 | +- Kubelet API listening on 127.0.0.1 |
| 118 | +- The `example` namespace created: `kubectl create namespace example` |
| 119 | + |
| 120 | +### SPIRE Deployment |
| 121 | + |
| 122 | +Deploy SPIRE using the official Helm chart with production-ready configuration: |
| 123 | + |
| 124 | +1. Create a `values.yaml` file with the following content: |
| 125 | + |
| 126 | + ```yaml |
| 127 | + global: |
| 128 | + openshift: false |
| 129 | + spire: |
| 130 | + recommendations: |
| 131 | + enabled: true |
| 132 | + namespaces: |
| 133 | + create: true |
| 134 | + ingressControllerType: '' |
| 135 | + clusterName: example-cluster |
| 136 | + trustDomain: example.org |
| 137 | + caSubject: |
| 138 | + country: CN |
| 139 | + organization: Example |
| 140 | + commonName: example.org |
| 141 | + persistence: |
| 142 | + storageClass: your-storage-class |
| 143 | + ``` |
| 144 | + |
| 145 | +2. Deploy SPIRE CRDs and main components: |
| 146 | + |
| 147 | + ```bash |
| 148 | + helm upgrade --install --create-namespace -n spire spire-crds spire-crds \ |
| 149 | + --repo https://spiffe.github.io/helm-charts-hardened/ |
| 150 | +
|
| 151 | + helm upgrade --install -n spire spire spire \ |
| 152 | + --repo https://spiffe.github.io/helm-charts-hardened -f values.yaml |
| 153 | + ``` |
| 154 | + |
| 155 | +3. Verify all pods are running: |
| 156 | + |
| 157 | + ```bash |
| 158 | + kubectl get pods -n spire |
| 159 | + ``` |
| 160 | + |
| 161 | + Expected output should show all SPIRE components in `Running` state: |
| 162 | + |
| 163 | + ``` |
| 164 | + NAME READY STATUS RESTARTS AGE |
| 165 | + spire-agent-xxx 1/1 Running 0 17h |
| 166 | + spire-server-0 2/2 Running 0 18h |
| 167 | + spire-spiffe-csi-driver-xxx 2/2 Running 0 19h |
| 168 | + spire-spiffe-oidc-discovery-provider-xxx 2/2 Running 0 17h |
| 169 | + ``` |
| 170 | +
|
| 171 | +### Example Workload Registration |
| 172 | +
|
| 173 | +Register the client and server workloads with SPIRE: |
| 174 | +
|
| 175 | +1. Register the client workload: |
| 176 | +
|
| 177 | + ```bash |
| 178 | + kubectl exec -n spire spire-server-0 -- \ |
| 179 | + /opt/spire/bin/spire-server entry create \ |
| 180 | + -spiffeID spiffe://example.org/ns/example/sa/client-sa \ |
| 181 | + -parentID spiffe://example.org/ns/spire/sa/spire-agent \ |
| 182 | + -selector k8s:ns:example |
| 183 | + ``` |
| 184 | + |
| 185 | +2. Register the server workload: |
| 186 | + |
| 187 | + ```bash |
| 188 | + kubectl exec -n spire spire-server-0 -- \ |
| 189 | + /opt/spire/bin/spire-server entry create \ |
| 190 | + -spiffeID spiffe://example.org/ns/example/sa/server-sa \ |
| 191 | + -parentID spiffe://example.org/ns/spire/sa/spire-agent \ |
| 192 | + -selector k8s:ns:example |
| 193 | + ``` |
| 194 | + |
| 195 | +Both commands will return entry IDs confirming successful registration. |
| 196 | + |
| 197 | +### Workload Deployment |
| 198 | + |
| 199 | +Deploy the workloads that use ghostunnel to handle mTLS with SPIRE identities. |
| 200 | + |
| 201 | +#### Deploy Server Workload |
| 202 | + |
| 203 | +Create the server workload that exposes an HTTPS endpoint with mTLS: |
| 204 | + |
| 205 | +```yaml |
| 206 | +apiVersion: v1 |
| 207 | +kind: ServiceAccount |
| 208 | +metadata: |
| 209 | + name: server-sa |
| 210 | + namespace: example |
| 211 | +--- |
| 212 | +apiVersion: apps/v1 |
| 213 | +kind: Deployment |
| 214 | +metadata: |
| 215 | + name: server-workload |
| 216 | + namespace: example |
| 217 | +spec: |
| 218 | + replicas: 1 |
| 219 | + selector: |
| 220 | + matchLabels: |
| 221 | + app: server-workload |
| 222 | + template: |
| 223 | + metadata: |
| 224 | + labels: |
| 225 | + app: server-workload |
| 226 | + spec: |
| 227 | + containers: |
| 228 | + - args: |
| 229 | + - echo 'Authenticated SPIFFE Content' > index.html && python3 -m http.server 8080 --bind 127.0.0.1 |
| 230 | + command: |
| 231 | + - /bin/sh |
| 232 | + - -c |
| 233 | + image: python:3.9-alpine |
| 234 | + imagePullPolicy: IfNotPresent |
| 235 | + name: my-app |
| 236 | + ports: |
| 237 | + - containerPort: 8080 |
| 238 | + protocol: TCP |
| 239 | + - args: |
| 240 | + - server |
| 241 | + - --listen |
| 242 | + - :8443 |
| 243 | + - --use-workload-api-addr=unix:/run/spire/sockets/api.sock |
| 244 | + - --target |
| 245 | + - 127.0.0.1:8080 |
| 246 | + - --allow-uri |
| 247 | + - spiffe://example.org/ns/example/sa/client-sa |
| 248 | + image: docker-mirrors.alauda.cn/ghostunnel/ghostunnel:v1.9.0 |
| 249 | + imagePullPolicy: Always |
| 250 | + name: ghostunnel |
| 251 | + ports: |
| 252 | + - containerPort: 8443 |
| 253 | + protocol: TCP |
| 254 | + volumeMounts: |
| 255 | + - mountPath: /run/spire/sockets |
| 256 | + name: spiffe-socket |
| 257 | + serviceAccount: server-sa |
| 258 | + serviceAccountName: server-sa |
| 259 | + volumes: |
| 260 | + - hostPath: |
| 261 | + path: /run/spire/agent-sockets |
| 262 | + type: Directory |
| 263 | + name: spiffe-socket |
| 264 | +``` |
| 265 | +
|
| 266 | +Apply with: `kubectl apply -f server-workload.yaml` |
| 267 | + |
| 268 | +#### Deploy Client Workload |
| 269 | + |
| 270 | +Create the client workload that connects to the server using mTLS: |
| 271 | + |
| 272 | +```yaml |
| 273 | +apiVersion: v1 |
| 274 | +kind: ServiceAccount |
| 275 | +metadata: |
| 276 | + name: client-sa |
| 277 | + namespace: example |
| 278 | +--- |
| 279 | +apiVersion: apps/v1 |
| 280 | +kind: Deployment |
| 281 | +metadata: |
| 282 | + name: client-workload |
| 283 | + namespace: example |
| 284 | +spec: |
| 285 | + replicas: 1 |
| 286 | + selector: |
| 287 | + matchLabels: |
| 288 | + app: client-workload |
| 289 | + template: |
| 290 | + metadata: |
| 291 | + labels: |
| 292 | + app: client-workload |
| 293 | + spec: |
| 294 | + serviceAccountName: client-sa |
| 295 | + containers: |
| 296 | + - args: |
| 297 | + - client |
| 298 | + - --listen |
| 299 | + - 127.0.0.1:8080 |
| 300 | + - --target |
| 301 | + - server-workload:8443 |
| 302 | + - --use-workload-api-addr=unix:/run/spire/sockets/api.sock |
| 303 | + - --verify-uri |
| 304 | + - spiffe://example.org/ns/example/sa/server-sa |
| 305 | + image: ghostunnel/ghostunnel:v1.9.0 |
| 306 | + imagePullPolicy: IfNotPresent |
| 307 | + name: ghostunnel |
| 308 | + ports: |
| 309 | + - containerPort: 8080 |
| 310 | + protocol: TCP |
| 311 | + volumeMounts: |
| 312 | + - mountPath: /run/spire/sockets |
| 313 | + name: spiffe-socket |
| 314 | + volumes: |
| 315 | + - hostPath: |
| 316 | + path: /run/spire/agent-sockets |
| 317 | + type: Directory |
| 318 | + name: spiffe-socket |
| 319 | +``` |
| 320 | + |
| 321 | +Apply with: `kubectl apply -f client-workload.yaml` |
| 322 | + |
| 323 | +### Verification |
| 324 | + |
| 325 | +Test the mTLS authentication with success and failure scenarios. |
| 326 | + |
| 327 | +#### Authentication Success |
| 328 | + |
| 329 | +Execute from the client workload pod: |
| 330 | + |
| 331 | +```bash |
| 332 | +kubectl exec -n example deploy/client-workload -c ghostunnel -- curl -s http://127.0.0.1:8080 |
| 333 | +``` |
| 334 | + |
| 335 | +**Expected Output:** |
| 336 | + |
| 337 | +``` |
| 338 | +Authenticated SPIFFE Content |
| 339 | +``` |
| 340 | +
|
| 341 | +This confirms successful mTLS authentication. |
| 342 | +
|
| 343 | +#### Authentication Failure |
| 344 | +
|
| 345 | +To demonstrate proper security enforcement, modify the client's `--verify-uri` parameter to an incorrect URI (e.g., `spiffe://example.org/ns/example/sa/server` instead of `spiffe://example.org/ns/example/sa/server-sa`): |
| 346 | +
|
| 347 | +```bash |
| 348 | +kubectl exec -n example deploy/client-workload -c ghostunnel -- curl -s http://127.0.0.1:8080 |
| 349 | +``` |
| 350 | + |
| 351 | +**Expected Result:** |
| 352 | + |
| 353 | +- Command terminates with exit code 56 |
| 354 | +- Client logs show: `unauthorized: invalid principal, or principal not allowed` |
| 355 | + |
| 356 | +This demonstrates that SPIRE properly enforces authentication and rejects unauthorized connections. |
| 357 | + |
| 358 | +</Steps> |
0 commit comments