Skip to content

Commit 6839b7d

Browse files
committed
[supervisor] Introduce subcommand "dockerd-proxy" and GITPOD_DOCKERD_PROXY_ENABLED for control
docker-proxy is a MITM proxy to intercept HTTPS traffic. It does that to inject authentication for all registires configured Tool: gitpod/catfood.gitpod.cloud
1 parent cffb23c commit 6839b7d

File tree

8 files changed

+706
-65
lines changed

8 files changed

+706
-65
lines changed

components/supervisor/BUILD.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ packages:
1414
- components/ws-daemon-api/go:lib
1515
- components/ide-metrics-api/go:lib
1616
- components/public-api/go:lib
17+
- components/image-builder-bob:lib
1718
env:
1819
- CGO_ENABLED=0
1920
- GOOS=linux
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// Copyright (c) 2025 Gitpod GmbH. All rights reserved.
2+
// Licensed under the GNU Affero General Public License (AGPL).
3+
// See License.AGPL.txt in the project root for license information.
4+
5+
package cmd
6+
7+
import (
8+
"context"
9+
"net/http"
10+
"os"
11+
12+
"github.com/containerd/containerd/remotes/docker"
13+
"github.com/spf13/cobra"
14+
15+
log "github.com/gitpod-io/gitpod/common-go/log"
16+
"github.com/gitpod-io/gitpod/image-builder/bob/pkg/proxy"
17+
"github.com/gitpod-io/gitpod/supervisor/pkg/dockerd"
18+
)
19+
20+
var proxyOpts struct {
21+
GitpodImageAuth string
22+
}
23+
24+
// dockerdProxyCmd represents the build command
25+
var dockerdProxyCmd = &cobra.Command{
26+
Use: "dockerd-proxy",
27+
Short: "Runs an authenticating proxy",
28+
Run: func(cmd *cobra.Command, args []string) {
29+
log.Init("dockerd-proxy", "", true, os.Getenv("SUPERVISOR_DEBUG_ENABLE") == "true")
30+
log := log.WithField("command", "dockerd-proxy")
31+
32+
auth, err := proxy.NewAuthorizerFromGitpodImageAuth(proxyOpts.GitpodImageAuth)
33+
if err != nil {
34+
log.WithError(err).WithField("gitpodImageAuth", proxyOpts.GitpodImageAuth).Fatal("cannot unmarshal gitpodImageAuth")
35+
}
36+
37+
//certDir := "/workspace/.dockerd-proxy/certs"
38+
certDir, err := os.MkdirTemp("/tmp", "gitpod-dockerd-proxy-certs")
39+
if err != nil {
40+
log.WithError(err).Fatal("cannot create temporary directory for certificates")
41+
}
42+
certPath, keyPath, err := dockerd.EnsureProxyCaAndCertificatesInstalled(certDir)
43+
if err != nil {
44+
log.WithError(err).Fatal("failed to ensure proxy CA and certificates are installed")
45+
}
46+
47+
// Setup the (authenticating) MITM proxy to handle CONNECT requests
48+
authorizer := func() docker.Authorizer { return docker.NewDockerAuthorizer(docker.WithAuthCreds(auth.Authorize)) }
49+
mitmProxy, err := dockerd.CreateMitmProxy(certPath, keyPath, func(r *http.Request) *http.Request {
50+
ctx := r.Context()
51+
52+
auth := authorizer()
53+
r = r.WithContext(context.WithValue(ctx, proxy.CONTEXT_KEY_AUTHORIZER, auth)) // install to context, as the proxy relies on it
54+
55+
err = auth.Authorize(ctx, r)
56+
if err != nil {
57+
log.WithError(err).Error("cannot authorize request")
58+
}
59+
return r
60+
})
61+
if err != nil {
62+
log.Fatal(err)
63+
}
64+
65+
// Setup the (authenticating) forwarding proxy to handle all other requests
66+
handler := func(scheme string) http.Handler {
67+
httpProxy, err := proxy.NewForwardProxy(authorizer, scheme)
68+
if err != nil {
69+
log.Fatal(err)
70+
}
71+
72+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
73+
if r.Method == http.MethodConnect {
74+
mitmProxy.ServeHTTP(w, r)
75+
} else {
76+
httpProxy.ServeHTTP(w, r)
77+
}
78+
})
79+
}
80+
81+
log.Info("starting https dockerd proxy on :38081")
82+
go (func() {
83+
err := http.ListenAndServeTLS(":38081", certPath, keyPath, handler("https"))
84+
if err != nil {
85+
log.Fatal(err)
86+
}
87+
})()
88+
log.Info("starting http dockerd proxy on :38080")
89+
err = http.ListenAndServe(":38080", handler("http"))
90+
if err != nil {
91+
log.Fatal(err)
92+
}
93+
},
94+
}
95+
96+
func init() {
97+
rootCmd.AddCommand(dockerdProxyCmd)
98+
99+
// These env vars start with `WORKSPACEKIT_` so that they aren't passed on to ring2
100+
dockerdProxyCmd.Flags().StringVar(&proxyOpts.GitpodImageAuth, "gitpod-image-auth", os.Getenv("WORKSPACEKIT_GITPOD_IMAGE_AUTH"), "docker credentials in the GITPOD_IMAGE_AUTH format")
101+
}

