Securing TCP-based services
Learn how to use Pomerium's TCP Proxying support to connect to TCP services, such as databases and non-HTTP protocols.
Background
When replacing a traditional VPN, there are often non-HTTP based applications you still need to reach. Pomerium can provide the same type of protection to these services with Pomerium CLI, a client-side application to proxy TCP connections.
Authentication and authorization configuration is shared with standard HTTP routes, and the underlying transport is still encrypted between the end-user and Pomerium.
- Pomerium authorizes TCP connections on a per-connection basis (unlike HTTP requests, which it authorizes on a per-request basis)
- Pomerium only authorizes the TCP connection; it does not interact with application level authorization systems
Overview
Review the steps below to understand how you will secure TCP connections with Pomerium:
- Run Pomerium CLI's
tcp
command in your workstation to listen for TCP connections on loopback - When an inbound connection is made, Pomerium CLI proxies the connection through
pomerium
, authenticating the user if needed - Pomerium authorizes the connection and forwards it to the upstream service
Before you start
To complete this guide, you need:
- Docker
- Docker Compose
- Pomerium CLI
- mkcert (optional)
Certificates (optional)
If you want to generate your own locally trusted certificates with mkcert
, run the following command:
mkcert -install
mkcert '*.localhost.pomerium.io'
This will install a trusted CA and generate a new wildcard certificate:
_wildcard.localhost.pomerium.io.pem
_wildcard.localhost.pomerium.io-key.pem
Configure
Pomerium
Add the configuration below to your configuration file:
authenticate_service_url: https://authenticate.pomerium.app
# Uncomment to use certificates (optional)
# certificates:
# - cert: /pomerium/cert.pem
# key: /pomerium/key.pem
databroker_storage_type: postgres
databroker_storage_connection_string: postgresql://postgres:postgres@pgsql:5432
routes:
- from: tcp+https://redis.localhost.pomerium.io:6379
to: tcp://redis:6379
policy:
- allow:
or:
- domain:
is: example.com
- from: tcp+https://ssh.localhost.pomerium.io:22
to: tcp://ssh:2222
policy:
- allow:
or:
- domain:
is: example.com
- from: tcp+https://pgsql.localhost.pomerium.io:5432
to: tcp://pgsql:5432
policy:
- allow:
or:
- domain:
is: example.com
Make sure you update each example.com
instance to match the domain of your email address.
Docker Compose
Create a docker-compose.yaml
file to run Pomerium and the services you will connect to over TCP.
The following services are included in the Docker Compose file:
- Redis
- SSH
- Postgres
version: "3"
services:
pomerium:
image: pomerium/pomerium:latest
volumes:
# Uncomment to mount certificates (optional)
# - ./_wildcard.localhost.pomerium.io.pem:/pomerium/cert.pem:ro
# - ./_wildcard.localhost.pomerium.io-key.pem:/pomerium/key.pem:ro
- ./config.yaml:/pomerium/config.yaml:ro
ports:
- 443:443
redis:
image: redis:latest
expose:
- 6379
ssh:
image: linuxserver/openssh-server:latest
expose:
- 2222
environment:
PASSWORD_ACCESS: "true"
USER_PASSWORD: supersecret
USER_NAME: user
pgsql:
image: postgres
restart: always
environment:
- POSTGRES_PASSWORD=postgres
- POSTGRES_USER=postgres
- POSTGRES_DB=postgres
expose:
- 5432
Connect
To connect to your service, ensure pomerium-cli
is in your $PATH
and run the tcp
command, specifying the service you wish to reach.
pomerium-cli tcp [hostname]:[port]
pomerium-cli
will select a random port on localhost
by default, but you can specify a port manually if desired. Keep reading for some specific application examples using the sample docker-compose.yaml
.
If you haven't configured a trusted certificate, you'll need to add the --disable-tls-verification
flag to the pomerium-cli
commands below.
Without this flag, TCP connections will fail unless you include a trusted CA and certificate in your configuration.
In a production environment, it's critical that you configure Pomerium to use correct server certificates.
See Certificates settings and Upstream mTLS (services) for more information on configuring certificates in Pomerium
See the TCP Reference page for a complete list of commands available in Pomerium CLI
Redis
Start a proxy to Redis in the background:
$ pomerium-cli tcp redis.localhost.pomerium.io:6379 --listen localhost:6379
2023/10/02 12:20:05 listening on 127.0.0.1:6379
Start the Redis client:
$ redis-cli info
# Server
redis_version:7.0.5
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:d9291579292e26e3
redis_mode:standalone
os:Linux 6.3.13-linuxkit aarch64
arch_bits:64
monotonic_clock:POSIX clock_gettime
multiplexing_api:epoll
atomicvar_api:c11-builtin
gcc_version:10.2.1
process_id:1
process_supervised:no
run_id:e4c843df14511765f0e6284690be2f10c6b39e28
tcp_port:6379
server_time_usec:1696349965506132
uptime_in_seconds:75
uptime_in_days:0
hz:10
configured_hz:10
lru_clock:1851149
executable:/data/redis-server
config_file:
io_threads_active:0
Postgres
In your Docker Compose file, postgres
is the configured password for the postgres
user and database.
Start a proxy to Postgres in the background:
$ pomerium-cli tcp pgsql.localhost.pomerium.io:5432 --listen localhost:5432
2023/10/03 12:22:08 listening on 127.0.0.1:5432
After password authentication, connect and list the schemas:
$ psql -h localhost -W -U postgres -c '\dn'
Password:
List of schemas
Name | Owner
----------+-------------------
pomerium | postgres
public | pg_database_owner
(2 rows)
SSH
Configure
To configure your SSH client to use Pomerium's TCP support for SSH routes, create the following entry in your ssh_config
or ~/.ssh/config
:
Host *.localhost.pomerium.io
ProxyCommand pomerium-cli tcp --listen - %h:%p
- Be sure to substitute your domain for
localhost.pomerium.io
- Be sure
pomerium-cli
is in your$PATH
SSH clients can use external programs to establish a connection to a host. Most frequently, this is for using an SSH jump host to reach a target system. However, you can use any transport application. You can use Pomerium CLI's tcp
command in conjunction with this configuration.
See the following links for more information:
Connect
Start a proxy to the SSH client in the background:
$ pomerium-cli tcp ssh.localhost.pomerium.io:22 --listen :2222
2023/10/03 12:29:17 listening on 127.0.0.1:50741
Initiate the SSH connection:
$ ssh myuser@ssh.localhost.pomerium.io -p 2222
myuser@ssh.localhost.pomerium.io's password:
Welcome to OpenSSH Server
4e737e02c43f:~$
In your example Docker Compose file, you have an SSH server configured with supersecret
as the password for myuser
.
That's it! A Pomerium proxy will be started automatically whenever you SSH to a host under localhost.pomerium.io
.