buildkit secrets support

- Secrets are never exposed in plaintext in the Cue tree. `dagger query`
  won't dump secrets anymore, Cue errors won't contain them either.
- BuildKit-native secrets support through a new `mount` type. This
  ensures secrets will never be part of containerd layers, buildkit
  cache and generally speaking will never be saved to disk in plaintext.
- Updated netlify as an example
- Added tests
- Changed the Cue definition of a secret to:

```
	@dagger(secret)

	id: string
}
```

This is to ensure both that setting the wrong input type on a secret
(e.g. `dagger input text`) will fail, and attempting to misuse the
secret (e.g. interpolating, passing as an env variable, etc) will also
fail properly.

Signed-off-by: Andrea Luzzardi <aluzzardi@gmail.com>
This commit is contained in:
Andrea Luzzardi
2021-05-25 18:56:16 -07:00
parent 15f4c4877d
commit 9c0e2d1d95
15 changed files with 244 additions and 59 deletions

View File

@@ -44,7 +44,7 @@ func New(st *state.State) (*Environment, error) {
// Prepare inputs
for key, input := range st.Inputs {
v, err := input.Compile(st)
v, err := input.Compile(key, st)
if err != nil {
return nil, err
}
@@ -86,7 +86,7 @@ func (e *Environment) LoadPlan(ctx context.Context, s solver.Solver) error {
span, ctx := opentracing.StartSpanFromContext(ctx, "environment.LoadPlan")
defer span.Finish()
planSource, err := e.state.PlanSource().Compile(e.state)
planSource, err := e.state.PlanSource().Compile("", e.state)
if err != nil {
return err
}
@@ -157,7 +157,7 @@ func (e *Environment) LocalDirs() map[string]string {
}
// 2. Scan the plan
plan, err := e.state.PlanSource().Compile(e.state)
plan, err := e.state.PlanSource().Compile("", e.state)
if err != nil {
panic(err)
}

View File

@@ -490,6 +490,25 @@ func (p *Pipeline) mount(ctx context.Context, dest string, mnt *compiler.Value)
return nil, fmt.Errorf("invalid mount source: %q", s)
}
}
// eg. mount: "/foo": secret: mysecret
if secret := mnt.Lookup("secret"); secret.Exists() {
if !secret.HasAttr("secret") {
return nil, fmt.Errorf("invalid secret %q: not a secret", secret.Path().String())
}
idValue := secret.Lookup("id")
if !idValue.Exists() {
return nil, fmt.Errorf("invalid secret %q: no id field", secret.Path().String())
}
id, err := idValue.String()
if err != nil {
return nil, fmt.Errorf("invalid secret id: %w", err)
}
return llb.AddSecret(dest,
llb.SecretID(id),
llb.SecretFileOpt(0, 0, 0400), // uid, gid, mask)
), nil
}
// eg. mount: "/foo": { from: www.source }
from := NewPipeline(mnt.Lookup("from"), p.s)
if err := from.Run(ctx); err != nil {