0
0
mirror of https://github.com/go-gitea/gitea.git synced 2026-06-22 01:27:16 +02:00

auto ssghost key verification conf

This commit is contained in:
pomidorry 2026-05-17 01:59:44 +03:00
parent f7a5ac5cf2
commit 2ae1e055eb
3 changed files with 37 additions and 2 deletions

View File

@ -2717,6 +2717,12 @@ LEVEL = Info
;; Allow private addresses defined by RFC 1918, RFC 1122, RFC 4632 and RFC 4291 (false by default)
;; If a domain is allowed by ALLOWED_DOMAINS, this option will be ignored.
;ALLOW_LOCALNETWORKS = false
;;
;; SSH host key verification for SSH migrations and mirrors. One of:
;; "accept-new" (default) - trust a host on first use, reject if its key later changes
;; "yes" - strict: the host key must already be known
;; "no" - disable host key verification (insecure, MITM risk)
;SSH_HOST_KEY_CHECKING = accept-new
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

View File

@ -20,6 +20,7 @@ import (
"code.gitea.io/gitea/modules/gtprof"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
)
@ -56,6 +57,27 @@ type Command struct {
cmdManagedStderr *bytes.Buffer
}
// managedSSHCommand builds the GIT_SSH_COMMAND used for Gitea-managed SSH
// operations (migration / mirror with a generated keypair). ssh runs
// non-interactively (BatchMode) so the worker never hangs on an unknown host,
// and the configured host-key policy is applied.
func managedSSHCommand() string {
mode := setting.Migrations.SSHHostKeyChecking
if mode == "no" {
return "ssh -o BatchMode=yes -o StrictHostKeyChecking=no -o UserKnownHostsFile=" + util.ShellEscape(os.DevNull)
}
cmd := "ssh -o BatchMode=yes -o StrictHostKeyChecking=" + mode
// Persist accepted host keys in a Gitea-managed file so a later key change
// is detected (TOFU); fall back to ssh's default known_hosts if unset.
if setting.AppDataPath != "" {
knownHosts := filepath.Join(setting.AppDataPath, "home", ".ssh", "known_hosts")
if err := os.MkdirAll(filepath.Dir(knownHosts), 0o700); err == nil {
cmd += " -o UserKnownHostsFile=" + util.ShellEscape(knownHosts)
}
}
return cmd
}
func logArgSanitize(arg string) string {
if filepath.IsAbs(arg) {
base := filepath.Base(arg)
@ -453,6 +475,7 @@ func (c *Command) Start(ctx context.Context) (retErr error) {
if c.opts.SSHAuthSock != "" {
c.cmd.Env = append(c.cmd.Env, "SSH_AUTH_SOCK="+c.opts.SSHAuthSock)
c.cmd.Env = append(c.cmd.Env, "GIT_SSH_COMMAND="+managedSSHCommand())
}
c.cmd.Dir = c.opts.Dir

View File

@ -11,9 +11,14 @@ var Migrations = struct {
BlockedDomains string
AllowLocalNetworks bool
SkipTLSVerify bool
// SSHHostKeyChecking controls StrictHostKeyChecking for SSH migrations/mirrors:
// "accept-new" (default, trust on first use, reject changed keys), "yes" (strict,
// host must already be known) or "no" (disable verification).
SSHHostKeyChecking string
}{
MaxAttempts: 3,
RetryBackoff: 3,
MaxAttempts: 3,
RetryBackoff: 3,
SSHHostKeyChecking: "accept-new",
}
func loadMigrationsFrom(rootCfg ConfigProvider) {
@ -25,4 +30,5 @@ func loadMigrationsFrom(rootCfg ConfigProvider) {
Migrations.BlockedDomains = sec.Key("BLOCKED_DOMAINS").MustString("")
Migrations.AllowLocalNetworks = sec.Key("ALLOW_LOCALNETWORKS").MustBool(false)
Migrations.SkipTLSVerify = sec.Key("SKIP_TLS_VERIFY").MustBool(false)
Migrations.SSHHostKeyChecking = sec.Key("SSH_HOST_KEY_CHECKING").In("accept-new", []string{"accept-new", "yes", "no"})
}