16053: Run postgresql as "postgres" user if supervisor is root.
authorTom Clegg <tom@tomclegg.ca>
Sat, 14 Mar 2020 01:16:36 +0000 (21:16 -0400)
committerTom Clegg <tom@tomclegg.ca>
Sat, 14 Mar 2020 01:16:36 +0000 (21:16 -0400)
Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom@tomclegg.ca>

lib/boot/postgresql.go
lib/boot/supervisor.go

index df98904151834a8b22dfbfc429f7e9882ad6e7ae..a08180e0c39a51ad685c08fdb16707605fd33b20 100644 (file)
@@ -11,7 +11,9 @@ import (
        "fmt"
        "os"
        "os/exec"
+       "os/user"
        "path/filepath"
+       "strconv"
        "strings"
        "time"
 
@@ -34,6 +36,13 @@ func (runPostgreSQL) Run(ctx context.Context, fail func(error), super *Superviso
                return err
        }
 
+       iamroot := false
+       if u, err := user.Current(); err != nil {
+               return fmt.Errorf("user.Current(): %s", err)
+       } else if u.Uid == "0" {
+               iamroot = true
+       }
+
        buf := bytes.NewBuffer(nil)
        err = super.RunProgram(ctx, super.tempdir, buf, nil, "pg_config", "--bindir")
        if err != nil {
@@ -42,11 +51,40 @@ func (runPostgreSQL) Run(ctx context.Context, fail func(error), super *Superviso
        bindir := strings.TrimSpace(buf.String())
 
        datadir := filepath.Join(super.tempdir, "pgdata")
-       err = os.Mkdir(datadir, 0755)
+       err = os.Mkdir(datadir, 0700)
        if err != nil {
                return err
        }
-       err = super.RunProgram(ctx, super.tempdir, nil, nil, filepath.Join(bindir, "initdb"), "-D", datadir)
+       prog, args := filepath.Join(bindir, "initdb"), []string{"-D", datadir, "-E", "utf8"}
+       if iamroot {
+               postgresUser, err := user.Lookup("postgres")
+               if err != nil {
+                       return fmt.Errorf("user.Lookup(\"postgres\"): %s", err)
+               }
+               postgresUid, err := strconv.Atoi(postgresUser.Uid)
+               if err != nil {
+                       return fmt.Errorf("user.Lookup(\"postgres\"): non-numeric uid?: %q", postgresUser.Uid)
+               }
+               postgresGid, err := strconv.Atoi(postgresUser.Gid)
+               if err != nil {
+                       return fmt.Errorf("user.Lookup(\"postgres\"): non-numeric gid?: %q", postgresUser.Gid)
+               }
+               err = os.Chown(super.tempdir, 0, postgresGid)
+               if err != nil {
+                       return err
+               }
+               err = os.Chmod(super.tempdir, 0710)
+               if err != nil {
+                       return err
+               }
+               err = os.Chown(datadir, postgresUid, 0)
+               if err != nil {
+                       return err
+               }
+               args = append([]string{"-u", "postgres", prog}, args...)
+               prog = "sudo"
+       }
+       err = super.RunProgram(ctx, super.tempdir, nil, nil, prog, args...)
        if err != nil {
                return err
        }
@@ -55,18 +93,29 @@ func (runPostgreSQL) Run(ctx context.Context, fail func(error), super *Superviso
        if err != nil {
                return err
        }
+       if iamroot {
+               err = super.RunProgram(ctx, super.tempdir, nil, nil, "chown", "postgres", datadir+"/server.crt", datadir+"/server.key")
+               if err != nil {
+                       return err
+               }
+       }
 
        port := super.cluster.PostgreSQL.Connection["port"]
 
        super.waitShutdown.Add(1)
        go func() {
                defer super.waitShutdown.Done()
-               fail(super.RunProgram(ctx, super.tempdir, nil, nil, filepath.Join(bindir, "postgres"),
+               prog, args := filepath.Join(bindir, "postgres"), []string{
                        "-l",          // enable ssl
                        "-D", datadir, // data dir
                        "-k", datadir, // socket dir
                        "-p", super.cluster.PostgreSQL.Connection["port"],
-               ))
+               }
+               if iamroot {
+                       args = append([]string{"-u", "postgres", prog}, args...)
+                       prog = "sudo"
+               }
+               fail(super.RunProgram(ctx, super.tempdir, nil, nil, prog, args...))
        }()
 
        for {
@@ -78,11 +127,15 @@ func (runPostgreSQL) Run(ctx context.Context, fail func(error), super *Superviso
                }
                time.Sleep(time.Second / 2)
        }
-       db, err := sql.Open("postgres", arvados.PostgreSQLConnection{
+       pgconn := arvados.PostgreSQLConnection{
                "host":   datadir,
                "port":   port,
                "dbname": "postgres",
-       }.String())
+       }
+       if iamroot {
+               pgconn["user"] = "postgres"
+       }
+       db, err := sql.Open("postgres", pgconn.String())
        if err != nil {
                return fmt.Errorf("db open failed: %s", err)
        }
index 4a4ab4d98b886e0bb037544b24d244c8d6478901..d230dcc3ed0e3440ab654208afb16bdcc56f20f3 100644 (file)
@@ -406,7 +406,11 @@ func (super *Supervisor) RunProgram(ctx context.Context, dir string, output io.W
        cmdline := fmt.Sprintf("%s", append([]string{prog}, args...))
        super.logger.WithField("command", cmdline).WithField("dir", dir).Info("executing")
 
-       logprefix := strings.TrimPrefix(prog, super.tempdir+"/bin/")
+       logprefix := prog
+       if logprefix == "sudo" && len(args) >= 3 && args[0] == "-u" {
+               logprefix = args[2]
+       }
+       logprefix = strings.TrimPrefix(logprefix, super.tempdir+"/bin/")
        if logprefix == "bundle" && len(args) > 2 && args[0] == "exec" {
                logprefix = args[1]
        } else if logprefix == "arvados-server" && len(args) > 1 {