A scalable, secure multi-tenant mTLS proxy written in Go that manages mutual TLS authentication for multiple backend services.
- Mutual TLS (mTLS) authentication between clients and proxy
- Multi-tenancy support with tenant isolation
- Dynamic certificate management and rotation
- High performance with minimal overhead
- Detailed access logging and metrics
- Prerequisites
- Installation
- Configuration
- Usage
- Architecture
- API Reference
- Performance
- Security Considerations
- Contributing
- License
- Go 1.24 or higher
git clone https://github.com/prestonchoate/multi-mtls-proxy.git
cd multi-mtls-proxy
go build -o mtls-admin ./cmd/admin/git clone https://github.com/prestonchoate/multi-mtls-proxy.git
cd multi-mtls-proxy
go build -o mtls-proxy ./cmd/proxy/No official Docker image yet
A generator is included to help you quickly set up a local development environment with all required services and self-signed certificates.
go run ./cmd/dev-env-generatorThis will create a dev-env/ directory containing:
docker-compose.ymlβ Compose file for Traefik, mTLS proxy, admin API, and MongoDBtraefik.ymlβ Traefik configuration referencing generated certscerts/mtls.localhost.crtand.keyβ Self-signed cert for mTLS proxycerts/admin.localhost.crtand.keyβ Self-signed cert for admin API
Note: Existing files are not overwritten.
cd dev-env
docker compose up --build- mTLS Proxy:
- Host: https://mtls.localhost (mTLS required)
- Admin API:
- Host: https://admin.localhost
Add these to your /etc/hosts if needed:
127.0.0.1 mtls.localhost admin.localhost
docker compose downBoth the admin API and proxy can be configured using environment variables:
ADMIN_API_PORT: Admin Server Port (default:8080)PROXY_PORT: Server port (default:8443)CA_KEY_NAME: Path to Root CA key file (default:ca/ca.key)CA_CERT_NAME: Path to Root CA Cert file (default:ca/ca.crt)PROXY_SERVER_CERT_NAME: Path to server certificate (default:proxy/server.crt)PROXY_SERVER_KEY_NAME: Path to server private key (default:proxy/server.key)CERT_VALIDITY_DAYS: Number of days to issue client certificates for (default:365)HOSTNAME: Hostname for the server (default:localhost)DEFAULT_ADMIN_USER: Default admin username (default:admin)DEFAULT_ADMIN_PASSWORD: Default admin password (default:password)JWT_SIGNING_KEY_NAME: Path to admin JWT signing key (default:admin/signing.key)JWT_SIGNING_CERT_NAME: Path to admin JWT signing cert (default:admin/signing.crt)MONGO_URI: MongoDB connection string (default:mongodb://localhost:27017)MONGO_DB: MongoDB database name (default:mtlsAdmin)MONGO_APPS_COLL: MongoDB collection for apps (default:apps)MONGO_USERS_COLL: MongoDB collection for users (default:users)MONGO_CERT_COLL: MongoDB collection for certificates (default:certs)ENCRYPTION_KEY: 32-byte Base64 encoded encryption key for sensitive data (default:rTdRG79RqfXnHVIrPui3d4qW7qaF/uVQj5VnkWb96KQ=)
The repository provides a .env.dist with these default values. It is not required to copy this into a .env file, but if you choose to change any configs you may do so with that method.
WARNING: The default credentials are not secure. Always change DEFAULT_ADMIN_USER and DEFAULT_ADMIN_PASSWORD in production deployments!
WARNING: The default encryption key is not secure. Always change ENCRYPTION_KEY in production deployments to prevent unauthorized access to sensitive data!
./mtls-admin./mtls-proxyWARNING: The proxy server will not hot reload app configs if they change from the admin while both binaries are running. This is due to the app config living in a file on the local filesystem. Simply restart the proxy server binary to pick up the latest changes. This will change in a future release
curl --cert client.crt --key client.key --cacert ca.crt https://proxy.example.com:8443/api/endpoint- Send POST request to
/admin/appswith the following payload structure
{
"appId": "test-app",
"targetUrls": {
"/get": "https://postman-echo.com/get",
"/post": "https://postman-echo.com/post"
}
}- Distribute client cert and key to end user. This will live in the
CERT_DIRdirectory and be named the clientappId(test-app.crtandtest-app.keyfor this example)
- Send a
POSTrequest to/admin/apps/:appId/rotate-certand re-distribute the new cert/key pair
- Send a
PUTrequest to/admin/apps/:appId/targetswith the following payload structure
{
"targetUrls": {
"/newProxyUrl": "https://exmple.com/newProxyUrl"
}
}See Roadmap for future considerations
The multi-tenant mTLS proxy consists of the following components:
- TLS Termination Layer: Handles incoming mTLS connections and certificate validation
- Tenant Router: Routes requests to the appropriate backend based on tenant configuration
- Certificate Manager: Handles certificate storage, retrieval, and rotation
- Backend Connector: Establishes secure connections to backend services
- Metrics and Monitoring: Collects and exposes operational metrics
See API Reference Guide or the OpenAPI spec
[TODO: Include performance metrics, benchmarks, or considerations]
- Certificate rotation practices
- Tenant isolation mechanisms
- Authentication and authorization
- Fork the repository
- Create a feature branch:
git checkout -b feature/your-feature-name - Commit your changes:
git commit -am 'Add some feature' - Push to the branch:
git push origin feature/your-feature-name - Submit a pull request
See LICENSE
