Skip to content

Commit

Permalink
Dagger: support secrets in mounts + env
Browse files Browse the repository at this point in the history
  • Loading branch information
vito committed Mar 26, 2023
1 parent 1b75faa commit 5c8a251
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 17 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/vito/bass
go 1.20

require (
dagger.io/dagger v0.5.0
dagger.io/dagger v0.5.2
github.com/adrg/xdg v0.4.0
github.com/agext/levenshtein v1.2.3
github.com/ajstarks/svgo v0.0.0-20210406150507-75cfd577ce75
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ dagger.io/dagger v0.4.6 h1:1GpHJuGrDcLCCIprLpwTXBpKg8Te/RVIDo1qpzkL/QE=
dagger.io/dagger v0.4.6/go.mod h1:1nbGnLdIfoBV2ahbQjheI//SNGz+b5q1jqf0A+pJ+Oc=
dagger.io/dagger v0.5.0 h1:7hQnA/pFMpEkuaU2ScNWoZznTa6DbIqHnwBJwL5bBQY=
dagger.io/dagger v0.5.0/go.mod h1:1nbGnLdIfoBV2ahbQjheI//SNGz+b5q1jqf0A+pJ+Oc=
dagger.io/dagger v0.5.1 h1:xu+jG2+ya1nhjUDInn8pG2s/4RJkUUis1bywFTZyvtA=
dagger.io/dagger v0.5.1/go.mod h1:1nbGnLdIfoBV2ahbQjheI//SNGz+b5q1jqf0A+pJ+Oc=
dagger.io/dagger v0.5.2 h1:xNMUnLWqcsb5UrvqOgJx4MJVfe7xDb50kBMXdC63Cjs=
dagger.io/dagger v0.5.2/go.mod h1:1nbGnLdIfoBV2ahbQjheI//SNGz+b5q1jqf0A+pJ+Oc=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU=
filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
Expand Down
6 changes: 6 additions & 0 deletions pkg/runtimes/buildkit.go
Original file line number Diff line number Diff line change
Expand Up @@ -759,6 +759,12 @@ func (b *buildkitBuilder) llb(ctx context.Context, thunk bass.Thunk, extraOpts .
runOpt = append(runOpt, llb.AddEnv("_BASS_DEBUG", "1"))
}

for _, env := range cmd.SecretEnv {
id := env.Secret.Name
b.secrets[id] = env.Secret.Reveal()
runOpt = append(runOpt, llb.AddSecret(env.Name, llb.SecretID(id), llb.SecretAsEnv(true)))
}

if thunk.Insecure {
needsInsecure = true

Expand Down
19 changes: 17 additions & 2 deletions pkg/runtimes/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ type Command struct {

// these don't need to be marshaled, since they're part of the container
// setup and not passed to the shim
Mounts []CommandMount `json:"-"`
Services []bass.Thunk `json:"-"`
Mounts []CommandMount `json:"-"`
Services []bass.Thunk `json:"-"`
SecretEnv []CommandSecretEnv `json:"-"`

mounted map[string]bool
starter Starter
Expand All @@ -43,6 +44,11 @@ type CommandHost struct {
Target net.IP
}

type CommandSecretEnv struct {
Name string
Secret bass.Secret
}

type Starter interface {
// Start starts the thunk and waits for its ports to be ready.
Start(context.Context, bass.Thunk) (StartResult, error)
Expand Down Expand Up @@ -101,6 +107,15 @@ func NewCommand(ctx context.Context, starter Starter, thunk bass.Thunk) (Command
return nil
}

var secret bass.Secret
if v.Decode(&secret) == nil {
cmd.SecretEnv = append(cmd.SecretEnv, CommandSecretEnv{
Name: name.JSONKey(),
Secret: secret,
})
return nil
}

val, err := cmd.resolveStr(ctx, v)
if err != nil {
return fmt.Errorf("resolve env %s: %w", name, err)
Expand Down
11 changes: 11 additions & 0 deletions pkg/runtimes/dagger.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,14 @@ func (runtime *Dagger) container(ctx context.Context, thunk bass.Thunk) (*dagger
ctr = ctr.WithEnvVariable(name, val)
}

for _, env := range cmd.SecretEnv {
secret := runtime.client.SetSecret(
env.Secret.Name,
string(env.Secret.Reveal()),
)
ctr = ctr.WithSecretVariable(env.Name, secret)
}

return ctr.WithExec(cmd.Args, dagger.ContainerWithExecOpts{
Stdin: string(cmd.Stdin),
InsecureRootCapabilities: thunk.Insecure,
Expand Down Expand Up @@ -365,6 +373,9 @@ func (runtime *Dagger) mount(ctx context.Context, ctr *dagger.Container, target
} else {
return ctr.WithMountedFile(target, dir.File(fsp.FromSlash())), nil
}
case src.Secret != nil:
secret := runtime.client.SetSecret(src.Secret.Name, string(src.Secret.Reveal()))
return ctr.WithMountedSecret(target, secret), nil
default:
return nil, fmt.Errorf("mounting %T not implemented yet", src.ToValue())
}
Expand Down
8 changes: 2 additions & 6 deletions pkg/runtimes/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,12 +237,8 @@ func Suite(t *testing.T, config bass.RuntimeConfig) {
Result: bass.Bool(true),
},
{
File: "secrets.bass",
Result: bass.NewList(
bass.String("stdin hunter2"),
bass.String("env hunter2"),
bass.String("mount hunter2"),
),
File: "secrets.bass",
Result: bass.Null{},
Bindings: bass.Bindings{
"assert-export-does-not-contain-secret": bass.Func("assert-export-does-not-contain-secret", "[thunk]", func(ctx context.Context, thunk bass.Thunk) error {
pool, err := bass.RuntimePoolFromContext(ctx)
Expand Down
19 changes: 11 additions & 8 deletions pkg/runtimes/testdata/secrets.bass
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
(def *memos* *dir*/bass.lock)

; these tests are tricky, since we have to prevent the assertions themselves
; from leaking secrets. so we just test against their hash.

(def stdin-secret
(from (linux/alpine)
(.cat (mask "stdin hunter2" :stdin-secret))))
(-> ($ sh -c "test $(cat | sha1sum | awk '{print $1}') = 633f9fe12bfc15c301898555bfca62d852a1ad36")
(with-stdin [(mask "stdin hunter2" :stdin-secret)]))))

(def env-secret
(from (linux/alpine)
(-> ($ sh -c "echo $SECRET")
(-> ($ sh -c "test $(echo -n $SECRET | sha1sum | awk '{print $1}') = 2ce29a2cf01ba01a109ce23a6d98d9fa59c6410c")
(with-env {:SECRET (mask "env hunter2" :env-secret)}))))

(def file-secret
(from (linux/alpine)
(-> ($ cat /tmp/secret)
(-> ($ sh -c "test $(sha1sum /tmp/secret | awk '{print $1}') = 0a1980f57ebfb1b2cc022a6722a653be2f6eaaf2")
(with-mount (mask "mount hunter2" :mount-secret) /tmp/secret))))

(def results
[(-> stdin-secret (read :json) next)
(-> env-secret (read :lines) next)
(-> file-secret (read :lines) next)])
(run stdin-secret)
(run env-secret)
(run file-secret)

(assert-does-not-contain-secret (*display*))

(map assert-export-does-not-contain-secret
[stdin-secret env-secret file-secret])

results
null

0 comments on commit 5c8a251

Please sign in to comment.