Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

secrets: allow providing secrets with env #1534

Merged
merged 3 commits into from
Jul 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions cmd/buildctl/build/secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,30 +11,31 @@ import (

// ParseSecret parses --secret
func ParseSecret(sl []string) (session.Attachable, error) {
fs := make([]secretsprovider.FileSource, 0, len(sl))
fs := make([]secretsprovider.Source, 0, len(sl))
for _, v := range sl {
s, err := parseSecret(v)
if err != nil {
return nil, err
}
fs = append(fs, *s)
}
store, err := secretsprovider.NewFileStore(fs)
store, err := secretsprovider.NewStore(fs)
if err != nil {
return nil, err
}
return secretsprovider.NewSecretProvider(store), nil
}

func parseSecret(value string) (*secretsprovider.FileSource, error) {
func parseSecret(value string) (*secretsprovider.Source, error) {
csvReader := csv.NewReader(strings.NewReader(value))
fields, err := csvReader.Read()
if err != nil {
return nil, errors.Wrap(err, "failed to parse csv secret")
}

fs := secretsprovider.FileSource{}
fs := secretsprovider.Source{}

var typ string
for _, field := range fields {
parts := strings.SplitN(field, "=", 2)
key := strings.ToLower(parts[0])
Expand All @@ -46,16 +47,23 @@ func parseSecret(value string) (*secretsprovider.FileSource, error) {
value := parts[1]
switch key {
case "type":
if value != "file" {
if value != "file" && value != "env" {
return nil, errors.Errorf("unsupported secret type %q", value)
}
typ = value
case "id":
fs.ID = value
case "source", "src":
fs.FilePath = value
case "env":
fs.Env = value
default:
return nil, errors.Errorf("unexpected key '%s' in '%s'", key, field)
}
}
if typ == "env" {
fs.Env = fs.FilePath
fs.FilePath = ""
}
return &fs, nil
}
54 changes: 0 additions & 54 deletions session/secrets/secretsprovider/file.go

This file was deleted.

86 changes: 86 additions & 0 deletions session/secrets/secretsprovider/store.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package secretsprovider

import (
"context"
"io/ioutil"
"os"
"runtime"
"strings"

"github.com/moby/buildkit/session/secrets"
"github.com/pkg/errors"
"github.com/tonistiigi/units"
)

type Source struct {
ID string
FilePath string
Env string
}

func NewStore(files []Source) (secrets.SecretStore, error) {
m := map[string]Source{}
for _, f := range files {
if f.ID == "" {
return nil, errors.Errorf("secret missing ID")
}
if f.Env == "" && f.FilePath == "" {
if hasEnv(f.ID) {
f.Env = f.ID
} else {
f.FilePath = f.ID
}
}
if f.FilePath != "" {
fi, err := os.Stat(f.FilePath)
if err != nil {
return nil, errors.Wrapf(err, "failed to stat %s", f.FilePath)
}
if fi.Size() > MaxSecretSize {
return nil, errors.Errorf("secret %s too big. max size %#.f", f.ID, MaxSecretSize*units.B)
}
}
m[f.ID] = f
}
return &fileStore{
m: m,
}, nil
}

type fileStore struct {
m map[string]Source
}

func (fs *fileStore) GetSecret(ctx context.Context, id string) ([]byte, error) {
v, ok := fs.m[id]
if !ok {
return nil, errors.WithStack(secrets.ErrNotFound)
}
if v.Env != "" {
return []byte(os.Getenv(v.Env)), nil
}
dt, err := ioutil.ReadFile(v.FilePath)
if err != nil {
return nil, err
}
return dt, nil
}

func hasEnv(name string) bool {
for _, entry := range os.Environ() {
idx := strings.IndexRune(entry, '=')
if idx == -1 {
continue
}
if runtime.GOOS == "windows" {
// Environment variable are case-insensitive on Windows. PaTh, path and PATH are equivalent.
if strings.EqualFold(entry[:idx], name) {
return true
}
}
if entry[:idx] == name {
return true
}
}
return false
}