Skip to content

Commit

Permalink
build: provides rpm and deb packages with a hardened systemd service
Browse files Browse the repository at this point in the history
These packages also configure logrotate and a cron to manage session and audit logfiles
  • Loading branch information
libvoid committed Aug 25, 2023
1 parent 53a64f7 commit 8ee742a
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 83 deletions.
29 changes: 28 additions & 1 deletion .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,31 @@ changelog:
- '^docs:'
- '^test:'
- '^style:'
- '^ci:'
- '^ci:'

nfpms:
- file_name_template: "{{ .ConventionalFileName }}"
vendor: Alterway
maintainer: [email protected]
license: Apache 2.0

formats:
- deb
- rpm

dependencies:
- systemd

provides:
- sshportal

bindir: /usr/bin

contents:
- src: packaging/etc/
dst: /etc/
type: tree

scripts:
postinstall: "packaging/postinstall.sh"
postremove: "packaging/postremove.sh"
137 changes: 55 additions & 82 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
# sshportal

[![Go Report Card](https://goreportcard.com/badge/moul.io/sshportal)](https://goreportcard.com/report/moul.io/sshportal)
[![GoDoc](https://godoc.org/moul.io/sshportal?status.svg)](https://godoc.org/moul.io/sshportal)
[![License](https://img.shields.io/github/license/moul/sshportal.svg)](https://github.com/libvoid/sshportal/blob/master/LICENSE)
[![GitHub release](https://img.shields.io/github/v/release/libvoid/sshportal.svg)](https://github.com/libvoid/sshportal/releases)
[![License](https://img.shields.io/github/license/alterway/sshportal.svg)](https://github.com/alterway/sshportal/blob/master/LICENSE)
[![GitHub release](https://img.shields.io/github/v/release/alterway/sshportal.svg)](https://github.com/alterway/sshportal/releases)

Jump host/Jump server without the jump, a.k.a Transparent SSH bastion

## IMPORTANT NOTE
**The [original project](https://github.com/moul/sshportal) is no longer being maintained. This fork includes some bugfixes and features but it is on MAINTENANCE mode and only security issues and major bugs will be fixed. You should consider using [Teleport](https://github.com/gravitational/teleport) instead.**
**The [original project](https://github.com/moul/sshportal) is no longer being maintained. This fork includes important security fixes, some bugfixes and features but it is on MAINTENANCE mode and only security issues and major bugs will be fixed. You should consider using [Teleport](https://github.com/gravitational/teleport) instead.**

<p align="center">
<img src="https://raw.githubusercontent.com/libvoid/sshportal/master/.assets/bastion.jpg" width="45%">
<img src="https://raw.githubusercontent.com/alterway/sshportal/master/.assets/bastion.jpg" width="45%">
</p>


![Flow Diagram](https://raw.githubusercontent.com/libvoid/sshportal/master/.assets/flow-diagram.png)
![Flow Diagram](https://raw.githubusercontent.com/alterway/sshportal/master/.assets/flow-diagram.png)

---

Expand All @@ -40,93 +38,56 @@ Jump host/Jump server without the jump, a.k.a Transparent SSH bastion

## Installation and usage

### Docker

Docker is the recommended way to run sshportal.
Packaged installation is privileged as it comes with a hardened systemd service config.

An [automated build is setup on the Github registry](https://github.com/libvoid/sshportal/pkgs/container/sshportal).
### Debian-based distributions

```console
# Start a server in background
# mount `pwd` to persist the sqlite database file
docker run -p 2222:2222 -d --name=sshportal -v "$(pwd):$(pwd)" -w "$(pwd)" ghcr.io/alterway/sshportal:latest
1) Get the latest version from https://github.com/alterway/sshportal/releases

# check logs (mandatory on first run to get the administrator invite token)
docker logs -f sshportal
```bash
apt install ./sshportal.deb
```

The easier way to upgrade sshportal is to do the following:

```sh
# we consider you were using an old version and you want to use the new version v1.10.0

# stop and rename the last working container + backup the database
docker stop sshportal
docker rename sshportal sshportal_old
cp sshportal.db sshportal.db.bkp

# run the new version
docker run -p 2222:2222 -d --name=sshportal -v "$(pwd):$(pwd)" -w "$(pwd)" ghcr.io/alterway/sshportal:latest
# check the logs for migration or cross-version incompatibility errors
docker logs -f sshportal
```
This will install sshportal as a systemd service, configure logrotate to keep 1 year of audit logs and add a dedicated cron for session logs. See [`packaging`](https://github.com/alterway/sshportal/tree/master/packaging).

Now you can test ssh-ing to sshportal to check if everything looks OK.

In case of problem, you can rollback to the latest working version with the latest working backup, using:
2) Get the invite token

```sh
docker stop sshportal
docker rm sshportal
cp sshportal.db.bkp sshportal.db
docker rename sshportal_old sshportal
docker start sshportal
docker logs -f sshportal
```bash
cat /var/log/sshportal/audit/audit.log
```

---

### Manual Install

Get the latest version from https://github.com/libvoid/sshportal/releases
3) Make sure you have a ssh key pair and associate your public key to the bastion

```bash
ssh localhost -p 2222 -l invite:xxxxxxx

Start the server
Welcome sshportal!

```console
$ sshportal server
2023/08/09 16:20:52 info: 'root' user created. Run 'ssh localhost -p 2222 -l invite:JBU86sSiJTVgcJwZ' to associate your public key with this account
2023/08/09 16:20:52 info: SSH Server accepting connections on :2222, idle-timout=0s
Your key is now associated with the user "sshportal@localhost".
```

Link your SSH key with the admin account
4) Your first user is the admin. To access to the console, connect like a normal server

```console
$ ssh localhost -p 2222 -l invite:JBU86sSiJTVgcJwZ
Welcome root!

Your key is now associated with the user "root@localhost".
Shared connection to localhost closed.
$
```bash
ssh sshportal@localhost -p 2222
```

If the association fails and you are prompted for a password, verify that the host you're connecting from has a SSH key set up or generate one with ```ssh-keygen -t ed25519 -c $USER@localhost```

Drop an interactive administrator shell

```console
ssh root@localhost -p 2222

### Docker

__________ _____ __ __
/ __/ __/ // / _ \___ ____/ /____ _/ /
_\ \_\ \/ _ / ___/ _ \/ __/ __/ _ '/ /
/___/___/_//_/_/ \___/_/ \__/\_,_/_/
An [automated build is setup on the Github registry](https://github.com/alterway/sshportal/pkgs/container/sshportal).

```bash
# Start a server in background
# mount `pwd` to persist the sqlite database file
docker run -p 2222:2222 -d --name=sshportal -v "$(pwd):$(pwd)" -w "$(pwd)" ghcr.io/alterway/sshportal:latest

config>
# check logs (mandatory on first run to get the administrator invite token)
docker logs -f sshportal
```

### Quick start

Create your first host

```console
Expand All @@ -146,10 +107,22 @@ Total: 1 hosts.
config>
```

Add the key to the server
Add the `host` key to the server

```console
config> host ls
ID | NAME | URL | KEY | GROUPS | UPDATED | CREATED | COMMENT | HOP | LOGGING
-----+------+-----+-----+--------+---------+---------+---------+-----+----------
Total: 0 hosts.
config> key ls
ID | NAME | TYPE | LENGTH | HOSTS | UPDATED | CREATED | COMMENT
-----+---------+---------+--------+-------+--------------+--------------+-----------------------
2 | host | ed25519 | 1 | 0 | 1 minute ago | 1 minute ago | created by sshportal
1 | default | ed25519 | 1 | 0 | 1 minute ago | 1 minute ago | created by sshportal
```

```console
ssh [email protected] "$(ssh localhost -p 2222 -l root key setup default)"
ssh [email protected] "$(ssh sshportal@localhost -p 2222 key setup host)"
```

Profit
Expand All @@ -170,15 +143,15 @@ To associate this account with a key, use the following SSH user: 'invite:NfHK5a
```

Demo gif:
![sshportal demo](https://github.com/libvoid/sshportal/raw/master/.assets/demo.gif)
![sshportal demo](https://github.com/alterway/sshportal/raw/master/.assets/demo.gif)

---

## Features and limitations

* Single autonomous binary (~20Mb) with no runtime dependencies (except glibc)
* Portable / Cross-platform (regularly tested on linux and OSX/darwin)
* Store data in [Sqlite3](https://www.sqlite.org/) or [MySQL](https://www.mysql.com) (probably easy to add postgres, mssql thanks to gorm)
* Store data in [Sqlite3](https://www.sqlite.org/) or [MySQL](https://www.mysql.com)
* Stateless -> horizontally scalable when using [MySQL](https://www.mysql.com) as the backend
* Connect to remote host using key or password
* Admin commands can be run directly or in an interactive shell
Expand Down Expand Up @@ -259,7 +232,7 @@ ssh [email protected] host inspect toto

You can enter in interactive mode using this syntax: `ssh [email protected]`

![sshportal overview](https://raw.github.com/libvoid/sshportal/master/.assets/overview.png)
![sshportal overview](https://raw.github.com/alterway/sshportal/master/.assets/overview.png)
---

## Shell commands
Expand Down Expand Up @@ -372,13 +345,13 @@ config>

---

## portal alias (.ssh/config)
## Portal alias (.ssh/config)

Edit your `~/.ssh/config` file (create it first if needed)

```ini
Host portal
User root
User root # or 'sshportal' if you use the packaged binary
Port 2222 # portal port
HostName 127.0.0.1 # portal hostname
```
Expand All @@ -405,16 +378,16 @@ By default, `sshportal` uses a local [sqlite](https://www.sqlite.org/) database

You can run multiple instances of `sshportal` sharing the same [MySQL](https://www.mysql.com) database, using `sshportal --db-conn=user:pass@host/dbname?parseTime=true --db-driver=mysql`.

![sshportal cluster with MySQL backend](https://raw.github.com/libvoid/sshportal/master/.assets/cluster-mysql.png)
![sshportal cluster with MySQL backend](https://raw.github.com/alterway/sshportal/master/.assets/cluster-mysql.png)

See [examples/mysql](http://github.com/libvoid/sshportal/tree/master/examples/mysql).
See [examples/mysql](http://github.com/alterway/sshportal/tree/master/examples/mysql).

---

## Under the hood

* Docker first (used in dev, tests, by the CI and in production)
* Backed by (see [dep graph](https://godoc.org/github.com/libvoid/sshportal?import-graph&hide=2)):
* Backed by (see [dep graph](https://godoc.org/github.com/alterway/sshportal?import-graph&hide=2)):
* SSH
* https://github.com/gliderlabs/ssh: SSH server made easy (well-designed golang library to build SSH servers)
* https://godoc.org/golang.org/x/crypto/ssh: both client and server SSH protocol and helpers
Expand All @@ -428,7 +401,7 @@ See [examples/mysql](http://github.com/libvoid/sshportal/tree/master/examples/my
* https://github.com/mgutz/ansi: Terminal color helpers
* https://github.com/urfave/cli: CLI flag parsing with subcommands support

![sshportal data model](https://raw.github.com/libvoid/sshportal/master/.assets/sql-schema.png)
![sshportal data model](https://raw.github.com/alterway/sshportal/master/.assets/sql-schema.png)

---

Expand Down
13 changes: 13 additions & 0 deletions packaging/etc/logrotate.d/sshportal
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/var/log/sshportal/audit.log {
daily
missingok
rotate 365
compress
notifempty
create 640 root root
dateext
dateformat -%Y-%m-%d
postrotate
invoke-rc.d rsyslog rotate > /dev/null
endscript
}
47 changes: 47 additions & 0 deletions packaging/etc/systemd/system/sshportal.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
[Unit]
After=ssh.service

[Service]
Type=exec
DynamicUser=yes
User=sshportal
#Restart=on-failure
RestartSec=10s
StandardOutput=append:/var/log/sshportal/audit/audit.log
LogsDirectory=sshportal
StateDirectory=sshportal
Environment=SSHPORTAL_LOGS_LOCATION=/var/log/sshportal/session
Environment=SSHPORTAL_DATABASE_URL=/var/lib/sshportal/sshportal.db
ExecStartPre=mkdir -p /var/log/sshportal/audit
ExecStart=/usr/bin/sshportal server
ExecStop=/bin/kill -SIGTERM $MAINPID

ProtectSystem=full
DevicePolicy=closed
DeviceAllow=/dev/tpm0
DeviceAllow=/dev/tpmrm0
ProtectKernelLogs=true
ProtectProc=invisible
PrivateUsers=true
ProtectHome=true
UMask=0077
RestrictNamespaces=true
LockPersonality=true
NoNewPrivileges=true
ProtectKernelModules=true
SystemCallArchitectures=native
ProtectHostname=true
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
RestrictRealtime=true
ProtectControlGroups=true
ProtectKernelTunables=true
RestrictSUIDSGID=true
ProtectClock=true
SystemCallFilter=@system-service
SystemCallFilter=~@privileged @resources
SystemCallFilter=setrlimit
CapabilityBoundingSet=
MemoryDenyWriteExecute=true

[Install]
WantedBy=default.target
7 changes: 7 additions & 0 deletions packaging/postinstall.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/sh

mkdir -p /var/log/sshportal/audit
echo "0 1 * * 0 root find /var/log/sshportal/session/ -ctime +365 -type f -delete" > /etc/cron.d/sshportal
systemctl daemon-reload
systemctl enable sshportal
systemctl start sshportal
6 changes: 6 additions & 0 deletions packaging/postremove.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/sh

systemctl is-active --quiet sshportal && systemctl stop sshportal
rm -f /etc/cron.d/sshportal
systemctl daemon-reload
systemctl reset-failed

0 comments on commit 8ee742a

Please sign in to comment.