From 763ced752456a48b7954965f8780d83e7f374084 Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Sat, 4 Jul 2020 21:31:28 +0200 Subject: [PATCH] feat: host logging modes (disabled, commands, everything) Signed-off-by: Manfred Touron <94029+moul@users.noreply.github.com> --- .gitignore | 3 +- Makefile | 1 + README.md | 4 +- go.mod | 3 +- go.sum | 8 +--- main.go | 1 + pkg/bastion/dbinit.go | 42 ++++++++++++++++---- pkg/bastion/session.go | 82 ++++++++++++++++++++++++++------------- pkg/bastion/shell.go | 21 +++++++++- pkg/bastion/ssh.go | 3 +- pkg/dbmodels/dbmodels.go | 1 + pkg/dbmodels/validator.go | 14 +++++++ 12 files changed, 136 insertions(+), 47 deletions(-) diff --git a/.gitignore b/.gitignore index b0e1bc9..0eeb82e 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ dist/ /log/ /sshportal *.db -/data \ No newline at end of file +/data +sshportal.history \ No newline at end of file diff --git a/Makefile b/Makefile index 4f3fd21..679f302 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,7 @@ DOCKER_IMAGE ?= moul/sshportal VERSION ?= `git describe --tags --always` VCS_REF ?= `git rev-parse --short HEAD` GO_INSTALL_OPTS = -ldflags="-X main.GitSha=$(VCS_REF) -X main.GitTag=$(VERSION)" +PORT ?= 2222 include rules.mk diff --git a/README.md b/README.md index 025a46e..08c381f 100644 --- a/README.md +++ b/README.md @@ -326,11 +326,11 @@ event inspect [-h] EVENT... # host management host help -host create [-h] [--name=] [--password=] [--comment=] [--key=KEY] [--group=HOSTGROUP...] [--hop=HOST] [:]@[:] +host create [-h] [--name=] [--password=] [--comment=] [--key=KEY] [--group=HOSTGROUP...] [--hop=HOST] [--logging=MODE] [:]@[:] host inspect [-h] [--decrypt] HOST... host ls [-h] [--latest] [--quiet] host rm [-h] HOST... -host update [-h] [--name=] [--comment=] [--key=KEY] [--assign-group=HOSTGROUP...] [--unassign-group=HOSTGROUP...] [--set-hop=HOST] [--unset-hop] HOST... +host update [-h] [--name=] [--comment=] [--key=KEY] [--assign-group=HOSTGROUP...] [--unassign-group=HOSTGROUP...] [--logging-MODE] [--set-hop=HOST] [--unset-hop] HOST... # hostgroup management hostgroup help diff --git a/go.mod b/go.mod index 675d97f..b5b6974 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/docker/docker v1.13.1 github.com/dustin/go-humanize v1.0.0 github.com/gliderlabs/ssh v0.3.0 - github.com/go-sql-driver/mysql v1.5.0 // indirect + github.com/go-sql-driver/mysql v1.5.0 github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e // indirect github.com/jinzhu/gorm v1.9.14 github.com/kr/pty v1.1.8 @@ -18,6 +18,7 @@ require ( github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b github.com/olekukonko/tablewriter v0.0.4 + 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 github.com/sabban/bastion v0.0.0-20180110125408-b9d3c9b1f4d3 diff --git a/go.sum b/go.sum index e881843..d70f02d 100644 --- a/go.sum +++ b/go.sum @@ -43,8 +43,6 @@ github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1 github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/jinzhu/gorm v1.9.2 h1:lCvgEaqe/HVE+tjAR2mt4HbbHAZsQOv3XAZiEZV37iw= github.com/jinzhu/gorm v1.9.2/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo= -github.com/jinzhu/gorm v1.9.12 h1:Drgk1clyWT9t9ERbzHza6Mj/8FY/CqMyVzOiHviMo6Q= -github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs= github.com/jinzhu/gorm v1.9.14 h1:Kg3ShyTPcM6nzVo148fRrcMO6MNKuqtOUwnzqMgVniM= github.com/jinzhu/gorm v1.9.14/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs= github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a h1:eeaG9XMUvRBYXJi4pg1ZKM7nxc5AfXfojeLLW7O5J3k= @@ -75,13 +73,14 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= -github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U= github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8= github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/reiver/go-oi v1.0.0 h1:nvECWD7LF+vOs8leNGV/ww+F2iZKf3EYjYZ527turzM= @@ -108,8 +107,6 @@ golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 h1:vEg9joUBmeBcK9iSJftGNf3coIG4HqZElCPehJsfAYM= -golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -128,7 +125,6 @@ golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/gormigrate.v1 v1.6.0 h1:XpYM6RHQPmzwY7Uyu+t+xxMXc86JYFJn4nEc9HzQjsI= gopkg.in/gormigrate.v1 v1.6.0/go.mod h1:Lf00lQrHqfSYWiTtPcyQabsDdM6ejZaMgV0OU6JMSlw= diff --git a/main.go b/main.go index f5f20be..a0daf7e 100644 --- a/main.go +++ b/main.go @@ -6,6 +6,7 @@ import ( "os" "path" + _ "github.com/go-sql-driver/mysql" _ "github.com/jinzhu/gorm/dialects/mysql" _ "github.com/jinzhu/gorm/dialects/sqlite" "github.com/urfave/cli" diff --git a/pkg/bastion/dbinit.go b/pkg/bastion/dbinit.go index 0ff46cc..6be4773 100644 --- a/pkg/bastion/dbinit.go +++ b/pkg/bastion/dbinit.go @@ -40,7 +40,6 @@ func DBInit(db *gorm.DB) error { ID: "2", Migrate: func(tx *gorm.DB) error { type SSHKey struct { - // FIXME: use uuid for ID gorm.Model Name string Type string @@ -60,7 +59,6 @@ func DBInit(db *gorm.DB) error { ID: "3", Migrate: func(tx *gorm.DB) error { type Host struct { - // FIXME: use uuid for ID gorm.Model Name string `gorm:"size:32"` Addr string @@ -96,7 +94,6 @@ func DBInit(db *gorm.DB) error { ID: "5", Migrate: func(tx *gorm.DB) error { type User struct { - // FIXME: use uuid for ID gorm.Model IsAdmin bool Email string @@ -382,17 +379,16 @@ func DBInit(db *gorm.DB) error { ID: "25", Migrate: func(tx *gorm.DB) error { type Host struct { - // FIXME: use uuid for ID gorm.Model Name string `gorm:"size:32" valid:"required,length(1|32),unix_user"` Addr string `valid:"required"` User string `valid:"optional"` Password string `valid:"optional"` - SSHKey *dbmodels.SSHKey `gorm:"ForeignKey:SSHKeyID"` // SSHKey used to connect by the client + SSHKey *dbmodels.SSHKey `gorm:"ForeignKey:SSHKeyID"` SSHKeyID uint `gorm:"index"` HostKey []byte `sql:"size:10000" valid:"optional"` Groups []*dbmodels.HostGroup `gorm:"many2many:host_host_groups;"` - Fingerprint string `valid:"optional"` // FIXME: replace with hostKey ? + Fingerprint string `valid:"optional"` Comment string `valid:"optional"` } return tx.AutoMigrate(&Host{}).Error @@ -443,7 +439,6 @@ func DBInit(db *gorm.DB) error { ID: "28", Migrate: func(tx *gorm.DB) error { type Host struct { - // FIXME: use uuid for ID gorm.Model Name string `gorm:"size:32"` Addr string @@ -465,7 +460,6 @@ func DBInit(db *gorm.DB) error { ID: "29", Migrate: func(tx *gorm.DB) error { type Host struct { - // FIXME: use uuid for ID gorm.Model Name string `gorm:"size:32"` Addr string @@ -485,6 +479,38 @@ func DBInit(db *gorm.DB) error { Rollback: func(tx *gorm.DB) error { return fmt.Errorf("not implemented") }, + }, { + ID: "30", + Migrate: func(tx *gorm.DB) error { + type Host struct { + gorm.Model + Name string `gorm:"size:32"` + Addr string + User string + Password string + URL string + SSHKey *dbmodels.SSHKey `gorm:"ForeignKey:SSHKeyID"` + SSHKeyID uint `gorm:"index"` + HostKey []byte `sql:"size:10000"` + Groups []*dbmodels.HostGroup `gorm:"many2many:host_host_groups;"` + Comment string + Hop *dbmodels.Host + Logging string + HopID uint + } + return tx.AutoMigrate(&Host{}).Error + }, + Rollback: func(tx *gorm.DB) error { + return fmt.Errorf("not implemented") + }, + }, { + ID: "31", + Migrate: func(tx *gorm.DB) error { + return tx.Model(&dbmodels.Host{}).Updates(&dbmodels.Host{Logging: "everything"}).Error + }, + Rollback: func(tx *gorm.DB) error { + return fmt.Errorf("not implemented") + }, }, }) if err := m.Migrate(); err != nil { diff --git a/pkg/bastion/session.go b/pkg/bastion/session.go index fb40731..8a4c6a3 100644 --- a/pkg/bastion/session.go +++ b/pkg/bastion/session.go @@ -3,20 +3,23 @@ package bastion // import "moul.io/sshportal/pkg/bastion" import ( "fmt" "io" + "io/ioutil" "log" "os" - "strings" + "path/filepath" "time" "github.com/gliderlabs/ssh" + "github.com/pkg/errors" "github.com/sabban/bastion/pkg/logchannel" gossh "golang.org/x/crypto/ssh" ) type sessionConfig struct { Addr string - Logs string + LogsLocation string ClientConfig *gossh.ClientConfig + LoggingMode string } func multiChannelHandler(conn *gossh.ServerConn, newChan gossh.NewChannel, ctx ssh.Context, configs []sessionConfig, sessionID uint) error { @@ -62,7 +65,7 @@ func multiChannelHandler(conn *gossh.ServerConn, newChan gossh.NewChannel, ctx s actx := ctx.Value(authContextKey).(*authContext) username := actx.user.Name // pipe everything - return pipe(lreqs, rreqs, lch, rch, configs[len(configs)-1].Logs, user, username, sessionID, newChan) + return pipe(lreqs, rreqs, lch, rch, configs[len(configs)-1], user, username, sessionID, newChan) case "direct-tcpip": lch, lreqs, err := newChan.Accept() // TODO: defer clean closer @@ -107,7 +110,7 @@ func multiChannelHandler(conn *gossh.ServerConn, newChan gossh.NewChannel, ctx s actx := ctx.Value(authContextKey).(*authContext) username := actx.user.Name // pipe everything - return pipe(lreqs, rreqs, lch, rch, configs[len(configs)-1].Logs, user, username, sessionID, newChan) + return pipe(lreqs, rreqs, lch, rch, configs[len(configs)-1], user, username, sessionID, newChan) default: if err := newChan.Reject(gossh.UnknownChannelType, "unsupported channel type"); err != nil { log.Printf("failed to reject chan: %v", err) @@ -116,7 +119,7 @@ func multiChannelHandler(conn *gossh.ServerConn, newChan gossh.NewChannel, ctx s } } -func pipe(lreqs, rreqs <-chan *gossh.Request, lch, rch gossh.Channel, logsLocation string, user string, username string, sessionID uint, newChan gossh.NewChannel) error { +func pipe(lreqs, rreqs <-chan *gossh.Request, lch, rch gossh.Channel, sessConfig sessionConfig, user string, username string, sessionID uint, newChan gossh.NewChannel) error { defer func() { _ = lch.Close() _ = rch.Close() @@ -126,36 +129,51 @@ func pipe(lreqs, rreqs <-chan *gossh.Request, lch, rch gossh.Channel, logsLocati quit := make(chan string, 1) channeltype := newChan.ChannelType() - filename := strings.Join([]string{logsLocation, "/", user, "-", username, "-", channeltype, "-", fmt.Sprint(sessionID), "-", time.Now().Format(time.RFC3339)}, "") // get user - f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0440) - defer func() { - _ = f.Close() - }() - - if err != nil { - log.Fatalf("error: %v", err) + var logWriter io.WriteCloser = newDiscardWriteCloser() + if sessConfig.LoggingMode != "disabled" { + filename := filepath.Join(sessConfig.LogsLocation, fmt.Sprintf("%s-%s-%s-%d-%s", user, username, channeltype, sessionID, time.Now().Format(time.RFC3339))) + f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0440) + if err != nil { + return errors.Wrap(err, "open log file") + } + defer func() { + _ = f.Close() + }() + log.Printf("Session %v is recorded in %v", channeltype, filename) + logWriter = f } - log.Printf("Session %v is recorded in %v", channeltype, filename) if channeltype == "session" { - wrappedlch := logchannel.New(lch, f) - go func(quit chan string) { - _, _ = io.Copy(wrappedlch, rch) - quit <- "rch" - }(quit) - - go func(quit chan string) { - _, _ = io.Copy(rch, lch) - quit <- "lch" - }(quit) + switch sessConfig.LoggingMode { + case "input": + wrappedrch := logchannel.New(rch, logWriter) + go func(quit chan string) { + _, _ = io.Copy(lch, rch) + quit <- "rch" + }(quit) + go func(quit chan string) { + _, _ = io.Copy(wrappedrch, lch) + quit <- "lch" + }(quit) + default: // everything, disabled + wrappedlch := logchannel.New(lch, logWriter) + go func(quit chan string) { + _, _ = io.Copy(wrappedlch, rch) + quit <- "rch" + }(quit) + go func(quit chan string) { + _, _ = io.Copy(rch, lch) + quit <- "lch" + }(quit) + } } if channeltype == "direct-tcpip" { d := logTunnelForwardData{} if err := gossh.Unmarshal(newChan.ExtraData(), &d); err != nil { return err } - wrappedlch := newLogTunnel(lch, f, d.SourceHost) - wrappedrch := newLogTunnel(rch, f, d.DestinationHost) + wrappedlch := newLogTunnel(lch, logWriter, d.SourceHost) + wrappedrch := newLogTunnel(rch, logWriter, d.DestinationHost) go func(quit chan string) { _, _ = io.Copy(wrappedlch, rch) quit <- "rch" @@ -171,7 +189,7 @@ func pipe(lreqs, rreqs <-chan *gossh.Request, lch, rch gossh.Channel, logsLocati for req := range lreqs { b, err := rch.SendRequest(req.Type, req.WantReply, req.Payload) if req.Type == "exec" { - wrappedlch := logchannel.New(lch, f) + wrappedlch := logchannel.New(lch, logWriter) command := append(req.Payload, []byte("\n")...) if _, err := wrappedlch.LogWrite(command); err != nil { log.Printf("failed to write log: %v", err) @@ -234,3 +252,13 @@ func pipe(lreqs, rreqs <-chan *gossh.Request, lch, rch gossh.Channel, logsLocati } } } + +func newDiscardWriteCloser() io.WriteCloser { return &discardWriteCloser{ioutil.Discard} } + +type discardWriteCloser struct { + io.Writer +} + +func (discardWriteCloser) Close() error { + return nil +} diff --git a/pkg/bastion/shell.go b/pkg/bastion/shell.go index 6d12893..24b8531 100644 --- a/pkg/bastion/shell.go +++ b/pkg/bastion/shell.go @@ -672,6 +672,7 @@ GLOBAL OPTIONS: cli.StringFlag{Name: "comment, c"}, 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.StringSliceFlag{Name: "group, g", Usage: "Assigns the host to `HOSTGROUPS` (default: \"default\")"}, }, Action: func(c *cli.Context) error { @@ -714,6 +715,11 @@ GLOBAL OPTIONS: if c.String("name") != "" { host.Name = c.String("name") } + + host.Logging = "everything" // default is everything + if c.String("logging") != "" { + host.Logging = c.String("logging") + } // FIXME: check if name already exists if _, err := govalidator.ValidateStruct(host); err != nil { @@ -819,7 +825,7 @@ GLOBAL OPTIONS: } table := tablewriter.NewWriter(s) - table.SetHeader([]string{"ID", "Name", "URL", "Key", "Groups", "Updated", "Created", "Comment", "Hop"}) + table.SetHeader([]string{"ID", "Name", "URL", "Key", "Groups", "Updated", "Created", "Comment", "Hop", "Logging"}) table.SetBorder(false) table.SetCaption(true, fmt.Sprintf("Total: %d hosts.", len(hosts))) for _, host := range hosts { @@ -851,6 +857,7 @@ GLOBAL OPTIONS: humanize.Time(host.CreatedAt), host.Comment, hop, + host.Logging, //FIXME: add some stats about last access time etc }) } @@ -882,6 +889,7 @@ GLOBAL OPTIONS: cli.StringFlag{Name: "comment, c", Usage: "Update/set a host comment"}, 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.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`"}, @@ -944,6 +952,17 @@ GLOBAL OPTIONS: } } + // logging + if logging := c.String("logging"); logging != "" { + if !dbmodels.IsValidHostLoggingMode(logging) { + return fmt.Errorf("invalid host logging mode: %q", logging) + } + if err := model.Update("logging", logging).Error; err != nil { + tx.Rollback() + return err + } + } + // remove the hop if c.Bool("unset-hop") { var hopHost dbmodels.Host diff --git a/pkg/bastion/ssh.go b/pkg/bastion/ssh.go index c81cc02..33b4a6f 100644 --- a/pkg/bastion/ssh.go +++ b/pkg/bastion/ssh.go @@ -122,7 +122,8 @@ func ChannelHandler(srv *ssh.Server, conn *gossh.ServerConn, newChan gossh.NewCh sessionConfigs = append([]sessionConfig{{ Addr: currentHost.DialAddr(), ClientConfig: clientConfig, - Logs: actx.logsLocation, + LogsLocation: actx.logsLocation, + LoggingMode: currentHost.Logging, }}, sessionConfigs...) if currentHost.HopID != 0 { var newHost dbmodels.Host diff --git a/pkg/dbmodels/dbmodels.go b/pkg/dbmodels/dbmodels.go index d5198cb..7e51d35 100644 --- a/pkg/dbmodels/dbmodels.go +++ b/pkg/dbmodels/dbmodels.go @@ -61,6 +61,7 @@ type Host struct { HostKey []byte `sql:"size:10000" valid:"optional"` Groups []*HostGroup `gorm:"many2many:host_host_groups;"` Comment string `valid:"optional"` + Logging string `valid:"optional,host_logging_mode"` Hop *Host HopID uint } diff --git a/pkg/dbmodels/validator.go b/pkg/dbmodels/validator.go index 7dd0efa..e9cbd4d 100644 --- a/pkg/dbmodels/validator.go +++ b/pkg/dbmodels/validator.go @@ -16,4 +16,18 @@ func InitValidator() { } return unixUserRegexp.MatchString(name) })) + govalidator.CustomTypeTagMap.Set("host_logging_mode", govalidator.CustomTypeValidator(func(i interface{}, context interface{}) bool { + name, ok := i.(string) + if !ok { + return false + } + if name == "" { + return true + } + return IsValidHostLoggingMode(name) + })) +} + +func IsValidHostLoggingMode(name string) bool { + return name == "disabled" || name == "input" || name == "everything" }