# 配置第一个工作负载 本教程将指导您如何在应用程序中集成 SPIRE 获取身份凭证。 ## 概述 工作负载通过 Workload API 从 SPIRE Agent 获取 SVID。有多种集成方式: 1. **go-spiffe 库**: Go 应用程序 2. **java-spiffe 库**: Java 应用程序 3. **spiffe-helper**: 任意应用程序 4. **Envoy SDS**: 服务网格 ## Go 应用程序 ### 安装依赖 ```bash go get github.com/spiffe/go-spiffe/v2 ``` ### 获取 X.509-SVID ```go package main import ( "context" "log" "time" "github.com/spiffe/go-spiffe/v2/workloadapi" ) func main() { ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() // 创建 X.509 源 source, err := workloadapi.NewX509Source(ctx) if err != nil { log.Fatalf("无法创建 X509Source: %v", err) } defer source.Close() // 获取 SVID svid, err := source.GetX509SVID() if err != nil { log.Fatalf("无法获取 SVID: %v", err) } log.Printf("SPIFFE ID: %s", svid.ID) log.Printf("证书过期时间: %v", svid.Certificates[0].NotAfter) } ``` ### mTLS 服务端 ```go package main import ( "context" "log" "net/http" "github.com/spiffe/go-spiffe/v2/spiffetls/tlsconfig" "github.com/spiffe/go-spiffe/v2/workloadapi" ) func main() { ctx := context.Background() source, err := workloadapi.NewX509Source(ctx) if err != nil { log.Fatal(err) } defer source.Close() // 创建 TLS 配置 tlsConfig := tlsconfig.MTLSServerConfig(source, source, tlsconfig.AuthorizeAny()) server := &http.Server{ Addr: ":8443", TLSConfig: tlsConfig, } http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Hello, SPIFFE!")) }) log.Println("服务器启动在 :8443") log.Fatal(server.ListenAndServeTLS("", "")) } ``` ### mTLS 客户端 ```go package main import ( "context" "io" "log" "net/http" "github.com/spiffe/go-spiffe/v2/spiffeid" "github.com/spiffe/go-spiffe/v2/spiffetls/tlsconfig" "github.com/spiffe/go-spiffe/v2/workloadapi" ) func main() { ctx := context.Background() source, err := workloadapi.NewX509Source(ctx) if err != nil { log.Fatal(err) } defer source.Close() // 只允许特定 SPIFFE ID serverID := spiffeid.RequireFromString("spiffe://example.org/server") tlsConfig := tlsconfig.MTLSClientConfig(source, source, tlsconfig.AuthorizeID(serverID)) client := &http.Client{ Transport: &http.Transport{ TLSClientConfig: tlsConfig, }, } resp, err := client.Get("https://localhost:8443/") if err != nil { log.Fatal(err) } defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) log.Printf("响应: %s", body) } ``` ## Java 应用程序 ### Maven 依赖 ```xml io.spiffe java-spiffe 0.8.0 ``` ### 获取 SVID ```java import io.spiffe.workloadapi.WorkloadApiClient; import io.spiffe.workloadapi.X509Context; public class Main { public static void main(String[] args) throws Exception { try (WorkloadApiClient client = WorkloadApiClient.newClient()) { X509Context context = client.fetchX509Context(); System.out.println("SPIFFE ID: " + context.getDefaultSvid().getSpiffeId()); System.out.println("证书: " + context.getDefaultSvid().getChain()); } } } ``` ## spiffe-helper 对于非 Go/Java 应用程序,可以使用 spiffe-helper 将 SVID 写入文件。 ### 安装 ```bash go install github.com/spiffe/spiffe-helper/cmd/spiffe-helper@latest ``` ### 配置 创建 `helper.conf`: ```hcl agent_address = "/tmp/spire-agent/public/api.sock" cmd = "/path/to/your/app" cmd_args = "--cert=/certs/svid.pem" cert_dir = "/certs" renew_signal = "SIGHUP" svid_file_name = "svid.pem" svid_key_file_name = "svid-key.pem" svid_bundle_file_name = "bundle.pem" ``` ### 运行 ```bash spiffe-helper -config helper.conf ``` ## Envoy SDS SPIRE Agent 提供 Envoy SDS API,可直接集成 Envoy。 ### Envoy 配置 ```yaml node: id: "envoy-proxy" cluster: "cluster1" static_resources: listeners: - name: listener_0 address: socket_address: address: 0.0.0.0 port_value: 8443 filter_chains: - filters: - name: envoy.filters.network.http_connection_manager typed_config: "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager stat_prefix: ingress_http route_config: name: local_route virtual_hosts: - name: backend domains: ["*"] routes: - match: { prefix: "/" } route: { cluster: backend } http_filters: - name: envoy.filters.http.router transport_socket: name: envoy.transport_sockets.tls typed_config: "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext common_tls_context: tls_certificate_sds_secret_configs: - name: "spiffe://example.org/envoy" sds_config: resource_api_version: V3 api_config_source: api_type: GRPC transport_api_version: V3 grpc_services: - envoy_grpc: cluster_name: spire_agent combined_validation_context: default_validation_context: match_subject_alt_names: - prefix: "spiffe://example.org/" validation_context_sds_secret_config: name: "spiffe://example.org" sds_config: resource_api_version: V3 api_config_source: api_type: GRPC transport_api_version: V3 grpc_services: - envoy_grpc: cluster_name: spire_agent clusters: - name: spire_agent connect_timeout: 1s type: STATIC lb_policy: ROUND_ROBIN typed_extension_protocol_options: envoy.extensions.upstreams.http.v3.HttpProtocolOptions: "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions explicit_http_config: http2_protocol_options: {} load_assignment: cluster_name: spire_agent endpoints: - lb_endpoints: - endpoint: address: pipe: path: /tmp/spire-agent/public/api.sock ``` ## 注册工作负载 无论使用哪种集成方式,都需要在 SPIRE Server 上创建注册条目: ```bash # Unix 进程 spire-server entry create \ -spiffeID spiffe://example.org/myapp \ -parentID spiffe://example.org/agent \ -selector unix:user:appuser # Kubernetes Pod spire-server entry create \ -spiffeID spiffe://example.org/myapp \ -parentID spiffe://example.org/agent \ -selector k8s:ns:default \ -selector k8s:sa:myapp-sa # Docker 容器 spire-server entry create \ -spiffeID spiffe://example.org/myapp \ -parentID spiffe://example.org/agent \ -selector docker:label:app:myapp ``` ## 最佳实践 :::{admonition} 建议 :class: tip 1. **使用库而非文件**: 优先使用 go-spiffe/java-spiffe 库 2. **实现优雅轮换**: 监听 SVID 更新事件 3. **验证对端身份**: 不仅仅接受任何 SVID 4. **处理错误**: Agent 不可用时有降级策略 :::