diff options
author | feistel <6742251-feistel@users.noreply.gitlab.com> | 2021-08-10 19:44:16 +0300 |
---|---|---|
committer | feistel <6742251-feistel@users.noreply.gitlab.com> | 2021-10-07 16:40:43 +0300 |
commit | dc7d694f00eadd078a05991bff7c78cb29efeff4 (patch) | |
tree | ca2c07cc40a46e67623c598a6735d49458a2e157 | |
parent | 64f914a804a4da8a521c5cbe7df1b8cb73f45a4f (diff) |
refactor: stop running gitlab-pages as root
We have now disabled chroot by default since %14.1, and
recently removed support for disk-based configuration
coming in %14.3. And we've also removed the chroot
completely from Pages.
Since nginx can do TCP proxying and there's no need to use
privileged ports, Pages has been confirmed to run as non-root
in k8s environment without any issues.
This MR removes support for the gitlab-pages daemon completely.
Changelog: removed
-rw-r--r-- | daemon.go | 189 | ||||
-rw-r--r-- | internal/config/config.go | 13 | ||||
-rw-r--r-- | internal/config/flags.go | 4 | ||||
-rw-r--r-- | main.go | 16 | ||||
-rw-r--r-- | test/acceptance/helpers_test.go | 4 |
5 files changed, 2 insertions, 224 deletions
diff --git a/daemon.go b/daemon.go deleted file mode 100644 index 86ede6be..00000000 --- a/daemon.go +++ /dev/null @@ -1,189 +0,0 @@ -package main - -import ( - "encoding/json" - "os" - "os/exec" - "os/signal" - "path/filepath" - "strings" - "syscall" - - "github.com/sirupsen/logrus" - - "gitlab.com/gitlab-org/gitlab-pages/internal/config" -) - -const ( - daemonRunProgram = "gitlab-pages-unprivileged" -) - -func daemonMain() { - if os.Args[0] != daemonRunProgram { - return - } - - // Validate that a working directory is valid - // https://man7.org/linux/man-pages/man2/getcwd.2.html - wd, err := os.Getwd() - if err != nil { - fatal(err, "could not get current working directory") - } else if strings.HasPrefix(wd, "(unreachable)") { - fatal(os.ErrPermission, "could not get current working directory") - } - - logrus.WithFields(logrus.Fields{ - "uid": syscall.Getuid(), - "gid": syscall.Getgid(), - "wd": wd, - }).Info("starting the daemon as unprivileged user") - - // read the configuration from the pipe "ExtraFiles" - var config config.Config - if err := json.NewDecoder(os.NewFile(3, "options")).Decode(&config); err != nil { - fatal(err, "could not decode app config") - } - runApp(&config) - os.Exit(0) -} - -func daemonReexec(uid, gid uint, args ...string) (cmd *exec.Cmd, err error) { - path, err := os.Executable() - if err != nil { - return - } - - cmd = &exec.Cmd{ - Path: path, - Args: args, - Env: os.Environ(), - Stdin: os.Stdin, - Stdout: os.Stdout, - Stderr: os.Stderr, - SysProcAttr: &syscall.SysProcAttr{ - Credential: &syscall.Credential{ - Uid: uint32(uid), - Gid: uint32(gid), - }, - Setsid: true, - }, - } - return -} - -func daemonUpdateFd(cmd *exec.Cmd, fd uintptr) (childFd uintptr) { - file := os.NewFile(fd, "[socket]") - - // we add 3 since, we have a 3 predefined FDs - childFd = uintptr(3 + len(cmd.ExtraFiles)) - cmd.ExtraFiles = append(cmd.ExtraFiles, file) - - return -} - -func daemonUpdateFds(cmd *exec.Cmd, fds []uintptr) { - for idx, fd := range fds { - fds[idx] = daemonUpdateFd(cmd, fd) - } -} - -func killProcess(cmd *exec.Cmd) { - if cmd.Process != nil { - cmd.Process.Kill() - } - cmd.Wait() - for _, file := range cmd.ExtraFiles { - file.Close() - } -} - -func passSignals(cmd *exec.Cmd) { - if cmd.Process == nil { - return - } - - s := make(chan os.Signal, 1) - signal.Notify(s, syscall.SIGTERM, os.Interrupt, os.Kill) - - go func() { - for cmd.Process != nil { - cmd.Process.Signal(<-s) - } - }() -} - -func daemonize(config *config.Config) error { - uid := config.Daemon.UID - gid := config.Daemon.GID - pagesRoot := config.General.RootDir - - // Ensure pagesRoot is an absolute path. This will produce a different path - // if any component of pagesRoot is a symlink (not likely). For example, - // -pages-root=/some-path where ln -s /other-path /some-path - // pagesPath will become: /other-path and we will fail to serve files from /some-path. - // GitLab Rails also resolves the absolute path for `pages_path` - // https://gitlab.com/gitlab-org/gitlab/blob/981ad651d8bd3690e28583eec2363a79f775af89/config/initializers/1_settings.rb#L296 - pagesRoot, err := filepath.Abs(pagesRoot) - if err != nil { - return err - } - - logrus.WithFields(logrus.Fields{ - "uid": uid, - "gid": gid, - "pages-root": pagesRoot, - }).Info("running the daemon as unprivileged user") - - cmd, err := daemonReexec(uid, gid, daemonRunProgram) - if err != nil { - return err - } - defer killProcess(cmd) - - // Create a pipe to pass the configuration - configReader, configWriter, err := os.Pipe() - if err != nil { - return err - } - defer configWriter.Close() - cmd.ExtraFiles = append(cmd.ExtraFiles, configReader) - - updateFds(config, cmd) - - // Start the process - if err := cmd.Start(); err != nil { - logrus.WithError(err).Error("start failed") - return err - } - - // Write the configuration - if err := json.NewEncoder(configWriter).Encode(config); err != nil { - return err - } - configWriter.Close() - - // Pass through signals - passSignals(cmd) - - // Wait for process to exit - return cmd.Wait() -} - -func updateFds(config *config.Config, cmd *exec.Cmd) { - for _, fds := range [][]uintptr{ - config.Listeners.HTTP, - config.Listeners.HTTPS, - config.Listeners.Proxy, - config.Listeners.HTTPSProxyv2, - } { - daemonUpdateFds(cmd, fds) - } - - for _, fdPtr := range []*uintptr{ - &config.ListenMetrics, - } { - if *fdPtr != 0 { - *fdPtr = daemonUpdateFd(cmd, *fdPtr) - } - } -} diff --git a/internal/config/config.go b/internal/config/config.go index 71ff0eed..860ea4be 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -18,7 +18,6 @@ type Config struct { General General ArtifactsServer ArtifactsServer Authentication Auth - Daemon Daemon GitLab GitLab Listeners Listeners Log Log @@ -80,12 +79,6 @@ type Auth struct { Scope string } -// Daemon groups settings related to configuring GitLab Pages daemon -type Daemon struct { - UID uint - GID uint -} - // Cache configuration for GitLab API type Cache struct { CacheExpiry time.Duration @@ -215,10 +208,6 @@ func loadConfig() (*Config, error) { RedirectURI: *redirectURI, Scope: *authScope, }, - Daemon: Daemon{ - UID: *daemonUID, - GID: *daemonGID, - }, Log: Log{ Format: *logFormat, Verbose: *logVerbose, @@ -281,8 +270,6 @@ func LogConfig(config *Config) { log.WithFields(log.Fields{ "artifacts-server": *artifactsServer, "artifacts-server-timeout": *artifactsServerTimeout, - "daemon-gid": *daemonGID, - "daemon-uid": *daemonUID, "default-config-filename": flag.DefaultConfigFlagname, "disable-cross-origin-requests": *disableCrossOriginRequests, "domain": config.General.Domain, diff --git a/internal/config/flags.go b/internal/config/flags.go index aa5bf1c5..6523c20a 100644 --- a/internal/config/flags.go +++ b/internal/config/flags.go @@ -21,8 +21,8 @@ var ( metricsAddress = flag.String("metrics-address", "", "The address to listen on for metrics requests") sentryDSN = flag.String("sentry-dsn", "", "The address for sending sentry crash reporting to") sentryEnvironment = flag.String("sentry-environment", "", "The environment for sentry crash reporting") - daemonUID = flag.Uint("daemon-uid", 0, "Drop privileges to this user") - daemonGID = flag.Uint("daemon-gid", 0, "Drop privileges to this group") + _ = flag.Uint("daemon-uid", 0, "Drop privileges to this user") + _ = flag.Uint("daemon-gid", 0, "Drop privileges to this group") _ = flag.Bool("daemon-enable-jail", false, "DEPRECATED and ignored, will be removed in 15.0") _ = flag.Bool("daemon-inplace-chroot", false, "DEPRECATED and ignored, will be removed in 15.0") // TODO: https://gitlab.com/gitlab-org/gitlab-pages/-/issues/599 propagateCorrelationID = flag.Bool("propagate-correlation-id", false, "Reuse existing Correlation-ID from the incoming request header `X-Request-ID` if present") @@ -5,7 +5,6 @@ import ( "io" "math/rand" "os" - "strings" "time" "github.com/sirupsen/logrus" @@ -82,20 +81,6 @@ func appMain() { defer closeAll(cs) } - if config.Daemon.UID != 0 || config.Daemon.GID != 0 { - if err := daemonize(config); err != nil { - if strings.Contains(err.Error(), "signal:") { - log.WithField("signal", err.Error()).Info("daemon received signal") - return - } - - errortracking.Capture(err) - fatal(err, "could not create pages daemon") - } - - return - } - runApp(config) } @@ -202,6 +187,5 @@ func main() { metrics.MustRegister() - daemonMain() appMain() } diff --git a/test/acceptance/helpers_test.go b/test/acceptance/helpers_test.go index b8181dca..8ad0166f 100644 --- a/test/acceptance/helpers_test.go +++ b/test/acceptance/helpers_test.go @@ -381,10 +381,6 @@ func getPagesDaemonArgs(t *testing.T) []string { t.Log("Running pages as a daemon") - // This triggers the drop-privileges-and-chroot code in the pages daemon - out = append(out, "-daemon-uid", "0") - out = append(out, "-daemon-gid", "65534") - return out } |