Documentation
¶
Overview ¶
Package kernel provides authenticated cross-account calls to kernel services.
This package enables partner account services to make SigV4-authenticated API calls to services running in the kernel account (qakernel or production kernel).
Overview ¶
The kernel client handles:
- STS AssumeRole for cross-account authentication
- SigV4 request signing for API Gateway
- Automatic kernel environment detection (qakernel vs kernel)
- URL construction with region/service prefix support
- Integration with Lift observability (logger, metrics, tracing)
Authentication Modes ¶
Mode 1: Shared Role (Default for trusted partners in AWS Organization)
- Uses role: kernel-access
- No External ID required
- For partners: qakernel, paytheory, etc.
Mode 2: External Partner Role (For partners outside AWS Organization)
- Uses role: kernel-access-external
- Requires External ID via K3_EXTERNAL_ID environment variable
- For external partners with additional security requirements
Environment Variables ¶
Required:
- PARTNER: Partner identifier (e.g., "qakernel", "paytheory")
- STAGE: Deployment stage (e.g., "dev", "stage", "prod")
Optional:
- TARGET_REGION: AWS region (default: "us-east-1")
- K3_EXTERNAL_ID: External ID for Mode 2 authentication
- KERNEL_ENV_OVERRIDE: Force kernel environment ("qakernel" or "kernel")
Kernel Environment Selection ¶
The client automatically selects the kernel environment based on partner:
- Partners "innovate" and "austin" → qakernel (account: 058264189048)
- All other partners → kernel (account: 075149869707)
- Override with KERNEL_ENV_OVERRIDE environment variable
URL Patterns ¶
K3 (without region):
https://k3.{kernel_env}.{stage}.com/{endpoint}
Other services (with region):
https://{region}.{kernel_env}.{stage}.com/{service-prefix}/{endpoint}
Usage Examples ¶
Basic client creation:
import (
"context"
"github.com/pay-theory/lift/pkg/services/kernel"
pkglogger "github.com/yourservice/internal/logger"
)
// Create kernel client using your service's singleton logger
ctx := context.Background()
client, err := kernel.NewClient(ctx, pkglogger.GetLiftLogger)
if err != nil {
log.Fatal(err)
}
Call Paze wallet service:
response, err := client.PazeWalletCall(ctx, "decode-token", map[string]any{
"token": "encrypted_paze_token...",
})
if err != nil {
log.Printf("Paze call failed: %v", err)
return err
}
var result map[string]any
if err := response.Unmarshal(&result); err != nil {
log.Printf("Failed to unmarshal response: %v", err)
return err
}
Call K3 API:
response, err := client.K3Call(ctx, "v1/tokenize", map[string]any{
"card_number": "4111111111111111",
"exp_month": "12",
"exp_year": "2025",
"cvv": "123",
}, "POST")
if err != nil {
log.Printf("K3 call failed: %v", err)
return err
}
Call bin lookup service:
response, err := client.BinLookupCall(ctx, "?card_bin=411111", "GET", nil)
if err != nil {
log.Printf("Bin lookup failed: %v", err)
return err
}
var binData struct {
CardBrand string `json:"card_brand"`
CardType string `json:"card_type"`
BankName string `json:"bank_name"`
}
if err := response.Unmarshal(&binData); err != nil {
log.Printf("Failed to unmarshal bin data: %v", err)
return err
}
Generic call with custom options:
response, err := client.Call(ctx, &kernel.CallOptions{
ServicePrefix: "custom-service",
Endpoint: "api/v1/process",
Method: "POST",
Body: map[string]any{"data": "value"},
IncludeRegion: true,
Subsystem: "CUSTOM SERVICE",
ConnectTimeout: 10 * time.Second,
ReadTimeout: 30 * time.Second,
Headers: map[string]string{
"X-Custom-Header": "custom-value",
},
})
if err != nil {
log.Printf("Custom call failed: %v", err)
return err
}
Using with Lift middleware:
import (
"github.com/pay-theory/lift/pkg/lift"
"github.com/pay-theory/lift/pkg/services/kernel"
pkglogger "github.com/yourservice/internal/logger"
)
// In main.go Lambda setup
app := lift.New()
// Create kernel client with your singleton logger getter
kernelClient, err := kernel.NewClient(ctx, pkglogger.GetLiftLogger)
if err != nil {
log.Fatal(err)
}
// Register middleware
app.Use(kernel.KernelClientMiddleware(kernelClient))
// In handler function
func MyHandler(ctx *lift.Context) error {
// Get kernel client from context
kernelClient := kernel.GetKernelClient(ctx)
if kernelClient == nil {
return lift.SystemError("Kernel client not available")
}
// Use kernel client
response, err := kernelClient.PazeWalletCall(ctx, "decode-token", data, "POST")
if err != nil {
return lift.SystemError("Paze call failed").WithCause(err)
}
return ctx.OK(response)
}
Convenience Functions ¶
The package provides service-specific convenience functions:
- K3Call: Call K3 API Gateway
- PazeWalletCall: Call Paze Wallet Key Service
- AppleWalletCall: Call Apple Wallet Key Service
- GoogleWalletCall: Call Google Wallet Key Service
- BinLookupCall: Call Bin Lookup Service
- BankDataCall: Call Bank Data Service
All convenience functions use sensible defaults for method, region inclusion, and subsystem logging names.
Error Handling ¶
The client returns errors for:
- Missing required environment variables
- STS AssumeRole failures (invalid credentials, role not found)
- HTTP request failures (network errors, timeouts)
- HTTP status codes >= 400 (includes error details in logs)
Logging ¶
All calls are logged with structured logging including:
- Request details (service, endpoint, method)
- Response details (status code, duration)
- Error details (for failures)
- Subsystem tags (for filtering logs by service)
Security ¶
The client implements AWS best practices:
- STS AssumeRole with least-privilege temporary credentials
- SigV4 request signing for authentication
- External ID support for cross-organization access
- Automatic credential expiration handling
- TLS encryption for all HTTP requests
Performance ¶
The client is designed for performance:
- Reusable HTTP client with connection pooling
- Configurable timeouts (connect, read)
- Efficient request signing
- Minimal memory allocations
Thread Safety ¶
The Client struct is safe for concurrent use. Multiple goroutines can call methods on the same Client instance simultaneously.
Index ¶
- Constants
- func KernelClientMiddleware(client *Client) lift.Middleware
- type CallOptions
- type Client
- func (c *Client) AppleWalletCall(ctx context.Context, endpoint string, body any, method string) (*Response, error)
- func (c *Client) BankDataCall(ctx context.Context, endpoint string, method string, body any) (*Response, error)
- func (c *Client) BinLookupCall(ctx context.Context, endpoint string, method string, body any) (*Response, error)
- func (c *Client) Call(ctx context.Context, opts *CallOptions) (*Response, error)
- func (c *Client) GoogleWalletCall(ctx context.Context, endpoint string, body any, method string) (*Response, error)
- func (c *Client) K3Call(ctx context.Context, endpoint string, body any, method string) (*Response, error)
- func (c *Client) PazeWalletCall(ctx context.Context, endpoint string, body any, method string) (*Response, error)
- type LoggerFunc
- type Response
Constants ¶
const ( // Kernel account IDs QAKernelAccountID = "058264189048" KernelAccountID = "075149869707" // Default timeouts DefaultConnectTimeout = 30 * time.Second DefaultReadTimeout = 30 * time.Second )
Variables ¶
This section is empty.
Functions ¶
func KernelClientMiddleware ¶
func KernelClientMiddleware(client *Client) lift.Middleware
KernelClientMiddleware creates middleware for kernel client integration
Types ¶
type CallOptions ¶
type CallOptions struct {
Body any // Request payload (will be JSON marshaled)
Headers map[string]string // Additional headers (optional)
ServicePrefix string // Service name (e.g., "k3", "paze-wallet-key-service")
Endpoint string // API endpoint path
Method string // HTTP method (GET, POST, etc.)
Subsystem string // Logging subsystem name (optional)
ConnectTimeout time.Duration // Connection timeout (optional)
ReadTimeout time.Duration // Read timeout (optional)
IncludeRegion bool // Whether to include region in URL
}
CallOptions configures a kernel service call
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client provides authenticated cross-account calls to kernel services
func GetKernelClient ¶
GetKernelClient retrieves the kernel client from Lift context
func NewClient ¶
func NewClient(ctx context.Context, loggerFunc LoggerFunc) (*Client, error)
NewClient creates a new kernel service client loggerFunc should return the calling service's singleton logger (e.g., logger.GetLiftLogger)
func NewClientWithConfig ¶
func NewClientWithConfig( ctx context.Context, loggerFunc LoggerFunc, partner, stage, region string, connectTimeout, readTimeout time.Duration, ) (*Client, error)
NewClientWithConfig creates a client with custom configuration
func (*Client) AppleWalletCall ¶
func (c *Client) AppleWalletCall(ctx context.Context, endpoint string, body any, method string) (*Response, error)
AppleWalletCall makes an authenticated call to Apple Wallet Key Service
func (*Client) BankDataCall ¶
func (c *Client) BankDataCall(ctx context.Context, endpoint string, method string, body any) (*Response, error)
BankDataCall makes an authenticated call to Bank Data Service
func (*Client) BinLookupCall ¶
func (c *Client) BinLookupCall(ctx context.Context, endpoint string, method string, body any) (*Response, error)
BinLookupCall makes an authenticated call to Bin Lookup Service
func (*Client) GoogleWalletCall ¶
func (c *Client) GoogleWalletCall(ctx context.Context, endpoint string, body any, method string) (*Response, error)
GoogleWalletCall makes an authenticated call to Google Wallet Key Service
type LoggerFunc ¶
type LoggerFunc func() observability.StructuredLogger
LoggerFunc is a function that returns the singleton logger from the calling service