mirror of
https://github.com/moul/sshportal.git
synced 2025-10-25 05:27:10 +08:00
Add Docker healthcheck helper
This commit is contained in:
parent
d6ea80dab1
commit
6494e69632
6 changed files with 74 additions and 8 deletions
|
|
@ -9,6 +9,8 @@ Changes:
|
|||
* Fix connection failure when sending too many environment variables (fix [#22](https://github.com/moul/sshportal/issues/22))
|
||||
* Fix panic when entering empty command (fix [#13](https://github.com/moul/sshportal/issues/13))
|
||||
* Add `config backup --ignore-events` option
|
||||
* Add `sshportal healthcheck` cli command
|
||||
* Add [Docker Healthcheck](https://docs.docker.com/engine/reference/builder/#healthcheck) helper
|
||||
|
||||
## v1.6.0 (2017-12-12)
|
||||
|
||||
|
|
|
|||
|
|
@ -5,8 +5,9 @@ WORKDIR /go/src/github.com/moul/sshportal
|
|||
RUN make _docker_install
|
||||
|
||||
# minimal runtime
|
||||
FROM scratch
|
||||
FROM alpine
|
||||
COPY --from=builder /go/bin/sshportal /bin/sshportal
|
||||
ENTRYPOINT ["/bin/sshportal"]
|
||||
CMD ["server"]
|
||||
EXPOSE 2222
|
||||
HEALTHCHECK --interval=10s --timeout=10s CMD /bin/sshportal healthcheck
|
||||
|
|
|
|||
15
README.md
15
README.md
|
|
@ -43,7 +43,7 @@ Jump host/Jump server without the jump, a.k.a Transparent SSH bastion
|
|||
* [`scp`](https://linux.die.net/man/1/scp) support
|
||||
* [`rsync`](https://linux.die.net/man/1/rsync) support
|
||||
* Git support (can be used to easily use multiple user keys on GitHub, or access your own firewalled gitlab server)
|
||||
* Do not require any SSH client modification or custom `.ssh/config`, works with every tested SSH programming libraries and every tested SSH
|
||||
* Do not require any SSH client modification or custom `.ssh/config`, works with every tested SSH programming libraries and every tested SSH
|
||||
|
||||
## (Known) limitations
|
||||
|
||||
|
|
@ -54,7 +54,7 @@ Jump host/Jump server without the jump, a.k.a Transparent SSH bastion
|
|||
Start the server
|
||||
|
||||
```console
|
||||
$ sshportal
|
||||
$ sshportal server
|
||||
2017/11/13 10:58:35 Admin user created, use the user 'invite:BpLnfgDsc2WD8F2q' to associate a public key with this account
|
||||
2017/11/13 10:58:35 SSH Server accepting connections on :2222
|
||||
```
|
||||
|
|
@ -346,6 +346,15 @@ $
|
|||
|
||||
the `healtcheck` user can be changed using the `healthcheck-user` option.
|
||||
|
||||
---
|
||||
|
||||
Alternatively, you can run the built-in healthcheck helper (requiring no ssh client nor ssh key):
|
||||
|
||||
```console
|
||||
$ sshportal healthcheck --addr=localhost:2222; echo $?
|
||||
$ 0
|
||||
```
|
||||
|
||||
## Scaling
|
||||
|
||||
`sshportal` is stateless but relies on a database to store configuration and logs.
|
||||
|
|
@ -383,4 +392,4 @@ This is totally experimental for now, so please file issues to let me know what
|
|||
|
||||
|
||||
## License
|
||||
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fmoul%2Fsshportal?ref=badge_large)
|
||||
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fmoul%2Fsshportal?ref=badge_large)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
run:
|
||||
docker-compose down
|
||||
|
||||
docker-compose up -d sshportal
|
||||
@echo "Waiting for sshportal to be healthy"
|
||||
@sleep 3
|
||||
|
||||
docker-compose build client
|
||||
docker-compose run client /integration/_client.sh
|
||||
|
||||
docker-compose down
|
||||
|
|
|
|||
|
|
@ -11,9 +11,6 @@ Host sshportal
|
|||
HostName sshportal
|
||||
EOF
|
||||
|
||||
#ping -c 1 sshportal
|
||||
sleep 3
|
||||
|
||||
set -x
|
||||
|
||||
# login
|
||||
|
|
|
|||
54
main.go
54
main.go
|
|
@ -1,10 +1,12 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
|
@ -86,6 +88,15 @@ func main() {
|
|||
Usage: "Encrypt sensitive data in database (length: 16, 24 or 32)",
|
||||
},
|
||||
},
|
||||
}, {
|
||||
Name: "healthcheck",
|
||||
Action: healthcheck,
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "addr, a",
|
||||
Value: "localhost:2222",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
if err := app.Run(os.Args); err != nil {
|
||||
|
|
@ -122,7 +133,9 @@ func server(c *cli.Context) error {
|
|||
// ssh server
|
||||
ssh.Handle(func(s ssh.Session) {
|
||||
currentUser := s.Context().Value(userContextKey).(User)
|
||||
log.Printf("New connection: sshUser=%q remote=%q local=%q command=%q dbUser=id:%q,email:%s", s.User(), s.RemoteAddr(), s.LocalAddr(), s.Command(), currentUser.ID, currentUser.Email)
|
||||
if s.User() != "healthcheck" {
|
||||
log.Printf("New connection: sshUser=%q remote=%q local=%q command=%q dbUser=id:%q,email:%s", s.User(), s.RemoteAddr(), s.LocalAddr(), s.Command(), currentUser.ID, currentUser.Email)
|
||||
}
|
||||
|
||||
if err := s.Context().Value(errorContextKey); err != nil {
|
||||
fmt.Fprintf(s, "error: %v\n", err)
|
||||
|
|
@ -208,6 +221,11 @@ func server(c *cli.Context) error {
|
|||
})
|
||||
|
||||
opts := []ssh.Option{}
|
||||
opts = append(opts, ssh.PasswordAuth(func(ctx ssh.Context, pass string) bool {
|
||||
ctx.SetValue(userContextKey, User{})
|
||||
return ctx.User() == "healthcheck"
|
||||
}))
|
||||
|
||||
opts = append(opts, ssh.PublicKeyAuth(func(ctx ssh.Context, key ssh.PublicKey) bool {
|
||||
var (
|
||||
userKey UserKey
|
||||
|
|
@ -278,3 +296,37 @@ func server(c *cli.Context) error {
|
|||
log.Printf("info: SSH Server accepting connections on %s", c.String("bind-address"))
|
||||
return ssh.ListenAndServe(c.String("bind-address"), nil, opts...)
|
||||
}
|
||||
|
||||
// perform a healthcheck test without requiring an ssh client or an ssh key (used for Docker's HEALTHCHECK)
|
||||
func healthcheck(c *cli.Context) error {
|
||||
config := gossh.ClientConfig{
|
||||
User: "healthcheck",
|
||||
HostKeyCallback: func(hostname string, remote net.Addr, key gossh.PublicKey) error { return nil },
|
||||
Auth: []gossh.AuthMethod{gossh.Password("healthcheck")},
|
||||
}
|
||||
client, err := gossh.Dial("tcp", c.String("addr"), &config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
session, err := client.NewSession()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err := session.Close(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
var b bytes.Buffer
|
||||
session.Stdout = &b
|
||||
if err := session.Run(""); err != nil {
|
||||
return err
|
||||
}
|
||||
stdout := strings.TrimSpace(b.String())
|
||||
if stdout != "OK" {
|
||||
return fmt.Errorf("invalid stdout: %q expected 'OK'", stdout)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue