Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[docker-up] Auto-login if GITPOD_IMAGE_AUTH is set #20571

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 3 additions & 96 deletions components/docker-up/docker-up/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,9 @@ package main

import (
"archive/tar"
"bufio"
"compress/gzip"
"context"
"embed"
"encoding/json"
"fmt"
"io"
"os"
Expand All @@ -25,6 +23,7 @@ import (
"syscall"
"time"

"github.com/gitpod-io/gitpod/docker-up/dockerd"
"github.com/rootless-containers/rootlesskit/pkg/sigproxy"
sigproxysignal "github.com/rootless-containers/rootlesskit/pkg/sigproxy/signal"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -57,7 +56,6 @@ var aptUpdated = false

const (
dockerSocketFN = "/var/run/docker.sock"
gitpodUserId = 33333
containerIf = "eth0"
)

Expand Down Expand Up @@ -118,7 +116,8 @@ func runWithinNetns() (err error) {
)
}

userArgs, err := userArgs()
userArgsValue, _ := os.LookupEnv(DaemonArgs)
userArgs, err := dockerd.ParseUserArgs(log, userArgsValue)
if err != nil {
return xerrors.Errorf("cannot add user supplied docker args: %w", err)
}
Expand Down Expand Up @@ -192,98 +191,6 @@ func runWithinNetns() (err error) {
return nil
}

type ConvertUserArg func(arg, value string) ([]string, error)

var allowedDockerArgs = map[string]ConvertUserArg{
"remap-user": convertRemapUser,
}

func userArgs() ([]string, error) {
userArgs, exists := os.LookupEnv(DaemonArgs)
args := []string{}
if !exists {
return args, nil
}

var providedDockerArgs map[string]string
if err := json.Unmarshal([]byte(userArgs), &providedDockerArgs); err != nil {
return nil, xerrors.Errorf("unable to deserialize docker args: %w", err)
}

for userArg, userValue := range providedDockerArgs {
converter, exists := allowedDockerArgs[userArg]
if !exists {
continue
}

if converter != nil {
cargs, err := converter(userArg, userValue)
if err != nil {
return nil, xerrors.Errorf("could not convert %v - %v: %w", userArg, userValue, err)
}
args = append(args, cargs...)

} else {
args = append(args, "--"+userArg, userValue)
}
}

return args, nil
}

func convertRemapUser(arg, value string) ([]string, error) {
id, err := strconv.Atoi(value)
if err != nil {
return nil, err
}

for _, f := range []string{"/etc/subuid", "/etc/subgid"} {
err := adaptSubid(f, id)
if err != nil {
return nil, xerrors.Errorf("could not adapt subid files: %w", err)
}
}

return []string{"--userns-remap", "gitpod"}, nil
}

func adaptSubid(oldfile string, id int) error {
uid, err := os.Open(oldfile)
if err != nil {
return err
}

newfile, err := os.Create(oldfile + ".new")
if err != nil {
return err
}

mappingFmt := func(username string, id int, size int) string { return fmt.Sprintf("%s:%d:%d\n", username, id, size) }

if id != 0 {
newfile.WriteString(mappingFmt("gitpod", 1, id))
newfile.WriteString(mappingFmt("gitpod", gitpodUserId, 1))
} else {
newfile.WriteString(mappingFmt("gitpod", gitpodUserId, 1))
newfile.WriteString(mappingFmt("gitpod", 1, gitpodUserId-1))
newfile.WriteString(mappingFmt("gitpod", gitpodUserId+1, 32200)) // map rest of user ids in the user namespace
}

uidScanner := bufio.NewScanner(uid)
for uidScanner.Scan() {
l := uidScanner.Text()
if !strings.HasPrefix(l, "gitpod") {
newfile.WriteString(l + "\n")
}
}

if err = os.Rename(newfile.Name(), oldfile); err != nil {
return err
}

return nil
}

var prerequisites = map[string]func() error{
"dockerd": installDocker,
"docker-compose": installDockerCompose,
Expand Down
144 changes: 144 additions & 0 deletions components/docker-up/dockerd/args.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package dockerd

import (
"bufio"
"encoding/json"
"fmt"
"os"
"strconv"
"strings"

"github.com/sirupsen/logrus"
"golang.org/x/xerrors"
)

const (
gitpodUserId = 33333
)

type ConvertUserArg func(arg string, value interface{}) ([]string, error)

var allowedDockerArgs = map[string]ConvertUserArg{
"remap-user": convertRemapUser,
// TODO(gpl): Why this allow-list instead of a converter lookup only?
"proxies": nil,
"http-proxy": nil,
"https-proxy": nil,
}

func ParseUserArgs(log *logrus.Entry, userArgs string) ([]string, error) {
if userArgs == "" {
return nil, nil
}

var providedDockerArgs map[string]interface{}
if err := json.Unmarshal([]byte(userArgs), &providedDockerArgs); err != nil {
return nil, xerrors.Errorf("unable to deserialize docker args: %w", err)
}

return mapUserArgs(log, providedDockerArgs)
}

func mapUserArgs(log *logrus.Entry, jsonObj map[string]interface{}) ([]string, error) {
args := []string{}
for userArg, userValue := range jsonObj {
converter, exists := allowedDockerArgs[userArg]
if !exists {
// TODO(gpl): Why this allow-list instead of a converter lookup only?
continue
}

if converter != nil {
cargs, err := converter(userArg, userValue)
if err != nil {
return nil, xerrors.Errorf("could not convert %v - %v: %w", userArg, userValue, err)
}
args = append(args, cargs...)
continue
}

strValue, ok := (userValue).(string)
if ok {
args = append(args, fmt.Sprintf("--%s=%s", userArg, strValue))
continue
}

bValue, ok := (userValue).(bool)
if ok {
args = append(args, fmt.Sprintf("--%s=%t", userArg, bValue))
continue
}

obj, ok := (userValue).(map[string]interface{})
if ok {
nestedArgs, err := mapUserArgs(log, obj)
if err != nil {
return nil, xerrors.Errorf("could not convert nested arg %v - %v: %w", userArg, userValue, err)
}
args = append(args, nestedArgs...)
continue
}

log.WithField("arg", userArg).WithField("value", userValue).Warn("could not map userArg to dockerd argument, skipping.")
}

return args, nil
}

func convertRemapUser(arg string, value interface{}) ([]string, error) {
v, ok := (value).(string)
if !ok {
return nil, xerrors.Errorf("userns-remap expects a string argument")
}

id, err := strconv.Atoi(v)
if err != nil {
return nil, err
}

for _, f := range []string{"/etc/subuid", "/etc/subgid"} {
err := adaptSubid(f, id)
if err != nil {
return nil, xerrors.Errorf("could not adapt subid files: %w", err)
}
}

return []string{"--userns-remap", "gitpod"}, nil
}

func adaptSubid(oldfile string, id int) error {
uid, err := os.Open(oldfile)
if err != nil {
return err
}

newfile, err := os.Create(oldfile + ".new")
if err != nil {
return err
}

mappingFmt := func(username string, id int, size int) string { return fmt.Sprintf("%s:%d:%d\n", username, id, size) }

if id != 0 {
newfile.WriteString(mappingFmt("gitpod", 1, id))
newfile.WriteString(mappingFmt("gitpod", gitpodUserId, 1))
} else {
newfile.WriteString(mappingFmt("gitpod", gitpodUserId, 1))
newfile.WriteString(mappingFmt("gitpod", 1, gitpodUserId-1))
newfile.WriteString(mappingFmt("gitpod", gitpodUserId+1, 32200)) // map rest of user ids in the user namespace
}

uidScanner := bufio.NewScanner(uid)
for uidScanner.Scan() {
l := uidScanner.Text()
if !strings.HasPrefix(l, "gitpod") {
newfile.WriteString(l + "\n")
}
}

if err = os.Rename(newfile.Name(), oldfile); err != nil {
return err
}

return nil
}
62 changes: 62 additions & 0 deletions components/docker-up/dockerd/args_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright (c) 2020 Gitpod GmbH. All rights reserved.
// Licensed under the GNU Affero General Public License (AGPL).
// See License.AGPL.txt in the project root for license information.

package dockerd

import (
"reflect"
"sort"
"testing"

"github.com/sirupsen/logrus"
)

func TestMapUserArgs(t *testing.T) {
tests := []struct {
name string
input map[string]interface{}
expected []string
wantErr bool
}{
{
name: "empty input",
input: map[string]interface{}{},
expected: []string{},
wantErr: false,
},
{
name: "tls and proxy settings",
input: map[string]interface{}{
"proxies": map[string]interface{}{
"http-proxy": "localhost:38080",
"https-proxy": "localhost:38081",
},
},
expected: []string{
"--http-proxy=localhost:38080",
"--https-proxy=localhost:38081",
},
wantErr: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
log := logrus.New().WithField("test", t.Name())
got, err := mapUserArgs(log, tt.input)
if (err != nil) != tt.wantErr {
t.Errorf("mapUserArgs() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !tt.wantErr {
sort.Strings(got)
sort.Strings(tt.expected)
// Sort both slices to ensure consistent comparison
if !reflect.DeepEqual(got, tt.expected) {
t.Errorf("mapUserArgs() = %v, want %v", got, tt.expected)
}
}
})
}
}
13 changes: 13 additions & 0 deletions components/image-builder-bob/BUILD.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,19 @@ packages:
- ["go", "mod", "tidy"]
config:
packaging: app
- name: lib
type: go
deps:
- components/common-go:lib
srcs:
- "cmd/*.go"
- "pkg/**/*.go"
- "main.go"
- "go.mod"
- "go.sum"
config:
packaging: library
dontTest: false
- name: runc-facade
type: go
srcs:
Expand Down
2 changes: 1 addition & 1 deletion components/image-builder-bob/cmd/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ var proxyCmd = &cobra.Command{
}
authA, err := proxy.NewAuthorizerFromEnvVar(proxyOpts.AdditionalAuth)
if err != nil {
log.WithError(err).WithField("auth", proxyOpts.Auth).Fatal("cannot unmarshal auth")
log.WithError(err).WithField("additionalAuth", proxyOpts.AdditionalAuth).Fatal("cannot unmarshal additionalAuth")
}
authP = authP.AddIfNotExists(authA)

Expand Down
Loading
Loading