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

47
solver/secretsprovider.go Normal file
View File

@@ -0,0 +1,47 @@
package solver
import (
"context"
"strings"
"github.com/moby/buildkit/session"
"github.com/moby/buildkit/session/secrets"
"github.com/moby/buildkit/session/secrets/secretsprovider"
"github.com/rs/zerolog/log"
"go.dagger.io/dagger/state"
)
func NewSecretsProvider(st *state.State) session.Attachable {
return secretsprovider.NewSecretProvider(&inputStore{st})
}
type inputStore struct {
st *state.State
}
func (s *inputStore) GetSecret(ctx context.Context, id string) ([]byte, error) {
lg := log.Ctx(ctx)
const secretPrefix = "secret="
if !strings.HasPrefix(id, secretPrefix) {
return nil, secrets.ErrNotFound
}
id = strings.TrimPrefix(id, secretPrefix)
input, ok := s.st.Inputs[id]
if !ok {
return nil, secrets.ErrNotFound
}
if input.Secret == nil {
return nil, secrets.ErrNotFound
}
lg.
Debug().
Str("id", id).
Msg("injecting secret")
return []byte(input.Secret.PlainText()), nil
}

View File

@@ -3,7 +3,9 @@ package solver
import (
"context"
"encoding/json"
"errors"
"fmt"
"strings"
bk "github.com/moby/buildkit/client"
"github.com/moby/buildkit/client/llb"
@@ -25,6 +27,7 @@ type Opts struct {
Gateway bkgw.Client
Events chan *bk.SolveStatus
Auth *RegistryAuthProvider
Secrets session.Attachable
NoCache bool
}
@@ -100,7 +103,11 @@ func (s Solver) ResolveImageConfig(ctx context.Context, ref string, opts llb.Res
// Solve will block until the state is solved and returns a Reference.
func (s Solver) SolveRequest(ctx context.Context, req bkgw.SolveRequest) (*bkgw.Result, error) {
return s.opts.Gateway.Solve(ctx, req)
res, err := s.opts.Gateway.Solve(ctx, req)
if err != nil {
return nil, CleanError(err)
}
return res, nil
}
// Solve will block until the state is solved and returns a Reference.
@@ -150,7 +157,7 @@ func (s Solver) Export(ctx context.Context, st llb.State, img *dockerfile2llb.Im
opts := bk.SolveOpt{
Exports: []bk.ExportEntry{output},
Session: []session.Attachable{s.opts.Auth},
Session: []session.Attachable{s.opts.Auth, s.opts.Secrets},
}
ch := make(chan *bk.SolveStatus)
@@ -204,3 +211,22 @@ func dumpLLB(def *bkpb.Definition) ([]byte, error) {
}
return json.Marshal(ops)
}
// A helper to remove noise from buildkit error messages.
// FIXME: Obviously a cleaner solution would be nice.
func CleanError(err error) error {
noise := []string{
"executor failed running ",
"buildkit-runc did not terminate successfully",
"rpc error: code = Unknown desc = ",
"failed to solve: ",
}
msg := err.Error()
for _, s := range noise {
msg = strings.ReplaceAll(msg, s, "")
}
return errors.New(msg)
}