components/supervisor/go.mod

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,27 @@ go 1.22
55
require (
66
github.com/Netflix/go-env v0.0.0-20220526054621-78278af1949d
77
github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8
8-
github.com/cenkalti/backoff/v4 v4.2.0
8+
github.com/cenkalti/backoff/v4 v4.2.1
9+
github.com/containerd/containerd v1.7.25
910
github.com/creack/pty v1.1.18
10-
github.com/fsnotify/fsnotify v1.4.9
11+
github.com/fsnotify/fsnotify v1.6.0
1112
github.com/gitpod-io/gitpod/common-go v0.0.0-00010101000000-000000000000
1213
github.com/gitpod-io/gitpod/components/public-api/go v0.0.0-00010101000000-000000000000
1314
github.com/gitpod-io/gitpod/content-service v0.0.0-00010101000000-000000000000
1415
github.com/gitpod-io/gitpod/content-service/api v0.0.0-00010101000000-000000000000
1516
github.com/gitpod-io/gitpod/gitpod-protocol v0.0.0-00010101000000-000000000000
1617
github.com/gitpod-io/gitpod/ide-metrics-api v0.0.0-00010101000000-000000000000
18+
github.com/gitpod-io/gitpod/image-builder/bob v0.0.0-00010101000000-000000000000
1719
github.com/gitpod-io/gitpod/supervisor/api v0.0.0-00010101000000-000000000000
1820
github.com/gitpod-io/gitpod/ws-daemon/api v0.0.0-00010101000000-000000000000
19-
github.com/gitpod-io/go-reaper v0.0.0-20241024192051-78d04cc2e25f
2021
github.com/golang/mock v1.6.0
2122
github.com/google/go-cmp v0.6.0
2223
github.com/google/uuid v1.6.0
2324
github.com/gorilla/websocket v1.5.0
2425
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
2526
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
26-
github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3
27+
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0
28+
github.com/hashicorp/go-retryablehttp v0.7.2
2729
github.com/improbable-eng/grpc-web v0.14.0
2830
github.com/prometheus/client_golang v1.16.0
2931
github.com/prometheus/client_model v0.3.0
@@ -33,27 +35,33 @@ require (
3335
github.com/ramr/go-reaper v0.2.2
3436
github.com/sirupsen/logrus v1.9.3
3537
github.com/soheilhy/cmux v0.1.5
36-
github.com/spf13/cobra v1.4.0
38+
github.com/spf13/cobra v1.7.0
3739
golang.org/x/crypto v0.31.0
3840
golang.org/x/net v0.25.0
3941
golang.org/x/sync v0.10.0
4042
golang.org/x/sys v0.28.0
4143
golang.org/x/term v0.27.0
4244
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028
4345
google.golang.org/grpc v1.62.1
44-
google.golang.org/protobuf v1.33.0
46+
google.golang.org/protobuf v1.35.2
4547
gopkg.in/yaml.v3 v3.0.1
4648
)
4749

4850
require (
51+
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
52+
github.com/containerd/errdefs v0.3.0 // indirect
53+
github.com/containerd/log v0.1.0 // indirect
54+
github.com/containerd/platforms v0.2.1 // indirect
4955
github.com/felixge/httpsnoop v1.0.4 // indirect
5056
github.com/go-logr/logr v1.4.1 // indirect
5157
github.com/go-logr/stdr v1.2.2 // indirect
5258
github.com/google/s2a-go v0.1.7 // indirect
59+
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
5360
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
5461
github.com/mattn/go-colorable v0.1.8 // indirect
5562
github.com/mattn/go-isatty v0.0.14 // indirect
5663
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
64+
github.com/moby/locker v1.0.1 // indirect
5765
github.com/onsi/ginkgo v1.16.5 // indirect
5866
github.com/onsi/gomega v1.27.10 // indirect
5967
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect
@@ -62,7 +70,7 @@ require (
6270
go.opentelemetry.io/otel/metric v1.24.0 // indirect
6371
go.opentelemetry.io/otel/trace v1.24.0 // indirect
6472
google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 // indirect
65-
google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c // indirect
73+
google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect
6674
)
6775

6876
require (
@@ -100,21 +108,21 @@ require (
100108
github.com/blang/semver v3.5.1+incompatible // indirect
101109
github.com/cenkalti/backoff v2.2.1+incompatible // indirect
102110
github.com/cespare/xxhash/v2 v2.2.0 // indirect
103-
github.com/cilium/ebpf v0.4.0 // indirect
111+
github.com/cilium/ebpf v0.9.1 // indirect
104112
github.com/configcat/go-sdk/v7 v7.6.0 // indirect
105-
github.com/containerd/cgroups v1.0.4 // indirect
106-
github.com/coreos/go-systemd/v22 v22.4.0 // indirect
113+
github.com/containerd/cgroups v1.1.0 // indirect
114+
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
107115
github.com/davecgh/go-spew v1.1.1 // indirect
108116
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect
109-
github.com/docker/go-units v0.4.0 // indirect
117+
github.com/docker/go-units v0.5.0 // indirect
110118
github.com/dustin/go-humanize v1.0.1 // indirect
111119
github.com/fatih/camelcase v1.0.0 // indirect
112120
github.com/fatih/gomodifytags v1.14.0 // indirect
113121
github.com/fatih/structtag v1.2.0 // indirect
114122
github.com/go-kit/log v0.2.1 // indirect
115123
github.com/go-logfmt/logfmt v0.5.1 // indirect
116124
github.com/go-ozzo/ozzo-validation v3.5.0+incompatible // indirect
117-
github.com/godbus/dbus/v5 v5.0.4 // indirect
125+
github.com/godbus/dbus/v5 v5.1.0 // indirect
118126
github.com/gogo/protobuf v1.3.2 // indirect
119127
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
120128
github.com/golang/protobuf v1.5.4 // indirect
@@ -123,7 +131,7 @@ require (
123131
github.com/hashicorp/golang-lru v1.0.2 // indirect
124132
github.com/heptiolabs/healthcheck v0.0.0-20211123025425-613501dd5deb // indirect
125133
github.com/iancoleman/orderedmap v0.2.0
126-
github.com/inconshreveable/mousetrap v1.0.0 // indirect
134+
github.com/inconshreveable/mousetrap v1.1.0 // indirect
127135
github.com/jmespath/go-jmespath v0.4.0 // indirect
128136
github.com/json-iterator/go v1.1.12 // indirect
129137
github.com/julienschmidt/httprouter v1.3.0 // indirect
@@ -136,8 +144,8 @@ require (
136144
github.com/modern-go/reflect2 v1.0.2 // indirect
137145
github.com/moredure/easygo v0.0.0-20220122214504-21cd2ebdd15b
138146
github.com/opencontainers/go-digest v1.0.0 // indirect
139-
github.com/opencontainers/image-spec v1.0.2 // indirect
140-
github.com/opencontainers/runtime-spec v1.0.2 // indirect
147+
github.com/opencontainers/image-spec v1.1.0 // indirect
148+
github.com/opencontainers/runtime-spec v1.1.0 // indirect
141149
github.com/opentracing/opentracing-go v1.2.0 // indirect
142150
github.com/pkg/errors v0.9.1 // indirect
143151
github.com/pmezard/go-difflib v1.0.0 // indirect
@@ -184,6 +192,8 @@ replace github.com/gitpod-io/gitpod/supervisor/api => ../supervisor-api/go // le
184192

185193
replace github.com/gitpod-io/gitpod/ws-daemon/api => ../ws-daemon-api/go // leeway
186194

195+
replace github.com/gitpod-io/gitpod/image-builder/bob => ../image-builder-bob // leeway
196+
187197
replace k8s.io/api => k8s.io/api v0.29.3 // leeway indirect from components/common-go:lib
188198

189199
replace k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.29.3 // leeway indirect from components/common-go:lib

0 commit comments

Comments
 (0)