dashboard / erock/tuns / feat: metric drain #34 rss

accepted · opened on 2024-11-13T02:18:51Z by erock
Help
checkout latest patchset:
ssh pr.pico.sh print pr-34 | git am -3
checkout any patchset in a patch request:
ssh pr.pico.sh print ps-X | git am -3
add changes to patch request:
git format-patch main --stdout | ssh pr.pico.sh pr add 34
add review to patch request:
git format-patch main --stdout | ssh pr.pico.sh pr add --review 34
accept PR:
ssh pr.pico.sh pr accept 34
close PR:
ssh pr.pico.sh pr close 34

Logs

erock created pr with ps-69 on 2024-11-13T02:18:51Z
erock added ps-70 on 2024-11-14T03:06:46Z
erock added ps-71 on 2024-11-14T03:22:31Z
erock changed status on 2024-11-23T03:33:38Z {"status":"accepted"}

Patchsets

ps-69 by erock on 2024-11-13T02:18:51Z
Range Diff ↕ rd-70
1: 4bd8050 = 1: 4bd8050 feat: metric drain
-: ------- > 2: ea49338 chore: add userId to metric drain visit
ps-70 by erock on 2024-11-14T03:06:46Z
Range Diff ↕ rd-71
1: 4bd8050 = 1: 4bd8050 feat: metric drain
2: ea49338 = 2: ea49338 chore: add userId to metric drain visit
-: ------- > 3: 343f29e chore: update pubsub
ps-71 by erock on 2024-11-14T03:22:31Z

Patchset ps-71

feat: metric drain

Eric Bower
2024-11-13T02:16:16Z
Makefile
+4 -0
cmd/sish.go
+7 -2
go.mod
+2 -0
utils/conn.go
+10 -0

chore: add userId to metric drain visit

Eric Bower
2024-11-14T03:05:56Z

chore: update pubsub

Eric Bower
2024-11-14T03:21:06Z
go.mod
+1 -3
go.sum
+2 -2
Back to top

feat: metric drain

This change will enable http remote forwards to have site analytics
enabled automatically.
Makefile link
+4 -0
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
diff --git a/Makefile b/Makefile
index 8b36002..31e617e 100644
--- a/Makefile
+++ b/Makefile
@@ -19,3 +19,7 @@ docs-prod: ssg
 dev:
 	go run main.go --http-address localhost:3000 --domain testing.ssi.sh
 .PHONY: dev
+
+fmt:
+	go fmt ./...
+.PHONY: fmt
cmd/sish.go link
+7 -2
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
diff --git a/cmd/sish.go b/cmd/sish.go
index 159f02e..bba3f45 100644
--- a/cmd/sish.go
+++ b/cmd/sish.go
@@ -17,6 +17,7 @@ import (
 	"github.com/spf13/viper"
 	"gopkg.in/natefinch/lumberjack.v2"
 
+	"github.com/picosh/pubsub"
 	pipeLogger "github.com/picosh/pubsub/log"
 	picoUtils "github.com/picosh/utils"
 )
@@ -206,17 +207,21 @@ func initConfig() {
 		slog.NewTextHandler(multiWriter, &slog.HandlerOptions{AddSource: true, Level: logLevel}),
 	)
 
-	realLogger, err := pipeLogger.SendLogRegister(logger, &pipeLogger.PubSubConnectionInfo{
+	info := &pubsub.RemoteClientInfo{
 		RemoteHost:     picoUtils.GetEnv("PICO_PIPE_ENDPOINT", "send.pico.sh:22"),
 		KeyLocation:    picoUtils.GetEnv("PICO_PIPE_KEY", "ssh_data/term_info_ed25519"),
 		KeyPassphrase:  picoUtils.GetEnv("PICO_PIPE_PASSPHRASE", ""),
 		RemoteHostname: picoUtils.GetEnv("PICO_PIPE_REMOTE_HOST", "send.pico.sh"),
 		RemoteUser:     picoUtils.GetEnv("PICO_PIPE_USER", "pico"),
-	}, 100)
+	}
+	realLogger, err := pipeLogger.SendLogRegister(logger, info, 100)
 	if err != nil {
 		slog.Error("unable to set real logger", slog.Any("error", err))
 	}
 
