pico

created pr with 84.1 on 2025-12-01T05:25:52Z · by c8ef7d19
added 84.2 on 2025-12-13T00:51:45Z · by c8ef7d19
1: 659964e ! 1: af4cda9 feat: access control using ssh certs
-: ------- > 2: d9a74df chore: logging and cleanup
added 84.3 on 2025-12-13T02:02:13Z · by c8ef7d19
1: af4cda9 < -: ------- feat: access control using ssh certs
2: d9a74df ! 1: bb8ef88 feat: access control using ssh certs
cmds
checkout latest patchset:
ssh pr.pico.sh print 84 | git am -3
checkout any patchset in a patch request:
ssh pr.pico.sh print 84.[rev] | git am -3
add changes to patch request:
git format-patch main --stdout | ssh pr.pico.sh pr add 84
+1 -1 pkg/apps/feeds/ssh.go #
......@@ -46,7 +46,7 @@ func StartSshServer() {
4646 }
4747 handler := filehandlers.NewFileHandlerRouter(cfg, dbh, fileMap)
4848
49- sshAuth := shared.NewSshAuthHandler(dbh, logger)
49+ sshAuth := shared.NewSshAuthHandler(dbh, logger, "feeds")
5050
5151 // Create a new SSH server
5252 server, err := pssh.NewSSHServerWithConfig(
+1 -1 pkg/apps/pastes/ssh.go #
......@@ -45,7 +45,7 @@ func StartSshServer() {
4545 "fallback": filehandlers.NewScpPostHandler(dbh, cfg, hooks),
4646 }
4747 handler := filehandlers.NewFileHandlerRouter(cfg, dbh, fileMap)
48- sshAuth := shared.NewSshAuthHandler(dbh, logger)
48+ sshAuth := shared.NewSshAuthHandler(dbh, logger, "pastes")
4949
5050 // Create a new SSH server
5151 server, err := pssh.NewSSHServerWithConfig(
+1 -1 pkg/apps/pgs/ssh.go #
......@@ -34,7 +34,7 @@ func StartSshServer(cfg *PgsConfig, killCh chan error) {
3434 ctx,
3535 )
3636
37- sshAuth := shared.NewSshAuthHandler(cfg.DB, logger)
37+ sshAuth := shared.NewSshAuthHandler(cfg.DB, logger, "pgs")
3838
3939 webTunnel := &tunkit.WebTunnelHandler{
4040 Logger: logger,
+3 -2 pkg/apps/pico/ssh.go #
......@@ -64,7 +64,7 @@ func StartSshServer() {
6464 DBPool: dbpool,
6565 }
6666
67- sshAuth := shared.NewSshAuthHandler(dbpool, logger)
67+ sshAuth := shared.NewSshAuthHandler(dbpool, logger, "pico")
6868
6969 // Create a new SSH server
7070 server, err := pssh.NewSSHServerWithConfig(
......@@ -76,7 +76,8 @@ func StartSshServer() {
7676 promPort,
7777 "ssh_data/term_info_ed25519",
7878 func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
79- perms, _ := sshAuth.PubkeyAuthHandler(conn, key)
79+ perms, err := sshAuth.PubkeyAuthHandler(conn, key)
80+ logger.Warn("pubkey auth handler", "err", err)
8081 if perms == nil {
8182 perms = &ssh.Permissions{
8283 Extensions: map[string]string{
+1 -1 pkg/apps/pipe/ssh.go #
......@@ -46,7 +46,7 @@ func StartSshServer() {
4646 Access: syncmap.New[string, []string](),
4747 }
4848
49- sshAuth := shared.NewSshAuthHandler(dbh, logger)
49+ sshAuth := shared.NewSshAuthHandler(dbh, logger, "pipe")
5050
5151 // Create a new SSH server
5252 server, err := pssh.NewSSHServerWithConfig(
+1 -1 pkg/apps/prose/ssh.go #
......@@ -59,7 +59,7 @@ func StartSshServer() {
5959 }
6060 handler := filehandlers.NewFileHandlerRouter(cfg, dbh, fileMap)
6161
62- sshAuth := shared.NewSshAuthHandler(dbh, logger)
62+ sshAuth := shared.NewSshAuthHandler(dbh, logger, "prose")
6363
6464 // Create a new SSH server
6565 server, err := pssh.NewSSHServerWithConfig(
+47 -9 pkg/shared/ssh.go #
......@@ -4,6 +4,7 @@ import (
44 "fmt"
55 "log/slog"
66 "strings"
7+ "time"
78
89 "github.com/picosh/pico/pkg/db"
910 "github.com/picosh/utils"
......@@ -13,8 +14,9 @@ import (
1314 const adminPrefix = "admin__"
1415
1516 type SshAuthHandler struct {
16- DB AuthFindUser
17- Logger *slog.Logger
17+ DB AuthFindUser
18+ Logger *slog.Logger
19+ Principal string
1820 }
1921
2022 type AuthFindUser interface {
......@@ -23,18 +25,54 @@ type AuthFindUser interface {
2325 FindFeature(userID, name string) (*db.FeatureFlag, error)
2426 }
2527
26-func NewSshAuthHandler(dbh AuthFindUser, logger *slog.Logger) *SshAuthHandler {
28+func NewSshAuthHandler(dbh AuthFindUser, logger *slog.Logger, principal string) *SshAuthHandler {
2729 return &SshAuthHandler{
28- DB: dbh,
29- Logger: logger,
30+ DB: dbh,
31+ Logger: logger,
32+ Principal: principal,
3033 }
3134 }
3235
3336 func (r *SshAuthHandler) PubkeyAuthHandler(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
34- pubkey := utils.KeyForKeyText(key)
35- user, err := r.DB.FindUserByPubkey(pubkey)
37+ log := r.Logger
38+ var user *db.User
39+ var err error
40+ pubkey := ""
41+
42+ cert, ok := key.(*ssh.Certificate)
43+ if ok {
44+ if cert.CertType != ssh.UserCert {
45+ return nil, fmt.Errorf("ssh-cert has type %d", cert.CertType)
46+ }
47+
48+ found := false
49+ for _, princ := range cert.ValidPrincipals {
50+ if princ == "admin" || princ == r.Principal {
51+ found = true
52+ break
53+ }
54+ }
55+ if !found {
56+ return nil, fmt.Errorf("ssh-cert principals not valid")
57+ }
58+
59+ clock := time.Now
60+ unixNow := clock().Unix()
61+ if after := int64(cert.ValidAfter); after < 0 || unixNow < int64(cert.ValidAfter) {
62+ return nil, fmt.Errorf("ssh-cert is not yet valid")
63+ }
64+ if before := int64(cert.ValidBefore); cert.ValidBefore != uint64(ssh.CertTimeInfinity) && (unixNow >= before || before < 0) {
65+ return nil, fmt.Errorf("ssh-cert has expired")
66+ }
67+
68+ pubkey = utils.KeyForKeyText(cert.SignatureKey)
69+ } else {
70+ pubkey = utils.KeyForKeyText(key)
71+ }
72+
73+ user, err = r.DB.FindUserByPubkey(pubkey)
3674 if err != nil {
37- r.Logger.Error(
75+ log.Error(
3876 "could not find user for key",
3977 "keyType", key.Type(),
4078 "key", string(key.Marshal()),
......@@ -44,7 +82,7 @@ func (r *SshAuthHandler) PubkeyAuthHandler(conn ssh.ConnMetadata, key ssh.Public
4482 }
4583
4684 if user.Name == "" {
47- r.Logger.Error("username is not set")
85+ log.Error("username is not set")
4886 return nil, fmt.Errorf("username is not set")
4987 }
5088
Back to top