Buckle up for a smooth and safe remote access.
15 min.
In this unit you will learn how to install Passenger using Docker.
At the end of this section, you will have a working Passenger instance behind a reverse proxy. The reverse proxy used in this guide is traefik, but any other preferable option would work fine.
Before you begin, make sure you have the following tools installed:
- Docker - Containerization platform for running Passenger.
- Docker Compose - Used to manage multi-container Docker applications (only necessary for older Docker versions; Compose V2 is included in newer versions).
- KeePass - Used for the local and static vault
This step-by-step installation guide is intended for testing and development purposes and should not be used in a production environment.
Open a terminal session and create a folder /opt/passenger
(or any other location). Create following folders:
cd /opt/passenger
mkdir config
mkdir db
Run vi .env
and paste following content:
SSH_FQDN=example.com
WRITE_FQDN=write.example.com
READ_FQDN=read.example.com
[email protected]
EXPOSED_SSH_PORT=22
NOTE:
- DNS Entries: Make sure that you have configured DNS entries for
$SSH_FQDN
,$WRITE_FQDN
and$READ_FQDN
to point to the machine where you are installing the software. These entries are necessary for proper operation and accessibility.- POSTMASTER_EMAIL: The email address specified in
POSTMASTER_EMAIL
must be valid and correctly configured. This email is used by Traefik to issue Let's Encrypt certificates.
Run vi config/passenger.yml
and paste following content:
# Database
dsn: /db/passenger.db
# HTTP Read Server
readServer:
address: 0.0.0.0:8711
credentials:
- root/server/read-api
# HTTP Write Server
writeServer:
address: 0.0.0.0:8712
credentials:
- root/server/write-api
# SSH Server
server:
address: 0.0.0.0:2222
# Vault
vault:
static:
path: /db/vault.kdbx
passwordPath: /config/vault-password
# User Management
users:
provider: static
Run vi docker-compose.yml
and paste following content:
version: "3.6"
services:
traefik:
image: "traefik:v2.10"
container_name: "traefik"
network_mode: bridge # bad design, fixme sometime
command:
# - "--log.level=DEBUG"
- "--api.insecure=false"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.myresolver.acme.tlschallenge=true"
- "--certificatesresolvers.myresolver.acme.email=${POSTMASTER_EMAIL}"
- "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
ports:
- "443:443"
- "8080:8080"
volumes:
- "letsencrypt:/letsencrypt"
- "/var/run/docker.sock:/var/run/docker.sock:ro"
passenger:
restart: always
image: dariocalovic/passenger:latest
network_mode: bridge # bad design, fixme sometime
labels:
- "traefik.enable=true"
- "traefik.http.routers.passenger-read.rule=Host(`${READ_FQDN}`)"
- "traefik.http.routers.passenger-read.entrypoints=websecure"
- "traefik.http.routers.passenger-read.tls.certresolver=myresolver"
- "traefik.http.routers.passenger-read.service=passenger-read"
- "traefik.http.services.passenger-read.loadbalancer.server.port=8711"
- "traefik.http.routers.passenger-write.rule=Host(`${WRITE_FQDN}`)"
- "traefik.http.routers.passenger-write.entrypoints=websecure"
- "traefik.http.routers.passenger-write.tls.certresolver=myresolver"
- "traefik.http.routers.passenger-write.service=passenger-write"
- "traefik.http.services.passenger-write.loadbalancer.server.port=8712"
ports:
- "${EXPOSED_SSH_PORT}:2222"
volumes:
- ./db:/db
- ./config:/config
volumes:
letsencrypt:
Run the following command to create a vault password:
Run echo -n $(openssl rand -base64 32) > config/vault-password
Pull the Docker images defined in docker-compose.yml
:
docker-compose pull
Verification
When the required images are successfully pulled, the terminal will return the following:
Pulling traefik ... done
Pulling passenger ... done
To start the Passenger instance, run:
docker-compose up -d
The terminal will return the following:
Creating passenger_passenger_1 ... done
Creating traefik ... done
Verification
Run the following command to see a list of running containers:
docker ps -a
Run following command, to see if passenger has started:
docker logs -f passenger_passenger_1
You should see following logs:
2024/07/24 18:50:24 SSH proxy server listening on 0.0.0.0:2222
time="2024-07-24T18:50:24Z" level=info msg="Server listening on 0.0.0.0:8712" endpoint=write
time="2024-07-24T18:50:24Z" level=info msg="Server listening on 0.0.0.0:8711" endpoint=read
Before using Passenger, you need to extract the write and read users from the vault to perform actions.
On the initial start, Passenger should have created a file called /opt/passenger/db/vault.kdbx
. To access this file, follow these steps:
- Open the
/opt/passenger/db/vault.kdbx
file with KeePass. - Retrieve the master password from
/opt/passenger/config/vault-password
.
You should find two entries under root/server
:
write-api
read-api
- Copy the content of the
write-api
entry. - Run the following command to set the
WRITE_AUTH_TOKEN
environment variable (replace username and password with the actual values from KeePass):
export WRITE_AUTH_TOKEN=$(echo -n 'username:password' | base64 -w 0)
- Repeat the above steps for the
read-api
entry:
export READ_AUTH_TOKEN=$(echo -n 'username:password' | base64 -w 0)
- Set the environment variables for the Fully Qualified Domain Names (FQDNs) of your endpoints:
export WRITE_FQDN="write.example.com"
export READ_FQDN="read.example.com"
Now you can use Passenger in your console session with a web client like curl
.
To add a user, you first need to create a credential:
-
Run the following command to create a credential for the user:
curl --request PUT \ --url https://$WRITE_FQDN/credential \ --header "authorization: Basic $WRITE_AUTH_TOKEN" \ --data '{ "identifier": "root/users/tony", "provider": "static", "data": { "username": "tony", "password": "secret" } }'
-
To verify your newly created credential, run the following command:
curl --silent --request GET \ --url https://$READ_FQDN/credential?identifier=root/users/tony \ --header "authorization: Basic $READ_AUTH_TOKEN" \ | jq
-
Add the user by referencing the created credential:
curl --request PUT \ --url https://$WRITE_FQDN/user \ --header "authorization: Basic $WRITE_AUTH_TOKEN" \ --data '{ "identifier": "tony", "username": "tony", "credential": "root/users/tony", "roles": [ "admin" ] }'
-
To verify your newly created user, run the following command:
curl --silent --request GET \ --url https://$READ_FQDN/user?identifier=tony \ --header "authorization: Basic $READ_AUTH_TOKEN" \ | jq
To add a target, follow these steps:
-
Create a credential for the target. Note that this credential is used to connect to the target, so the user with this credential needs to exist on the Linux host.
curl --request PUT \ --url https://$WRITE_FQDN/credential \ --header "authorization: Basic $WRITE_AUTH_TOKEN" \ --data '{ "identifier": "root/targets/eclipse/john", "provider": "static", "data": { "username": "clark", "password": "secret" } }'
-
To verify your newly created credential, run the following command:
curl --silent --request GET \ --url https://$READ_FQDN/credential?identifier=root/targets/eclipse/john \ --header "authorization: Basic $READ_AUTH_TOKEN" \ | jq
-
Add the target with the appropriate details. Note that the address should be specified as
host:port
of the target machine. Additionally, ensure thatallowed_ips
includes your remote IP address in CIDR notation, e.g.,YOUR_IP/32
.curl --request PUT \ --url https://$WRITE_FQDN/target \ --header "authorization: Basic $WRITE_AUTH_TOKEN" \ --data '{ "identifier": "eclipse", "address": "192.168.1.21:22", "credential": "root/targets/eclipse/john", "policy": { "reason_required": true, "session_max_connections": 2, "session_max_seconds": 30, "allowed_roles": [ "admin" ], "allowed_ips": [ "80.333.444.55/32" ] } }'
-
To verify your newly created target, run the following command:
curl --silent --request GET \ --url https://$READ_FQDN/target?identifier=eclipse \ --header "authorization: Basic $READ_AUTH_TOKEN" \ | jq
You have set up your user and target with the necessary credentials. You are now ready to log in to your target via the configured Passenger proxy.
-
Run the following command to initiate the SSH session (
example.com
with your passenger's ssh endpointSSH_FQDN
):ssh tony@[email protected]
-
Enter the user password you defined in the credential setup.
-
Upon successful password authentication, you will be prompted for a Reason. Enter any reason you like.
-
Passenger will inject the credential and establish a remote connection to the specified target.
Happy Shelling!
To retrieve all sessions, run the following command:
curl --silent --request GET \
--url https://$READ_FQDN/session \
--header "authorization: Basic $READ_AUTH_TOKEN" \
| jq
Note: If you do not have jq
installed, you can omit the | jq
part of the command. This will output the raw JSON response directly.
Run the following command to view real-time logs from the Passenger container:
docker logs -f passenger_passenger_1
This command will stream the logs to your terminal, allowing you to observe any errors or warnings that may be occurring.