diff --git a/components/content-service-api/go/go.mod b/components/content-service-api/go/go.mod index 675f3ecd2c181b..9e07833e271c8e 100644 --- a/components/content-service-api/go/go.mod +++ b/components/content-service-api/go/go.mod @@ -4,8 +4,10 @@ go 1.18 require ( github.com/gitpod-io/gitpod/common-go v0.0.0-00010101000000-000000000000 + github.com/google/go-cmp v0.5.7 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.0.2 + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 google.golang.org/grpc v1.45.0 google.golang.org/protobuf v1.28.0 ) @@ -33,7 +35,6 @@ require ( golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect - golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect ) diff --git a/components/content-service-api/go/go.sum b/components/content-service-api/go/go.sum index db77fc4c3e69cf..23c871ecbd0018 100644 --- a/components/content-service-api/go/go.sum +++ b/components/content-service-api/go/go.sum @@ -120,6 +120,7 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= diff --git a/components/content-service-api/go/initializer.go b/components/content-service-api/go/initializer.go new file mode 100644 index 00000000000000..6fe6dffda48abf --- /dev/null +++ b/components/content-service-api/go/initializer.go @@ -0,0 +1,132 @@ +// Copyright (c) 2022 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 api + +import ( + "fmt" + "strconv" + "strings" + + "golang.org/x/xerrors" +) + +// GetCheckoutLocationsFromInitializer returns a list of all checkout locations from the initializer +func GetCheckoutLocationsFromInitializer(init *WorkspaceInitializer) []string { + var res []string + _ = WalkInitializer(nil, init, func(path []string, init *WorkspaceInitializer) error { + switch spec := init.Spec.(type) { + case *WorkspaceInitializer_Git: + res = append(res, spec.Git.CheckoutLocation) + case *WorkspaceInitializer_Backup: + res = append(res, spec.Backup.CheckoutLocation) + + case *WorkspaceInitializer_Prebuild: + // walkInitializer will visit the Git initializer + } + + return nil + }) + return res +} + +const extractedSecretPrefix = "extracted-secret/" + +// ExtractSecretsFromInitializer removes secrets to the initializer. +// This is the counterpart of InjectSecretsToInitializer. +func ExtractSecretsFromInitializer(init *WorkspaceInitializer) map[string]string { + res := make(map[string]string) + + _ = WalkInitializer([]string{"initializer"}, init, func(path []string, init *WorkspaceInitializer) error { + git, ok := init.Spec.(*WorkspaceInitializer_Git) + if !ok { + return nil + } + + pwd := git.Git.Config.AuthPassword + if pwd == "" || strings.HasPrefix(pwd, extractedSecretPrefix) { + return nil + } + + name := strings.Join(path, ".") + res[name] = pwd + git.Git.Config.AuthPassword = extractedSecretPrefix + name + + return nil + }) + + return res +} + +// InjectSecretsToInitializer injects secrets to the initializer. This is the counterpart of ExtractSecretsFromInitializer. +func InjectSecretsToInitializer(init *WorkspaceInitializer, secrets map[string][]byte) error { + return WalkInitializer([]string{"initializer"}, init, func(path []string, init *WorkspaceInitializer) error { + git, ok := init.Spec.(*WorkspaceInitializer_Git) + if !ok { + return nil + } + + pwd := git.Git.Config.AuthPassword + if !strings.HasPrefix(pwd, extractedSecretPrefix) { + return nil + } + + name := strings.TrimPrefix(pwd, extractedSecretPrefix) + val, ok := secrets[name] + if !ok { + return xerrors.Errorf("secret %s not found", name) + } + + git.Git.Config.AuthPassword = string(val) + + return nil + }) +} + +// WalkInitializer walks the initializer structure +func WalkInitializer(path []string, init *WorkspaceInitializer, visitor func(path []string, init *WorkspaceInitializer) error) error { + if init == nil { + return nil + } + + switch spec := init.Spec.(type) { + case *WorkspaceInitializer_Backup: + return visitor(append(path, "backup"), init) + case *WorkspaceInitializer_Composite: + path = append(path, "composite") + err := visitor(path, init) + if err != nil { + return err + } + for i, p := range spec.Composite.Initializer { + err := WalkInitializer(append(path, strconv.Itoa(i)), p, visitor) + if err != nil { + return err + } + } + return nil + case *WorkspaceInitializer_Download: + return visitor(append(path, "download"), init) + case *WorkspaceInitializer_Empty: + return visitor(append(path, "empty"), init) + case *WorkspaceInitializer_Git: + return visitor(append(path, "git"), init) + case *WorkspaceInitializer_Prebuild: + child := append(path, "prebuild") + err := visitor(child, init) + if err != nil { + return err + } + for i, g := range spec.Prebuild.Git { + err = WalkInitializer(append(child, strconv.Itoa(i)), &WorkspaceInitializer{Spec: &WorkspaceInitializer_Git{Git: g}}, visitor) + if err != nil { + return err + } + } + return nil + + default: + return fmt.Errorf("unsupported workspace initializer in walkInitializer - this is a bug in Gitpod") + } +} diff --git a/components/content-service-api/go/initializer_test.go b/components/content-service-api/go/initializer_test.go new file mode 100644 index 00000000000000..369efbdfb4c136 --- /dev/null +++ b/components/content-service-api/go/initializer_test.go @@ -0,0 +1,219 @@ +// Copyright (c) 2022 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 api_test + +import ( + "path/filepath" + "strings" + "testing" + + "github.com/gitpod-io/gitpod/content-service/api" + "github.com/google/go-cmp/cmp" +) + +func TestGetCheckoutLocationsFromInitializer(t *testing.T) { + var init []*api.WorkspaceInitializer + init = append(init, &api.WorkspaceInitializer{ + Spec: &api.WorkspaceInitializer_Git{ + Git: &api.GitInitializer{ + CheckoutLocation: "/foo", + CloneTaget: "head", + Config: &api.GitConfig{ + Authentication: api.GitAuthMethod_NO_AUTH, + }, + RemoteUri: "somewhere-else", + TargetMode: api.CloneTargetMode_LOCAL_BRANCH, + }, + }, + }) + init = append(init, &api.WorkspaceInitializer{ + Spec: &api.WorkspaceInitializer_Git{ + Git: &api.GitInitializer{ + CheckoutLocation: "/bar", + CloneTaget: "head", + Config: &api.GitConfig{ + Authentication: api.GitAuthMethod_NO_AUTH, + }, + RemoteUri: "somewhere-else", + TargetMode: api.CloneTargetMode_LOCAL_BRANCH, + }, + }, + }) + + tests := []struct { + Name string + Initializer *api.WorkspaceInitializer + Expectation string + }{ + { + Name: "single git initializer", + Initializer: &api.WorkspaceInitializer{ + Spec: &api.WorkspaceInitializer_Git{ + Git: &api.GitInitializer{ + CheckoutLocation: "/foo", + CloneTaget: "head", + Config: &api.GitConfig{ + Authentication: api.GitAuthMethod_NO_AUTH, + }, + RemoteUri: "somewhere-else", + TargetMode: api.CloneTargetMode_LOCAL_BRANCH, + }, + }, + }, + Expectation: "/foo", + }, + { + Name: "multiple git initializer", + Initializer: &api.WorkspaceInitializer{ + Spec: &api.WorkspaceInitializer_Composite{ + Composite: &api.CompositeInitializer{ + Initializer: init, + }, + }, + }, + Expectation: "/foo,/bar", + }, + { + Name: "backup initializer", + Initializer: &api.WorkspaceInitializer{ + Spec: &api.WorkspaceInitializer_Backup{ + Backup: &api.FromBackupInitializer{ + CheckoutLocation: "/foobar", + }, + }, + }, + Expectation: "/foobar", + }, + { + Name: "prebuild initializer", + Initializer: &api.WorkspaceInitializer{ + Spec: &api.WorkspaceInitializer_Prebuild{ + Prebuild: &api.PrebuildInitializer{ + Git: []*api.GitInitializer{ + {CheckoutLocation: "/foo"}, + {CheckoutLocation: "/bar"}, + }, + }, + }, + }, + Expectation: "/foo,/bar", + }, + { + Name: "nil initializer", + }, + } + + for _, test := range tests { + t.Run(test.Name, func(t *testing.T) { + locations := strings.Join(api.GetCheckoutLocationsFromInitializer(test.Initializer), ",") + if locations != test.Expectation { + t.Errorf("expected %s, got %s", test.Expectation, locations) + } + }) + } +} + +func TestExtractInjectSecretsFromInitializer(t *testing.T) { + tests := []struct { + Name string + Input *api.WorkspaceInitializer + Expectation map[string]string + }{ + { + Name: "git initializer", + Input: &api.WorkspaceInitializer{ + Spec: &api.WorkspaceInitializer_Git{ + Git: &api.GitInitializer{ + Config: &api.GitConfig{ + AuthPassword: "foobar", + }, + }, + }, + }, + Expectation: map[string]string{ + "initializer.git": "foobar", + }, + }, + { + Name: "no secret git initializer", + Input: &api.WorkspaceInitializer{ + Spec: &api.WorkspaceInitializer_Git{ + Git: &api.GitInitializer{ + Config: &api.GitConfig{}, + }, + }, + }, + Expectation: map[string]string{}, + }, + { + Name: "prebuild initializer", + Input: &api.WorkspaceInitializer{ + Spec: &api.WorkspaceInitializer_Prebuild{ + Prebuild: &api.PrebuildInitializer{ + Git: []*api.GitInitializer{ + { + Config: &api.GitConfig{ + AuthPassword: "foobar", + }, + }, + { + Config: &api.GitConfig{ + AuthPassword: "some value", + }, + }, + }, + }, + }, + }, + Expectation: map[string]string{ + "initializer.prebuild.0.git": "foobar", + "initializer.prebuild.1.git": "some value", + }, + }, + } + + for _, test := range tests { + t.Run(test.Name, func(t *testing.T) { + act := api.ExtractSecretsFromInitializer(test.Input) + if diff := cmp.Diff(test.Expectation, act); diff != "" { + t.Errorf("unexpected ExtractSecretsFromInitializer (-want +got):\n%s", diff) + } + + _ = api.WalkInitializer(nil, test.Input, func(path []string, init *api.WorkspaceInitializer) error { + git, ok := init.Spec.(*api.WorkspaceInitializer_Git) + if !ok { + return nil + } + if pwd := git.Git.Config.AuthPassword; pwd != "" && !strings.HasPrefix(pwd, "extracted-secret/") { + t.Errorf("expected authPassword to be extracted, but got %s at %s", pwd, filepath.Join(path...)) + } + + return nil + }) + + injection := make(map[string][]byte, len(act)) + for k, v := range act { + injection[k] = []byte(v) + } + + err := api.InjectSecretsToInitializer(test.Input, injection) + if err != nil { + t.Fatal(err) + } + + _ = api.WalkInitializer(nil, test.Input, func(path []string, init *api.WorkspaceInitializer) error { + git, ok := init.Spec.(*api.WorkspaceInitializer_Git) + if !ok { + return nil + } + if pwd := git.Git.Config.AuthPassword; pwd != "" && strings.HasPrefix(pwd, "extracted-secret/") { + t.Errorf("expected authPassword to be injected, but got %s at %s", pwd, filepath.Join(path...)) + } + + return nil + }) + }) + } +} diff --git a/components/content-service/pkg/initializer/initializer.go b/components/content-service/pkg/initializer/initializer.go index e905c5ca4b5348..d70deaaed6f171 100644 --- a/components/content-service/pkg/initializer/initializer.go +++ b/components/content-service/pkg/initializer/initializer.go @@ -524,25 +524,3 @@ func PlaceWorkspaceReadyFile(ctx context.Context, wspath string, initsrc csapi.W return nil } - -func GetCheckoutLocationsFromInitializer(init *csapi.WorkspaceInitializer) []string { - switch { - case init.GetGit() != nil: - return []string{init.GetGit().CheckoutLocation} - case init.GetPrebuild() != nil && len(init.GetPrebuild().Git) > 0: - var result = make([]string, len(init.GetPrebuild().Git)) - for i, c := range init.GetPrebuild().Git { - result[i] = c.CheckoutLocation - } - return result - case init.GetBackup() != nil: - return []string{init.GetBackup().CheckoutLocation} - case init.GetComposite() != nil: - var result []string - for _, c := range init.GetComposite().Initializer { - result = append(result, GetCheckoutLocationsFromInitializer(c)...) - } - return result - } - return nil -} diff --git a/components/content-service/pkg/initializer/initializer_test.go b/components/content-service/pkg/initializer/initializer_test.go index 5238b3d426ef32..0a9c770979dae1 100644 --- a/components/content-service/pkg/initializer/initializer_test.go +++ b/components/content-service/pkg/initializer/initializer_test.go @@ -7,7 +7,6 @@ package initializer_test import ( "context" "fmt" - "strings" "testing" csapi "github.com/gitpod-io/gitpod/content-service/api" @@ -30,82 +29,6 @@ func (f *RecordingInitializer) Run(ctx context.Context, mappings []archive.IDMap return csapi.WorkspaceInitFromOther, nil } -func TestGetCheckoutLocationsFromInitializer(t *testing.T) { - - var init []*csapi.WorkspaceInitializer - init = append(init, &csapi.WorkspaceInitializer{ - Spec: &csapi.WorkspaceInitializer_Git{ - Git: &csapi.GitInitializer{ - CheckoutLocation: "/foo", - CloneTaget: "head", - Config: &csapi.GitConfig{ - Authentication: csapi.GitAuthMethod_NO_AUTH, - }, - RemoteUri: "somewhere-else", - TargetMode: csapi.CloneTargetMode_LOCAL_BRANCH, - }, - }, - }) - init = append(init, &csapi.WorkspaceInitializer{ - Spec: &csapi.WorkspaceInitializer_Git{ - Git: &csapi.GitInitializer{ - CheckoutLocation: "/bar", - CloneTaget: "head", - Config: &csapi.GitConfig{ - Authentication: csapi.GitAuthMethod_NO_AUTH, - }, - RemoteUri: "somewhere-else", - TargetMode: csapi.CloneTargetMode_LOCAL_BRANCH, - }, - }, - }) - - tests := []struct { - Name string - Initializer *csapi.WorkspaceInitializer - Expectation string - }{ - { - Name: "single git initializer", - Initializer: &csapi.WorkspaceInitializer{ - Spec: &csapi.WorkspaceInitializer_Git{ - Git: &csapi.GitInitializer{ - CheckoutLocation: "/foo", - CloneTaget: "head", - Config: &csapi.GitConfig{ - Authentication: csapi.GitAuthMethod_NO_AUTH, - }, - RemoteUri: "somewhere-else", - TargetMode: csapi.CloneTargetMode_LOCAL_BRANCH, - }, - }, - }, - Expectation: "/foo", - }, - { - Name: "multiple git initializer", - Initializer: &csapi.WorkspaceInitializer{ - Spec: &csapi.WorkspaceInitializer_Composite{ - Composite: &csapi.CompositeInitializer{ - Initializer: init, - }, - }, - }, - Expectation: "/foo,/bar", - }, - } - - for _, test := range tests { - t.Run(test.Name, func(t *testing.T) { - locations := strings.Join(initializer.GetCheckoutLocationsFromInitializer(test.Initializer), ",") - if locations != test.Expectation { - t.Errorf("expected %s, got %s", test.Expectation, locations) - } - }) - } - -} - func TestCompositeInitializer(t *testing.T) { tests := []struct { Name string diff --git a/components/gitpod-protocol/src/protocol.ts b/components/gitpod-protocol/src/protocol.ts index df6ca44934c4d7..b03569f20ccd23 100644 --- a/components/gitpod-protocol/src/protocol.ts +++ b/components/gitpod-protocol/src/protocol.ts @@ -206,6 +206,7 @@ export const WorkspaceFeatureFlags = { full_workspace_backup: undefined, fixed_resources: undefined, persistent_volume_claim: undefined, + protected_secrets: undefined, }; export type NamedWorkspaceFeatureFlag = keyof typeof WorkspaceFeatureFlags; diff --git a/components/server/src/workspace/workspace-starter.ts b/components/server/src/workspace/workspace-starter.ts index 2c556a4555c4bc..21620eca8aaa76 100644 --- a/components/server/src/workspace/workspace-starter.ts +++ b/components/server/src/workspace/workspace-starter.ts @@ -897,7 +897,7 @@ export class WorkspaceStarter { // TODO(se): we cannot change this initializer structure now because it is part of how baserefs are computed in image-builder. // Image builds should however just use the initialization if the workspace they are running for (i.e. the one from above). checkoutLocation = "."; - const { initializer, disposable } = await this.createCommitInitializer( + const { initializer } = await this.createCommitInitializer( { span }, workspace, { @@ -908,7 +908,6 @@ export class WorkspaceStarter { }, user, ); - disp.push(disposable); let git: GitInitializer; if (initializer instanceof CompositeInitializer) { // we use the first git initializer for image builds only @@ -1189,23 +1188,7 @@ export class WorkspaceStarter { allEnvVars = allEnvVars.concat(context.envvars); } - // we copy the envvars to a stable format so that things don't break when someone changes the - // EnvVarWithValue shape. The JSON.stringify(envvars) will be consumed by supervisor and we - // need to make sure we're speaking the same language. - const stableEnvvars = allEnvVars.map((e) => { - return { name: e.name, value: e.value }; - }); - - // we ship the user-specific env vars as OTS because they might contain secrets - const envvarOTSExpirationTime = new Date(); - envvarOTSExpirationTime.setMinutes(envvarOTSExpirationTime.getMinutes() + 30); - const envvarOTS = await this.otsServer.serve(traceCtx, JSON.stringify(stableEnvvars), envvarOTSExpirationTime); - const envvars: EnvironmentVariable[] = []; - const ev = new EnvironmentVariable(); - ev.setName("SUPERVISOR_ENVVAR_OTS"); - ev.setValue(envvarOTS.token); - envvars.push(ev); // TODO(cw): for the time being we're still pushing the env vars as we did before. // Once everything is running with the latest supervisor, we can stop doing that. @@ -1272,19 +1255,15 @@ export class WorkspaceStarter { }; await this.userDB.trace(traceCtx).storeGitpodToken(dbToken); - const otsExpirationTime = new Date(); - otsExpirationTime.setMinutes(otsExpirationTime.getMinutes() + 30); const tokenExpirationTime = new Date(); tokenExpirationTime.setMinutes(tokenExpirationTime.getMinutes() + 24 * 60); - const ots = await this.otsServer.serve(traceCtx, token, otsExpirationTime); const ev = new EnvironmentVariable(); ev.setName("THEIA_SUPERVISOR_TOKENS"); ev.setValue( JSON.stringify([ { - tokenOTS: ots.token, - token: "ots", + token: token, kind: "gitpod", host: this.config.hostUrl.url.host, scope: scopes, @@ -1554,8 +1533,7 @@ export class WorkspaceStarter { } else if (WorkspaceProbeContext.is(context)) { // workspace probes have no workspace initializer as they need no content } else if (CommitContext.is(context)) { - const { initializer, disposable } = await this.createCommitInitializer(traceCtx, workspace, context, user); - disp.push(disposable); + const { initializer } = await this.createCommitInitializer(traceCtx, workspace, context, user); if (initializer instanceof CompositeInitializer) { result.setComposite(initializer); } else { @@ -1607,7 +1585,7 @@ export class WorkspaceStarter { workspace: Workspace, context: CommitContext, user: User, - ): Promise<{ initializer: GitInitializer | CompositeInitializer; disposable: Disposable }> { + ): Promise<{ initializer: GitInitializer | CompositeInitializer }> { const span = TraceContext.startSpan("createInitializerForCommit", ctx); try { const mainGit = this.createGitInitializer({ span }, workspace, context, user); @@ -1620,16 +1598,13 @@ export class WorkspaceStarter { } const inits = await Promise.all(subRepoInitializers); const compositeInit = new CompositeInitializer(); - const compositeDisposable = new DisposableCollection(); for (const r of inits) { const wsinit = new WorkspaceInitializer(); wsinit.setGit(r.initializer); compositeInit.addInitializer(wsinit); - compositeDisposable.push(r.disposable); } return { initializer: compositeInit, - disposable: compositeDisposable, }; } catch (e) { TraceContext.setError({ span }, e); @@ -1644,7 +1619,7 @@ export class WorkspaceStarter { workspace: Workspace, context: GitCheckoutInfo, user: User, - ): Promise<{ initializer: GitInitializer; disposable: Disposable }> { + ): Promise<{ initializer: GitInitializer }> { const host = context.repository.host; const hostContext = this.hostContextProvider.get(host); if (!hostContext) { @@ -1656,25 +1631,6 @@ export class WorkspaceStarter { throw new Error("User is unauthorized!"); } - const tokenExpirationTime = new Date(); - tokenExpirationTime.setMinutes(tokenExpirationTime.getMinutes() + 30); - let tokenOTS: string | undefined; - let disposable: Disposable | undefined; - try { - const token = await this.tokenProvider.getTokenForHost(user, host); - const username = token.username || "oauth2"; - const res = await this.otsServer.serve(traceCtx, `${username}:${token.value}`, tokenExpirationTime); - tokenOTS = res.token; - disposable = res.disposable; - } catch (error) { - // no token - log.error( - { workspaceId: workspace.id, userId: workspace.ownerId }, - "cannot authenticate user for Git initializer", - error, - ); - throw new Error("User is unauthorized!"); - } const cloneUrl = context.repository.cloneUrl; var cloneTarget: string | undefined; @@ -1695,9 +1651,13 @@ export class WorkspaceStarter { targetMode = CloneTargetMode.REMOTE_HEAD; } + const gitToken = await this.tokenProvider.getTokenForHost(user, host); + const username = gitToken.username || "oauth2"; + const gitConfig = new GitConfig(); - gitConfig.setAuthentication(GitAuthMethod.BASIC_AUTH_OTS); - gitConfig.setAuthOts(tokenOTS); + gitConfig.setAuthentication(GitAuthMethod.BASIC_AUTH); + gitConfig.setAuthUser(username); + gitConfig.setAuthPassword(gitToken.value); if (this.config.insecureNoDomain) { const token = await this.tokenProvider.getTokenForHost(user, host); @@ -1727,7 +1687,6 @@ export class WorkspaceStarter { return { initializer: result, - disposable, }; } diff --git a/components/ws-daemon-api/go/go.mod b/components/ws-daemon-api/go/go.mod index 3b4dfc7a145429..2061c5c2d0eebc 100644 --- a/components/ws-daemon-api/go/go.mod +++ b/components/ws-daemon-api/go/go.mod @@ -20,6 +20,7 @@ require ( golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/tools v0.1.1 // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154 // indirect ) diff --git a/components/ws-daemon-api/go/go.sum b/components/ws-daemon-api/go/go.sum index a27da51c3058a3..736b33e1a8b95a 100644 --- a/components/ws-daemon-api/go/go.sum +++ b/components/ws-daemon-api/go/go.sum @@ -48,8 +48,8 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= diff --git a/components/ws-daemon/pkg/content/service.go b/components/ws-daemon/pkg/content/service.go index d02a6f5d2a7855..92d758b08a1465 100644 --- a/components/ws-daemon/pkg/content/service.go +++ b/components/ws-daemon/pkg/content/service.go @@ -316,7 +316,7 @@ func (s *WorkspaceService) InitWorkspace(ctx context.Context, req *api.InitWorks func (s *WorkspaceService) creator(req *api.InitWorkspaceRequest) session.WorkspaceFactory { var checkoutLocation string - allLocations := wsinit.GetCheckoutLocationsFromInitializer(req.Initializer) + allLocations := csapi.GetCheckoutLocationsFromInitializer(req.Initializer) if len(allLocations) > 0 { checkoutLocation = allLocations[0] } diff --git a/components/ws-manager-api/core.proto b/components/ws-manager-api/core.proto index 322721ce0b813c..a5827227cb0627 100644 --- a/components/ws-manager-api/core.proto +++ b/components/ws-manager-api/core.proto @@ -594,6 +594,9 @@ enum WorkspaceFeatureFlag { // PERSISTENT_VOLUME_CLAIM feature flag for enabling PVC\Snapshot feature support PERSISTENT_VOLUME_CLAIM = 7; + + // PROTECTED_SECRETS feature flag for enable secrets support + PROTECTED_SECRETS = 8; } // GitSpec configures the Git available within the workspace diff --git a/components/ws-manager-api/go/core.pb.go b/components/ws-manager-api/go/core.pb.go index 72afc614cf9dfe..6806840e6d062b 100644 --- a/components/ws-manager-api/go/core.pb.go +++ b/components/ws-manager-api/go/core.pb.go @@ -319,6 +319,8 @@ const ( WorkspaceFeatureFlag_FIXED_RESOURCES WorkspaceFeatureFlag = 5 // PERSISTENT_VOLUME_CLAIM feature flag for enabling PVC\Snapshot feature support WorkspaceFeatureFlag_PERSISTENT_VOLUME_CLAIM WorkspaceFeatureFlag = 7 + // PROTECTED_SECRETS feature flag for enable secrets support + WorkspaceFeatureFlag_PROTECTED_SECRETS WorkspaceFeatureFlag = 8 ) // Enum value maps for WorkspaceFeatureFlag. @@ -328,12 +330,14 @@ var ( 4: "FULL_WORKSPACE_BACKUP", 5: "FIXED_RESOURCES", 7: "PERSISTENT_VOLUME_CLAIM", + 8: "PROTECTED_SECRETS", } WorkspaceFeatureFlag_value = map[string]int32{ "NOOP": 0, "FULL_WORKSPACE_BACKUP": 4, "FIXED_RESOURCES": 5, "PERSISTENT_VOLUME_CLAIM": 7, + "PROTECTED_SECRETS": 8, } ) @@ -3647,94 +3651,96 @@ var file_core_proto_rawDesc = []byte{ 0x03, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x55, 0x4e, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x04, 0x12, 0x0f, 0x0a, 0x0b, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x52, 0x55, 0x50, 0x54, 0x45, 0x44, 0x10, 0x07, 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x54, 0x4f, 0x50, 0x50, 0x49, 0x4e, 0x47, 0x10, 0x05, 0x12, 0x0b, 0x0a, - 0x07, 0x53, 0x54, 0x4f, 0x50, 0x50, 0x45, 0x44, 0x10, 0x06, 0x2a, 0x85, 0x01, 0x0a, 0x14, 0x57, + 0x07, 0x53, 0x54, 0x4f, 0x50, 0x50, 0x45, 0x44, 0x10, 0x06, 0x2a, 0x9c, 0x01, 0x0a, 0x14, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4f, 0x50, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x46, 0x55, 0x4c, 0x4c, 0x5f, 0x57, 0x4f, 0x52, 0x4b, 0x53, 0x50, 0x41, 0x43, 0x45, 0x5f, 0x42, 0x41, 0x43, 0x4b, 0x55, 0x50, 0x10, 0x04, 0x12, 0x13, 0x0a, 0x0f, 0x46, 0x49, 0x58, 0x45, 0x44, 0x5f, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x53, 0x10, 0x05, 0x12, 0x1b, 0x0a, 0x17, 0x50, 0x45, 0x52, 0x53, 0x49, 0x53, 0x54, 0x45, 0x4e, 0x54, 0x5f, 0x56, 0x4f, 0x4c, 0x55, - 0x4d, 0x45, 0x5f, 0x43, 0x4c, 0x41, 0x49, 0x4d, 0x10, 0x07, 0x22, 0x04, 0x08, 0x01, 0x10, 0x01, - 0x22, 0x04, 0x08, 0x02, 0x10, 0x02, 0x22, 0x04, 0x08, 0x03, 0x10, 0x03, 0x22, 0x04, 0x08, 0x06, - 0x10, 0x06, 0x2a, 0x4b, 0x0a, 0x0d, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, - 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x45, 0x47, 0x55, 0x4c, 0x41, 0x52, 0x10, 0x00, - 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x52, 0x45, 0x42, 0x55, 0x49, 0x4c, 0x44, 0x10, 0x01, 0x12, 0x09, - 0x0a, 0x05, 0x50, 0x52, 0x4f, 0x42, 0x45, 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x49, 0x4d, 0x41, - 0x47, 0x45, 0x42, 0x55, 0x49, 0x4c, 0x44, 0x10, 0x04, 0x22, 0x04, 0x08, 0x03, 0x10, 0x03, 0x32, - 0xe7, 0x08, 0x0a, 0x10, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4d, 0x61, 0x6e, - 0x61, 0x67, 0x65, 0x72, 0x12, 0x4c, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, 0x1b, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x47, 0x65, - 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x6f, - 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x00, 0x12, 0x4f, 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x12, 0x1c, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x74, 0x61, - 0x72, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, - 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x00, 0x12, 0x4c, 0x0a, 0x0d, 0x53, 0x74, 0x6f, 0x70, 0x57, 0x6f, 0x72, 0x6b, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x12, 0x1b, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x74, 0x6f, - 0x70, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x1c, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x57, 0x6f, - 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x00, 0x12, 0x58, 0x0a, 0x11, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x57, 0x6f, 0x72, - 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1f, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x44, - 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, - 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x52, 0x0a, 0x0f, 0x42, - 0x61, 0x63, 0x6b, 0x75, 0x70, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1d, - 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x57, 0x6f, 0x72, - 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, - 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x57, 0x6f, 0x72, 0x6b, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, - 0x42, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x12, 0x17, 0x2e, 0x77, + 0x4d, 0x45, 0x5f, 0x43, 0x4c, 0x41, 0x49, 0x4d, 0x10, 0x07, 0x12, 0x15, 0x0a, 0x11, 0x50, 0x52, + 0x4f, 0x54, 0x45, 0x43, 0x54, 0x45, 0x44, 0x5f, 0x53, 0x45, 0x43, 0x52, 0x45, 0x54, 0x53, 0x10, + 0x08, 0x22, 0x04, 0x08, 0x01, 0x10, 0x01, 0x22, 0x04, 0x08, 0x02, 0x10, 0x02, 0x22, 0x04, 0x08, + 0x03, 0x10, 0x03, 0x22, 0x04, 0x08, 0x06, 0x10, 0x06, 0x2a, 0x4b, 0x0a, 0x0d, 0x57, 0x6f, 0x72, + 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x45, + 0x47, 0x55, 0x4c, 0x41, 0x52, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x52, 0x45, 0x42, 0x55, + 0x49, 0x4c, 0x44, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x50, 0x52, 0x4f, 0x42, 0x45, 0x10, 0x02, + 0x12, 0x0e, 0x0a, 0x0a, 0x49, 0x4d, 0x41, 0x47, 0x45, 0x42, 0x55, 0x49, 0x4c, 0x44, 0x10, 0x04, + 0x22, 0x04, 0x08, 0x03, 0x10, 0x03, 0x32, 0xe7, 0x08, 0x0a, 0x10, 0x57, 0x6f, 0x72, 0x6b, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x12, 0x4c, 0x0a, 0x0d, 0x47, + 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, 0x1b, 0x2e, 0x77, + 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x77, 0x73, 0x6d, 0x61, + 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4f, 0x0a, 0x0e, 0x53, 0x74, 0x61, + 0x72, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1c, 0x2e, 0x77, 0x73, + 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x77, 0x73, 0x6d, 0x61, + 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4c, 0x0a, 0x0d, 0x53, 0x74, + 0x6f, 0x70, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1b, 0x2e, 0x77, 0x73, + 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, + 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x58, 0x0a, 0x11, 0x44, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x62, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1f, 0x2e, + 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x57, 0x6f, + 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, + 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x57, + 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x12, 0x52, 0x0a, 0x0f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x57, 0x6f, 0x72, 0x6b, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1d, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x42, 0x61, + 0x63, 0x6b, 0x75, 0x70, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x42, 0x61, 0x63, + 0x6b, 0x75, 0x70, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x42, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, + 0x69, 0x62, 0x65, 0x12, 0x17, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x75, 0x62, 0x73, + 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x75, - 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x00, 0x30, 0x01, 0x12, 0x43, 0x0a, 0x0a, 0x4d, 0x61, 0x72, 0x6b, 0x41, 0x63, 0x74, 0x69, 0x76, - 0x65, 0x12, 0x18, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x4d, 0x61, 0x72, 0x6b, 0x41, 0x63, - 0x74, 0x69, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x77, 0x73, - 0x6d, 0x61, 0x6e, 0x2e, 0x4d, 0x61, 0x72, 0x6b, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x43, 0x0a, 0x0a, 0x53, 0x65, 0x74, 0x54, - 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x18, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x53, - 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x19, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, - 0x6f, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x46, 0x0a, - 0x0b, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x19, 0x2e, 0x77, - 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x50, 0x6f, 0x72, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, - 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x49, 0x0a, 0x0c, 0x54, 0x61, 0x6b, 0x65, 0x53, 0x6e, 0x61, - 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x1a, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x54, 0x61, - 0x6b, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x1b, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x54, 0x61, 0x6b, 0x65, 0x53, 0x6e, - 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, - 0x12, 0x55, 0x0a, 0x10, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x41, 0x64, 0x6d, 0x69, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x43, 0x6f, 0x6e, - 0x74, 0x72, 0x6f, 0x6c, 0x41, 0x64, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x43, 0x6f, 0x6e, - 0x74, 0x72, 0x6f, 0x6c, 0x41, 0x64, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x61, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, - 0x22, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x56, 0x6f, - 0x6c, 0x75, 0x6d, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x49, 0x0a, 0x0c, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x53, 0x53, 0x48, 0x4b, 0x65, 0x79, 0x12, 0x1a, 0x2e, 0x77, 0x73, 0x6d, - 0x61, 0x6e, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x53, 0x48, 0x4b, 0x65, 0x79, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x53, 0x48, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x52, 0x0a, 0x0f, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, - 0x65, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x1d, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, - 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, - 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x2c, 0x5a, 0x2a, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x69, 0x74, 0x70, 0x6f, 0x64, 0x2d, 0x69, - 0x6f, 0x2f, 0x67, 0x69, 0x74, 0x70, 0x6f, 0x64, 0x2f, 0x77, 0x73, 0x2d, 0x6d, 0x61, 0x6e, 0x61, - 0x67, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x43, 0x0a, 0x0a, 0x4d, 0x61, + 0x72, 0x6b, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x12, 0x18, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, + 0x2e, 0x4d, 0x61, 0x72, 0x6b, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x4d, 0x61, 0x72, 0x6b, 0x41, + 0x63, 0x74, 0x69, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, + 0x43, 0x0a, 0x0a, 0x53, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x18, 0x2e, + 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, + 0x53, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x00, 0x12, 0x46, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x50, + 0x6f, 0x72, 0x74, 0x12, 0x19, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x43, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, + 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x50, 0x6f, + 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x49, 0x0a, 0x0c, + 0x54, 0x61, 0x6b, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x1a, 0x2e, 0x77, + 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x54, 0x61, 0x6b, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, + 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, + 0x2e, 0x54, 0x61, 0x6b, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x55, 0x0a, 0x10, 0x43, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x41, 0x64, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x2e, 0x77, 0x73, + 0x6d, 0x61, 0x6e, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x41, 0x64, 0x6d, 0x69, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x77, 0x73, + 0x6d, 0x61, 0x6e, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x41, 0x64, 0x6d, 0x69, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x61, + 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x53, 0x6e, + 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x22, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, + 0x68, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x77, 0x73, 0x6d, + 0x61, 0x6e, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x53, + 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x00, 0x12, 0x49, 0x0a, 0x0c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x53, 0x48, 0x4b, 0x65, + 0x79, 0x12, 0x1a, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x53, 0x53, 0x48, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, + 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x53, 0x48, 0x4b, + 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x52, 0x0a, 0x0f, + 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, + 0x1d, 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, + 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, + 0x2e, 0x77, 0x73, 0x6d, 0x61, 0x6e, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x43, + 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, + 0x42, 0x2c, 0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, + 0x69, 0x74, 0x70, 0x6f, 0x64, 0x2d, 0x69, 0x6f, 0x2f, 0x67, 0x69, 0x74, 0x70, 0x6f, 0x64, 0x2f, + 0x77, 0x73, 0x2d, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/components/ws-manager-api/typescript/src/core_pb.d.ts b/components/ws-manager-api/typescript/src/core_pb.d.ts index 36d0429532b39d..aee6e365962326 100644 --- a/components/ws-manager-api/typescript/src/core_pb.d.ts +++ b/components/ws-manager-api/typescript/src/core_pb.d.ts @@ -1261,6 +1261,7 @@ export enum WorkspaceFeatureFlag { FULL_WORKSPACE_BACKUP = 4, FIXED_RESOURCES = 5, PERSISTENT_VOLUME_CLAIM = 7, + PROTECTED_SECRETS = 8, } export enum WorkspaceType { diff --git a/components/ws-manager-api/typescript/src/core_pb.js b/components/ws-manager-api/typescript/src/core_pb.js index b4eb3605ec262b..cb041e530b3aaa 100644 --- a/components/ws-manager-api/typescript/src/core_pb.js +++ b/components/ws-manager-api/typescript/src/core_pb.js @@ -9805,7 +9805,8 @@ proto.wsman.WorkspaceFeatureFlag = { NOOP: 0, FULL_WORKSPACE_BACKUP: 4, FIXED_RESOURCES: 5, - PERSISTENT_VOLUME_CLAIM: 7 + PERSISTENT_VOLUME_CLAIM: 7, + PROTECTED_SECRETS: 8 }; /** diff --git a/components/ws-manager/pkg/manager/create.go b/components/ws-manager/pkg/manager/create.go index 51c0250c77c0b3..8427d4109ce1d8 100644 --- a/components/ws-manager/pkg/manager/create.go +++ b/components/ws-manager/pkg/manager/create.go @@ -7,6 +7,7 @@ package manager import ( "context" "crypto/rand" + "crypto/sha256" "encoding/base64" "fmt" "io" @@ -28,7 +29,7 @@ import ( "github.com/gitpod-io/gitpod/common-go/kubernetes" wsk8s "github.com/gitpod-io/gitpod/common-go/kubernetes" "github.com/gitpod-io/gitpod/common-go/tracing" - content "github.com/gitpod-io/gitpod/content-service/pkg/initializer" + csapi "github.com/gitpod-io/gitpod/content-service/api" regapi "github.com/gitpod-io/gitpod/registry-facade/api" "github.com/gitpod-io/gitpod/ws-manager/api" config "github.com/gitpod-io/gitpod/ws-manager/api/config" @@ -41,6 +42,13 @@ var ( boolTrue = true ) +const ( + // maxSecretsLength is the maximum number of bytes a workspace secret may contain. This size is exhausted by + // environment variables provided as part of the start workspace request. + // The value of 768kb is a somewhat arbitrary choice, but steers way clear of the 1MiB Kubernetes imposes. + maxSecretsLength = 768 * 1024 * 1024 +) + // createWorkspacePod creates the actual workspace pod based on the definite workspace pod and appropriate // templates. The result of this function is not expected to be modified prior to being passed to Kubernetes. func (m *Manager) createWorkspacePod(startContext *startWorkspaceContext) (*corev1.Pod, error) { @@ -85,6 +93,21 @@ func (m *Manager) createWorkspacePod(startContext *startWorkspaceContext) (*core return pod, nil } +func podName(req *api.StartWorkspaceRequest) string { + var prefix string + switch req.Type { + case api.WorkspaceType_PREBUILD: + prefix = "prebuild" + case api.WorkspaceType_PROBE: + prefix = "probe" + case api.WorkspaceType_IMAGEBUILD: + prefix = "imagebuild" + default: + prefix = "ws" + } + return fmt.Sprintf("%s-%s", prefix, req.Id) +} + // combineDefiniteWorkspacePodWithTemplate merges a definite workspace pod with a user-provided template. // In essence this function just calls mergo, but we need to make sure we use the right flags (and that we can test the right flags). func combineDefiniteWorkspacePodWithTemplate(pod *corev1.Pod, template *corev1.Pod) error { @@ -330,28 +353,6 @@ func (m *Manager) createDefiniteWorkspacePod(startContext *startWorkspaceContext } admissionLevel = strings.ToLower(admissionLevel) - var prefix string - switch req.Type { - case api.WorkspaceType_PREBUILD: - prefix = "prebuild" - case api.WorkspaceType_PROBE: - prefix = "probe" - case api.WorkspaceType_IMAGEBUILD: - prefix = "imagebuild" - // mount self-signed gitpod CA certificate to ensure - // we can push images to the in-cluster registry - workspaceContainer.VolumeMounts = append(workspaceContainer.VolumeMounts, - corev1.VolumeMount{ - Name: "gitpod-ca-certificate", - MountPath: "/usr/local/share/ca-certificates/gitpod-ca.crt", - SubPath: "ca.crt", - ReadOnly: true, - }, - ) - default: - prefix = "ws" - } - annotations := map[string]string{ workspaceIDAnnotation: req.Id, servicePrefixAnnotation: getServicePrefix(req), @@ -452,6 +453,19 @@ func (m *Manager) createDefiniteWorkspacePod(startContext *startWorkspaceContext }) } + if req.Type == api.WorkspaceType_IMAGEBUILD { + // mount self-signed gitpod CA certificate to ensure + // we can push images to the in-cluster registry + workspaceContainer.VolumeMounts = append(workspaceContainer.VolumeMounts, + corev1.VolumeMount{ + Name: "gitpod-ca-certificate", + MountPath: "/usr/local/share/ca-certificates/gitpod-ca.crt", + SubPath: "ca.crt", + ReadOnly: true, + }, + ) + } + workloadType := "regular" if startContext.Headless { workloadType = "headless" @@ -482,10 +496,9 @@ func (m *Manager) createDefiniteWorkspacePod(startContext *startWorkspaceContext }, } - PodSecContext := corev1.PodSecurityContext{} pod := corev1.Pod{ ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf("%s-%s", prefix, req.Id), + Name: podName(req), Namespace: m.Config.Namespace, Labels: labels, Annotations: annotations, @@ -498,7 +511,7 @@ func (m *Manager) createDefiniteWorkspacePod(startContext *startWorkspaceContext SchedulerName: m.Config.SchedulerName, EnableServiceLinks: &boolFalse, Affinity: affinity, - SecurityContext: &PodSecContext, + SecurityContext: &corev1.PodSecurityContext{}, Containers: []corev1.Container{ *workspaceContainer, }, @@ -577,6 +590,28 @@ func (m *Manager) createDefiniteWorkspacePod(startContext *startWorkspaceContext gitpodGUID := int64(133332) pod.Spec.SecurityContext.FSGroup = &gitpodGUID + case api.WorkspaceFeatureFlag_PROTECTED_SECRETS: + for _, c := range pod.Spec.Containers { + if c.Name != "workspace" { + continue + } + + for i, env := range c.Env { + if !isProtectedEnvVar(env.Name) { + continue + } + + env.Value = "" + env.ValueFrom = &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{Name: pod.Name}, + Key: fmt.Sprintf("%x", sha256.Sum256([]byte(env.Name))), + }, + } + c.Env[i] = env + } + } + default: return nil, xerrors.Errorf("unknown feature flag: %v", feature) } @@ -709,7 +744,7 @@ func (m *Manager) createWorkspaceEnvironment(startContext *startWorkspaceContext return filepath.Join("/workspace", strings.TrimPrefix(segment, "/workspace")) } - allRepoRoots := content.GetCheckoutLocationsFromInitializer(spec.Initializer) + allRepoRoots := csapi.GetCheckoutLocationsFromInitializer(spec.Initializer) if len(allRepoRoots) == 0 { allRepoRoots = []string{""} // for backward compatibility, we are adding a single empty location (translates to /workspace/) } @@ -760,8 +795,11 @@ func (m *Manager) createWorkspaceEnvironment(startContext *startWorkspaceContext } } - env := corev1.EnvVar{Name: e.Name, Value: e.Value} - if len(e.Value) == 0 && e.Secret != nil { + env := corev1.EnvVar{ + Name: e.Name, + Value: e.Value, + } + if e.Value == "" && e.Secret != nil { env.ValueFrom = &corev1.EnvVarSource{ SecretKeyRef: &corev1.SecretKeySelector{ LocalObjectReference: corev1.LocalObjectReference{Name: e.Secret.SecretName}, @@ -769,7 +807,6 @@ func (m *Manager) createWorkspaceEnvironment(startContext *startWorkspaceContext }, } } - result = append(result, env) } } @@ -801,6 +838,22 @@ func (m *Manager) createWorkspaceEnvironment(startContext *startWorkspaceContext return cleanResult, nil } +func isGitpodInternalEnvVar(name string) bool { + return strings.HasPrefix(name, "GITPOD_") || + strings.HasPrefix(name, "SUPERVISOR_") || + strings.HasPrefix(name, "BOB_") || + strings.HasPrefix(name, "THEIA_") +} + +func isProtectedEnvVar(name string) bool { + switch name { + case "THEIA_SUPERVISOR_TOKENS": + return true + default: + return !isGitpodInternalEnvVar(name) + } +} + func (m *Manager) createWorkspaceVolumes(startContext *startWorkspaceContext) (workspace corev1.Volume, err error) { // silly protobuf structure design - this needs to be a reference to a string, // so we have to assign it to a variable first to take the address @@ -916,6 +969,30 @@ func (m *Manager) newStartWorkspaceContext(ctx context.Context, req *api.StartWo } } + var ( + secrets = make(map[string]string) + secretsLen int + ) + for _, env := range req.Spec.Envvars { + if env.Secret != nil { + continue + } + if !isProtectedEnvVar(env.Name) { + continue + } + + name := fmt.Sprintf("%x", sha256.Sum256([]byte(env.Name))) + secrets[name] = env.Value + secretsLen += len(env.Value) + } + for k, v := range csapi.ExtractSecretsFromInitializer(req.Spec.Initializer) { + secrets[k] = v + secretsLen += len(v) + } + if secretsLen > maxSecretsLength { + return nil, xerrors.Errorf("secrets exceed maximum permitted length (%d > %d bytes): please reduce the numer or length of environment variables", secretsLen, maxSecretsLength) + } + return &startWorkspaceContext{ Labels: labels, CLIAPIKey: cliAPIKey, @@ -927,6 +1004,7 @@ func (m *Manager) newStartWorkspaceContext(ctx context.Context, req *api.StartWo Headless: headless, Class: class, VolumeSnapshot: volumeSnapshot, + Secrets: secrets, }, nil } diff --git a/components/ws-manager/pkg/manager/create_test.go b/components/ws-manager/pkg/manager/create_test.go index 93e2db26ea1986..260692b9ec7e4d 100644 --- a/components/ws-manager/pkg/manager/create_test.go +++ b/components/ws-manager/pkg/manager/create_test.go @@ -17,8 +17,10 @@ import ( "sigs.k8s.io/yaml" ctesting "github.com/gitpod-io/gitpod/common-go/testing" + csapi "github.com/gitpod-io/gitpod/content-service/api" "github.com/gitpod-io/gitpod/ws-manager/api" config "github.com/gitpod-io/gitpod/ws-manager/api/config" + "github.com/google/go-cmp/cmp" ) var ( @@ -26,6 +28,56 @@ var ( project = "gitpod" ) +func TestNewStartWorkspaceContext(t *testing.T) { + type Expectation struct { + Context *startWorkspaceContext + Error string + } + tests := []struct { + Name string + Req *api.StartWorkspaceRequest + Expectation Expectation + }{ + { + Name: "oversized secrets", + Req: &api.StartWorkspaceRequest{ + Metadata: &api.WorkspaceMetadata{Owner: "foo"}, + Spec: &api.StartWorkspaceSpec{ + Initializer: &csapi.WorkspaceInitializer{ + Spec: &csapi.WorkspaceInitializer_Empty{}, + }, + Envvars: []*api.EnvironmentVariable{ + {Name: "too_large", Value: string(func() []byte { return make([]byte, 2*maxSecretsLength) }())}, + }, + }, + }, + Expectation: Expectation{ + Error: "secrets exceed maximum permitted length (1610612736 > 805306368 bytes): please reduce the numer or length of environment variables", + }, + }, + } + + for _, test := range tests { + t.Run(test.Name, func(t *testing.T) { + mgmtCfg := forTestingOnlyManagerConfig() + manager := &Manager{Config: mgmtCfg} + + sctx, err := manager.newStartWorkspaceContext(context.Background(), test.Req) + + act := Expectation{ + Context: sctx, + } + if err != nil { + act.Error = err.Error() + } + + if diff := cmp.Diff(test.Expectation, act); diff != "" { + t.Errorf("unexpected newStartWorkspaceContext (-want +got):\n%s", diff) + } + }) + } +} + func TestCreateDefiniteWorkspacePod(t *testing.T) { type WorkspaceClass struct { DefaultTemplate *corev1.Pod `json:"defaultTemplate,omitempty"` diff --git a/components/ws-manager/pkg/manager/manager.go b/components/ws-manager/pkg/manager/manager.go index 6b58ff97fadfcc..78a292dfdce004 100644 --- a/components/ws-manager/pkg/manager/manager.go +++ b/components/ws-manager/pkg/manager/manager.go @@ -82,6 +82,7 @@ type startWorkspaceContext struct { Headless bool `json:"headless"` Class *config.WorkspaceClass `json:"class"` VolumeSnapshot *workspaceVolumeSnapshotStatus `json:"volumeSnapshot"` + Secrets map[string]string `json:"secrets"` } func (swctx *startWorkspaceContext) ContainerConfiguration() config.ContainerConfiguration { @@ -258,6 +259,28 @@ func (m *Manager) StartWorkspace(ctx context.Context, req *api.StartWorkspaceReq } } + var createSecret bool + for _, feature := range startContext.Request.Spec.FeatureFlags { + if feature == api.WorkspaceFeatureFlag_PROTECTED_SECRETS { + createSecret = true + break + } + } + if createSecret { + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: podName(startContext.Request), + Namespace: m.Config.Namespace, + Labels: startContext.Labels, + }, + StringData: startContext.Secrets, + } + err = m.Clientset.Create(ctx, secret) + if err != nil && !k8serr.IsAlreadyExists(err) { + return nil, xerrors.Errorf("cannot create secret for workspace pod: %w", err) + } + } + // create the Pod in the cluster and wait until is scheduled // https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.22.md#workloads-that-saturate-nodes-with-pods-may-see-pods-that-fail-due-to-node-admission backoff := wait.Backoff{ @@ -708,6 +731,23 @@ func (m *Manager) stopWorkspace(ctx context.Context, workspaceID string, gracePe return nil } +func (m *Manager) deleteWorkspaceSecrets(ctx context.Context, podName string) error { + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: podName, + Namespace: m.Config.Namespace, + }, + } + err := m.Clientset.Delete(ctx, secret) + if k8serr.IsNotFound(err) { + err = nil + } + if err != nil { + return xerrors.Errorf("cannot delete workspace secrets: %w", err) + } + return nil +} + // findWorkspacePod finds the pod for a workspace func (m *Manager) findWorkspacePod(ctx context.Context, workspaceID string) (*corev1.Pod, error) { var pods corev1.PodList diff --git a/components/ws-manager/pkg/manager/monitor.go b/components/ws-manager/pkg/manager/monitor.go index 51eb1d553a88f1..d9356202ceff02 100644 --- a/components/ws-manager/pkg/manager/monitor.go +++ b/components/ws-manager/pkg/manager/monitor.go @@ -304,6 +304,12 @@ func actOnPodEvent(ctx context.Context, m actingManager, status *api.WorkspaceSt // login in any other phase, too. m.clearInitializerFromMap(pod.Name) + // if the secret is already gone, this won't error + err := m.deleteWorkspaceSecrets(ctx, pod.Name) + if err != nil { + return err + } + // Special case: workspaces timing out during backup. Normally a timed out workspace would just be stopped // regularly. When a workspace times out during backup though, stopping it won't do any good. // The workspace is already shutting down, it just fails to do so properly. Instead, we need @@ -416,6 +422,12 @@ func actOnPodEvent(ctx context.Context, m actingManager, status *api.WorkspaceSt if err != nil { log.WithError(err).Warn("was unable to add host IP annotation from/to workspace") } + + // workspace is running - we don't need the secret anymore + err = m.deleteWorkspaceSecrets(ctx, pod.Name) + if err != nil { + log.WithError(err).Warn("was unable to remove workspace secret") + } } if status.Phase == api.WorkspacePhase_STOPPING { @@ -477,6 +489,7 @@ type actingManager interface { waitForWorkspaceReady(ctx context.Context, pod *corev1.Pod) (err error) stopWorkspace(ctx context.Context, workspaceID string, gracePeriod time.Duration) (err error) markWorkspace(ctx context.Context, workspaceID string, annotations ...*annotation) error + deleteWorkspaceSecrets(ctx context.Context, podName string) error clearInitializerFromMap(podName string) initializeWorkspaceContent(ctx context.Context, pod *corev1.Pod) (err error) @@ -529,8 +542,7 @@ func (m *Monitor) writeEventTraceLog(status *api.WorkspaceStatus, wso *workspace c.Env[i].Value = "[redacted]" continue } - isGitpodVar := strings.HasPrefix(env.Name, "GITPOD_") || strings.HasPrefix(env.Name, "SUPERVISOR_") || strings.HasPrefix(env.Name, "BOB_") || strings.HasPrefix(env.Name, "THEIA_") - if isGitpodVar { + if isGitpodInternalEnvVar(env.Name) { continue } @@ -782,6 +794,19 @@ func (m *Monitor) initializeWorkspaceContent(ctx context.Context, pod *corev1.Po return xerrors.Errorf("cannot unmarshal init config: %w", err) } + var secret corev1.Secret + err = m.manager.Clientset.Get(ctx, types.NamespacedName{Namespace: pod.Namespace, Name: pod.Name}, &secret) + if k8serr.IsNotFound(err) { + // this is ok - do nothing + } else if err != nil { + return xerrors.Errorf("cannot get workspace secret: %w", err) + } else { + err = csapi.InjectSecretsToInitializer(&initializer, secret.Data) + if err != nil { + return xerrors.Errorf("cannot inject initializer secrets: %w", err) + } + } + if fullWorkspaceBackup { _, mf, err := m.manager.Content.GetContentLayer(ctx, workspaceMeta.Owner, workspaceMeta.MetaId, &initializer) if err != nil { diff --git a/components/ws-manager/pkg/manager/monitor_test.go b/components/ws-manager/pkg/manager/monitor_test.go index 1d8efaaf0f4138..1c40ec7acfeb05 100644 --- a/components/ws-manager/pkg/manager/monitor_test.go +++ b/components/ws-manager/pkg/manager/monitor_test.go @@ -137,4 +137,14 @@ func (r *actRecorder) modifyFinalizer(ctx context.Context, workspaceID string, f return nil } +func (r *actRecorder) deleteWorkspaceSecrets(ctx context.Context, podName string) error { + r.Records = append(r.Records, actRecord{ + Func: "deleteWorkspaceSecrets", + Params: map[string]interface{}{ + "podName": podName, + }, + }) + return nil +} + var _ actingManager = &actRecorder{} diff --git a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_cannotPull_005_STOPPED00.golden b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_cannotPull_005_STOPPED00.golden index 58a15d99fac9ee..ff2273fef09e3c 100644 --- a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_cannotPull_005_STOPPED00.golden +++ b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_cannotPull_005_STOPPED00.golden @@ -6,6 +6,12 @@ "podName": "ws-5031df46-db5e-43ae-91bd-1448305c001d" } }, + { + "Func": "deleteWorkspaceSecrets", + "Params": { + "podName": "ws-5031df46-db5e-43ae-91bd-1448305c001d" + } + }, { "Func": "modifyFinalizer", "Params": { @@ -15,4 +21,4 @@ } } ] -} \ No newline at end of file +} diff --git a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_containerd4214_STOPPING00.golden b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_containerd4214_STOPPING00.golden index 09938bf72629f1..ec1522431217f2 100644 --- a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_containerd4214_STOPPING00.golden +++ b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_containerd4214_STOPPING00.golden @@ -6,6 +6,12 @@ "podName": "ws-cc1a3979-4e0e-42cc-bba5-a8d66485bdee" } }, + { + "Func": "deleteWorkspaceSecrets", + "Params": { + "podName": "ws-cc1a3979-4e0e-42cc-bba5-a8d66485bdee" + } + }, { "Func": "modifyFinalizer", "Params": { @@ -15,4 +21,4 @@ } } ] -} \ No newline at end of file +} diff --git a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_contentInitFailed_005_STOPPED00.golden b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_contentInitFailed_005_STOPPED00.golden index 3e2e25b7cb1b85..15d23079496f1f 100644 --- a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_contentInitFailed_005_STOPPED00.golden +++ b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_contentInitFailed_005_STOPPED00.golden @@ -6,6 +6,12 @@ "podName": "prebuild-50bff6fd-2b1f-4d33-8b74-5362739add6f" } }, + { + "Func": "deleteWorkspaceSecrets", + "Params": { + "podName": "prebuild-50bff6fd-2b1f-4d33-8b74-5362739add6f" + } + }, { "Func": "modifyFinalizer", "Params": { @@ -15,4 +21,4 @@ } } ] -} \ No newline at end of file +} diff --git a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_disposal_STOPPED01.golden b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_disposal_STOPPED01.golden index 9ceef818443280..e0d7f644dbd7b6 100644 --- a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_disposal_STOPPED01.golden +++ b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_disposal_STOPPED01.golden @@ -6,6 +6,12 @@ "podName": "ws-60a694b3-ac7d-4a24-8ad9-2d8d5eb56de0" } }, + { + "Func": "deleteWorkspaceSecrets", + "Params": { + "podName": "ws-60a694b3-ac7d-4a24-8ad9-2d8d5eb56de0" + } + }, { "Func": "modifyFinalizer", "Params": { @@ -15,4 +21,4 @@ } } ] -} \ No newline at end of file +} diff --git a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_disposal_STOPPED02.golden b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_disposal_STOPPED02.golden index 2a0ff7a4f5ac7f..a00f4ef24f3649 100644 --- a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_disposal_STOPPED02.golden +++ b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_disposal_STOPPED02.golden @@ -6,6 +6,12 @@ "podName": "ws-7bc61b1f-60ae-4bfb-b01c-6339a018b3e8" } }, + { + "Func": "deleteWorkspaceSecrets", + "Params": { + "podName": "ws-7bc61b1f-60ae-4bfb-b01c-6339a018b3e8" + } + }, { "Func": "modifyFinalizer", "Params": { @@ -15,4 +21,4 @@ } } ] -} \ No newline at end of file +} diff --git a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_disposal_STOPPED03.golden b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_disposal_STOPPED03.golden index 2a0ff7a4f5ac7f..a00f4ef24f3649 100644 --- a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_disposal_STOPPED03.golden +++ b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_disposal_STOPPED03.golden @@ -6,6 +6,12 @@ "podName": "ws-7bc61b1f-60ae-4bfb-b01c-6339a018b3e8" } }, + { + "Func": "deleteWorkspaceSecrets", + "Params": { + "podName": "ws-7bc61b1f-60ae-4bfb-b01c-6339a018b3e8" + } + }, { "Func": "modifyFinalizer", "Params": { @@ -15,4 +21,4 @@ } } ] -} \ No newline at end of file +} diff --git a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_disposal_STOPPING01.golden b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_disposal_STOPPING01.golden index 1fa06a1aca5bcd..177e4d6d765a73 100644 --- a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_disposal_STOPPING01.golden +++ b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_disposal_STOPPING01.golden @@ -5,6 +5,12 @@ "Params": { "podName": "ws-60a694b3-ac7d-4a24-8ad9-2d8d5eb56de0" } + }, + { + "Func": "deleteWorkspaceSecrets", + "Params": { + "podName": "ws-60a694b3-ac7d-4a24-8ad9-2d8d5eb56de0" + } } ] -} \ No newline at end of file +} diff --git a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_disposal_STOPPING02.golden b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_disposal_STOPPING02.golden index 9ceef818443280..e0d7f644dbd7b6 100644 --- a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_disposal_STOPPING02.golden +++ b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_disposal_STOPPING02.golden @@ -6,6 +6,12 @@ "podName": "ws-60a694b3-ac7d-4a24-8ad9-2d8d5eb56de0" } }, + { + "Func": "deleteWorkspaceSecrets", + "Params": { + "podName": "ws-60a694b3-ac7d-4a24-8ad9-2d8d5eb56de0" + } + }, { "Func": "modifyFinalizer", "Params": { @@ -15,4 +21,4 @@ } } ] -} \ No newline at end of file +} diff --git a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_errimgpull_CREATING01.golden b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_errimgpull_CREATING01.golden index 3f2108cf3cf4fc..06987715763b0e 100644 --- a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_errimgpull_CREATING01.golden +++ b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_errimgpull_CREATING01.golden @@ -6,6 +6,12 @@ "podName": "ws-79be1e8b-a6de-4572-8627-99ef12303a88" } }, + { + "Func": "deleteWorkspaceSecrets", + "Params": { + "podName": "ws-79be1e8b-a6de-4572-8627-99ef12303a88" + } + }, { "Func": "modifyFinalizer", "Params": { @@ -15,4 +21,4 @@ } } ] -} \ No newline at end of file +} diff --git a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_failedBeforeStopping_explicitFail.golden b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_failedBeforeStopping_explicitFail.golden index 7722bbf8067c8e..0edd1f198af046 100644 --- a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_failedBeforeStopping_explicitFail.golden +++ b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_failedBeforeStopping_explicitFail.golden @@ -6,6 +6,12 @@ "podName": "ws-4f8ea7b8-b87d-42f2-b8dd-1a32fdbdf0d4" } }, + { + "Func": "deleteWorkspaceSecrets", + "Params": { + "podName": "ws-4f8ea7b8-b87d-42f2-b8dd-1a32fdbdf0d4" + } + }, { "Func": "modifyFinalizer", "Params": { @@ -15,4 +21,4 @@ } } ] -} \ No newline at end of file +} diff --git a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_failedPending_evicted_UNKNOWN02.golden b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_failedPending_evicted_UNKNOWN02.golden index 268400ae166d93..71ee2121410ae9 100644 --- a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_failedPending_evicted_UNKNOWN02.golden +++ b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_failedPending_evicted_UNKNOWN02.golden @@ -6,6 +6,12 @@ "podName": "ws-cecf2a75-7225-4056-a125-fa3144b9c012" } }, + { + "Func": "deleteWorkspaceSecrets", + "Params": { + "podName": "ws-cecf2a75-7225-4056-a125-fa3144b9c012" + } + }, { "Func": "modifyFinalizer", "Params": { @@ -15,4 +21,4 @@ } } ] -} \ No newline at end of file +} diff --git a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_firstUserActivity_RUNNING.golden b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_firstUserActivity_RUNNING.golden index 4b34665b60179c..ca2903d89eab7b 100644 --- a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_firstUserActivity_RUNNING.golden +++ b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_firstUserActivity_RUNNING.golden @@ -20,6 +20,12 @@ ], "workspaceID": "df376c57-7a0e-4233-976a-7a021e6f088c" } + }, + { + "Func": "deleteWorkspaceSecrets", + "Params": { + "podName": "ws-df376c57-7a0e-4233-976a-7a021e6f088c" + } } ] } diff --git a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_headlessTaskFailed_STOPPING00.golden b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_headlessTaskFailed_STOPPING00.golden index db9b99ff6f0023..463d629f882f87 100644 --- a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_headlessTaskFailed_STOPPING00.golden +++ b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_headlessTaskFailed_STOPPING00.golden @@ -6,6 +6,12 @@ "podName": "prebuild-60116ccc-1593-41f5-880e-6c4010dc4d1d" } }, + { + "Func": "deleteWorkspaceSecrets", + "Params": { + "podName": "prebuild-60116ccc-1593-41f5-880e-6c4010dc4d1d" + } + }, { "Func": "stopWorkspace", "Params": { @@ -14,4 +20,4 @@ } } ] -} \ No newline at end of file +} diff --git a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_headless_STOPPING00.golden b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_headless_STOPPING00.golden index adbf75ba65d2fe..30df55ce0ce3e7 100644 --- a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_headless_STOPPING00.golden +++ b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_headless_STOPPING00.golden @@ -6,6 +6,12 @@ "podName": "imagebuild-0dd5700a790e7ca2-95291c91f6e61c2e-e06ba50b" } }, + { + "Func": "deleteWorkspaceSecrets", + "Params": { + "podName": "imagebuild-0dd5700a790e7ca2-95291c91f6e61c2e-e06ba50b" + } + }, { "Func": "stopWorkspace", "Params": { @@ -14,4 +20,4 @@ } } ] -} \ No newline at end of file +} diff --git a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_imagespec_RUNNING00.golden b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_imagespec_RUNNING00.golden index 95c19e920c57a9..6f779979af782b 100644 --- a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_imagespec_RUNNING00.golden +++ b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_imagespec_RUNNING00.golden @@ -20,6 +20,12 @@ ], "workspaceID": "27e46234-5004-44c1-a2e8-56d68ac3c70b" } + }, + { + "Func": "deleteWorkspaceSecrets", + "Params": { + "podName": "ws-27e46234-5004-44c1-a2e8-56d68ac3c70b" + } } ] } diff --git a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_interrupted_networkNotReady_1_event_only.golden b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_interrupted_networkNotReady_1_event_only.golden index 6d3f56d525ac52..e780e2aed9ee0e 100644 --- a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_interrupted_networkNotReady_1_event_only.golden +++ b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_interrupted_networkNotReady_1_event_only.golden @@ -20,6 +20,12 @@ ], "workspaceID": "da9ffbf1-a12d-4a58-8593-475394eedb00" } + }, + { + "Func": "deleteWorkspaceSecrets", + "Params": { + "podName": "ws-da9ffbf1-a12d-4a58-8593-475394eedb00" + } } ] } diff --git a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_interrupted_networkNotReady_3_recovered_CONSTRUCTED.golden b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_interrupted_networkNotReady_3_recovered_CONSTRUCTED.golden index d73dcb0d3aa5cf..c20cac15fc1adb 100644 --- a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_interrupted_networkNotReady_3_recovered_CONSTRUCTED.golden +++ b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_interrupted_networkNotReady_3_recovered_CONSTRUCTED.golden @@ -20,6 +20,12 @@ ], "workspaceID": "0c5a8ef3-052b-44a7-b11c-3542a0928076" } + }, + { + "Func": "deleteWorkspaceSecrets", + "Params": { + "podName": "ws-0c5a8ef3-052b-44a7-b11c-3542a0928076" + } } ] } diff --git a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_metadata.golden b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_metadata.golden index a99834901c8da3..6c49059703a1e7 100644 --- a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_metadata.golden +++ b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_metadata.golden @@ -20,6 +20,12 @@ ], "workspaceID": "foobas" } + }, + { + "Func": "deleteWorkspaceSecrets", + "Params": { + "podName": "ws-foobas" + } } ] } diff --git a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_ownerToken.golden b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_ownerToken.golden index 4b34665b60179c..ca2903d89eab7b 100644 --- a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_ownerToken.golden +++ b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_ownerToken.golden @@ -20,6 +20,12 @@ ], "workspaceID": "df376c57-7a0e-4233-976a-7a021e6f088c" } + }, + { + "Func": "deleteWorkspaceSecrets", + "Params": { + "podName": "ws-df376c57-7a0e-4233-976a-7a021e6f088c" + } } ] } diff --git a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_prebuildFail_STOPPED00.golden b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_prebuildFail_STOPPED00.golden index e895b0e37db7d9..2b1e964d2d6c7e 100644 --- a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_prebuildFail_STOPPED00.golden +++ b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_prebuildFail_STOPPED00.golden @@ -6,6 +6,12 @@ "podName": "prebuild-dbc45dce-611a-49a8-bd76-7afda76a1e24" } }, + { + "Func": "deleteWorkspaceSecrets", + "Params": { + "podName": "prebuild-dbc45dce-611a-49a8-bd76-7afda76a1e24" + } + }, { "Func": "modifyFinalizer", "Params": { @@ -15,4 +21,4 @@ } } ] -} \ No newline at end of file +} diff --git a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_prebuildFail_STOPPING00.golden b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_prebuildFail_STOPPING00.golden index 6b58c88269ceb7..49a8cd0c2a4694 100644 --- a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_prebuildFail_STOPPING00.golden +++ b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_prebuildFail_STOPPING00.golden @@ -6,6 +6,12 @@ "podName": "prebuild-dbc45dce-611a-49a8-bd76-7afda76a1e24" } }, + { + "Func": "deleteWorkspaceSecrets", + "Params": { + "podName": "prebuild-dbc45dce-611a-49a8-bd76-7afda76a1e24" + } + }, { "Func": "stopWorkspace", "Params": { @@ -14,4 +20,4 @@ } } ] -} \ No newline at end of file +} diff --git a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_prebuildSuccess_STOPPED00.golden b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_prebuildSuccess_STOPPED00.golden index ae3ce7264188f8..1a441296989852 100644 --- a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_prebuildSuccess_STOPPED00.golden +++ b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_prebuildSuccess_STOPPED00.golden @@ -6,6 +6,12 @@ "podName": "prebuild-8e0bbcdf-a926-4670-8c40-b718f035b2ae" } }, + { + "Func": "deleteWorkspaceSecrets", + "Params": { + "podName": "prebuild-8e0bbcdf-a926-4670-8c40-b718f035b2ae" + } + }, { "Func": "modifyFinalizer", "Params": { @@ -15,4 +21,4 @@ } } ] -} \ No newline at end of file +} diff --git a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_prebuildSuccess_STOPPING00.golden b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_prebuildSuccess_STOPPING00.golden index b3abcfe671ed16..af18454ed80165 100644 --- a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_prebuildSuccess_STOPPING00.golden +++ b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_prebuildSuccess_STOPPING00.golden @@ -6,6 +6,12 @@ "podName": "prebuild-8e0bbcdf-a926-4670-8c40-b718f035b2ae" } }, + { + "Func": "deleteWorkspaceSecrets", + "Params": { + "podName": "prebuild-8e0bbcdf-a926-4670-8c40-b718f035b2ae" + } + }, { "Func": "stopWorkspace", "Params": { @@ -14,4 +20,4 @@ } } ] -} \ No newline at end of file +} diff --git a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_stoppedByRequest_000_RUNNING00.golden b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_stoppedByRequest_000_RUNNING00.golden index 25282058573eca..f4824619b0ffad 100644 --- a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_stoppedByRequest_000_RUNNING00.golden +++ b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_stoppedByRequest_000_RUNNING00.golden @@ -27,6 +27,12 @@ ], "workspaceID": "18f99de5-090f-4318-9759-05f5ef0277f7" } + }, + { + "Func": "deleteWorkspaceSecrets", + "Params": { + "podName": "ws-18f99de5-090f-4318-9759-05f5ef0277f7" + } } ] } diff --git a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_stuckInStopping_STOPPING00.golden b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_stuckInStopping_STOPPING00.golden index 3c40884dac4ef0..7d55146600558d 100644 --- a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_stuckInStopping_STOPPING00.golden +++ b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_stuckInStopping_STOPPING00.golden @@ -6,6 +6,12 @@ "podName": "ws-48f13cc4-6311-48c2-950a-4b7ddedc3037" } }, + { + "Func": "deleteWorkspaceSecrets", + "Params": { + "podName": "ws-48f13cc4-6311-48c2-950a-4b7ddedc3037" + } + }, { "Func": "modifyFinalizer", "Params": { @@ -15,4 +21,4 @@ } } ] -} \ No newline at end of file +} diff --git a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_workspace_startup_failed.golden b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_workspace_startup_failed.golden index 4b2df75908e75c..e46dc4be88bee7 100644 --- a/components/ws-manager/pkg/manager/testdata/actOnPodEvent_workspace_startup_failed.golden +++ b/components/ws-manager/pkg/manager/testdata/actOnPodEvent_workspace_startup_failed.golden @@ -6,6 +6,12 @@ "podName": "ws-7b26a643-d588-4346-bc9e-b46e70831078" } }, + { + "Func": "deleteWorkspaceSecrets", + "Params": { + "podName": "ws-7b26a643-d588-4346-bc9e-b46e70831078" + } + }, { "Func": "modifyFinalizer", "Params": { diff --git a/components/ws-manager/pkg/manager/testdata/cdwp_secrets.golden b/components/ws-manager/pkg/manager/testdata/cdwp_secrets.golden new file mode 100644 index 00000000000000..e88b28e62ff15e --- /dev/null +++ b/components/ws-manager/pkg/manager/testdata/cdwp_secrets.golden @@ -0,0 +1,279 @@ +{ + "reason": { + "metadata": { + "name": "ws-test", + "namespace": "default", + "creationTimestamp": null, + "labels": { + "app": "gitpod", + "component": "workspace", + "gitpod.io/networkpolicy": "default", + "gitpod.io/workspaceClass": "default", + "gpwsman": "true", + "headless": "false", + "metaID": "foobar", + "owner": "tester", + "project": "gitpod", + "team": "awesome", + "workspaceID": "test", + "workspaceType": "regular" + }, + "annotations": { + "cluster-autoscaler.kubernetes.io/safe-to-evict": "false", + "container.apparmor.security.beta.kubernetes.io/workspace": "unconfined", + "gitpod.io/attemptingToCreate": "true", + "gitpod/admission": "admit_owner_only", + "gitpod/contentInitializer": "GmcKZXdvcmtzcGFjZXMvY3J5cHRpYy1pZC1nb2VzLWhlcmcvZmQ2MjgwNGItNGNhYi0xMWU5LTg0M2EtNGU2NDUzNzMwNDhlLnRhckBnaXRwb2QtZGV2LXVzZXItY2hyaXN0ZXN0aW5n", + "gitpod/id": "test", + "gitpod/imageSpec": "CrwBZXUuZ2NyLmlvL2dpdHBvZC1kZXYvd29ya3NwYWNlLWltYWdlcy9hYzFjMDc1NTAwNzk2NmU0ZDZlMDkwZWE4MjE3MjlhYzc0N2QyMmFjL2V1Lmdjci5pby9naXRwb2QtZGV2L3dvcmtzcGFjZS1iYXNlLWltYWdlcy9naXRodWIuY29tL3R5cGVmb3gvZ2l0cG9kOjgwYTdkNDI3YTFmY2QzNDZkNDIwNjAzZDgwYTMxZDU3Y2Y3NWE3YWYSNGV1Lmdjci5pby9naXRwb2QtY29yZS1kZXYvYnVpZC90aGVpYS1pZGU6c29tZXZlcnNpb24=", + "gitpod/never-ready": "true", + "gitpod/ownerToken": "%7J'[Of/8NDiWE+9F,I6^Jcj_1\u0026}-F8p", + "gitpod/servicePrefix": "foobarservice", + "gitpod/url": "test-foobarservice-gitpod.io", + "seccomp.security.alpha.kubernetes.io/pod": "localhost/workspace-default" + }, + "finalizers": [ + "gitpod.io/finalizer" + ] + }, + "spec": { + "volumes": [ + { + "name": "vol-this-workspace", + "hostPath": { + "path": "/tmp/workspaces/test", + "type": "DirectoryOrCreate" + } + }, + { + "name": "daemon-mount", + "hostPath": { + "path": "/tmp/workspaces/test-daemon", + "type": "DirectoryOrCreate" + } + } + ], + "containers": [ + { + "name": "workspace", + "image": "registry-facade:8080/remote/test", + "command": [ + "/.supervisor/workspacekit", + "ring0" + ], + "ports": [ + { + "containerPort": 23000 + }, + { + "name": "supervisor", + "containerPort": 22999 + } + ], + "env": [ + { + "name": "GITPOD_REPO_ROOT", + "value": "/workspace" + }, + { + "name": "GITPOD_REPO_ROOTS", + "value": "/workspace" + }, + { + "name": "GITPOD_CLI_APITOKEN", + "value": "Ab=5=rRA*9:C'T{;RRB\u003e]vK2p6`fFfrS" + }, + { + "name": "GITPOD_OWNER_ID", + "value": "tester" + }, + { + "name": "GITPOD_WORKSPACE_ID", + "value": "foobar" + }, + { + "name": "GITPOD_INSTANCE_ID", + "value": "test" + }, + { + "name": "GITPOD_THEIA_PORT", + "value": "23000" + }, + { + "name": "THEIA_WORKSPACE_ROOT", + "value": "/workspace" + }, + { + "name": "GITPOD_HOST", + "value": "gitpod.io" + }, + { + "name": "GITPOD_WORKSPACE_URL", + "value": "test-foobarservice-gitpod.io" + }, + { + "name": "THEIA_SUPERVISOR_ENDPOINT", + "value": ":22999" + }, + { + "name": "THEIA_WEBVIEW_EXTERNAL_ENDPOINT", + "value": "webview-{{hostname}}" + }, + { + "name": "THEIA_MINI_BROWSER_HOST_PATTERN", + "value": "browser-{{hostname}}" + }, + { + "name": "GITPOD_GIT_USER_NAME", + "value": "usernameGoesHere" + }, + { + "name": "GITPOD_GIT_USER_EMAIL", + "value": "some@user.com" + }, + { + "name": "foo", + "valueFrom": { + "secretKeyRef": { + "name": "ws-test", + "key": "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae" + } + } + }, + { + "name": "THEIA_SUPERVISOR_TOKENS", + "valueFrom": { + "secretKeyRef": { + "name": "ws-test", + "key": "3a3b612491764cccf7a5bccafc73031bb965cad1592bf600f2c3edca7c6e41bb" + } + } + }, + { + "name": "GITPOD_INTERVAL", + "value": "30000" + }, + { + "name": "GITPOD_MEMORY", + "value": "999" + } + ], + "resources": { + "limits": { + "cpu": "900m", + "memory": "1G" + }, + "requests": { + "cpu": "899m", + "ephemeral-storage": "5Gi", + "memory": "999M" + } + }, + "volumeMounts": [ + { + "name": "vol-this-workspace", + "mountPath": "/workspace", + "mountPropagation": "HostToContainer" + }, + { + "name": "daemon-mount", + "mountPath": "/.workspace", + "mountPropagation": "HostToContainer" + } + ], + "readinessProbe": { + "httpGet": { + "path": "/_supervisor/v1/status/content/wait/true", + "port": 22999, + "scheme": "HTTP" + }, + "initialDelaySeconds": 2, + "timeoutSeconds": 1, + "periodSeconds": 1, + "successThreshold": 1, + "failureThreshold": 600 + }, + "terminationMessagePolicy": "File", + "imagePullPolicy": "IfNotPresent", + "securityContext": { + "capabilities": { + "add": [ + "AUDIT_WRITE", + "FSETID", + "KILL", + "NET_BIND_SERVICE", + "SYS_PTRACE" + ], + "drop": [ + "SETPCAP", + "CHOWN", + "NET_RAW", + "DAC_OVERRIDE", + "FOWNER", + "SYS_CHROOT", + "SETFCAP", + "SETUID", + "SETGID" + ] + }, + "privileged": false, + "runAsUser": 33333, + "runAsGroup": 33333, + "runAsNonRoot": true, + "readOnlyRootFilesystem": false, + "allowPrivilegeEscalation": true + } + } + ], + "restartPolicy": "Never", + "serviceAccountName": "workspace", + "automountServiceAccountToken": false, + "securityContext": {}, + "hostname": "foobar", + "affinity": { + "nodeAffinity": { + "requiredDuringSchedulingIgnoredDuringExecution": { + "nodeSelectorTerms": [ + { + "matchExpressions": [ + { + "key": "gitpod.io/workload_workspace_regular", + "operator": "Exists" + }, + { + "key": "gitpod.io/ws-daemon_ready_ns_default", + "operator": "Exists" + }, + { + "key": "gitpod.io/registry-facade_ready_ns_default", + "operator": "Exists" + } + ] + } + ] + } + } + }, + "tolerations": [ + { + "key": "node.kubernetes.io/disk-pressure", + "operator": "Exists", + "effect": "NoExecute" + }, + { + "key": "node.kubernetes.io/memory-pressure", + "operator": "Exists", + "effect": "NoExecute" + }, + { + "key": "node.kubernetes.io/network-unavailable", + "operator": "Exists", + "effect": "NoExecute", + "tolerationSeconds": 30 + } + ], + "enableServiceLinks": false + }, + "status": {} + } +} diff --git a/components/ws-manager/pkg/manager/testdata/cdwp_secrets.json b/components/ws-manager/pkg/manager/testdata/cdwp_secrets.json new file mode 100644 index 00000000000000..2e0ef7fdafced3 --- /dev/null +++ b/components/ws-manager/pkg/manager/testdata/cdwp_secrets.json @@ -0,0 +1,35 @@ +{ + "spec": { + "ideImage": { + "webRef": "eu.gcr.io/gitpod-core-dev/buid/theia-ide:someversion" + }, + "workspaceImage": "eu.gcr.io/gitpod-dev/workspace-images/ac1c0755007966e4d6e090ea821729ac747d22ac/eu.gcr.io/gitpod-dev/workspace-base-images/github.com/typefox/gitpod:80a7d427a1fcd346d420603d80a31d57cf75a7af", + "featureFlags": [ + 8 + ], + "initializer": { + "snapshot": { + "snapshot": "workspaces/cryptic-id-goes-herg/fd62804b-4cab-11e9-843a-4e645373048e.tar@gitpod-dev-user-christesting" + } + }, + "ports": [ + { + "port": 8080 + } + ], + "envvars": [ + { + "name": "foo", + "value": "bar" + }, + { + "name": "THEIA_SUPERVISOR_TOKENS", + "value": "some-secret-value" + } + ], + "git": { + "username": "usernameGoesHere", + "email": "some@user.com" + } + } +} diff --git a/install/installer/pkg/components/ws-manager/role.go b/install/installer/pkg/components/ws-manager/role.go index 21eaa76b44937a..1d56f5744fbb62 100644 --- a/install/installer/pkg/components/ws-manager/role.go +++ b/install/installer/pkg/components/ws-manager/role.go @@ -73,6 +73,19 @@ func role(ctx *common.RenderContext) ([]runtime.Object, error) { "deletecollection", }, }, + { + APIGroups: []string{""}, + Resources: []string{ + "secrets", + }, + Verbs: []string{ + "get", + "create", + "delete", + "watch", + "list", + }, + }, { APIGroups: []string{"snapshot.storage.k8s.io"}, Resources: []string{