+	metricDrain := pubsub.NewRemoteClientWriter(info, logger, 100)
+	go metricDrain.KeepAlive("pub metric-drain -b=false")
+
 	trueLogger := logger
 
 	if realLogger != nil {
go.mod link
+2 -0
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
diff --git a/go.mod b/go.mod
index 32259c2..043199f 100644
--- a/go.mod
+++ b/go.mod
@@ -2,6 +2,8 @@ module github.com/antoniomika/sish
 
 go 1.23.1
 
+replace github.com/picosh/pubsub => /home/erock/dev/pico/pubsub
+
 require (
 	github.com/ScaleFT/sshkeys v1.2.0
 	github.com/antoniomika/multilistener v0.0.0-20240307222635-f0dc097d8acc
httpmuxer/httpmuxer.go link
+28 -0
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
diff --git a/httpmuxer/httpmuxer.go b/httpmuxer/httpmuxer.go
index 7ab9094..1888123 100644
--- a/httpmuxer/httpmuxer.go
+++ b/httpmuxer/httpmuxer.go
@@ -31,6 +31,16 @@ import (
 	"github.com/gin-gonic/gin"
 )
 
+type MetricDrainVisit struct {
+	UserID    string `json:"user_id"`
+	Host      string `json:"host"`
+	Path      string `json:"path"`
+	IpAddress string `json:"ip_adress"`
+	UserAgent string `json:"user_agent"`
+	Referer   string `json:"referer"`
+	Status    int    `json:"status"`
+}
+
 // Start initializes the HTTP service.
 func Start(state *utils.State) {
 	releaseMode := gin.ReleaseMode
@@ -106,6 +116,24 @@ func Start(state *utils.State) {
 			param.ErrorMessage,
 		)
 
+		visit := MetricDrainVisit{
+			UserID:    "",
+			Host:      param.Request.Host,
+			IpAddress: param.ClientIP,
+			Status:    param.StatusCode,
+			Path:      originalURI,
+			UserAgent: param.Request.UserAgent(),
+			Referer:   param.Request.Referer(),
+		}
+		data, err := json.Marshal(visit)
+		if err != nil {
+			slog.Error("could not json marshall visit record", "err", err)
+		}
+		_, err = state.MetricDrain.Write(data)
+		if err != nil {
+			slog.Error("could not send to visit to metric-drain", "err", err)
+		}
+
 		slog.Info(logLine)
 
 		if viper.GetBool("log-to-client") && param.Keys["httpHolder"] != nil {
sshmuxer/sshmuxer.go link
+13 -0
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
diff --git a/sshmuxer/sshmuxer.go b/sshmuxer/sshmuxer.go
index e200bb7..1a6c014 100644
--- a/sshmuxer/sshmuxer.go
+++ b/sshmuxer/sshmuxer.go
@@ -16,6 +16,8 @@ import (
 	"github.com/antoniomika/sish/httpmuxer"
 	"github.com/antoniomika/sish/utils"
 	"github.com/antoniomika/syncmap"
+	"github.com/picosh/pubsub"
+	picoUtils "github.com/picosh/utils"
 	"github.com/pires/go-proxyproto"
 	"github.com/spf13/viper"
 	"golang.org/x/crypto/ssh"
@@ -70,10 +72,21 @@ func Start() {
 
 	utils.WatchKeys()
 
+	info := &pubsub.RemoteClientInfo{
+		RemoteHost:     picoUtils.GetEnv("PICO_PIPE_ENDPOINT", "send.pico.sh:22"),
+		KeyLocation:    picoUtils.GetEnv("PICO_PIPE_KEY", "ssh_data/term_info_ed25519"),
+		KeyPassphrase:  picoUtils.GetEnv("PICO_PIPE_PASSPHRASE", ""),
+		RemoteHostname: picoUtils.GetEnv("PICO_PIPE_REMOTE_HOST", "send.pico.sh"),
+		RemoteUser:     picoUtils.GetEnv("PICO_PIPE_USER", "pico"),
+	}
+	metricDrain := pubsub.NewRemoteClientWriter(info, slog.Default(), 100)
+	go metricDrain.KeepAlive("pub metric-drain -b=false")
+
 	state := utils.NewState()
 	state.Ports.HTTPPort = httpPort
 	state.Ports.HTTPSPort = httpsPort
 	state.Ports.SSHPort = sshPort
+	state.MetricDrain = metricDrain
 
 	state.Console.State = state
 
utils/conn.go link
+10 -0
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
diff --git a/utils/conn.go b/utils/conn.go
index 4ce0ebc..57ef9e6 100644
--- a/utils/conn.go
+++ b/utils/conn.go
@@ -99,6 +99,16 @@ func (s *SSHConnection) User() string {
 	return user
 }
 
+// User returns the user of the session, either using the extensions user or the passed user.
+func (s *SSHConnection) UserId() string {
+	user, ok := s.SSHConn.Permissions.Extensions["userId"]
+	if !ok {
+		user = ""
+	}
+
+	return user
+}
+
 // TeeConn represents a simple net.Conn interface for SNI Processing.
 type TeeConn struct {
 	Conn     net.Conn
utils/state.go link
+1 -0
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
diff --git a/utils/state.go b/utils/state.go
index 594c299..f27e201 100644
--- a/utils/state.go
+++ b/utils/state.go
@@ -231,6 +231,7 @@ type State struct {
 	ActiveConnections prometheus.GaugeFunc
 	ActiveTunnels     *prometheus.GaugeVec
 	ConnectionTime    *prometheus.GaugeVec
+	MetricDrain       io.Writer
 }
 
 // NewState returns a new State struct.
utils/utils.go link
+6 -0
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
diff --git a/utils/utils.go b/utils/utils.go
index 013c13c..aa3c403 100644
--- a/utils/utils.go
+++ b/utils/utils.go
@@ -597,7 +597,13 @@ func checkAuthenticationKeyRequest(authUrl string, authKey []byte, addr net.Addr
 			return false, extensionsInfo, nil
 		}
 
+		userId, ok := userData["id"].(string)
+		if !ok {
+			return false, extensionsInfo, nil
+		}
+
 		extensionsInfo["user"] = userName
+		extensionsInfo["userId"] = userId
 	}
 
 	return true, extensionsInfo, nil

chore: add userId to metric drain visit

chore: add user scope to http request log line
httpmuxer/httpmuxer.go link
+24 -19
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
diff --git a/httpmuxer/httpmuxer.go b/httpmuxer/httpmuxer.go
index 1888123..8bf5317 100644
--- a/httpmuxer/httpmuxer.go
+++ b/httpmuxer/httpmuxer.go
@@ -116,25 +116,30 @@ func Start(state *utils.State) {
 			param.ErrorMessage,
 		)
 
-		visit := MetricDrainVisit{
-			UserID:    "",
-			Host:      param.Request.Host,
-			IpAddress: param.ClientIP,
-			Status:    param.StatusCode,
-			Path:      originalURI,
-			UserAgent: param.Request.UserAgent(),
-			Referer:   param.Request.Referer(),
-		}
-		data, err := json.Marshal(visit)
-		if err != nil {
-			slog.Error("could not json marshall visit record", "err", err)
-		}
-		_, err = state.MetricDrain.Write(data)
-		if err != nil {
-			slog.Error("could not send to visit to metric-drain", "err", err)
-		}
-
-		slog.Info(logLine)
+		state.SSHConnections.Range(func(I string, conn *utils.SSHConnection) bool {
+			user := conn.User()
+			userId := conn.UserId()
+			slog.Info(logLine, "user", user, "userId", userId)
+
+			visit := MetricDrainVisit{
+				UserID:    userId,
+				Host:      param.Request.Host,
+				IpAddress: param.ClientIP,
+				Status:    param.StatusCode,
+				Path:      originalURI,
+				UserAgent: param.Request.UserAgent(),
+				Referer:   param.Request.Referer(),
+			}
+			data, err := json.Marshal(visit)
+			if err != nil {
+				slog.Error("could not json marshall visit record", "err", err)
+			}
+			_, err = state.MetricDrain.Write(data)
+			if err != nil {
+				slog.Error("could not send to visit to metric-drain", "err", err)
+			}
+			return true
+		})
 
 		if viper.GetBool("log-to-client") && param.Keys["httpHolder"] != nil {
 			currentListener := param.Keys["httpHolder"].(*utils.HTTPHolder)

chore: update pubsub

go.mod link
+1 -3
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
diff --git a/go.mod b/go.mod
index 043199f..3fad528 100644
--- a/go.mod
+++ b/go.mod
@@ -2,8 +2,6 @@ module github.com/antoniomika/sish
 
 go 1.23.1
 
-replace github.com/picosh/pubsub => /home/erock/dev/pico/pubsub
-
 require (
 	github.com/ScaleFT/sshkeys v1.2.0
 	github.com/antoniomika/multilistener v0.0.0-20240307222635-f0dc097d8acc
@@ -16,7 +14,7 @@ require (
 	github.com/logrusorgru/aurora v2.0.3+incompatible
 	github.com/mikesmitty/edkey v0.0.0-20170222072505-3356ea4e686a
 	github.com/picosh/pdocs v0.0.0-20240626184614-7aff67648d6e
-	github.com/picosh/pubsub v0.0.0-20241008010300-a63fd95dc8ed
+	github.com/picosh/pubsub v0.0.0-20241114025640-35db438302b4
 	github.com/picosh/utils v0.0.0-20241008004349-f48b50af554b
 	github.com/pires/go-proxyproto v0.7.0
 	github.com/prometheus/client_golang v1.20.2
go.sum link
+2 -2
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
diff --git a/go.sum b/go.sum
index fd2d443..611100f 100644
--- a/go.sum
+++ b/go.sum
@@ -136,8 +136,8 @@ github.com/phuslu/iploc v1.0.20240731 h1:4fLlMTe1bGrKfraWclGGC3WqndKzDv7xpKgVRvX
 github.com/phuslu/iploc v1.0.20240731/go.mod h1:VZqAWoi2A80YPvfk1AizLGHavNIG9nhBC8d87D/SeVs=
 github.com/picosh/pdocs v0.0.0-20240626184614-7aff67648d6e h1:SdfU2G7pMYi1pZd4khx/prmgfF5WZ0pRROhCpPMq0H4=
 github.com/picosh/pdocs v0.0.0-20240626184614-7aff67648d6e/go.mod h1:KXO3Z0EVdA811AX6mlK4lwFDT+KgmegRVrEmZU5uLXU=
-github.com/picosh/pubsub v0.0.0-20241008010300-a63fd95dc8ed h1:aBJeQoLvq/V3hX6bgWjuuTmGzgbPNYuuwaCWU4aSJcU=
-github.com/picosh/pubsub v0.0.0-20241008010300-a63fd95dc8ed/go.mod h1:ajolgob5MxlHdp5HllF7u3rTlCgER4InqfP7M/xl6HQ=
+github.com/picosh/pubsub v0.0.0-20241114025640-35db438302b4 h1:pITSRXb9NDGdC6AmuS3JE+8Ek4/pUG7tXJPP3cOaqf4=
+github.com/picosh/pubsub v0.0.0-20241114025640-35db438302b4/go.mod h1:m6ZZpg+lZB3XTIKlbSqQgi4NrBPtARv23b8vGYDoCo4=
 github.com/picosh/utils v0.0.0-20241008004349-f48b50af554b h1:PvWk8Y7JhC1bK4Ns7FUFfcvi+BGZ+K07wTA2VDTmfDQ=
 github.com/picosh/utils v0.0.0-20241008004349-f48b50af554b/go.mod h1:ftrp1FjbKK/mFnBAYGymA1QEtPlkA0+lWkPI5h0HKt4=
 github.com/pires/go-proxyproto v0.7.0 h1:IukmRewDQFWC7kfnb66CSomk2q/seBuilHBYFwyq0Hs=