transport

package
v0.0.78 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 30, 2025 License: Apache-2.0 Imports: 11 Imported by: 0

README

WHEN Transport Layer

Multi-transport support for WHEN semantic action executor, enabling HTTP requests over different network layers: direct HTTP/HTTPS, SSH tunnels, and OpenZiti overlay networks.

Features

  • HTTP/HTTPS Transport: Direct connections with connection pooling
  • SSH Tunnel Transport: HTTP over SSH tunnels for secure remote access
  • OpenZiti Transport: Zero-trust overlay networking with identity-based access control
  • Automatic URL Scheme Routing: Seamless transport selection based on URL scheme
  • Connection Pooling: Efficient resource management across all transports

URL Schemes

The transport manager automatically routes requests based on URL scheme:

URL Scheme Transport Description
http:// HTTPTransport Standard HTTP
https:// HTTPTransport Standard HTTPS
ssh:// SSHTunnelTransport HTTP over SSH tunnel
ssh+http:// SSHTunnelTransport Explicit HTTP over SSH
ssh+https:// SSHTunnelTransport HTTPS over SSH tunnel
ziti:// ZitiTransport HTTP over OpenZiti
ziti+http:// ZitiTransport Explicit HTTP over OpenZiti

Configuration

Environment Variables
HTTP Transport
# HTTP client configuration
WHEN_HTTP_TIMEOUT=30                    # Request timeout in seconds (default: 30)
WHEN_MAX_IDLE_CONNS=100                # Max idle connections (default: 100)
WHEN_MAX_IDLE_CONNS_PER_HOST=10        # Max idle per host (default: 10)
WHEN_IDLE_CONN_TIMEOUT=90              # Idle timeout in seconds (default: 90)
SSH Transport
# SSH tunnel configuration
WHEN_SSH_HOST=example.com              # SSH server hostname (required)
WHEN_SSH_USER=root                     # SSH username (default: root)
WHEN_SSH_PORT=22                       # SSH port (default: 22)
WHEN_SSH_KEY_FILE=/path/to/key         # Path to SSH private key
WHEN_SSH_PASSWORD=secret               # SSH password (if not using key)
WHEN_SSH_KNOWN_HOSTS=/path/to/known   # Path to known_hosts file
WHEN_SSH_TIMEOUT=30                    # SSH connection timeout (default: 30)

Note: Either WHEN_SSH_KEY_FILE or WHEN_SSH_PASSWORD must be set.

OpenZiti Transport
# Ziti overlay network configuration
WHEN_ZITI_IDENTITY_FILE=/path/to/identity.json    # Ziti identity file
WHEN_ZITI_IDENTITY_JSON='{"id":"...","ztAPI":...}' # Or identity as JSON
WHEN_ZITI_TIMEOUT=30                              # Request timeout (default: 30)

Note: Either WHEN_ZITI_IDENTITY_FILE or WHEN_ZITI_IDENTITY_JSON must be set.

Usage Examples

Direct HTTP/HTTPS

Standard HTTP requests work without any configuration:

import "eve.evalgo.org/transport"

// Create manager with HTTP transport
mgr, err := transport.DefaultManager(ctx)
if err != nil {
    log.Fatal(err)
}
defer mgr.Close()

// Make HTTP request
req, _ := http.NewRequest("GET", "http://example.com/api/data", nil)
resp, err := mgr.RoundTrip(req)
SSH Tunnel

Route HTTP requests through SSH tunnels:

# Set SSH configuration
export WHEN_SSH_HOST=jumphost.example.com
export WHEN_SSH_USER=admin
export WHEN_SSH_KEY_FILE=/home/user/.ssh/id_rsa
// Use ssh:// URL scheme
req, _ := http.NewRequest("POST", "ssh://internal-service:8080/api/action", body)
resp, err := mgr.RoundTrip(req)

The request will automatically:

  1. Connect to jumphost.example.com via SSH
  2. Tunnel the HTTP request to internal-service:8080
  3. Return the response
OpenZiti Overlay Network

Use zero-trust networking with OpenZiti:

# Set Ziti identity
export WHEN_ZITI_IDENTITY_FILE=/etc/ziti/when-identity.json
// Use ziti:// URL scheme
// The host is the Ziti service name, not a hostname
req, _ := http.NewRequest("POST", "ziti://workflowservice/v1/api/semantic/action", body)
resp, err := mgr.RoundTrip(req)

Benefits:

  • Zero-trust authentication (no IP addresses, no ports)
  • Automatic mutual TLS
  • Identity-based access control
  • Works across NATs and firewalls

