From d7c9333ff490944f6a455d5084489c6363782664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Yule=20B=C3=A4dorf?= Date: Fri, 5 Apr 2024 15:35:47 +0200 Subject: [PATCH] forgejo: allow multiple host addresses for SSH --- hosts/flora-6/wireguard.nix | 11 ++ .../apps/{forgejo.nix => forgejo/default.nix} | 9 +- .../apps/forgejo/multiple-ssh-host.patch | 131 ++++++++++++++++++ hosts/nachtigall/default.nix | 2 +- hosts/nachtigall/wireguard.nix | 11 ++ 5 files changed, 162 insertions(+), 2 deletions(-) rename hosts/nachtigall/apps/{forgejo.nix => forgejo/default.nix} (93%) create mode 100644 hosts/nachtigall/apps/forgejo/multiple-ssh-host.patch diff --git a/hosts/flora-6/wireguard.nix b/hosts/flora-6/wireguard.nix index f51d3b7..83406ba 100644 --- a/hosts/flora-6/wireguard.nix +++ b/hosts/flora-6/wireguard.nix @@ -26,4 +26,15 @@ ]; }; }; + + services.openssh.listenAddresses = [ + { + addr = "10.7.6.2"; + port = 22; + } + { + addr = "[fd00:fae:fae:fae:fae:2::]"; + port = 22; + } + ]; } diff --git a/hosts/nachtigall/apps/forgejo.nix b/hosts/nachtigall/apps/forgejo/default.nix similarity index 93% rename from hosts/nachtigall/apps/forgejo.nix rename to hosts/nachtigall/apps/forgejo/default.nix index fdc941f..967e653 100644 --- a/hosts/nachtigall/apps/forgejo.nix +++ b/hosts/nachtigall/apps/forgejo/default.nix @@ -41,11 +41,16 @@ users.groups.gitea = {}; + # Expose SSH port only for forgejo SSH + networking.firewall.interfaces.enp35s0.allowedTCPPorts = [ 22 ]; + services.forgejo = { enable = true; user = "gitea"; group = "gitea"; - package = pkgs.forgejo; + package = pkgs.forgejo.overrideAttrs (o: { + patches = (o.patches or [ ]) ++ [ ./multiple-ssh-host.patch ]; + }); database = { type = "postgres"; passwordFile = config.age.secrets.forgejo-database-password.path; @@ -63,6 +68,8 @@ DOMAIN = "git.pub.solar"; HTTP_ADDR = "127.0.0.1"; HTTP_PORT = 3000; + START_SSH_SERVER = true; + SSH_LISTEN_HOST = "138.201.80.102,[2a01:4f8:172:1c25::1]"; }; log.LEVEL = "Warn"; diff --git a/hosts/nachtigall/apps/forgejo/multiple-ssh-host.patch b/hosts/nachtigall/apps/forgejo/multiple-ssh-host.patch new file mode 100644 index 0000000..058a7bd --- /dev/null +++ b/hosts/nachtigall/apps/forgejo/multiple-ssh-host.patch @@ -0,0 +1,131 @@ +diff --git a/docs/content/administration/config-cheat-sheet.en-us.md b/docs/content/administration/config-cheat-sheet.en-us.md +index 16e1e8223a..54d710b3d7 100644 +--- a/docs/content/administration/config-cheat-sheet.en-us.md ++++ b/docs/content/administration/config-cheat-sheet.en-us.md +@@ -327,7 +327,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a + - `SSH_USER`: **%(BUILTIN_SSH_SERVER_USER)s**: SSH username displayed in clone URLs. This is only for people who configure the SSH server themselves; in most cases, you want to leave this blank and modify the `BUILTIN_SSH_SERVER_USER`. + - `SSH_DOMAIN`: **%(DOMAIN)s**: Domain name of this server, used for displayed clone URL. + - `SSH_PORT`: **22**: SSH port displayed in clone URL. +-- `SSH_LISTEN_HOST`: **0.0.0.0**: Listen address for the built-in SSH server. ++- `SSH_LISTEN_HOST`: **0.0.0.0**: Listen address(es) for the built-in SSH server; multiple addresses can be separated by comma, addresses can include a port statement to override SSH_LISTEN_PORT. + - `SSH_LISTEN_PORT`: **%(SSH\_PORT)s**: Port for the built-in SSH server. + - `SSH_ROOT_PATH`: **~/.ssh**: Root path of SSH directory. + - `SSH_CREATE_AUTHORIZED_KEYS_FILE`: **true**: Gitea will create a authorized_keys file by default when it is not using the internal ssh server. If you intend to use the AuthorizedKeysCommand functionality then you should turn this off. +diff --git a/modules/graceful/manager.go b/modules/graceful/manager.go +index 068de21076..1e1a8239e8 100644 +--- a/modules/graceful/manager.go ++++ b/modules/graceful/manager.go +@@ -272,6 +272,12 @@ func (g *Manager) InformCleanup() { + g.createServerWaitGroup.Done() + } + ++// Should we need to create multile listener for one type (e.g. SSH built-in server), ++// the number of expected routines needs to be increased accordingly. ++func (g *Manager) IncreaseListenerCountBy(extraNumberOfServersToCreate int) { ++ g.createServerWaitGroup.Add(extraNumberOfServersToCreate) ++} ++ + // Done allows the manager to be viewed as a context.Context, it returns a channel that is closed when the server is finished terminating + func (g *Manager) Done() <-chan struct{} { + return g.managerCtx.Done() +diff --git a/modules/setting/ssh.go b/modules/setting/ssh.go +index a5a9da0b36..e73aa0115a 100644 +--- a/modules/setting/ssh.go ++++ b/modules/setting/ssh.go +@@ -25,7 +25,7 @@ var SSH = struct { + Domain string `ini:"SSH_DOMAIN"` + Port int `ini:"SSH_PORT"` + User string `ini:"SSH_USER"` +- ListenHost string `ini:"SSH_LISTEN_HOST"` ++ ListenHost []string `ini:"SSH_LISTEN_HOST"` + ListenPort int `ini:"SSH_LISTEN_PORT"` + RootPath string `ini:"SSH_ROOT_PATH"` + ServerCiphers []string `ini:"SSH_SERVER_CIPHERS"` +@@ -54,6 +54,7 @@ var SSH = struct { + Disabled: false, + StartBuiltinServer: false, + Domain: "", ++ ListenHost: []string{"0.0.0.0"}, + Port: 22, + ServerCiphers: []string{"chacha20-poly1305@openssh.com", "aes128-ctr", "aes192-ctr", "aes256-ctr", "aes128-gcm@openssh.com", "aes256-gcm@openssh.com"}, + ServerKeyExchanges: []string{"curve25519-sha256", "ecdh-sha2-nistp256", "ecdh-sha2-nistp384", "ecdh-sha2-nistp521", "diffie-hellman-group14-sha256", "diffie-hellman-group14-sha1"}, +diff --git a/modules/ssh/init.go b/modules/ssh/init.go +index 21d4f89936..3800762632 100644 +--- a/modules/ssh/init.go ++++ b/modules/ssh/init.go +@@ -11,6 +11,7 @@ import ( + "strconv" + "strings" + ++ "code.gitea.io/gitea/modules/graceful" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + ) +@@ -22,12 +23,23 @@ func Init() error { + } + + 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, +- ) ++ if len(setting.SSH.ListenHost) > 1 { ++ graceful.GetManager().IncreaseListenerCountBy(len(setting.SSH.ListenHost) - 1) ++ } ++ for _, listenHost := range setting.SSH.ListenHost { ++ var addr string ++ if _, _, err := net.SplitHostPort(listenHost); err == nil { ++ addr = listenHost ++ } else { ++ addr = net.JoinHostPort(listenHost, strconv.Itoa(setting.SSH.ListenPort)) ++ } ++ Listen(addr, 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)", ++ addr, setting.SSH.ServerCiphers, setting.SSH.ServerKeyExchanges, setting.SSH.ServerMACs, ++ ) ++ } + return nil ++ + } + + builtinUnused() +diff --git a/modules/ssh/ssh.go b/modules/ssh/ssh.go +index a5af5c129b..ab2021cfbd 100644 +--- a/modules/ssh/ssh.go ++++ b/modules/ssh/ssh.go +@@ -18,7 +18,6 @@ import ( + "os/exec" + "path/filepath" + "reflect" +- "strconv" + "strings" + "sync" + "syscall" +@@ -279,10 +278,10 @@ func sshConnectionFailed(conn net.Conn, err error) { + log.Warn("Failed authentication attempt from %s", conn.RemoteAddr()) + } + +-// Listen starts a SSH server listens on given port. +-func Listen(host string, port int, ciphers, keyExchanges, macs []string) { ++// Listen starts a SSH server listens on given addr (host, port combination). ++func Listen(addr string, ciphers, keyExchanges, macs []string) { + srv := ssh.Server{ +- Addr: net.JoinHostPort(host, strconv.Itoa(port)), ++ Addr: addr, + PublicKeyHandler: publicKeyHandler, + Handler: sessionHandler, + ServerConfigCallback: func(ctx ssh.Context) *gossh.ServerConfig { +diff --git a/tests/integration/git_helper_for_declarative_test.go b/tests/integration/git_helper_for_declarative_test.go +index 1e99783096..a099d414c6 100644 +--- a/tests/integration/git_helper_for_declarative_test.go ++++ b/tests/integration/git_helper_for_declarative_test.go +@@ -52,7 +52,7 @@ func createSSHUrl(gitPath string, u *url.URL) *url.URL { + u2 := *u + u2.Scheme = "ssh" + u2.User = url.User("git") +- u2.Host = net.JoinHostPort(setting.SSH.ListenHost, strconv.Itoa(setting.SSH.ListenPort)) ++ u2.Host = net.JoinHostPort(setting.SSH.ListenHost[0], strconv.Itoa(setting.SSH.ListenPort)) + u2.Path = gitPath + return &u2 + } diff --git a/hosts/nachtigall/default.nix b/hosts/nachtigall/default.nix index 69428bf..f0945cd 100644 --- a/hosts/nachtigall/default.nix +++ b/hosts/nachtigall/default.nix @@ -14,7 +14,7 @@ ./apps/collabora.nix ./apps/coturn.nix - ./apps/forgejo.nix + ./apps/forgejo ./apps/keycloak.nix ./apps/mailman.nix ./apps/mastodon.nix diff --git a/hosts/nachtigall/wireguard.nix b/hosts/nachtigall/wireguard.nix index e349694..7b8d6f4 100644 --- a/hosts/nachtigall/wireguard.nix +++ b/hosts/nachtigall/wireguard.nix @@ -26,4 +26,15 @@ ]; }; }; + + services.openssh.listenAddresses = [ + { + addr = "10.7.6.1"; + port = 22; + } + { + addr = "[fd00:fae:fae:fae:fae:1::]"; + port = 22; + } + ]; }