Skip to content

Commit

Permalink
Revert "Relax assumptions in supervisor (#18782)" (#18857)
Browse files Browse the repository at this point in the history
This reverts commit 9a38b60.
  • Loading branch information
akosyakov authored Oct 2, 2023
1 parent 9179f65 commit 40c39f5
Show file tree
Hide file tree
Showing 14 changed files with 123 additions and 235 deletions.
4 changes: 2 additions & 2 deletions components/content-service/pkg/executor/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func Prepare(req *csapi.WorkspaceInitializer, urls map[string]string) ([]byte, e

// Execute runs an initializer to place content in destination based on the configuration read
// from the cfgin stream.
func Execute(ctx context.Context, destination string, cfgin io.Reader, runAs *initializer.User, opts ...initializer.InitializeOpt) (src csapi.WorkspaceInitSource, err error) {
func Execute(ctx context.Context, destination string, cfgin io.Reader, forceGitUser bool, opts ...initializer.InitializeOpt) (src csapi.WorkspaceInitSource, err error) {
var cfg config
err = json.NewDecoder(cfgin).Decode(&cfg)
if err != nil {
Expand All @@ -64,7 +64,7 @@ func Execute(ctx context.Context, destination string, cfgin io.Reader, runAs *in

rs = &storage.NamedURLDownloader{URLs: cfg.URLs}
ilr, err = initializer.NewFromRequest(ctx, destination, rs, &req, initializer.NewFromRequestOpts{
RunAs: runAs,
ForceGitpodUserForGit: forceGitUser,
})
if err != nil {
return "", err
Expand Down
25 changes: 8 additions & 17 deletions components/content-service/pkg/git/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import (
"os/exec"
"path/filepath"
"strings"
"syscall"

"github.com/opentracing/opentracing-go"
"golang.org/x/xerrors"
Expand Down Expand Up @@ -94,12 +93,8 @@ type Client struct {
// UpstreamCloneURI is the fork upstream of a repository
UpstreamRemoteURI string

// RunAs runs the Git commands as a particular user - if not nil
RunAs *User
}

type User struct {
UID, GID uint32
// if true will run git command as gitpod user (should be executed as root that has access to sudo in this case)
RunAsGitpodUser bool
}

// Status describes the status of a Git repo/working copy akin to "git status"
Expand Down Expand Up @@ -183,6 +178,8 @@ func (c *Client) GitWithOutput(ctx context.Context, ignoreErr *string, subcomman
env = append(env, fmt.Sprintf("GIT_AUTH_PASSWORD=%s", pwd))
}

env = append(env, "HOME=/home/gitpod")

fullArgs = append(fullArgs, subcommand)
fullArgs = append(fullArgs, args...)

Expand All @@ -204,19 +201,13 @@ func (c *Client) GitWithOutput(ctx context.Context, ignoreErr *string, subcomman
span.LogKV("args", fullArgs)

cmdName := "git"
if c.RunAsGitpodUser {
cmdName = "sudo"
fullArgs = append([]string{"-u", "gitpod", "git"}, fullArgs...)
}
cmd := exec.Command(cmdName, fullArgs...)
cmd.Dir = c.Location
cmd.Env = env
if c.RunAs != nil {
if cmd.SysProcAttr == nil {
cmd.SysProcAttr = &syscall.SysProcAttr{}
}
if cmd.SysProcAttr.Credential == nil {
cmd.SysProcAttr.Credential = &syscall.Credential{}
}
cmd.SysProcAttr.Credential.Uid = c.RunAs.UID
cmd.SysProcAttr.Credential.Gid = c.RunAs.UID
}

res, err := cmd.CombinedOutput()
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions components/content-service/pkg/initializer/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ func (ws *GitInitializer) Run(ctx context.Context, mappings []archive.IDMapping)

// make sure that folder itself is owned by gitpod user prior to doing git clone
// this is needed as otherwise git clone will fail if the folder is owned by root
if ws.RunAs != nil {
args := []string{fmt.Sprintf("%d:%d", ws.RunAs.UID, ws.RunAs.GID), ws.Location}
if ws.RunAsGitpodUser {
args := []string{"gitpod", ws.Location}
cmd := exec.Command("chown", args...)
res, cerr := cmd.CombinedOutput()
if cerr != nil && !process.IsNotChildProcess(cerr) {
Expand Down
25 changes: 9 additions & 16 deletions components/content-service/pkg/initializer/initializer.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,11 @@ func (e CompositeInitializer) Run(ctx context.Context, mappings []archive.IDMapp

// NewFromRequestOpts configures the initializer produced from a content init request
type NewFromRequestOpts struct {
// RunAs - if not nil - decides the user with which the initiallisation will be executed
RunAs *User
}

type User struct {
UID uint32
GID uint32
// ForceGitpodUserForGit forces gitpod:gitpod ownership on all files produced by the Git initializer.
// For FWB workspaces the content init is run from supervisor which runs as UID 0. Using this flag, the
// Git content is forced to the Gitpod user. All other content (backup, prebuild, snapshot) will already
// have the correct user.
ForceGitpodUserForGit bool
}

// NewFromRequest picks the initializer from the request but does not execute it.
Expand Down Expand Up @@ -134,7 +132,7 @@ func NewFromRequest(ctx context.Context, loc string, rs storage.DirectDownloader
return nil, status.Error(codes.InvalidArgument, "missing Git initializer spec")
}

initializer, err = newGitInitializer(ctx, loc, ir.Git, opts.RunAs)
initializer, err = newGitInitializer(ctx, loc, ir.Git, opts.ForceGitpodUserForGit)
} else if ir, ok := spec.(*csapi.WorkspaceInitializer_Prebuild); ok {
if ir.Prebuild == nil {
return nil, status.Error(codes.InvalidArgument, "missing prebuild initializer spec")
Expand All @@ -148,7 +146,7 @@ func NewFromRequest(ctx context.Context, loc string, rs storage.DirectDownloader
}
var gits []*GitInitializer
for _, gi := range ir.Prebuild.Git {
gitinit, err := newGitInitializer(ctx, loc, gi, opts.RunAs)
gitinit, err := newGitInitializer(ctx, loc, gi, opts.ForceGitpodUserForGit)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -251,7 +249,7 @@ func (bi *fromBackupInitializer) Run(ctx context.Context, mappings []archive.IDM

// newGitInitializer creates a Git initializer based on the request.
// Returns gRPC errors.
func newGitInitializer(ctx context.Context, loc string, req *csapi.GitInitializer, runAs *User) (*GitInitializer, error) {
func newGitInitializer(ctx context.Context, loc string, req *csapi.GitInitializer, forceGitpodUser bool) (*GitInitializer, error) {
if req.Config == nil {
return nil, status.Error(codes.InvalidArgument, "Git initializer misses config")
}
Expand Down Expand Up @@ -296,11 +294,6 @@ func newGitInitializer(ctx context.Context, loc string, req *csapi.GitInitialize
return
})

var user *git.User
if runAs != nil {
user = &git.User{UID: runAs.UID, GID: runAs.GID}
}

log.WithField("location", loc).Debug("using Git initializer")
return &GitInitializer{
Client: git.Client{
Expand All @@ -310,7 +303,7 @@ func newGitInitializer(ctx context.Context, loc string, req *csapi.GitInitialize
Config: req.Config.CustomConfig,
AuthMethod: authMethod,
AuthProvider: authProvider,
RunAs: user,
RunAsGitpodUser: forceGitpodUser,
},
TargetMode: targetMode,
CloneTarget: req.CloneTaget,
Expand Down
38 changes: 0 additions & 38 deletions components/supervisor/cmd/dump-initializer.go

This file was deleted.

32 changes: 2 additions & 30 deletions components/supervisor/pkg/supervisor/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"math"
"net/http"
"net/url"
Expand Down Expand Up @@ -328,35 +329,6 @@ type WorkspaceConfig struct {

// ConfigcatEnabled controls whether configcat is enabled
ConfigcatEnabled bool `env:"GITPOD_CONFIGCAT_ENABLED"`

WorkspaceLinuxUID uint32 `env:"GITPOD_WORKSPACE_LINUX_UID,default=33333"`
WorkspaceLinuxGID uint32 `env:"GITPOD_WORKSPACE_LINUX_GID,default=33333"`

// ContentInitializer - if set - will run the content initializer instead of waiting for the ready file
ContentInitializer string `env:"SUPERVISOR_CONTENT_INITIALIZER"`

// WorkspaceRuntime configures the runtime supervisor is running in
WorkspaceRuntime WorkspaceRuntime `env:"SUPERVISOR_WORKSPACE_RUNTIME,default=container"`
}

type WorkspaceRuntime string

const (
WorkspaceRuntimeContainer WorkspaceRuntime = "container"
WorkspaceRuntimeNextgen WorkspaceRuntime = "nextgen"
WorkspaceRuntimeRunGP WorkspaceRuntime = "rungp"
)

func (rt *WorkspaceRuntime) UnmarshalEnvironmentValue(data string) error {
switch WorkspaceRuntime(data) {
case WorkspaceRuntimeContainer, WorkspaceRuntimeNextgen, WorkspaceRuntimeRunGP:
// everything's fine
default:
return fmt.Errorf("unknown workspace runtime: %s", data)
}

*rt = WorkspaceRuntime(data)
return nil
}

// WorkspaceGitpodToken is a list of tokens that should be added to supervisor's token service.
Expand Down Expand Up @@ -615,7 +587,7 @@ func loadDesktopIDEs(static *StaticConfig) ([]*IDEConfig, error) {
uniqueDesktopIDEs[desktopIDE.Name] = struct{}{}
}

files, err := os.ReadDir(static.DesktopIDERoot)
files, err := ioutil.ReadDir(static.DesktopIDERoot)
if err != nil {
return nil, err
}
Expand Down
10 changes: 5 additions & 5 deletions components/supervisor/pkg/supervisor/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func socketActivationForDocker(parentCtx context.Context, wg *sync.WaitGroup, te
return
}

logFile, err := openDockerUpLogFile(int(cfg.WorkspaceLinuxUID), int(cfg.WorkspaceLinuxGID))
logFile, err := openDockerUpLogFile()
if err != nil {
log.WithError(err).Error("docker-up: cannot open log file")
} else {
Expand Down Expand Up @@ -164,7 +164,7 @@ func listenToDockerSocket(parentCtx context.Context, term *terminal.Mux, cfg *Co
l.Close()
}()

_ = os.Chown(fn, int(cfg.WorkspaceLinuxUID), int(cfg.WorkspaceLinuxGID))
_ = os.Chown(fn, gitpodUID, gitpodGID)

var lastExitErrorTime time.Time
burstAttempts := 0
Expand Down Expand Up @@ -267,19 +267,19 @@ func listenToDockerSocket(parentCtx context.Context, term *terminal.Mux, cfg *Co
return ctx.Err()
}

func openDockerUpLogFile(uid, gid int) (*os.File, error) {
func openDockerUpLogFile() (*os.File, error) {
if err := os.MkdirAll(logsDir, 0755); err != nil {
return nil, xerrors.Errorf("cannot create logs dir: %w", err)
}
if err := os.Chown(logsDir, uid, gid); err != nil {
if err := os.Chown(logsDir, gitpodUID, gitpodGID); err != nil {
return nil, xerrors.Errorf("cannot chown logs dir: %w", err)
}
logFile, err := os.OpenFile(dockerUpLogFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return nil, xerrors.Errorf("cannot open docker-up log file: %w", err)
}

if err := os.Chown(dockerUpLogFilePath, uid, gid); err != nil {
if err := os.Chown(dockerUpLogFilePath, gitpodUID, gitpodGID); err != nil {
_ = logFile.Close()
return nil, xerrors.Errorf("cannot chown docker-up log file: %w", err)
}
Expand Down
2 changes: 1 addition & 1 deletion components/supervisor/pkg/supervisor/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ func (p *GitTokenProvider) openAccessControl() error {
return err
}
gpCmd := exec.Command(gpPath, "preview", "--external", p.workspaceConfig.GitpodHost+"/access-control")
runAsUser(gpCmd, p.workspaceConfig.WorkspaceLinuxUID, p.workspaceConfig.WorkspaceLinuxGID)
runAsGitpodUser(gpCmd)
if b, err := gpCmd.CombinedOutput(); err != nil {
log.WithField("Stdout", string(b)).WithError(err).Error("failed to exec gp preview to open access control")
return err
Expand Down
30 changes: 14 additions & 16 deletions components/supervisor/pkg/supervisor/services.go
Original file line number Diff line number Diff line change
Expand Up @@ -741,7 +741,7 @@ func (is *InfoService) WorkspaceInfo(ctx context.Context, req *api.WorkspaceInfo
}
}

resp.UserHome = os.Getenv("HOME")
resp.UserHome = "/home/gitpod"

endpoint, host, err := is.cfg.GitpodAPIEndpoint()
if err != nil {
Expand All @@ -763,8 +763,6 @@ type ControlService struct {
publicKey string
hostKey *api.SSHPublicKey

uid, gid int

api.UnimplementedControlServiceServer
}

Expand All @@ -785,24 +783,24 @@ func (c *ControlService) ExposePort(ctx context.Context, req *api.ExposePortRequ
}

// CreateSSHKeyPair create a ssh key pair for the workspace.
func (c *ControlService) CreateSSHKeyPair(ctx context.Context, req *api.CreateSSHKeyPairRequest) (response *api.CreateSSHKeyPairResponse, err error) {
home := os.Getenv("HOME")
if c.privateKey != "" && c.publicKey != "" {
func (ss *ControlService) CreateSSHKeyPair(ctx context.Context, req *api.CreateSSHKeyPairRequest) (response *api.CreateSSHKeyPairResponse, err error) {
home := "/home/gitpod/"
if ss.privateKey != "" && ss.publicKey != "" {
checkKey := func() error {
data, err := os.ReadFile(filepath.Join(home, ".ssh/authorized_keys"))
if err != nil {
return xerrors.Errorf("cannot read file ~/.ssh/authorized_keys: %w", err)
}
if !bytes.Contains(data, []byte(c.publicKey)) {
if !bytes.Contains(data, []byte(ss.publicKey)) {
return xerrors.Errorf("not found special publickey")
}
return nil
}
err := checkKey()
if err == nil {
return &api.CreateSSHKeyPairResponse{
PrivateKey: c.privateKey,
HostKey: c.hostKey,
PrivateKey: ss.privateKey,
HostKey: ss.hostKey,
}, nil
}
log.WithError(err).Error("check authorized_keys failed, will recreate")
Expand All @@ -813,7 +811,7 @@ func (c *ControlService) CreateSSHKeyPair(ctx context.Context, req *api.CreateSS
if err != nil {
return nil, xerrors.Errorf("cannot create tmpfile: %w", err)
}
err = prepareSSHKey(ctx, filepath.Join(dir, "ssh"), c.uid, c.gid)
err = prepareSSHKey(ctx, filepath.Join(dir, "ssh"))
if err != nil {
return nil, xerrors.Errorf("cannot create ssh key pair: %w", err)
}
Expand All @@ -837,7 +835,7 @@ func (c *ControlService) CreateSSHKeyPair(ctx context.Context, req *api.CreateSS
if err != nil {
return nil, xerrors.Errorf("cannot write file ~.ssh/authorized_keys: %w", err)
}
err = os.Chown(filepath.Join(home, ".ssh/authorized_keys"), c.uid, c.gid)
err = os.Chown(filepath.Join(home, ".ssh/authorized_keys"), gitpodUID, gitpodGID)
if err != nil {
return nil, xerrors.Errorf("cannot chown SSH authorized_keys file: %w", err)
}
Expand All @@ -847,25 +845,25 @@ func (c *ControlService) CreateSSHKeyPair(ctx context.Context, req *api.CreateSS
if err != nil {
return nil, status.Errorf(codes.Internal, "cannot create ssh key pair: %v", err)
}
c.privateKey = string(generated.PrivateKey)
c.publicKey = string(generated.PublicKey)
ss.privateKey = string(generated.PrivateKey)
ss.publicKey = string(generated.PublicKey)

hostKey, err := os.ReadFile("/.supervisor/ssh/sshkey.pub")
if err != nil {
log.WithError(err).Error("faled to read host key")
} else {
hostKeyParts := strings.Split(string(hostKey), " ")
if len(hostKeyParts) >= 2 {
c.hostKey = &api.SSHPublicKey{
ss.hostKey = &api.SSHPublicKey{
Type: hostKeyParts[0],
Value: hostKeyParts[1],
}
}
}

return &api.CreateSSHKeyPairResponse{
PrivateKey: c.privateKey,
HostKey: c.hostKey,
PrivateKey: ss.privateKey,
HostKey: ss.hostKey,
}, err
}

Expand Down
Loading

0 comments on commit 40c39f5

Please sign in to comment.