本文目录导读:

在 PHP 中使用 SPIFFE(Secure Production Identity Framework For Everyone)主要涉及两方面:SPIFFE 身份认证和SPIFFE API 集成,我来详细说明:
基础概念
SPIFFE 提供了一套标准的身份验证框架,核心是:
- SPIFFE ID:如
spiffe://example.com/web-server - SVID(SPIFFE Verifiable Identity Document):身份凭证
- Workload API:向工作负载提供身份的 API
安装必要的库
# 使用 Composer 安装主要库 composer require spiffe/spiffe
基本使用示例
1 获取 Workload API 客户端
<?php
use Spiffe\WorkloadApi\WorkloadApiClient;
use Spiffe\WorkloadApi\WorkloadApiClientBuilder;
// 创建客户端
$client = (new WorkloadApiClientBuilder())
->setSocketPath('/run/spire/sockets/agent.sock')
->build();
// 获取 SVID
$response = $client->fetchX509SVID();
$svid = $response->getSVID();
// 获取 SPIFFE ID
echo "SPIFFE ID: " . $svid->getSpiffeId();
2 使用 X.509 SVID
<?php
use Spiffe\Svid\X509Svid;
// 从 Workload API 获取
$x509Svid = $client->fetchX509SVID();
$certificate = $x509Svid->getCertificate();
// 获取证书链
$certChain = $x509Svid->getCertChain();
// 使用证书进行 TLS 连接
$context = stream_context_create([
'ssl' => [
'local_cert' => $certChain,
'verify_peer' => true,
'cafile' => '/path/to/trust/bundle',
]
]);
完整示例:MTLS 通信
<?php
require 'vendor/autoload.php';
use Spiffe\WorkloadApi\WorkloadApiClientBuilder;
use Spiffe\Svid\X509Svid;
class SpiffeClient {
private $workloadClient;
public function __construct() {
$this->workloadClient = (new WorkloadApiClientBuilder())
->setSocketPath(getenv('SPIFFE_ENDPOINT_SOCKET'))
->build();
}
public function getIdentity() {
$svid = $this->workloadClient->fetchX509SVID();
return [
'spiffe_id' => $svid->getSpiffeId(),
'certificate' => $svid->getCertificate(),
'private_key' => $svid->getPrivateKey()
];
}
public function makeSecureRequest($url) {
$identity = $this->getIdentity();
// 创建临时证书文件
$certFile = tempnam(sys_get_temp_dir(), 'cert');
$keyFile = tempnam(sys_get_temp_dir(), 'key');
file_put_contents($certFile, $identity['certificate']);
file_put_contents($keyFile, $identity['private_key']);
// 创建带有客户端证书的 cURL 请求
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSLCERT, $certFile);
curl_setopt($ch, CURLOPT_SSLKEY, $keyFile);
curl_setopt($ch, CURLOPT_CAINFO, getenv('TRUST_BUNDLE_PATH'));
$response = curl_exec($ch);
// 清理临时文件
unlink($certFile);
unlink($keyFile);
return $response;
}
}
// 使用
$client = new SpiffeClient();
echo "我的身份: " . $client->getIdentity()['spiffe_id'] . "\n";
$response = $client->makeSecureRequest('https://service.example.com/api');
高级功能
1 验证 SPIFFE ID
<?php
use Spiffe\SpiffeId\SpiffeId;
use Spiffe\SpiffeId\SpiffeIdException;
class SpiffeValidator {
public function isValidSpiffeId($id) {
try {
$spiffeId = new SpiffeId($id);
return $spiffeId->isValid();
} catch (SpiffeIdException $e) {
return false;
}
}
// 验证信任域
public function verifyTrustDomain($spiffeId) {
$trustDomain = 'example.com';
return strpos($spiffeId, "spiffe://$trustDomain/") === 0;
}
}
2 JWT SVID 支持
<?php
use Spiffe\Svid\JwtSvid;
class JwtSvidHandler {
private $workloadClient;
public function __construct() {
$this->workloadClient = (new WorkloadApiClientBuilder())
->setSocketPath('/run/spire/sockets/agent.sock')
->build();
}
public function getJwtSvid($audience) {
// 获取 JWT SVID
$response = $this->workloadClient->fetchJWTSVID($audience);
return $response->getToken();
}
public function validateJwtSvid($token) {
// 验证 JWT SVID
$jwtSvid = new JwtSvid($token);
return $jwtSvid->validate();
}
}
部署配置
SPIRE Agent 配置
# agent.conf
agent {
trust_domain = "example.com"
data_dir = "/opt/spire/data/agent"
log_level = "DEBUG"
server_address = "spire-server:8081"
server_port = "8081"
# Socket 位置
socket_path = "/run/spire/sockets/agent.sock"
# 工作负载 API 配置
workload_api {
socket_path = "/run/spire/sockets/agent.sock"
token = "change-me"
}
}
PHP 应用环境变量
# Dockerfile 或 .env SPIFFE_ENDPOINT_SOCKET=/run/spire/sockets/agent.sock SPIFFE_TRUST_DOMAIN=example.com
最佳实践
1 连接池和重试机制
<?php
class WorkloadApiConnection {
private $client;
private $lastConnection;
private $reconnectTimeout = 5;
public function getClient() {
if ($this->client === null || $this->isStale()) {
$this->connect();
}
return $this->client;
}
private function connect() {
$this->client = (new WorkloadApiClientBuilder())
->setSocketPath(getenv('SPIFFE_ENDPOINT_SOCKET'))
->withTimeout(10)
->build();
$this->lastConnection = time();
}
private function isStale() {
return (time() - $this->lastConnection) > 300; // 5分钟
}
}
2 日志和调试
<?php
class SpiffeLogger {
public function logAllSpiffeOperations() {
// 使用 Monolog 集成
$log = new \Monolog\Logger('spiffe');
$log->pushHandler(new \Monolog\Handler\StreamHandler('php://stderr'));
return function($operation, $message) use ($log) {
$log->info($operation, ['message' => $message]);
};
}
}
常见问题解决
1 Socket 权限问题
# 确保 PHP-FPM 用户有权限访问 socket sudo usermod -aG spire-agent www-data sudo chmod 755 /run/spire/sockets/
2 证书轮换处理
<?php
class CertificateRotator {
private $currentCert;
private $certExpiry;
public function getCertificate() {
if ($this->isExpiring()) {
$this->renewCertificate();
}
return $this->currentCert;
}
private function isExpiring() {
// 检查证书是否在24小时内过期
return $this->certExpiry - time() < 86400;
}
private function renewCertificate() {
// 重新获取证书
}
}
注意事项
- 安全性:敏感信息(私钥)不要硬编码
- 性能:实现连接池,避免频繁重建连接
- 错误处理:优雅处理 Workload API 不可用的情况
- 监控:记录所有 SPIFFE 相关操作日志
这个框架非常适合微服务架构,可以确保服务之间的安全通信,需要我详细解释某个特定部分吗?