Architecture

Transport Interface

All transports implement the Transport interface:

type Transport interface {
    RoundTrip(*http.Request) (*http.Response, error)
    Close() error
}
TransportManager

The manager routes requests to the appropriate transport:

type Manager struct {
    transports map[TransportType]Transport
    configs    map[TransportType]*Config
}

func (m *Manager) RoundTrip(req *http.Request) (*http.Response, error) {
    transport, err := m.GetTransportForURL(req.URL.Scheme)
    return transport.RoundTrip(req)
}
Integration with ActionExecutor

WHEN's ActionExecutor automatically uses the transport manager:

// In executor.go
type ActionExecutor struct {
    transportMgr *transport.Manager
    registry     *executor.Registry
}

func (e *ActionExecutor) executeHTTP(ctx context.Context, action *semantic.SemanticScheduledAction, defaultMethod string) error {
    // ... create request ...
    resp, err := e.transportMgr.RoundTrip(req)
    // ... handle response ...
}

SSH Transport Details

Authentication Methods

The SSH transport supports multiple authentication methods:

  1. Public Key: Recommended for production

    WHEN_SSH_KEY_FILE=/home/user/.ssh/id_rsa
    
  2. Encrypted Private Key: With passphrase protection

    WHEN_SSH_KEY_FILE=/home/user/.ssh/id_rsa_encrypted
    WHEN_SSH_PASSWORD=passphrase
    
  3. Password Authentication: For legacy systems

    WHEN_SSH_PASSWORD=sshpassword
    
Host Key Verification

For security, use known_hosts file:

WHEN_SSH_KNOWN_HOSTS=/home/user/.ssh/known_hosts

Without this, host key verification is disabled (insecure).

Connection Pooling

The SSH transport maintains a persistent SSH connection and creates tunnels on-demand for each HTTP request.

OpenZiti Transport Details

Identity Configuration

Ziti identities can be provided as:

  1. Identity File (recommended):

    WHEN_ZITI_IDENTITY_FILE=/etc/ziti/when-identity.json
    
  2. Inline JSON:

    WHEN_ZITI_IDENTITY_JSON='{"id":"when-client","ztAPI":"https://ctrl:1280",...}'
    
Service Names

In Ziti URLs, the hostname is the service name, not a DNS hostname:

// ✅ Correct: Service name
req, _ := http.NewRequest("POST", "ziti://workflowservice/v1/api/semantic/action", body)

// ❌ Wrong: DNS hostname
req, _ := http.NewRequest("POST", "ziti://workflow.example.com/v1/api/semantic/action", body)
Ziti SDK Compatibility
  • SDK Version: github.com/openziti/sdk-golang v1.2.2
  • Minimum Controller: v1.6.0
  • Recommended Controller: v1.6.5 - v1.6.7
  • Warning: SDK v1.2.3+ requires controller v1.6.8+

See EVE README for detailed compatibility information.

Error Handling

All transports return standard Go errors:

resp, err := mgr.RoundTrip(req)
if err != nil {
    // Check error type
    switch {
    case strings.Contains(err.Error(), "SSH"):
        log.Printf("SSH tunnel error: %v", err)
    case strings.Contains(err.Error(), "Ziti"):
        log.Printf("Ziti network error: %v", err)
    default:
        log.Printf("HTTP error: %v", err)
    }
}

Testing

Unit Tests

Test individual transports:

go test ./transport/...
Integration Tests

Test with real services:

# HTTP transport (no setup needed)
go test -v ./transport -run TestHTTPTransport

# SSH transport (requires SSH server)
export WHEN_SSH_HOST=localhost
export WHEN_SSH_USER=$USER
export WHEN_SSH_KEY_FILE=$HOME/.ssh/id_rsa
go test -v ./transport -run TestSSHTransport

# Ziti transport (requires Ziti network)
export WHEN_ZITI_IDENTITY_FILE=/path/to/identity.json
go test -v ./transport -run TestZitiTransport

Performance

Connection Pooling

All transports use connection pooling:

  • HTTP: Standard http.Transport with configurable pool size
  • SSH: Persistent SSH connection with on-demand tunnels
  • Ziti: Ziti SDK manages connection pool internally
Timeouts

Configure timeouts per transport:

WHEN_HTTP_TIMEOUT=30
WHEN_SSH_TIMEOUT=30
WHEN_ZITI_TIMEOUT=30

Security Considerations

HTTP/HTTPS
  • Use HTTPS for production
  • Validate TLS certificates
  • Consider client certificate authentication
