ITP is a high-performance mTLS proxy that translates identities between different security domains. It enables secure communication between services by handling certificate-based authentication and identity mapping.
- mTLS Support: Full mutual TLS authentication for both client and server connections
- Identity Translation: Map certificates between different security domains based on various certificate fields
- Flexible Routing: Multiple routing strategies including DNS-based, static, path-based, and pattern-based routing
- HTTP/HTTPS Upstreams: Support for both TLS and plain HTTP upstream connections
- WebSocket Support: Full WebSocket proxying with automatic upgrade detection and bidirectional message forwarding
- Dynamic Certificates: Automatic certificate selection based on client certificate attributes
- Real-time Echo Server: Built-in echo server for debugging TLS connections
- High Performance: Written in Go for optimal performance and minimal resource usage
- Header Injection: Inject custom headers based on certificate attributes
- Role-based Access: Add roles and auth values based on certificate fields
External Domain ITP Proxy Internal Domain
(external.com) (cluster.local)
┌──────────────┐
│ Identity │
│ Translation │
│ Proxy │
└──────────────┘
┌──────┐ 1. mTLS ┌──────┐ 3. mTLS ┌──────────┐
│Client├────Connection────────┤ ITP ├─────Connection───────┤ Backend │
└──────┘ └──────┘ └──────────┘
│ │ │
│ │ │
│ CN: user@external.com │ CN: user │
│ O: ExternalOrg │ O: Internal │
│ OU: DevTeam │ OU: Engineering │
│ │ │
│ 2. Translation │
│ ───────────────► │
│ - Map CN, O, OU │
│ - Add Roles │
│ - Add Auth │
│ - Inject Headers │
│ │
│ │
│ 4. Headers Injected │
│ X-User: user │
│ X-Roles: developer │
│ X-Auth: read,write │
go install github.com/taemon1337/itp@latestITP provides two Docker image variants:
-
Distroless variant (Recommended for Production)
docker pull taemon1337/itp:latest-distroless
- Minimal attack surface
- Smaller image size
- Based on Google's distroless base image
-
Alpine variant (Recommended for Development)
docker pull taemon1337/itp:latest-alpine
- Includes debugging tools
- Shell access available
git clone https://github.com/taemon1337/itp.git
cd itp
make build # Build binary
make test # Run tests
make docker-build # Build both Docker variantsITP supports comprehensive configuration through YAML files. This is the recommended way to configure the proxy as it provides better organization and maintainability:
itp --config config.yamlExample config.yaml:
server:
name: proxy.example.com
external_domain: external.com
internal_domain: cluster.local
listen: :8443
echo:
name: echo.cluster.local
addr: :8444
certificates:
cert_file: /path/to/cert.pem
key_file: /path/to/key.pem
ca_file: /path/to/ca.pem
k8s_cert_manager:
enabled: false
namespace: default
issuer:
name: default-issuer
kind: ClusterIssuer
group: cert-manager.io
security:
allow_unknown_certs: false
route_via_dns: true
auto_map_cn: true
routes:
- source: app.external.com
destination: app.cluster.local
- source: api.external.com
destination: api.cluster.local:8080
templates:
files:
- name: user-info
path: /path/to/user.tmpl
inline:
- name: role-info
template: "Role:{{.Role}}"
headers:
inject_upstream: true
inject_downstream: false
templates:
- upstream: app.cluster.local
header: X-User-Info
template: "{{template \"user-info\"}}"
mappings:
roles:
- cn: admin
value: admin-user
roles: [admin, superuser]
auth:
- cn: "*"
value: "*"
auth: [read, write]See examples/config.yaml for a complete example with comments.
Alternatively, you can configure the proxy using command line flags:
itp --server-name proxy.example.com \
--server-san "proxy.internal,proxy.dev" \
--map-auto \
--route "app.cluster.com=app.default.svc.cluster.local"Or use your own certificates:
itp --server-cert /path/to/cert.pem \
--server-key /path/to/key.pem \
--server-ca /path/to/ca.pem \
--server-name proxy.example.com \
--map-auto \
--route "app.cluster.com=app.default.svc.cluster.local"| Flag | Description | Default |
|------|-------------|---------||
| --server-name | Server name for the proxy | Required |
| --external-domain | External domain for connections | Required |
| --internal-domain | Internal domain for connections | Required |
| Flag | Description | Default |
|------|-------------|---------||
| --listen | Address to listen on | :8443 |
| --echo-name | Name for the echo server | echo.<internal-domain> |
| --echo-addr | Address for the echo server | :8444 |
| --routes | Comma-separated list of routes (e.g., localhost=echo,app=app.internal) | "" |
| Flag | Description | Default |
|---|---|---|
--cert |
Path to certificate file | "" |
--key |
Path to private key file | "" |
--ca |
Path to CA certificate file | "" |
| Flag | Description | Default |
|---|---|---|
--allow-unknown-certs |
Allow unknown client certificates | false |
--route-via-dns |
Enable DNS-based routing | false |
--auto-map-cn |
Automatically map CommonName | true |
| Flag | Description | Default |
|---|---|---|
--inject-headers-upstream |
Inject headers upstream | true |
--inject-headers-downstream |
Inject headers downstream | false |
--inject-header |
Header template (e.g., localhost=X-User={{.CommonName}}) |
"" |
--add-role |
Role mapping (e.g., cn=admin=admin-role) |
"" |
--add-auth |
Auth mapping (e.g., cn=*=read,write) |
"" |
--server-name |
Server name for TLS connection | proxy.test |
--server-san |
Additional DNS names for server certificate (comma-separated) | "" |
--server-allow-unknown-client-certs |
Allow client certificates from unknown CAs | false |
--internal-domain |
Internal domain for inside/upstream connections | internal.local |
--external-domain |
External domain for incoming connections | external.com |
When no certificate files are provided (--cert, --key, --ca), ITP will automatically generate certificates:
- Server certificate for external connections (proxy's public interface)
- Internal certificates for client authentication and upstream connections
- All certificates include appropriate SANs based on domains and server names
When certificate files are provided:
- Uses the specified certificate files for both server and client connections
- CA certificate is required for client certificate verification
- Certificate must be valid for the specified
--server-name
When injecting headers, you can use these template functions:
| Function | Description | Example |
|----------|-------------|---------||
| join | Join slice with custom separator | {{ .Groups \| join "; " }} |
| comma | Join slice with commas | {{ .Groups \| comma }} |
| space | Join slice with spaces | {{ .Groups \| space }} |
| Flag | Description | Default |
|---|---|---|
--echo |
Name for the echo upstream | "" |
--echo-addr |
Address for echo upstream server | :8444 |
--echo-san |
Additional DNS names for echo server certificate | "" |
| Flag | Description | Default |
|---|---|---|
--route |
Static routes (format: src=dest[,src=dest,...]), path-based routes (format: src/path=dest/path), or TLS-preserving routes (format: src=tls://dest) | "" |
--route-via-dns |
Allow routing via DNS | false |
--map-auto |
Automatically map client CN to upstream CN | false |
ITP supports path-based routing with prefix matching and path stripping:
# Route with path prefix replacement
itp --route "app.example.com/api=backend.cluster.local/v1"
# /api/users -> /v1/users
# Route with path stripping
itp --route "app.example.com/api=backend.cluster.local"
# /api/users -> /users
# Multiple path-based routes
itp --route "app.example.com/api=backend.cluster.local/v1,app.example.com/web=frontend.cluster.local"Path-based routing features:
- Prefix matching for flexible path routing
- Optional path stripping when destination has no path
- Compatible with existing routing strategies
- Preserves unmatched paths in requests
When routing to external services that have their own TLS certificates, you can preserve the original hostname for TLS verification:
# Route to external API with its own TLS certificate
itp --route "api.internal.com=tls://api.external.com:8443"
# Combine with path-based routing
itp --route "api.internal.com/v2=tls://api.external.com:8443/v1"This is useful when:
- The destination uses its own TLS certificates (not provided by the proxy)
- The destination's certificate doesn't include the internal domain names
- You need to maintain end-to-end TLS verification while still using the proxy's routing capabilities
For legacy services or internal APIs that don't support TLS, you can route to HTTP upstreams using the http:// prefix:
# Route to HTTP upstream service
itp --route "api.internal.com=http://legacy-api.internal:8080"
# Combine with path-based routing
itp --route "api.internal.com/v1=http://legacy-api.internal:8080/api"This is useful when:
- The upstream service doesn't support TLS/HTTPS
- You're connecting to legacy internal services
- You want to terminate TLS at the proxy and use plain HTTP internally
Security Note: HTTP upstreams are unencrypted between the proxy and the upstream service. Only use this for trusted internal networks.
The ITP proxy provides full WebSocket support for both HTTP and HTTPS upstreams. WebSocket connections are automatically detected and handled appropriately:
# WebSocket over HTTPS (WSS) - default behavior
itp --route "ws.internal.com=websocket-api.cluster.local:8080"
# WebSocket over HTTP (WS) for legacy services
itp --route "ws.internal.com=http://legacy-websocket.internal:8080"
# WebSocket with path-based routing
itp --route "app.internal.com/ws=websocket-api.cluster.local:8080/socket"WebSocket features:
- Automatic Detection: WebSocket upgrade requests are automatically detected via
Connection: UpgradeandUpgrade: websocketheaders - Bidirectional Proxying: Full duplex message forwarding between client and upstream
- Protocol Support: Supports both WS (HTTP) and WSS (HTTPS) upstream connections
- Identity Translation: Client certificates and identity headers are forwarded to WebSocket upstreams
- Connection Management: Proper connection lifecycle management with graceful close handling
- Message Types: Supports all WebSocket message types (text, binary, ping, pong, close)
The proxy maintains the WebSocket connection until either the client or upstream closes it, ensuring real-time bidirectional communication works seamlessly.
| Flag | Description | Default |
|---|---|---|
--inject-header |
Inject headers (format: upstream=name=template[,...]) | "" |
--inject-headers-upstream |
Inject headers into upstream requests | true |
--inject-headers-downstream |
Inject headers into downstream responses | false |
| Flag | Description | Default |
|---|---|---|
--add-role |
Add roles (format: field=value=role1,role2,...) | "" |
--add-auth |
Add auth values (format: field=value=auth1,auth2,...) | "" |
--config |
Path to YAML configuration file | "" |
.
├── cmd/ # Command-line interface
├── pkg/ # Core packages
│ ├── certstore/ # Certificate management
│ ├── echo/ # Echo server implementation
│ ├── identity/ # Identity translation
│ ├── logger/ # Logging utilities
│ ├── proxy/ # Core proxy functionality
│ └── router/ # Request routing
└── examples/ # Example configurations
A TLS proxy that translates client identities between different domains, with support for header injection and flexible routing.
- TLS termination with client certificate authentication
- Automatic certificate generation for server and clients
- Identity translation between external and internal domains
- Header injection based on client certificate attributes
- Flexible routing with DNS support
- Echo server for testing and development
go install github.com/taemon1337/itp@latestThe minimum required configuration needs a server name, external domain, and internal domain:
itp --server-name proxy.example.com \
--external-domain example.com \
--internal-domain internal.local--server-name: Server name for the proxy (e.g., proxy.example.com)--external-domain: External domain for connections (e.g., external.com)--internal-domain: Internal domain for connections (e.g., internal.local)
--listen: Address to listen on (default: ":8443")--echo-name: Name for the echo server (defaults to echo.)--echo-addr: Address for the echo server (default: ":8444")
--cert: Path to certificate file--key: Path to private key file--ca: Path to CA certificate file
--allow-unknown-certs: Allow unknown client certificates--route-via-dns: Enable DNS-based routing--auto-map-cn: Automatically map CommonName (default: true)
--inject-headers-upstream: Inject headers upstream (default: true)--inject-headers-downstream: Inject headers downstream (default: false)
itp --server-name proxy.example.com \
--external-domain example.com \
--internal-domain internal.local \
--echo-name echoitp --server-name proxy.example.com \
--external-domain example.com \
--internal-domain internal.local \
--cert /path/to/cert.pem \
--key /path/to/key.pem \
--ca /path/to/ca.pemitp --server-name proxy.test \
--external-domain test.com \
--internal-domain local \
--allow-unknown-certs \
--echo-name echo \
--route-via-dnsgit clone https://github.com/taemon1337/itp.git
cd itp
go buildgo test ./...This project is licensed under the MIT License - see the LICENSE file for details.