Skip to content

Commit 064c8fb

Browse files
committed
[docker-up] Read GITPOD_IMAGE_AUTH, and if set, call "docker login" for each host/credentials pair
Tool: gitpod/catfood.gitpod.cloud
1 parent 6048ca2 commit 064c8fb

File tree

1 file changed

+78
-0
lines changed
  • components/docker-up/docker-up

1 file changed

+78
-0
lines changed

components/docker-up/docker-up/main.go

+78
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@ package main
1010
import (
1111
"archive/tar"
1212
"bufio"
13+
"bytes"
1314
"compress/gzip"
1415
"context"
1516
"embed"
17+
"encoding/base64"
1618
"encoding/json"
1719
"fmt"
1820
"io"
@@ -58,6 +60,7 @@ var aptUpdated = false
5860
const (
5961
dockerSocketFN = "/var/run/docker.sock"
6062
gitpodUserId = 33333
63+
gitpodGroupId = 33333
6164
containerIf = "eth0"
6265
)
6366

@@ -185,13 +188,88 @@ func runWithinNetns() (err error) {
185188
}()
186189
}
187190

191+
if imageAuth, _ := os.LookupEnv("GITPOD_IMAGE_AUTH"); strings.TrimSpace(imageAuth) != "" {
192+
if err := waitUntilSocketPresent(dockerSocketFN); err == nil {
193+
tryAuthenticateForAllHosts(imageAuth)
194+
}
195+
}
196+
188197
err = cmd.Wait()
189198
if err != nil {
190199
return err
191200
}
192201
return nil
193202
}
194203

204+
func waitUntilSocketPresent(dockerSocketFN string) error {
205+
socketTimeout := 30 * time.Second
206+
socketCtx, cancel := context.WithTimeout(context.Background(), socketTimeout)
207+
defer cancel()
208+
209+
ticker := time.NewTicker(100 * time.Millisecond)
210+
defer ticker.Stop()
211+
212+
for {
213+
select {
214+
case <-socketCtx.Done():
215+
log.WithError(socketCtx.Err()).Warn("timeout waiting for docker socket")
216+
return socketCtx.Err()
217+
case <-ticker.C:
218+
if _, err := os.Stat(dockerSocketFN); err == nil {
219+
// Socket file exists
220+
return nil
221+
}
222+
}
223+
}
224+
}
225+
226+
func tryAuthenticateForAllHosts(imageAuth string) {
227+
splitHostAndCredentials := func(s string) (string, string) {
228+
parts := strings.SplitN(s, ":", 2)
229+
if len(parts) < 2 {
230+
return "", ""
231+
}
232+
return parts[0], parts[1]
233+
}
234+
splitCredentials := func(host, s string) (string, string, error) {
235+
credentials, err := base64.StdEncoding.DecodeString(s)
236+
if err != nil {
237+
return "", "", fmt.Errorf("Cannot decode docker credentials for host %s: %w", host, err)
238+
}
239+
parts := strings.SplitN(string(credentials), ":", 2)
240+
if len(parts) < 2 {
241+
return "", "", fmt.Errorf("Credentials in wrong format")
242+
}
243+
return parts[0], parts[1], nil
244+
}
245+
246+
authenticationPerHost := strings.Split(imageAuth, ",")
247+
for _, hostCredentials := range authenticationPerHost {
248+
host, credentials := splitHostAndCredentials(hostCredentials)
249+
if host == "" || credentials == "" {
250+
log.Warnf("Unable to authenticate with host %s, skipping.", host)
251+
continue
252+
}
253+
username, password, decodeErr := splitCredentials(host, credentials)
254+
if decodeErr != nil || username == "" || password == "" {
255+
log.WithError(decodeErr).Warnf("Unable to authenticate with host %s, skipping.", host)
256+
continue
257+
}
258+
259+
loginCmd := exec.Command("docker", "login", "--username", username, "--password-stdin", host)
260+
loginCmd.SysProcAttr = &syscall.SysProcAttr{}
261+
loginCmd.Env = append(loginCmd.Env, "USER=gitpod")
262+
loginCmd.SysProcAttr.Credential = &syscall.Credential{Uid: gitpodUserId, Gid: gitpodGroupId}
263+
loginCmd.Stdin = bytes.NewBufferString(password)
264+
loginErr := loginCmd.Run()
265+
if loginErr != nil {
266+
log.WithError(loginErr).Warnf("Unable to authenticate with host %s, skipping.%s", host)
267+
continue
268+
}
269+
log.Infof("Authenticated with host %s", host)
270+
}
271+
}
272+
195273
type ConvertUserArg func(arg, value string) ([]string, error)
196274

197275
var allowedDockerArgs = map[string]ConvertUserArg{

0 commit comments

Comments
 (0)