SSH
  • Always use public key authentication
  • Enable host key verification with known_hosts
  • Use strong SSH keys (RSA 4096, Ed25519)
  • Consider SSH certificate authentication
OpenZiti
  • Identity-based access control (no IP addresses)
  • Automatic mutual TLS
  • Zero-trust architecture
  • Centralized policy enforcement

Troubleshooting

SSH Connection Fails
# Test SSH connection manually
ssh -i $WHEN_SSH_KEY_FILE $WHEN_SSH_USER@$WHEN_SSH_HOST

# Enable debug logging
export WHEN_DEBUG=true
Ziti Service Not Found
# List available Ziti services
ziti edge list services

# Check identity can access service
ziti edge list service-policies
HTTP Timeout
# Increase timeout
export WHEN_HTTP_TIMEOUT=60
export WHEN_SSH_TIMEOUT=60
export WHEN_ZITI_TIMEOUT=60

Future Enhancements

  • HTTP/2 support for SSH and Ziti transports
  • Automatic failover between transports
  • Load balancing across multiple SSH jump hosts
  • Metrics and observability (request counts, latencies)
  • Circuit breaker pattern for failing transports
  • WebSocket support over SSH and Ziti
  • SOCKS5 proxy transport

References

Documentation

Index

Constants

This section is empty.

Variables

View Source
var URLScheme = map[string]TransportType{
	"http":      TransportHTTP,
	"https":     TransportHTTP,
	"ssh":       TransportSSH,
	"ssh+http":  TransportSSH,
	"ssh+https": TransportSSH,
	"ziti":      TransportZiti,
	"ziti+http": TransportZiti,
}

URLScheme maps URL schemes to transport types

Functions

This section is empty.

Types

type Config

type Config struct {
	// SSH configuration (for SSH transport)
	SSHUser       string
	SSHHost       string
	SSHPort       int
	SSHKeyFile    string
	SSHPassword   string
	SSHKnownHosts string

	// Ziti configuration (for Ziti transport)
	ZitiIdentityFile string
	ZitiIdentityJSON string

	// HTTP configuration (for all transports)
	Timeout             int // seconds
	MaxIdleConns        int
	MaxIdleConnsPerHost int
	IdleConnTimeout     int // seconds
}

Config holds configuration for transport creation

func DefaultConfig

func DefaultConfig() *Config

DefaultConfig returns a Config with sensible defaults

type Factory

type Factory interface {
	CreateTransport(ctx context.Context, transportType TransportType, config *Config) (Transport, error)
}

Factory creates a Transport based on the configuration and type

type HTTPTransport

type HTTPTransport struct {
	// contains filtered or unexported fields
}

HTTPTransport implements Transport for direct HTTP/HTTPS connections. This wraps the standard library's http.Transport with configured timeouts and connection pooling.

func NewHTTPTransport

func NewHTTPTransport(ctx context.Context, config *Config) (*HTTPTransport, error)

NewHTTPTransport creates a new HTTP transport with the given configuration

func (*HTTPTransport) Client

func (t *HTTPTransport) Client() *http.Client

Client returns the underlying http.Client for direct use

func (*HTTPTransport) Close

func (t *HTTPTransport) Close() error

Close closes idle connections

func (*HTTPTransport) RoundTrip

func (t *HTTPTransport) RoundTrip(req *http.Request) (*http.Response, error)

RoundTrip executes a single HTTP transaction using the standard library. This implements the http.RoundTripper interface.

type Manager

type Manager struct {
	// contains filtered or unexported fields
}

Manager manages multiple transports and routes requests based on URL scheme. This allows WHEN to support multiple network transports transparently.

func DefaultManager

func DefaultManager(ctx context.Context) (*Manager, error)

DefaultManager creates a manager with HTTP transport pre-configured

func DefaultManagerWithAllTransports

func DefaultManagerWithAllTransports(ctx context.Context, httpConfig, sshConfig, zitiConfig *Config) (*Manager, error)

DefaultManagerWithAllTransports creates a manager with all transports configured from environment

func NewManager

func NewManager(ctx context.Context) *Manager

NewManager creates a new transport manager

func (*Manager) Client

func (m *Manager) Client(timeout int) *http.Client

Client creates an http.Client that uses this transport manager

func (*Manager) Close

func (m *Manager) Close() error

Close closes all registered transports

func (*Manager) GetConfig

func (m *Manager) GetConfig(transportType TransportType) (*Config, bool)

GetConfig returns the configuration for a transport type

func (*Manager) GetTransport

