Compare commits

...

36 Commits

Author SHA1 Message Date
tqcq
85cabeefa5 feat: push with docker 2026-03-01 20:07:25 +08:00
Manfred Touron
f9c8f60365 Merge pull request #465 from Doozers/fix/isma/rand-lib
fix: change rand lib(math/rand => crypto/rand)
2023-05-20 11:26:37 +02:00
Manfred Touron
db5cfec59a Merge pull request #416 from omahs/patch-1 2023-05-19 09:14:19 +02:00
Manfred Touron
672ef1724e Merge pull request #466 from Doozers/fix/isma/fix-lint
chore: fix golangci-lint on CI
2023-05-19 07:33:09 +02:00
ismael FALL
35b76f9063 fix: CI
Signed-off-by: ismael FALL <ismael.fall@epitech.eu>
2023-05-18 21:03:39 +02:00
ismael FALL
a30952348b fix: change rand lib(math/rand => crypto/rand)
Signed-off-by: ismael FALL <ismael.fall@epitech.eu>
2023-05-17 11:33:00 +02:00
omahs
dd4a21032f Fix: typos
Fix: typos
2022-11-01 14:23:37 +01:00
semgrep.dev on behalf of @moul
73926212d5 Add Semgrep CI 2022-05-18 18:23:41 +00:00
Manfred Touron
773b7d5a8b Merge pull request #333 from moul/dependabot/go_modules/golang.org/x/tools-0.1.10 2022-03-22 23:06:12 +01:00
Manfred Touron
3ee75e47dd Merge pull request #334 from moul/dependabot/docker/golang-1.18.0 2022-03-22 23:06:05 +01:00
dependabot[bot]
bb6e7c46cc chore(deps): bump golang from 1.17.6 to 1.18.0
Bumps golang from 1.17.6 to 1.18.0.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-17 04:06:08 +00:00
dependabot[bot]
111ced03ad chore(deps): bump golang.org/x/tools from 0.1.9 to 0.1.10
Bumps [golang.org/x/tools](https://github.com/golang/tools) from 0.1.9 to 0.1.10.
- [Release notes](https://github.com/golang/tools/releases)
- [Commits](https://github.com/golang/tools/compare/v0.1.9...v0.1.10)

---
updated-dependencies:
- dependency-name: golang.org/x/tools
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-16 04:06:02 +00:00
Manfred Touron
46970b6d17 Merge pull request #318 from moul/renovate/all 2022-02-08 12:27:47 +01:00
Renovate Bot
afc3888afe fix(deps): update golang.org/x/crypto commit hash to 20e1d8d 2022-02-08 05:38:20 +00:00
Manfred Touron
7ecdb808df Merge pull request #317 from moul/renovate/all
fix(deps): update golang.org/x/crypto commit hash to 30dcbda
2022-02-06 21:07:55 +01:00
Renovate Bot
d3d45da163 fix(deps): update golang.org/x/crypto commit hash to 30dcbda 2022-02-02 20:50:26 +00:00
Manfred Touron
2287353585 Merge pull request #315 from moul/renovate/all
fix(deps): update golang.org/x/crypto commit hash to 198e437
2022-01-30 20:37:31 +01:00
Manfred Touron
ee5a89413e Merge pull request #316 from moul/dependabot/go_modules/golang.org/x/tools-0.1.9
chore(deps): bump golang.org/x/tools from 0.1.8 to 0.1.9
2022-01-29 21:08:51 +01:00
Renovate Bot
9b30972e1e fix(deps): update all 2022-01-28 21:08:08 +00:00
dependabot[bot]
9b849441fa chore(deps): bump golang.org/x/tools from 0.1.8 to 0.1.9
Bumps [golang.org/x/tools](https://github.com/golang/tools) from 0.1.8 to 0.1.9.
- [Release notes](https://github.com/golang/tools/releases)
- [Commits](https://github.com/golang/tools/compare/v0.1.8...v0.1.9)

---
updated-dependencies:
- dependency-name: golang.org/x/tools
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-27 04:04:25 +00:00
Manfred Touron
0a6ee0f985 Merge pull request #310 from moul/renovate/all 2022-01-24 11:14:17 +01:00
Manfred Touron
271f10d389 Merge pull request #313 from moul/dependabot/go_modules/gorm.io/driver/mysql-1.2.3 2022-01-20 16:28:04 +01:00
Manfred Touron
ec0a59a72b Merge pull request #312 from moul/dependabot/go_modules/github.com/docker/docker-20.10.12incompatible 2022-01-20 16:27:55 +01:00
Manfred Touron
e7ca57196e Merge pull request #311 from moul/dependabot/docker/golang-1.17.6 2022-01-20 16:27:50 +01:00
Manfred Touron
d05a6cd3bf Merge pull request #309 from Gurkengewuerz/dev/failed-auth-log 2022-01-20 16:27:24 +01:00
dependabot[bot]
68a4bf2bd3 chore(deps): bump gorm.io/driver/mysql from 1.2.2 to 1.2.3
Bumps [gorm.io/driver/mysql](https://github.com/go-gorm/mysql) from 1.2.2 to 1.2.3.
- [Release notes](https://github.com/go-gorm/mysql/releases)
- [Commits](https://github.com/go-gorm/mysql/compare/v1.2.2...v1.2.3)

---
updated-dependencies:
- dependency-name: gorm.io/driver/mysql
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-15 08:01:36 +00:00
Manfred Touron
3f6c5f1860 Merge pull request #314 from moul/dependabot/go_modules/gorm.io/gorm-1.22.5
chore(deps): bump gorm.io/gorm from 1.22.4 to 1.22.5
2022-01-15 09:00:49 +01:00
dependabot[bot]
4a2648f6be chore(deps): bump gorm.io/gorm from 1.22.4 to 1.22.5
Bumps [gorm.io/gorm](https://github.com/go-gorm/gorm) from 1.22.4 to 1.22.5.
- [Release notes](https://github.com/go-gorm/gorm/releases)
- [Commits](https://github.com/go-gorm/gorm/compare/v1.22.4...v1.22.5)

---
updated-dependencies:
- dependency-name: gorm.io/gorm
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-13 04:04:26 +00:00
Renovate Bot
3610fbeb04 chore(deps): update all docker tags 2022-01-12 19:14:52 +00:00
dependabot[bot]
d0ab97ebf7 chore(deps): bump github.com/docker/docker
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 20.10.9+incompatible to 20.10.12+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Changelog](https://github.com/moby/moby/blob/master/CHANGELOG.md)
- [Commits](https://github.com/docker/docker/compare/v20.10.9...v20.10.12)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-11 04:05:03 +00:00
dependabot[bot]
0e8da37c80 chore(deps): bump golang from 1.17.5 to 1.17.6
Bumps golang from 1.17.5 to 1.17.6.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-07 04:05:13 +00:00
Gurkengewuerz
2d7b79703a feat: added auth failed logging 2022-01-02 23:56:10 +01:00
Manfred Touron
d95f1bd145 Merge pull request #305 from moul/renovate/all 2021-12-29 23:33:42 +01:00
Renovate Bot
f8b0224c44 chore(deps): update all 2021-12-24 07:59:57 +00:00
Manfred Touron
1b97531c6e Merge pull request #308 from moul/dependabot/docker/golang-1.17.5
chore(deps): bump golang from 1.17.3 to 1.17.5
2021-12-12 14:52:40 +01:00
dependabot[bot]
4f38f0f507 chore(deps): bump golang from 1.17.3 to 1.17.5
Bumps golang from 1.17.3 to 1.17.5.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-10 04:05:10 +00:00
16 changed files with 276 additions and 85 deletions

View File

@@ -1,7 +1,7 @@
defaults: &defaults
working_directory: /go/src/moul.io/sshportal
docker:
- image: circleci/golang:1.17.3
- image: circleci/golang:1.17.5
environment:
GO111MODULE: "on"

16
.gitea/workflows/ci.yaml Normal file
View File

@@ -0,0 +1,16 @@
name: CI
on:
push:
tags:
- v*
branches:
- master
pull_request:
jobs:
docker-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build the Docker image
run: docker build . --file Dockerfile

View File

@@ -20,9 +20,9 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: lint
uses: golangci/golangci-lint-action@v2.5.2
uses: golangci/golangci-lint-action@v3
with:
version: v1.38
version: v1.50.1
github-token: ${{ secrets.GITHUB_TOKEN }}
tests-on-windows:
needs: golangci-lint # run after golangci-lint action to not produce duplicated errors
@@ -53,7 +53,7 @@ jobs:
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.golang }}
- uses: actions/cache@v2.1.6
- uses: actions/cache@v2.1.7
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ matrix.golang }}-${{ hashFiles('**/go.sum') }}
@@ -77,7 +77,7 @@ jobs:
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.golang }}
- uses: actions/cache@v2.1.6
- uses: actions/cache@v2.1.7
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ matrix.golang }}-${{ hashFiles('**/go.sum') }}

21
.github/workflows/semgrep.yml vendored Normal file
View File

@@ -0,0 +1,21 @@
on:
pull_request: {}
push:
branches:
- master
paths:
- .github/workflows/semgrep.yml
schedule:
- cron: '0 0 * * 0'
name: Semgrep
jobs:
semgrep:
name: Scan
runs-on: ubuntu-20.04
env:
SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
container:
image: returntocorp/semgrep
steps:
- uses: actions/checkout@v3
- run: semgrep ci

View File

@@ -47,7 +47,7 @@ linters:
- staticcheck
- structcheck
#- stylecheck
- typecheck
#- typecheck
- unconvert
- unparam
- unused

View File

@@ -1,5 +1,5 @@
# build
FROM golang:1.17.3 as builder
FROM golang:1.18.0 as builder
ENV GO111MODULE=on
WORKDIR /go/src/moul.io/sshportal
COPY go.mod go.sum ./

View File

@@ -61,7 +61,7 @@ Shared connection to localhost closed.
$
```
If the association fails and you are promted for a password, verify that the host you're connecting from has a SSH key set up or generate one with ```ssh-keygen -t rsa```
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 rsa```
Drop an interactive administrator shell
@@ -135,7 +135,7 @@ Used by educators to provide temporary access to students. [Feedback from a teac
There are companies who use a jump host to monitor connections at a single point.
A hosting company is using SSHportal for its “logging” feature, among the others. As every session is logged and introspectable, they have a detailed history of who performed which action. This company made its own contribution on the project, allowing the support of [more than 65.000 sessions in the database](https://github.com/moul/sshportal/pull/76).
A hosting company is using SSHportal for its “logging” feature, among others. As every session is logged and introspectable, they have a detailed history of who performed which action. This company made its own contribution to the project, allowing the support of [more than 65.000 sessions in the database](https://github.com/moul/sshportal/pull/76).
The project has also received [multiple contributions from a security researcher](https://github.com/moul/sshportal/pulls?q=is%3Apr+author%3Asabban+sort%3Aupdated-desc) that made a thesis on quantum cryptography. This person uses SSHportal in their security-hardened hosting company.
@@ -155,7 +155,7 @@ If you need to invite multiple people to an event (hackathon, course, etc), the
* User management (invite, group, stats)
* Host Key management (create, remove, update, import)
* Automatic remote host key learning
* User Key management (multile keys per user)
* User Key management (multiple keys per user)
* ACL management (acl+user-groups+host-groups)
* User roles (admin, trusted, standard, ...)
* User invitations (no more "give me your public ssh key please")
@@ -184,7 +184,7 @@ If you need to invite multiple people to an event (hackathon, course, etc), the
* Does not work (yet?) with [`mosh`](https://mosh.org/)
* It is not possible for a user to access a host with the same name as the user. This is easily circumvented by changing the user name, especially since the most common use cases does not expose it.
* It is not possible access a host named `healthcheck` as this is a built in command.
* It is not possible to access a host named `healthcheck` as this is a built-in command.
---
@@ -215,7 +215,7 @@ cp sshportal.db sshportal.db.bkp
# run the new version
docker run -p 2222:2222 -d --name=sshportal -v "$(pwd):$(pwd)" -w "$(pwd)" moul/sshportal:v1.10.0
# check the logs for migration or cross-version incompabitility errors
# check the logs for migration or cross-version incompatibility errors
docker logs -f sshportal
```
@@ -276,7 +276,7 @@ cp sshportal.db sshportal.db.bkp
By default, the configuration user is `admin`, (can be changed using `--config-user=<value>` when starting the server. The shell is also accessible through `ssh [username]@portal.example.org`.
Each commands can be run directly by using this syntax: `ssh admin@portal.example.org <command> [args]`:
Each command can be run directly by using this syntax: `ssh admin@portal.example.org <command> [args]`:
```
ssh admin@portal.example.org host inspect toto
@@ -446,7 +446,7 @@ ssh localhost -p 2222 -l hostname
By default, `sshportal` uses a local [sqlite](https://www.sqlite.org/) database which isn't scalable by design.
You can run multiple instances of `sshportal` sharing a same [MySQL](https://www.mysql.com) database, using `sshportal --db-conn=user:pass@host/dbname?parseTime=true --db-driver=mysql`.
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/moul/sshportal/master/.assets/cluster-mysql.png)

15
go.mod generated
View File

@@ -5,7 +5,7 @@ require (
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
github.com/creack/pty v1.1.11 // indirect
github.com/docker/docker v20.10.9+incompatible
github.com/docker/docker v20.10.12+incompatible
github.com/dustin/go-humanize v1.0.0
github.com/gliderlabs/ssh v0.3.3
github.com/go-gormigrate/gormigrate/v2 v2.0.0
@@ -14,6 +14,7 @@ require (
github.com/mattn/go-runewidth v0.0.12 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d
github.com/olekukonko/tablewriter v0.0.5
github.com/pires/go-proxyproto v0.6.2 // indirect
github.com/pkg/errors v0.9.1
github.com/reiver/go-oi v1.0.0
github.com/reiver/go-telnet v0.0.0-20180421082511-9ff0b2ab096e
@@ -23,13 +24,13 @@ require (
github.com/smartystreets/goconvey v1.7.2
github.com/tailscale/depaware v0.0.0-20210622194025-720c4b409502
github.com/urfave/cli v1.22.5
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871
golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab
golang.org/x/term v0.0.0-20210422114643-f5beecf764ed // indirect
golang.org/x/tools v0.1.7
gorm.io/driver/mysql v1.2.0
gorm.io/driver/postgres v1.2.2
gorm.io/driver/sqlite v1.2.4
gorm.io/gorm v1.22.3
golang.org/x/tools v0.1.10
gorm.io/driver/mysql v1.2.3
gorm.io/driver/postgres v1.2.3
gorm.io/driver/sqlite v1.2.6
gorm.io/gorm v1.22.5
moul.io/srand v1.6.1
)

63
go.sum generated
View File

@@ -22,8 +22,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc h1:VRRKCwnzqk8QCaRC4os14xoKDdbHqqlJtJA0oc1ZAjg=
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/docker/docker v20.10.9+incompatible h1:JlsVnETOjM2RLQa0Cc1XCIspUdXW3Zenq9P54uXBm6k=
github.com/docker/docker v20.10.9+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v20.10.12+incompatible h1:CEeNmFM0QZIsJCZKMkZx0ZcahTiewkrgiwfYD+dfl1U=
github.com/docker/docker v20.10.12+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/gliderlabs/ssh v0.3.3 h1:mBQ8NiOgDkINJrZtoizkC3nDNYgSaWtxyem6S2XHBtA=
@@ -59,8 +59,8 @@ github.com/jackc/pgconn v1.6.4/go.mod h1:w2pne1C2tZgP+TvjqLpOigGzNqjBgQW9dUw/4Ch
github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
github.com/jackc/pgconn v1.10.0 h1:4EYhlDVEMsJ30nNj0mmgwIUXoq7e9sMJrVC2ED6QlCU=
github.com/jackc/pgconn v1.10.0/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
github.com/jackc/pgconn v1.10.1 h1:DzdIHIjG1AxGwoEEqS+mGsURyjt4enSmqzACXvVzOT8=
github.com/jackc/pgconn v1.10.1/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
@@ -78,8 +78,9 @@ github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:
github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.0.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.1.1 h1:7PQ/4gLoqnl87ZxL7xjO0DR5gYuviDCZxQJsUlFW1eI=
github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.2.0 h1:r7JypeP2D3onoQTCxWdTpCtJ4D+qpKr0TxvoyMhZ5ns=
github.com/jackc/pgproto3/v2 v2.2.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
@@ -91,8 +92,8 @@ github.com/jackc/pgtype v1.3.1-0.20200510190516-8cd94a14c75a/go.mod h1:vaogEUkAL
github.com/jackc/pgtype v1.3.1-0.20200606141011-f6355165a91c/go.mod h1:cvk9Bgu/VzJ9/lxTO5R5sf80p0DiucVtN7ZxvaC4GmQ=
github.com/jackc/pgtype v1.4.2/go.mod h1:JCULISAZBFGrHaOXIIFiyfzW5VY0GRitRr8NeJsrdig=
github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
github.com/jackc/pgtype v1.8.1 h1:9k0IXtdJXHJbyAWQgbWr1lU+MEhPXZz6RIXxfR5oxXs=
github.com/jackc/pgtype v1.8.1/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
github.com/jackc/pgtype v1.9.0 h1:/SH1RxEtltvJgsDqp3TbiTFApD3mey3iygpuEGeuBXk=
github.com/jackc/pgtype v1.9.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
@@ -101,18 +102,21 @@ github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6
github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg=
github.com/jackc/pgx/v4 v4.8.1/go.mod h1:4HOLxrl8wToZJReD04/yB20GDwf4KBYETvlHciCnwW0=
github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
github.com/jackc/pgx/v4 v4.13.0 h1:JCjhT5vmhMAf/YwBHLvrBn4OGdIQBiFG6ym8Zmdx570=
github.com/jackc/pgx/v4 v4.13.0/go.mod h1:9P4X524sErlaxj0XSGZk7s+LD0eOyu1ZDUrrpznYDF0=
github.com/jackc/pgx/v4 v4.14.0 h1:TgdrmgnM7VY72EuSQzBbBd4JA1RLqJolrw9nQVZABVc=
github.com/jackc/pgx/v4 v4.14.0/go.mod h1:jT3ibf/A0ZVCp89rtCIN0zCJxcE74ypROmHEZYsG/j8=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.2.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.2 h1:eVKgfIdy9b6zbWBMgFpfDPoAMifwSZagU9HmEU6zgiI=
github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.3/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.4 h1:tHnRBy1i5F2Dh8BAFxqFzxKqqvezXrL2OW1TnX+Mlas=
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
@@ -154,6 +158,8 @@ github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQ
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/pires/go-proxyproto v0.6.2 h1:KAZ7UteSOt6urjme6ZldyFm4wDe/z0ZUP0Yv0Dos0d8=
github.com/pires/go-proxyproto v0.6.2/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY=
github.com/pkg/diff v0.0.0-20200914180035-5b29258ca4f7 h1:+/+DxvQaYifJ+grD4klzrS5y+KJXldn/2YTl5JG+vZ8=
github.com/pkg/diff v0.0.0-20200914180035-5b29258ca4f7/go.mod h1:zO8QMzTeZd5cpnIkz/Gn6iK0jDfGicM1nynOkkPIl28=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -205,7 +211,7 @@ github.com/tailscale/depaware v0.0.0-20210622194025-720c4b409502/go.mod h1:p9lPs
github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU=
github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
@@ -231,15 +237,15 @@ golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWP
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 h1:/pEO3GD/ABYAjuakUS6xSEmmlyVS4kxBNkeA9tLJiTI=
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab h1:lnZ4LoV0UMdibeCUfIB2a4uFwRu491WX/VB2reB8xNc=
golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@@ -249,7 +255,7 @@ golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -271,8 +277,8 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210422114643-f5beecf764ed h1:Ei4bQjjpYUsS4efOUz+5Nz++IVkHk87n2zBA0NxBWc0=
@@ -295,8 +301,8 @@ golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20201211185031-d93e913c1a58/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20=
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -313,21 +319,22 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.0.1/go.mod h1:KtqSthtg55lFp3S5kUXqlGaelnWpKitn4k1xZTnoiPw=
gorm.io/driver/mysql v1.2.0 h1:l8+9VwjjyzEkw0PNPBOr2JHhLOGVk7XEnl5hk42bcvs=
gorm.io/driver/mysql v1.2.0/go.mod h1:4RQmTg4okPghdt+kbe6e1bTXIQp7Ny1NnBn/3Z6ghjk=
gorm.io/driver/mysql v1.2.3 h1:cZqzlOfg5Kf1VIdLC1D9hT6Cy9BgxhExLj/2tIgUe7Y=
gorm.io/driver/mysql v1.2.3/go.mod h1:qsiz+XcAyMrS6QY+X3M9R6b/lKM1imKmcuK9kac5LTo=
gorm.io/driver/postgres v1.0.0/go.mod h1:wtMFcOzmuA5QigNsgEIb7O5lhvH1tHAF1RbWmLWV4to=
gorm.io/driver/postgres v1.2.2 h1:Ka9W6feOU+rPM9m007eYLMD4QoZuYGBnQ3Jp0faGSwg=
gorm.io/driver/postgres v1.2.2/go.mod h1:Ik3tK+a3FMp8ORZl29v4b3M0RsgXsaeMXh9s9eVMXco=
gorm.io/driver/postgres v1.2.3 h1:f4t0TmNMy9gh3TU2PX+EppoA6YsgFnyq8Ojtddb42To=
gorm.io/driver/postgres v1.2.3/go.mod h1:pJV6RgYQPG47aM1f0QeOzFH9HxQc8JcmAgjRCgS0wjs=
gorm.io/driver/sqlite v1.1.1/go.mod h1:hm2olEcl8Tmsc6eZyxYSeznnsDaMqamBvEXLNtBg4cI=
gorm.io/driver/sqlite v1.2.4 h1:jx16ESo1WzNjgBJNSbhEDoMKJnlhkU8BuBR2C0GC7D8=
gorm.io/driver/sqlite v1.2.4/go.mod h1:n8/CTEIEmo7lKrehQI4pd+rz6O514tMkBeCAR5UTXLs=
gorm.io/driver/sqlite v1.2.6 h1:SStaH/b+280M7C8vXeZLz/zo9cLQmIGwwj3cSj7p6l4=
gorm.io/driver/sqlite v1.2.6/go.mod h1:gyoX0vHiiwi0g49tv+x2E7l8ksauLK0U/gShcdUsjWY=
gorm.io/driver/sqlserver v1.0.2 h1:FzxAlw0/7hntMzSiNfotpYCo9Lz8dqWQGdmCGqIiFGo=
gorm.io/driver/sqlserver v1.0.2/go.mod h1:gb0Y9QePGgqjzrVyTQUZeh9zkd5v0iz71cM1B4ZycEY=
gorm.io/gorm v1.9.19/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
gorm.io/gorm v1.20.0/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
gorm.io/gorm v1.22.2/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
gorm.io/gorm v1.22.3 h1:/JS6z+GStEQvJNW3t1FTwJwG/gZ+A7crFdRqtvG5ehA=
gorm.io/gorm v1.22.3/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
gorm.io/gorm v1.22.4/go.mod h1:1aeVC+pe9ZmvKZban/gW4QPra7PRoTEssyc922qCAkk=
gorm.io/gorm v1.22.5 h1:lYREBgc02Be/5lSCTuysZZDb6ffL2qrat6fg9CFbvXU=
gorm.io/gorm v1.22.5/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
moul.io/srand v1.6.1 h1:SJ335F+54ivLdlH7wH52Rtyv0Ffos6DpsF5wu3ZVMXU=
moul.io/srand v1.6.1/go.mod h1:P2uaZB+GFstFNo8sEj6/U8FRV1n25kD0LLckFpJ+qvc=

15
main.go
View File

@@ -79,12 +79,17 @@ func main() {
Value: 0,
Usage: "Duration before an inactive connection is timed out (0 to disable)",
},
cli.StringFlag{
Name: "acl-check-cmd",
EnvVar: "SSHPORTAL_ACL_CHECK_CMD",
Usage: "Execute external command to check ACL",
},
cli.StringFlag{
Name: "acl-check-cmd",
EnvVar: "SSHPORTAL_ACL_CHECK_CMD",
Usage: "Execute external command to check ACL",
},
cli.BoolFlag{
Name: "no-proxy-protocol",
EnvVar: "SSHPORTAL_NO_PROXY_PROTOCOL",
Usage: "Disable Proxy Protocol auto-detection (default: enabled)",
},
},
}, {
Name: "healthcheck",
Action: func(c *cli.Context) error { return healthcheck(c.String("addr"), c.Bool("wait"), c.Bool("quiet")) },

View File

@@ -1,10 +1,11 @@
package bastion // import "moul.io/sshportal/pkg/bastion"
import (
"crypto/rand"
"fmt"
"io/ioutil"
"log"
"math/rand"
"math/big"
"os"
"os/user"
"strings"
@@ -617,7 +618,10 @@ func DBInit(db *gorm.DB) error {
}
if count == 0 {
// if no admin, create an account for the first connection
inviteToken := randStringBytes(16)
inviteToken, err := randStringBytes(16)
if err != nil {
return err
}
if os.Getenv("SSHPORTAL_DEFAULT_ADMIN_INVITE_TOKEN") != "" {
inviteToken = os.Getenv("SSHPORTAL_DEFAULT_ADMIN_INVITE_TOKEN")
}
@@ -673,12 +677,16 @@ func DBInit(db *gorm.DB) error {
}).Error
}
func randStringBytes(n int) string {
func randStringBytes(n int) (string, error) {
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
b := make([]byte, n)
for i := range b {
b[i] = letterBytes[rand.Intn(len(letterBytes))]
r, err := rand.Int(rand.Reader, big.NewInt(int64(len(letterBytes))))
if err != nil {
return "", fmt.Errorf("failed to generate random string: %s", err)
}
b[i] = letterBytes[r.Int64()]
}
return string(b)
return string(b), nil
}

View File

@@ -5,21 +5,83 @@ import (
"io"
"io/ioutil"
"log"
"net"
"os"
"path/filepath"
"time"
"github.com/gliderlabs/ssh"
"github.com/pires/go-proxyproto"
"github.com/pkg/errors"
"github.com/sabban/bastion/pkg/logchannel"
gossh "golang.org/x/crypto/ssh"
)
type sessionConfig struct {
Addr string
LogsLocation string
ClientConfig *gossh.ClientConfig
LoggingMode string
Addr string
LogsLocation string
ClientConfig *gossh.ClientConfig
LoggingMode string
ProxyProtocol string
ClientIP net.Addr
}
// dialWithProxyProto dials the target host with optional PROXY protocol header
// When PROXY protocol is enabled, the header is sent before the SSH handshake
func dialWithProxyProto(network, addr string, config *gossh.ClientConfig, proxyProtocol string, clientIP net.Addr) (*gossh.Client, error) {
// If Proxy Protocol is enabled, send the header before SSH handshake
if proxyProtocol == "v1" || proxyProtocol == "v2" {
// Parse target address
targetAddr, err := net.ResolveTCPAddr("tcp", addr)
if err != nil {
return nil, err
}
// Parse source address (client IP) or use localhost if unknown
var srcAddr net.Addr
if clientIP != nil {
srcAddr = clientIP
} else {
srcAddr, _ = net.ResolveTCPAddr("tcp", "127.0.0.1:0")
}
// Create a raw TCP connection
conn, err := net.Dial(network, addr)
if err != nil {
return nil, err
}
// Create a PROXY protocol header
header := proxyproto.HeaderProxyFromAddrs(0, srcAddr, targetAddr)
// Set protocol version if specified
if proxyProtocol == "v1" {
header.Version = 1
} else {
header.Version = 2
}
// Write PROXY protocol header before SSH handshake
_, err = header.WriteTo(conn)
if err != nil {
conn.Close()
return nil, err
}
// Create SSH client connection on top of the TCP connection (with PROXY header already sent)
// The SSH handshake will now continue after the PROXY header
c, chans, reqs, err := gossh.NewClientConn(conn, addr, config)
if err != nil {
conn.Close()
return nil, err
}
// Return a client from the connection
return gossh.NewClient(c, chans, reqs), nil
}
// Without Proxy Protocol - use standard dial
return gossh.Dial(network, addr, config)
}
func multiChannelHandler(conn *gossh.ServerConn, newChan gossh.NewChannel, ctx ssh.Context, configs []sessionConfig, sessionID uint) error {
@@ -37,7 +99,8 @@ func multiChannelHandler(conn *gossh.ServerConn, newChan gossh.NewChannel, ctx s
for _, config := range configs {
var client *gossh.Client
if lastClient == nil {
client, err = gossh.Dial("tcp", config.Addr, config.ClientConfig)
// First connection - use dialWithProxyProto if enabled
client, err = dialWithProxyProto("tcp", config.Addr, config.ClientConfig, config.ProxyProtocol, config.ClientIP)
} else {
rconn, err := lastClient.Dial("tcp", config.Addr)
if err != nil {
@@ -74,11 +137,12 @@ func multiChannelHandler(conn *gossh.ServerConn, newChan gossh.NewChannel, ctx s
return nil
}
// go through all the hops
// go through all hops
for _, config := range configs {
var client *gossh.Client
if lastClient == nil {
client, err = gossh.Dial("tcp", config.Addr, config.ClientConfig)
// First connection - use dialWithProxyProto if enabled
client, err = dialWithProxyProto("tcp", config.Addr, config.ClientConfig, config.ProxyProtocol, config.ClientIP)
} else {
rconn, err := lastClient.Dial("tcp", config.Addr)
if err != nil {

View File

@@ -728,6 +728,7 @@ GLOBAL OPTIONS:
cli.StringFlag{Name: "key, k", Usage: "`KEY` to use for authentication"},
cli.StringFlag{Name: "hop, o", Usage: "Hop to use for connecting to the server"},
cli.StringFlag{Name: "logging, l", Usage: "Logging mode (disabled, input, everything)"},
cli.StringFlag{Name: "proxy-protocol", Usage: "Proxy protocol version (ssh: default, v1, v2)"},
cli.StringSliceFlag{Name: "group, g", Usage: "Assigns the host to `HOSTGROUPS` (default: \"default\")"},
},
Action: func(c *cli.Context) error {
@@ -775,6 +776,12 @@ GLOBAL OPTIONS:
if c.String("logging") != "" {
host.Logging = c.String("logging")
}
if proxyProtocol := c.String("proxy-protocol"); proxyProtocol != "" || proxyProtocol == "ssh" {
if !dbmodels.ValidProxyProtocol(proxyProtocol) {
return fmt.Errorf("invalid proxy protocol version: %q (must be v1 or v2)", proxyProtocol)
}
host.ProxyProtocol = proxyProtocol
}
// FIXME: check if name already exists
if _, err := govalidator.ValidateStruct(host); err != nil {
@@ -882,7 +889,7 @@ GLOBAL OPTIONS:
}
table := tablewriter.NewWriter(s)
table.SetHeader([]string{"ID", "Name", "URL", "Key", "Groups", "Updated", "Created", "Comment", "Hop", "Logging"})
table.SetHeader([]string{"ID", "Name", "URL", "Key", "Groups", "Updated", "Created", "Comment", "Hop", "Logging", "ProxyProtocol"})
table.SetBorder(false)
table.SetCaption(true, fmt.Sprintf("Total: %d hosts.", len(hosts)))
for _, host := range hosts {
@@ -908,6 +915,11 @@ GLOBAL OPTIONS:
} else {
hop = ""
}
var protocol string = "ssh"
if len(host.ProxyProtocol) != 0 {
protocol = host.ProxyProtocol
}
table.Append([]string{
fmt.Sprintf("%d", host.ID),
host.Name,
@@ -919,6 +931,7 @@ GLOBAL OPTIONS:
host.Comment,
hop,
host.Logging,
protocol,
//FIXME: add some stats about last access time etc
})
}
@@ -951,6 +964,7 @@ GLOBAL OPTIONS:
cli.StringFlag{Name: "key, k", Usage: "Link a `KEY` to use for authentication"},
cli.StringFlag{Name: "hop, o", Usage: "Change the hop to use for connecting to the server"},
cli.StringFlag{Name: "logging, l", Usage: "Logging mode (disabled, input, everything)"},
cli.StringFlag{Name: "proxy-protocol, p", Usage: "Proxy protocol version (ssh, v1, v2)"},
cli.BoolFlag{Name: "unset-hop", Usage: "Remove the hop set for this host"},
cli.StringSliceFlag{Name: "assign-group, g", Usage: "Assign the host to a new `HOSTGROUPS`"},
cli.StringSliceFlag{Name: "unassign-group", Usage: "Unassign the host from a `HOSTGROUPS`"},
@@ -1024,6 +1038,17 @@ GLOBAL OPTIONS:
}
}
// proxy-protocol
if proxyProtocol := c.String("proxy-protocol"); proxyProtocol != "" || proxyProtocol == "ssh" {
if !dbmodels.ValidProxyProtocol(proxyProtocol) {
return fmt.Errorf("invalid proxy protocol version: %q (must be v1 or v2)", proxyProtocol)
}
if err := model.Update("proxy_protocol", proxyProtocol).Error; err != nil {
tx.Rollback()
return err
}
}
// remove the hop
if c.Bool("unset-hop") {
var hopHost dbmodels.Host
@@ -1640,11 +1665,15 @@ GLOBAL OPTIONS:
name = c.String("name")
}
r, err := randStringBytes(16)
if err != nil {
return err
}
user := dbmodels.User{
Name: name,
Email: email,
Comment: c.String("comment"),
InviteToken: randStringBytes(16),
InviteToken: r,
}
if _, err := govalidator.ValidateStruct(user); err != nil {

View File

@@ -89,6 +89,22 @@ func ChannelHandler(srv *ssh.Server, conn *gossh.ServerConn, newChan gossh.NewCh
actx := ctx.Value(authContextKey).(*authContext)
if actx.user.ID == 0 && actx.userType() != userTypeHealthcheck {
ip, err := net.ResolveTCPAddr(conn.RemoteAddr().Network(), conn.RemoteAddr().String())
if err == nil {
log.Printf("Auth failed: sshUser=%q remote=%q", conn.User(), ip.IP.String())
actx.err = errors.New("access denied")
ch, _, err2 := newChan.Accept()
if err2 != nil {
return
}
fmt.Fprintf(ch, "error: %v\n", actx.err)
_ = ch.Close()
return
}
}
switch actx.userType() {
case userTypeBastion:
log.Printf("New connection(bastion): sshUser=%q remote=%q local=%q dbUser=id:%d,email:%s", conn.User(), conn.RemoteAddr(), conn.LocalAddr(), actx.user.ID, actx.user.Email)
@@ -125,6 +141,8 @@ func ChannelHandler(srv *ssh.Server, conn *gossh.ServerConn, newChan gossh.NewCh
ClientConfig: clientConfig,
LogsLocation: actx.logsLocation,
LoggingMode: currentHost.Logging,
ProxyProtocol: currentHost.ProxyProtocol,
ClientIP: conn.RemoteAddr(),
}}, sessionConfigs...)
if currentHost.HopID != 0 {
var newHost dbmodels.Host

View File

@@ -58,12 +58,13 @@ type Host struct {
URL string `valid:"optional"`
SSHKey *SSHKey `gorm:"ForeignKey:SSHKeyID"` // SSHKey used to connect by the client
SSHKeyID uint `gorm:"index"`
HostKey []byte `sql:"size:1000" valid:"optional"`
Groups []*HostGroup `gorm:"many2many:host_host_groups;"`
Comment string `valid:"optional"`
Logging string `valid:"optional,host_logging_mode"`
Hop *Host
HopID uint
HostKey []byte `sql:"size:1000" valid:"optional"`
Groups []*HostGroup `gorm:"many2many:host_host_groups;"`
Comment string `valid:"optional"`
Logging string `valid:"optional,host_logging_mode"`
Hop *Host
HopID uint
ProxyProtocol string `gorm:"column:proxy_protocol;default:''" valid:"optional"`
}
// UserKey defines a user public key used by sshportal to identify the user
@@ -321,6 +322,16 @@ func (host *Host) ClientConfig(hk gossh.HostKeyCallback) (*gossh.ClientConfig, e
return &config, nil
}
// ValidProxyProtocol returns true if the ProxyProtocol value is valid
func ValidProxyProtocol(value string) bool {
switch value {
case "", "v1", "v2":
return true
default:
return false
}
}
// SSHKey helpers
func SSHKeysPreload(db *gorm.DB) *gorm.DB {

View File

@@ -14,10 +14,12 @@ import (
"gorm.io/gorm"
"gorm.io/gorm/logger"
"moul.io/sshportal/pkg/bastion"
"github.com/gliderlabs/ssh"
"github.com/pires/go-proxyproto"
"github.com/urfave/cli"
gossh "golang.org/x/crypto/ssh"
"moul.io/sshportal/pkg/bastion"
)
type serverConfig struct {
@@ -28,19 +30,21 @@ type serverConfig struct {
debug, demo bool
idleTimeout time.Duration
aclCheckCmd string
proxyProtocol bool
}
func parseServerConfig(c *cli.Context) (*serverConfig, error) {
ret := &serverConfig{
aesKey: c.String("aes-key"),
dbDriver: c.String("db-driver"),
dbURL: c.String("db-conn"),
bindAddr: c.String("bind-address"),
debug: c.Bool("debug"),
demo: c.Bool("demo"),
logsLocation: c.String("logs-location"),
idleTimeout: c.Duration("idle-timeout"),
aclCheckCmd: c.String("acl-check-cmd"),
aesKey: c.String("aes-key"),
dbDriver: c.String("db-driver"),
dbURL: c.String("db-conn"),
bindAddr: c.String("bind-address"),
debug: c.Bool("debug"),
demo: c.Bool("demo"),
logsLocation: c.String("logs-location"),
idleTimeout: c.Duration("idle-timeout"),
aclCheckCmd: c.String("acl-check-cmd"),
proxyProtocol: !c.Bool("no-proxy-protocol"), // Default to true (enabled)
}
switch len(ret.aesKey) {
case 0, 16, 24, 32:
@@ -83,7 +87,7 @@ func dbConnect(c *serverConfig, config gorm.Option) (*gorm.DB, error) {
func server(c *serverConfig) (err error) {
// configure db logging
db, err := dbConnect(c, &gorm.Config{
db, _ := dbConnect(c, &gorm.Config{
Logger: logger.Default.LogMode(logger.Silent),
})
sqlDB, err := db.DB()
@@ -110,6 +114,13 @@ func server(c *serverConfig) (err error) {
return err
}
// wrap listener with Proxy Protocol support if enabled
// When enabled, listener auto-detects: PROXY v1, PROXY v2, or no PROXY (regular SSH)
if c.proxyProtocol {
ln = &proxyproto.Listener{Listener: ln}
log.Printf("Proxy Protocol auto-detection enabled (accepts v1, v2, or plain SSH)")
}
// configure server
srv := &ssh.Server{
Addr: c.bindAddr,