ITADN

PCI Compliance & Vault Configuration Support

#620Openbernard-eugine 创建于 2026-03-12
B
bernard-euginecommented
## Overview Implement comprehensive PCI (Payment Card Industry) compliance support in UCS (Universal Connector Service) by enabling merchants to route sensitive payment data through secure vault providers. This eliminates the need for UCS to handle raw card data directly, reducing PCI scope and compliance burden. --- ## PCI Compliance Modes UCS supports three distinct PCI compliance modes, allowing merchants to choose the approach that best fits their infrastructure and compliance requirements: ### Mode 1: No Vault (Current/Default) **Description:** UCS connects directly to Payment Service Providers (PSPs) like Stripe, Checkout, etc. Merchants handle tokenization themselves or send raw card data (not recommended). **PCI Scope:** SAQ D (Full) - if handling raw card data ```mermaid sequenceDiagram autonumber participant FE as Merchant Frontend participant BE as Merchant Backend participant UCS as Connector Service participant PSP as Payment Provider FE->>BE: Payment request (merchant handles tokenization) BE->>UCS: POST /payments<br/>{token or card data, amount, connector} UCS->>PSP: POST api.stripe.com/v1/payment_intents PSP-->>UCS: Authorization response UCS-->>BE: Unified response BE-->>FE: Payment result ``` **Configuration:** ```toml [connectors.stripe] base_url = "https://api.stripe.com" api_key = "${STRIPE_API_KEY}" # enable_vault_proxy defaults to false ``` --- ### Mode 2: Network Proxy (VGS, Evervault) **Description:** Traffic is routed through a network-level proxy that transparently detokenizes in transit. UCS simply routes to the proxy URL instead of the PSP directly. **Key Characteristics:** - **Integration Level:** Network/Transport layer - **UCS Transformation:** ❌ None - just routes to proxy URL - **Token Handling:** Proxy detokenizes transparently **PCI Scope:** SAQ A or A-EP (Reduced) - card data never touches merchant servers ```mermaid sequenceDiagram autonumber participant FE as Merchant Frontend participant VSDK as Vault SDK (VGS Collect/Evervault) participant Vault as PCI Vault (VGS/Evervault) participant BE as Merchant Backend participant UCS as Connector Service participant PSP as Payment Provider Note over FE,Vault: Step 1: Card Tokenization FE->>VSDK: Render secure card fields VSDK->>Vault: Tokenize/encrypt card data Vault-->>VSDK: Return token VSDK-->>FE: Return token to frontend Note over BE,PSP: Step 2: Payment via Network Proxy FE->>BE: Send token + payment request BE->>UCS: authorize(token, amount, connector) UCS->>Vault: POST vault-proxy-url/v1/payment_intents Note over UCS: Same payload structure,<br/>just different URL Vault->>Vault: Auto-detokenize in transit Vault->>PSP: POST api.stripe.com/v1/payment_intents<br/>(with real card data) PSP-->>Vault: Authorization response Vault-->>UCS: Return response UCS-->>BE: Unified response BE-->>FE: Payment result ``` **Supported Providers:** | Provider | Mechanism | Token Format | |----------|-----------|--------------| | **VGS** | Forward proxy with route mapping | `tok_sandbox_xxxx` (Luhn-valid) | | **Evervault** | HTTP CONNECT Relay | `ev:encrypted:<base64>` | **Configuration:** ```toml [vault] provider = "vgs" tenant_id = "tntSANDBOX123" environment = "sandbox" [connectors.stripe] base_url = "https://api.stripe.com" # URL will be transformed to: tntSANDBOX123.sandbox.verygoodproxy.com enable_vault_proxy = true ``` --- ### Mode 3: Application Proxy (Hyperswitch Vault, TokenEx, Basis Theory) **Description:** UCS formats requests using vault-specific protocols - adding headers, wrapping in expressions, or constructing special request bodies. The vault provider acts as an application-level intermediary. **Key Characteristics:** - **Integration Level:** Application layer - **UCS Transformation:** ✅ Yes - formats tokens for vault protocol - **Token Handling:** UCS wraps tokens in vault-specific syntax **PCI Scope:** SAQ A or A-EP (Reduced) - card data never touches merchant servers ```mermaid sequenceDiagram autonumber participant FE as Merchant Frontend participant VaultSDK as Vault SDK participant Vault as PCI Vault participant BE as Merchant Backend participant UCS as Connector Service participant PSP as Payment Provider Note over FE,Vault: Step 1: Card Tokenization FE->>VaultSDK: Tokenize card data VaultSDK->>Vault: Store card data Vault-->>VaultSDK: Return vault_token VaultSDK-->>FE: Return token Note over BE,PSP: Step 2: Payment via Application Proxy FE->>BE: Send token + payment request BE->>UCS: authorize(token, amount, connector) Note over UCS: UCS constructs PSP request<br/>with token in vault format UCS->>Vault: Proxy request (vault-specific format) Note over Vault: Vault substitutes token<br/>with raw card data Vault->>PSP: Forward PSP request (with real card data) PSP-->>Vault: Authorization response Vault-->>UCS: Return response UCS-->>BE: Unified response BE-->>FE: Payment result ``` **Supported Providers:** | Provider | Routing Mechanism | Token Syntax | |----------|-------------------|--------------| | **Hyperswitch Vault** | Wrapped request body | `{{$card_number}}`, `{{$cvv}}` | | **TokenEx** | Headers (`TX-URL`, `TX-Method`) | `{token}` | | **Basis Theory** | Header (`BT-PROXY-URL`) | `{{ token.property }}` | **Configuration:** ```toml [vault] provider = "hyperswitch_vault" api_key = "${HYPERSWITCH_API_KEY}" profile_id = "${HYPERSWITCH_PROFILE_ID}" proxy_url = "https://sandbox.hyperswitch.io/proxy" [connectors.stripe] base_url = "https://api.stripe.com" enable_vault_proxy = true ``` --- ## Comparison: Network Proxy vs Application Proxy | Aspect | Network Proxy | Application Proxy | |--------|---------------|-------------------| | **What merchant sends** | Token | Token | | **UCS transformation** | ❌ No—routes to proxy URL | ✅ Yes—formats for vault protocol | | **Complexity** | Lower | Higher | | **Provider flexibility** | Coupled to specific vault | Can switch vaults without code changes | | **Best for** | Quick integration, existing vault users | Multi-PSP setups, vendor flexibility | --- ## Implementation Strategy ### Multi-PR Approach This feature is being implemented across multiple focused PRs: #### PR #1: Configuration Types (Current: #617) **Status:** In Review **Scope:** Core type definitions and config integration **Files Changed:** - `backend/domain_types/src/types.rs` - VaultConfig enum, provider configs, ConnectorParams updates - `backend/ucs_env/src/configs.rs` - Config integration - `backend/external-services/src/vault.rs` - HTTP client helpers - `backend/external-services/src/lib.rs` - Module export **What's Included:** - `VaultConfig` enum with 5 provider variants - Provider-specific config structs with `Secret<String>` for credentials - `ConnectorParams` updates: `enable_vault_proxy`, `vault_proxy_override` - `resolve_vault()` method for vault resolution logic - `transform_connector_url()`, `get_vault_headers()` helpers - Unit tests for VGS URL transformation **What's NOT Included (Intentional):** - HTTP request/response transformation for application proxies - Actual HTTP client integration with vault routing - Connector-level integration (each connector must opt-in) #### PR #2: HTTP Client Integration (Planned) **Scope:** Wire vault functions into actual HTTP request pipeline **Open Questions:** - How to handle TLS verification with VGS custom CA certificates - Request/response body transformation for application proxies - Error handling when vault tokenization fails #### PR #3: Connector Integrations (Planned) **Scope:** Update individual connectors to use vault-aware HTTP client **Approach:** - Start with Stripe as reference implementation - Each connector PR can proceed independently once PR #2 is merged --- ## Technical Design ### Configuration Schema ```toml # Global vault configuration (optional) [vault] provider = "vgs" # or "evervault", "hyperswitch_vault", "tokenex", "basis_theory" tenant_id = "tntSANDBOX123" environment = "sandbox" # Per-connector configuration [connectors.stripe] base_url = "https://api.stripe.com" enable_vault_proxy = true # Use global vault [connectors.checkout] base_url = "https://api.checkout.com" enable_vault_proxy = true vault_proxy_override = { provider = "hyperswitch_vault", api_key = "...", profile_id = "...", proxy_url = "..." } ``` ### Security Considerations 1. **No Default VaultConfig** - Vault configuration must be explicit; no insecure defaults 2. **Patch Ignore for Vault** - Vault settings require service restart (marked with `#[patch(ignore)]`) 3. **Secret Masking** - All credentials use `Secret<String>` from hyperswitch_masking crate 4. **PCI Compliance Note** - Changes to vault configuration require restart for PCI compliance ### Provider Summary | Provider | Pattern | Auth Method | Notes | |----------|---------|-------------|-------| | **VGS** | Network | URL-based (`{tenant}.{env}.verygoodproxy.com`) | CA cert reserved for future TLS work | | **Evervault** | Network | HTTP CONNECT + `Proxy-Authorization` header | Relay URL constructed from team_id | | **Hyperswitch Vault** | Application | `x-api-key`, `x-profile-id` headers | Requests wrapped with `{{$variable}}` | | **TokenEx** | Application | `TX-ApiKey`, `TX-TokenExID` headers | TGAPI protocol with token markers | | **Basis Theory** | Application | `BT-API-KEY`, `BT-PROXY-URL` headers | Proxy URL via header, `{{}}` token syntax | --- ## Migration Path ### For Existing Merchants No action required. `enable_vault_proxy` defaults to `false`, so existing configs continue working unchanged. ### For Merchants Enabling Vault 1. Choose vault provider and obtain credentials 2. Add `[vault]` section to TOML config 3. Set `enable_vault_proxy = true` for desired connectors 4. Restart UCS service (hot-reload not supported for vault config) 5. Test in sandbox environment first --- ## Open Questions / Future Work 1. **Request/Response Transformation**: Application proxies require formatting request bodies with vault-specific token syntax (e.g., `{{card_number}}`). This needs connector-specific integration. 2. **TLS Certificate Verification**: VGS optionally uses custom CA certificates for TLS verification. The `ca_certificate` field is reserved but not yet wired up. 3. **Multi-Vault Scenarios**: Current design supports one global vault + per-connector overrides. Do we need multi-vault fallback? 4. **Observability**: Should vault operations be explicitly logged/metrics for debugging? ---
0 条评论