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: cr.pomerium.com/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
.