Refactor SSH init code, fix directory creation for TrustedUserCAKeys file (#20299)
* Refactor SSH init code, fix directory creation for TrustedUserCAKeys file * Update modules/ssh/init.go Co-authored-by: zeripath <art27@cantab.net> * fix lint copyright * Update modules/ssh/init.go Co-authored-by: zeripath <art27@cantab.net> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
This commit is contained in:
parent
a9e66cfdad
commit
27e2def5f0
4 changed files with 63 additions and 29 deletions
|
@ -840,8 +840,9 @@ func loadFromConf(allowEmpty bool, extraConfig string) {
|
||||||
SSH.StartBuiltinServer = false
|
SSH.StartBuiltinServer = false
|
||||||
}
|
}
|
||||||
|
|
||||||
trustedUserCaKeys := sec.Key("SSH_TRUSTED_USER_CA_KEYS").Strings(",")
|
SSH.TrustedUserCAKeysFile = sec.Key("SSH_TRUSTED_USER_CA_KEYS_FILENAME").MustString(filepath.Join(SSH.RootPath, "gitea-trusted-user-ca-keys.pem"))
|
||||||
for _, caKey := range trustedUserCaKeys {
|
|
||||||
|
for _, caKey := range SSH.TrustedUserCAKeys {
|
||||||
pubKey, _, _, _, err := gossh.ParseAuthorizedKey([]byte(caKey))
|
pubKey, _, _, _, err := gossh.ParseAuthorizedKey([]byte(caKey))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Failed to parse TrustedUserCaKeys: %s %v", caKey, err)
|
log.Fatal("Failed to parse TrustedUserCaKeys: %s %v", caKey, err)
|
||||||
|
@ -849,7 +850,7 @@ func loadFromConf(allowEmpty bool, extraConfig string) {
|
||||||
|
|
||||||
SSH.TrustedUserCAKeysParsed = append(SSH.TrustedUserCAKeysParsed, pubKey)
|
SSH.TrustedUserCAKeysParsed = append(SSH.TrustedUserCAKeysParsed, pubKey)
|
||||||
}
|
}
|
||||||
if len(trustedUserCaKeys) > 0 {
|
if len(SSH.TrustedUserCAKeys) > 0 {
|
||||||
// Set the default as email,username otherwise we can leave it empty
|
// Set the default as email,username otherwise we can leave it empty
|
||||||
sec.Key("SSH_AUTHORIZED_PRINCIPALS_ALLOW").MustString("username,email")
|
sec.Key("SSH_AUTHORIZED_PRINCIPALS_ALLOW").MustString("username,email")
|
||||||
} else {
|
} else {
|
||||||
|
@ -858,20 +859,6 @@ func loadFromConf(allowEmpty bool, extraConfig string) {
|
||||||
|
|
||||||
SSH.AuthorizedPrincipalsAllow, SSH.AuthorizedPrincipalsEnabled = parseAuthorizedPrincipalsAllow(sec.Key("SSH_AUTHORIZED_PRINCIPALS_ALLOW").Strings(","))
|
SSH.AuthorizedPrincipalsAllow, SSH.AuthorizedPrincipalsEnabled = parseAuthorizedPrincipalsAllow(sec.Key("SSH_AUTHORIZED_PRINCIPALS_ALLOW").Strings(","))
|
||||||
|
|
||||||
if !SSH.Disabled && !SSH.StartBuiltinServer {
|
|
||||||
if err = os.MkdirAll(SSH.KeyTestPath, 0o644); err != nil {
|
|
||||||
log.Fatal("Failed to create '%s': %v", SSH.KeyTestPath, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(trustedUserCaKeys) > 0 && SSH.AuthorizedPrincipalsEnabled {
|
|
||||||
fname := sec.Key("SSH_TRUSTED_USER_CA_KEYS_FILENAME").MustString(filepath.Join(SSH.RootPath, "gitea-trusted-user-ca-keys.pem"))
|
|
||||||
if err := os.WriteFile(fname,
|
|
||||||
[]byte(strings.Join(trustedUserCaKeys, "\n")), 0o600); err != nil {
|
|
||||||
log.Fatal("Failed to create '%s': %v", fname, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SSH.MinimumKeySizeCheck = sec.Key("MINIMUM_KEY_SIZE_CHECK").MustBool(SSH.MinimumKeySizeCheck)
|
SSH.MinimumKeySizeCheck = sec.Key("MINIMUM_KEY_SIZE_CHECK").MustBool(SSH.MinimumKeySizeCheck)
|
||||||
minimumKeySizes := Cfg.Section("ssh.minimum_key_sizes").Keys()
|
minimumKeySizes := Cfg.Section("ssh.minimum_key_sizes").Keys()
|
||||||
for _, key := range minimumKeySizes {
|
for _, key := range minimumKeySizes {
|
||||||
|
|
55
modules/ssh/init.go
Normal file
55
modules/ssh/init.go
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package ssh
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Init() error {
|
||||||
|
if setting.SSH.Disabled {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if setting.SSH.StartBuiltinServer {
|
||||||
|
Listen(setting.SSH.ListenHost, setting.SSH.ListenPort, setting.SSH.ServerCiphers, setting.SSH.ServerKeyExchanges, setting.SSH.ServerMACs)
|
||||||
|
log.Info("SSH server started on %s. Cipher list (%v), key exchange algorithms (%v), MACs (%v)",
|
||||||
|
net.JoinHostPort(setting.SSH.ListenHost, strconv.Itoa(setting.SSH.ListenPort)),
|
||||||
|
setting.SSH.ServerCiphers, setting.SSH.ServerKeyExchanges, setting.SSH.ServerMACs,
|
||||||
|
)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
builtinUnused()
|
||||||
|
|
||||||
|
// FIXME: why 0o644 for a directory .....
|
||||||
|
if err := os.MkdirAll(setting.SSH.KeyTestPath, 0o644); err != nil {
|
||||||
|
return fmt.Errorf("failed to create directory %q for ssh key test: %w", setting.SSH.KeyTestPath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(setting.SSH.TrustedUserCAKeys) > 0 && setting.SSH.AuthorizedPrincipalsEnabled {
|
||||||
|
caKeysFileName := setting.SSH.TrustedUserCAKeysFile
|
||||||
|
caKeysFileDir := filepath.Dir(caKeysFileName)
|
||||||
|
|
||||||
|
err := os.MkdirAll(caKeysFileDir, 0o700) // SSH.RootPath by default (That is `~/.ssh` in most cases)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create directory %q for ssh trusted ca keys: %w", caKeysFileDir, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.WriteFile(caKeysFileName, []byte(strings.Join(setting.SSH.TrustedUserCAKeys, "\n")), 0o600); err != nil {
|
||||||
|
return fmt.Errorf("failed to write ssh trusted ca keys to %q: %w", caKeysFileName, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -29,7 +29,7 @@ func listen(server *ssh.Server) {
|
||||||
log.Info("SSH Listener: %s Closed", server.Addr)
|
log.Info("SSH Listener: %s Closed", server.Addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unused informs our cleanup routine that we will not be using a ssh port
|
// builtinUnused informs our cleanup routine that we will not be using a ssh port
|
||||||
func Unused() {
|
func builtinUnused() {
|
||||||
graceful.GetManager().InformCleanup()
|
graceful.GetManager().InformCleanup()
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,10 +6,8 @@ package routers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
asymkey_model "code.gitea.io/gitea/models/asymkey"
|
asymkey_model "code.gitea.io/gitea/models/asymkey"
|
||||||
|
@ -158,14 +156,8 @@ func GlobalInitInstalled(ctx context.Context) {
|
||||||
|
|
||||||
mustInitCtx(ctx, syncAppPathForGit)
|
mustInitCtx(ctx, syncAppPathForGit)
|
||||||
|
|
||||||
if setting.SSH.StartBuiltinServer {
|
mustInit(ssh.Init)
|
||||||
ssh.Listen(setting.SSH.ListenHost, setting.SSH.ListenPort, setting.SSH.ServerCiphers, setting.SSH.ServerKeyExchanges, setting.SSH.ServerMACs)
|
|
||||||
log.Info("SSH server started on %s. Cipher list (%v), key exchange algorithms (%v), MACs (%v)",
|
|
||||||
net.JoinHostPort(setting.SSH.ListenHost, strconv.Itoa(setting.SSH.ListenPort)),
|
|
||||||
setting.SSH.ServerCiphers, setting.SSH.ServerKeyExchanges, setting.SSH.ServerMACs)
|
|
||||||
} else {
|
|
||||||
ssh.Unused()
|
|
||||||
}
|
|
||||||
auth.Init()
|
auth.Init()
|
||||||
svg.Init()
|
svg.Init()
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue