diff --git a/hosts/common/configs/system/ssh/default.nix b/hosts/common/configs/system/ssh/default.nix index 39e593e..1b0a314 100644 --- a/hosts/common/configs/system/ssh/default.nix +++ b/hosts/common/configs/system/ssh/default.nix @@ -11,6 +11,11 @@ extraHostNames = [ "karaolidis.com" ]; }; + jupiter-sish = { + publicKeyFile = ../../../../jupiter/users/storm/configs/console/podman/sish/ssh_host_ed25519_key.pub; + extraHostNames = [ "karaolidis.com" ]; + }; + jupiter-vps = { publicKeyFile = ../../../../jupiter-vps/secrets/ssh_host_ed25519_key.pub; extraHostNames = [ "vps.karaolidis.com" ]; diff --git a/hosts/jupiter-vps/default.nix b/hosts/jupiter-vps/default.nix index 0d9a7c0..b9d1a68 100644 --- a/hosts/jupiter-vps/default.nix +++ b/hosts/jupiter-vps/default.nix @@ -13,6 +13,7 @@ ../common/configs/system/nixpkgs ../common/configs/system/podman ../common/configs/system/sops + ../common/configs/system/ssh ../common/configs/system/sshd ../common/configs/system/system ../common/configs/system/users diff --git a/hosts/jupiter/default.nix b/hosts/jupiter/default.nix index 90d8373..bc6678a 100644 --- a/hosts/jupiter/default.nix +++ b/hosts/jupiter/default.nix @@ -20,6 +20,7 @@ ../common/configs/system/podman ../common/configs/system/smartmontools ../common/configs/system/sops + ../common/configs/system/ssh ../common/configs/system/sshd ../common/configs/system/sudo ../common/configs/system/system diff --git a/hosts/jupiter/users/storm/configs/console/podman/default.nix b/hosts/jupiter/users/storm/configs/console/podman/default.nix index b7b8e20..7bf6bc3 100644 --- a/hosts/jupiter/users/storm/configs/console/podman/default.nix +++ b/hosts/jupiter/users/storm/configs/console/podman/default.nix @@ -13,6 +13,7 @@ in (import ./grafana { inherit user home; }) (import ./ntfy { inherit user home; }) (import ./prometheus { inherit user home; }) + (import ./sish { inherit user home; }) (import ./traefik { inherit user home; }) (import ./whoami { inherit user home; }) ]; diff --git a/hosts/jupiter/users/storm/configs/console/podman/sish/default.nix b/hosts/jupiter/users/storm/configs/console/podman/sish/default.nix new file mode 100644 index 0000000..869f582 --- /dev/null +++ b/hosts/jupiter/users/storm/configs/console/podman/sish/default.nix @@ -0,0 +1,72 @@ +{ + user ? throw "user argument is required", + home ? throw "home argument is required", +}: +{ + config, + inputs, + pkgs, + system, + ... +}: +let + selfPkgs = inputs.self.packages.${system}; + hmConfig = config.home-manager.users.${user}; + inherit (hmConfig.virtualisation.quadlet) networks; +in +{ + networking.firewall.allowedTCPPorts = [ 2222 ]; + + home-manager.users.${user} = { + sops.secrets."sish/ssh/key".sopsFile = ../../../../../../secrets/secrets.yaml; + + virtualisation.quadlet = { + networks.sish.networkConfig.internal = true; + + containers.sish = { + containerConfig = { + image = "docker-archive:${selfPkgs.docker-sish}"; + networks = [ + networks.sish.ref + networks.traefik.ref + ]; + volumes = + let + authorizedKeys = pkgs.writeTextFile { + name = "authorized_keys"; + text = '' + ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEWDA5vnIB7KE2VG28Ovg5rXtQqxFwMXsfozLsH0BNZS nick@karaolidis.com + ''; + }; + in + [ + "${hmConfig.sops.secrets."sish/ssh/key".path}:/etc/sish/keys/ssh_key:ro" + "${authorizedKeys}:/etc/sish/pubkeys/authorized_keys:ro" + ]; + labels = [ + "traefik.enable=true" + "traefik.http.routers.sish.rule=HostRegexp(`^(.+\.)?tunnel\.karaolidis\.com$`)" + "traefik.http.services.sish.loadbalancer.server.port=80" + ]; + publishPorts = [ "2222:2222/tcp" ]; + exec = [ + "--ssh-address=0.0.0.0:2222" + "--http-address=0.0.0.0:80" + "--load-templates=false" + "--private-keys-directory=/etc/sish/keys" + "--authentication-password=\"\"" + "--authentication-keys-directory=/etc/sish/pubkeys" + "--bind-random-ports=false" + "--bind-random-aliases=false" + "--bind-random-subdomains=false" + "--welcome-message=\"\"" + "--domain=tunnel.karaolidis.com" + "--proxy-ssl-termination=true" + ]; + }; + + unitConfig.After = [ "sops-nix.service" ]; + }; + }; + }; +} diff --git a/hosts/jupiter/users/storm/configs/console/podman/sish/ssh_host_ed25519_key.pub b/hosts/jupiter/users/storm/configs/console/podman/sish/ssh_host_ed25519_key.pub new file mode 100644 index 0000000..606a23c --- /dev/null +++ b/hosts/jupiter/users/storm/configs/console/podman/sish/ssh_host_ed25519_key.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILbYZvInRgXWVVi7pgP/rrOLPv9l7zH/TkPk7bb98OFp root@jupiter-sish diff --git a/hosts/jupiter/users/storm/configs/console/podman/traefik/default.nix b/hosts/jupiter/users/storm/configs/console/podman/traefik/default.nix index 387d115..9040e43 100644 --- a/hosts/jupiter/users/storm/configs/console/podman/traefik/default.nix +++ b/hosts/jupiter/users/storm/configs/console/podman/traefik/default.nix @@ -76,9 +76,9 @@ in "--entrypoints.https.http.tls=true" "--entrypoints.https.http.tls.certResolver=letsencrypt" "--entrypoints.https.http.tls.domains[0].main=karaolidis.com" - "--entrypoints.https.http.tls.domains[0].sans=*.karaolidis.com" + "--entrypoints.https.http.tls.domains[0].sans=*.karaolidis.com,*.tunnel.karaolidis.com,*.gaming.karaolidis.com" "--entrypoints.https.http.tls.domains[1].main=krlds.com" - "--entrypoints.https.http.tls.domains[1].sans=*.krlds.com" + "--entrypoints.https.http.tls.domains[1].sans=*.krlds.com,*.tunnel.krlds.com,*.gaming.krlds.com" "--entrypoints.https.http.middlewares=compress@docker" "--entryPoints.https.http3" "--entrypoints.https.forwardedHeaders.insecure=true" diff --git a/packages/default.nix b/packages/default.nix index 398cbd3..9166063 100644 --- a/packages/default.nix +++ b/packages/default.nix @@ -28,6 +28,7 @@ inherit pkgs; }; docker-redis = import ./docker/redis { inherit pkgs; }; + docker-sish = import ./docker/sish { inherit pkgs; }; docker-traefik = import ./docker/traefik { inherit pkgs; }; docker-whoami = import ./docker/whoami { inherit pkgs; }; docker-yq = import ./docker/yq { inherit pkgs; }; diff --git a/packages/docker/sish/default.nix b/packages/docker/sish/default.nix new file mode 100644 index 0000000..77ba346 --- /dev/null +++ b/packages/docker/sish/default.nix @@ -0,0 +1,38 @@ +{ pkgs, ... }: +pkgs.dockerTools.buildImage { + name = "sish"; + fromImage = import ../base { inherit pkgs; }; + + copyToRoot = pkgs.buildEnv { + name = "root"; + paths = with pkgs; [ + (sish.overrideAttrs (oldAttrs: { + patches = oldAttrs.patches or [ ] ++ [ ./proxy-ssl-termination.patch ]; + })) + ]; + pathsToLink = [ "/bin" ]; + }; + + runAsRoot = '' + mkdir -p /tmp + ''; + + config = { + Entrypoint = [ "/bin/sish" ]; + Cmd = [ + "--ssh-address=0.0.0.0:2222" + "--http-address=0.0.0.0:80" + "--load-templates=false" + "--private-keys-directory=/etc/sish/keys" + "--authentication-password=\"\"" + "--authentication-keys-directory=/etc/sish/pubkeys" + ]; + ExposedPorts = { + "2222/tcp" = { }; + }; + Volumes = { + "/etc/sish/keys" = { }; + "/etc/sish/pubkeys" = { }; + }; + }; +} diff --git a/packages/docker/sish/proxy-ssl-termination.patch b/packages/docker/sish/proxy-ssl-termination.patch new file mode 100644 index 0000000..1d4c911 --- /dev/null +++ b/packages/docker/sish/proxy-ssl-termination.patch @@ -0,0 +1,82 @@ +diff --git a/cmd/sish.go b/cmd/sish.go +index 0f7bee3..7fb1656 100644 +--- a/cmd/sish.go ++++ b/cmd/sish.go +@@ -99,6 +99,7 @@ func init() { + rootCmd.PersistentFlags().BoolP("proxy-protocol", "", false, "Use the proxy-protocol while proxying connections in order to pass-on IP address and port information") + rootCmd.PersistentFlags().BoolP("proxy-protocol-use-timeout", "", false, "Use a timeout for the proxy-protocol read") + rootCmd.PersistentFlags().BoolP("proxy-protocol-listener", "", false, "Use the proxy-protocol to resolve ip addresses from user connections") ++ rootCmd.PersistentFlags().BoolP("proxy-ssl-termination", "", false, "Whether sish is running behind an SSL-terminated reverse proxy\nIf true, the displayed HTTP URL will use `https://` despite running on port 80") + rootCmd.PersistentFlags().BoolP("https", "", false, "Listen for HTTPS connections. Requires a correct --https-certificate-directory") + rootCmd.PersistentFlags().BoolP("force-all-https", "", false, "Redirect all requests to the https server") + rootCmd.PersistentFlags().BoolP("force-https", "", false, "Allow indiviual binds to request for https to be enforced") +diff --git a/config.example.yml b/config.example.yml +index 2249f5d..fbac885 100644 +--- a/config.example.yml ++++ b/config.example.yml +@@ -79,6 +79,7 @@ proxy-protocol-policy: use + proxy-protocol-timeout: 200ms + proxy-protocol-use-timeout: false + proxy-protocol-version: "1" ++proxy-ssl-termination: false + redirect-root: true + redirect-root-location: https://github.com/antoniomika/sish + rewrite-host-header: true +diff --git a/docs/posts/cli.md b/docs/posts/cli.md +index f6891a0..c31ab1c 100644 +--- a/docs/posts/cli.md ++++ b/docs/posts/cli.md +@@ -1,6 +1,6 @@ + --- + title: CLI +-description: How use sish's CLI ++description: How use sish's CLI + keywords: [sish, cli] + --- + +@@ -107,6 +107,7 @@ Flags: + --proxy-protocol-use-timeout Use a timeout for the proxy-protocol read + -q, --proxy-protocol-version string What version of the proxy protocol to use. Can either be 1, 2, or userdefined. + If userdefined, the user needs to add a command to SSH called proxyproto=version (ie proxyproto=1) (default "1") ++ --proxy-ssl-termination Whether sish is running behind an SSL terminated reverse proxy + --redirect-root Redirect the root domain to the location defined in --redirect-root-location (default true) + -r, --redirect-root-location string The location to redirect requests to the root domain + to instead of responding with a 404 (default "https://github.com/antoniomika/sish") +@@ -129,6 +130,7 @@ Flags: + --verify-dns Verify DNS information for hosts and ensure it matches a connecting users sha256 key fingerprint (default true) + --verify-ssl Verify SSL certificates made on proxied HTTP connections (default true) + -v, --version version for sish ++ --welcome-message string Message displayed to users upon connection (default "Press Ctrl-C to close the session.") + -y, --whitelisted-countries string A comma separated list of whitelisted countries. Applies to HTTP, TCP, and SSH connections + -w, --whitelisted-ips string A comma separated list of whitelisted ips. Applies to HTTP, TCP, and SSH connections + ``` +diff --git a/sshmuxer/httphandler.go b/sshmuxer/httphandler.go +index eb8ad63..833ed6a 100644 +--- a/sshmuxer/httphandler.go ++++ b/sshmuxer/httphandler.go +@@ -121,16 +121,17 @@ func handleHTTPListener(check *channelForwardMsg, _ string, requestMessages stri + } + } + +- httpPortString := "" +- if state.Ports.HTTPPort != 80 { +- httpPortString = fmt.Sprintf(":%d", state.Ports.HTTPPort) +- } +- +- requestMessages += fmt.Sprintf("%s: http://%s%s%s%s\r\n", aurora.BgBlue("HTTP"), userPass, pH.HTTPUrl.Host, httpPortString, pH.HTTPUrl.Path) ++ if !viper.GetBool("proxy-ssl-termination") { ++ httpPortString := "" ++ if state.Ports.HTTPPort != 80 { ++ httpPortString = fmt.Sprintf(":%d", state.Ports.HTTPPort) ++ } + +- log.Printf("%s forwarding started: http://%s%s%s%s -> %s for client: %s\n", aurora.BgBlue("HTTP"), userPass, pH.HTTPUrl.Host, httpPortString, pH.HTTPUrl.Path, listenerHolder.Addr().String(), sshConn.SSHConn.RemoteAddr().String()) ++ requestMessages += fmt.Sprintf("%s: http://%s%s%s%s\r\n", aurora.BgBlue("HTTP"), userPass, pH.HTTPUrl.Host, httpPortString, pH.HTTPUrl.Path) ++ log.Printf("%s forwarding started: http://%s%s%s%s -> %s for client: %s\n", aurora.BgBlue("HTTP"), userPass, pH.HTTPUrl.Host, httpPortString, pH.HTTPUrl.Path, listenerHolder.Addr().String(), sshConn.SSHConn.RemoteAddr().String()) ++ } + +- if viper.GetBool("https") { ++ if viper.GetBool("https") || viper.GetBool("proxy-ssl-termination") { + httpsPortString := "" + if state.Ports.HTTPSPort != 443 { + httpsPortString = fmt.Sprintf(":%d", state.Ports.HTTPSPort)