func (m *Manager) GetTransport(transportType TransportType) (Transport, error)

GetTransport returns the transport for a given type

func (*Manager) GetTransportForURL

func (m *Manager) GetTransportForURL(urlScheme string) (Transport, error)

GetTransportForURL returns the appropriate transport based on URL scheme

func (*Manager) RegisterTransport

func (m *Manager) RegisterTransport(transportType TransportType, transport Transport)

RegisterTransport registers a transport for a specific type

func (*Manager) RegisterTransportWithConfig

func (m *Manager) RegisterTransportWithConfig(transportType TransportType, config *Config) error

RegisterTransportWithConfig registers and creates a transport based on configuration

func (*Manager) RoundTrip

func (m *Manager) RoundTrip(req *http.Request) (*http.Response, error)

RoundTrip implements http.RoundTripper interface. This routes the request to the appropriate transport based on URL scheme.

func (*Manager) SupportedSchemes

func (m *Manager) SupportedSchemes() []string

SupportedSchemes returns a list of supported URL schemes

type SSHTunnelTransport

type SSHTunnelTransport struct {
	// contains filtered or unexported fields
}

SSHTunnelTransport implements Transport for HTTP over SSH tunnels. This creates SSH connections to remote hosts and tunnels HTTP traffic through them.

func NewSSHTunnelTransport

func NewSSHTunnelTransport(ctx context.Context, config *Config) (*SSHTunnelTransport, error)

NewSSHTunnelTransport creates a new SSH tunnel transport

func (*SSHTunnelTransport) Client

func (t *SSHTunnelTransport) Client() *http.Client

Client returns the underlying http.Client for direct use

func (*SSHTunnelTransport) Close

func (t *SSHTunnelTransport) Close() error

Close closes the SSH connection and all tunnels

func (*SSHTunnelTransport) CreateLocalForward

func (t *SSHTunnelTransport) CreateLocalForward(localAddr, remoteAddr string) (net.Listener, error)

CreateLocalForward creates a local port forward through the SSH tunnel This can be used for long-lived tunnels to specific services

func (*SSHTunnelTransport) RoundTrip

func (t *SSHTunnelTransport) RoundTrip(req *http.Request) (*http.Response, error)

RoundTrip executes an HTTP request through the SSH tunnel

type Transport

type Transport interface {
	// RoundTrip executes a single HTTP transaction, returning the response.
	// This is compatible with http.RoundTripper interface.
	RoundTrip(*http.Request) (*http.Response, error)

	// Close closes any underlying connections and cleans up resources.
	Close() error
}

Transport represents a network transport mechanism for HTTP requests. This abstraction allows WHEN to support multiple transport layers: - Direct HTTP/HTTPS - HTTP over SSH tunnels - HTTP over OpenZiti overlay networks

type TransportType

type TransportType string

TransportType identifies the type of transport

const (
	TransportHTTP TransportType = "http"
	TransportSSH  TransportType = "ssh"
	TransportZiti TransportType = "ziti"
)

type ZitiTransport

type ZitiTransport struct {
	// contains filtered or unexported fields
}

ZitiTransport implements Transport for HTTP over OpenZiti overlay networks. This provides zero-trust networking with built-in encryption and identity-based access control.

func NewZitiTransport

func NewZitiTransport(ctx context.Context, cfg *Config) (*ZitiTransport, error)

NewZitiTransport creates a new OpenZiti transport

func (*ZitiTransport) Client

func (t *ZitiTransport) Client() *http.Client

Client returns the underlying http.Client for direct use

func (*ZitiTransport) Close

func (t *ZitiTransport) Close() error

Close closes the Ziti context

func (*ZitiTransport) Dial

func (t *ZitiTransport) Dial(serviceName string) (net.Conn, error)

Dial creates a direct connection to a Ziti service This can be used for non-HTTP protocols over Ziti

func (*ZitiTransport) GetZitiContext

func (t *ZitiTransport) GetZitiContext() ziti.Context

GetZitiContext returns the underlying Ziti context for direct service operations

func (*ZitiTransport) ListServices

func (t *ZitiTransport) ListServices() ([]string, error)

ListServices returns the list of available Ziti services

func (*ZitiTransport) Listen

func (t *ZitiTransport) Listen(serviceName string) (net.Listener, error)

Listen creates a Ziti service listener This allows the application to host services on the Ziti network

func (*ZitiTransport) RoundTrip

func (t *ZitiTransport) RoundTrip(req *http.Request) (*http.Response, error)

RoundTrip executes an HTTP request through the Ziti overlay network

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL