diff --git a/client/client.go b/client/client.go index 84ea75e5..e4e339a8 100644 --- a/client/client.go +++ b/client/client.go @@ -128,15 +128,15 @@ func (c *Client) buildfn(ctx context.Context, st *state.State, env *environment. // buildkit auth provider (registry) auth := solver.NewRegistryAuthProvider() - // secrets - secrets := solver.NewSecretsProvider(st) + // session (secrets & store) + secretsStore := solver.NewSecretsStoreProvider(st) // Setup solve options opts := bk.SolveOpt{ LocalDirs: localdirs, Session: []session.Attachable{ auth, - secrets, + secretsStore.Secrets, solver.NewDockerSocketProvider(), }, CacheExports: c.cfg.CacheExports, @@ -171,12 +171,12 @@ func (c *Client) buildfn(ctx context.Context, st *state.State, env *environment. resp, err := c.c.Build(ctx, opts, "", func(ctx context.Context, gw bkgw.Client) (*bkgw.Result, error) { s := solver.New(solver.Opts{ - Control: c.c, - Gateway: gw, - Events: eventsCh, - Auth: auth, - Secrets: secrets, - NoCache: c.cfg.NoCache, + Control: c.c, + Gateway: gw, + Events: eventsCh, + Auth: auth, + SecretsStore: secretsStore, + NoCache: c.cfg.NoCache, }) // Close events channel diff --git a/environment/pipeline.go b/environment/pipeline.go index 0d9dbb92..e515e040 100644 --- a/environment/pipeline.go +++ b/environment/pipeline.go @@ -651,9 +651,27 @@ func (p *Pipeline) DockerLogin(ctx context.Context, op *compiler.Value, st llb.S return st, err } - secret, err := op.Lookup("secret").String() + // Inject secret as plain text or retrieve string + // FIXME If we could create secret directly in `cue`, we could clean up + // that condition + // But currently it's not possible because ECR secret's is a string + // so we need to handle both options (string & secret) + secretValue, err := op.Lookup("secret").String() if err != nil { - return st, err + // Retrieve secret + if secret := op.Lookup("secret"); secret.Exists() { + id, err := getSecretID(secret) + if err != nil { + return st, err + } + secretBytes, err := p.s.GetOptions().SecretsStore.GetSecret(ctx, id) + if err != nil { + return st, err + } + secretValue = string(secretBytes) + } else { + return st, err + } } target, err := op.Lookup("target").String() @@ -661,7 +679,7 @@ func (p *Pipeline) DockerLogin(ctx context.Context, op *compiler.Value, st llb.S return st, err } - p.s.AddCredentials(target, username, secret) + p.s.AddCredentials(target, username, secretValue) log. Ctx(ctx). Debug(). diff --git a/solver/secretsprovider.go b/solver/secretsprovider.go index 67f8436e..3e255bcb 100644 --- a/solver/secretsprovider.go +++ b/solver/secretsprovider.go @@ -11,8 +11,22 @@ import ( "go.dagger.io/dagger/state" ) -func NewSecretsProvider(st *state.State) session.Attachable { - return secretsprovider.NewSecretProvider(&inputStore{st}) +type SecretsStore struct { + Secrets session.Attachable + store *inputStore +} + +func (s SecretsStore) GetSecret(ctx context.Context, id string) ([]byte, error) { + return s.store.GetSecret(ctx, id) +} + +func NewSecretsStoreProvider(st *state.State) SecretsStore { + store := &inputStore{st} + + return SecretsStore{ + Secrets: secretsprovider.NewSecretProvider(store), + store: store, + } } type inputStore struct { diff --git a/solver/solver.go b/solver/solver.go index d167675a..05f890ae 100644 --- a/solver/solver.go +++ b/solver/solver.go @@ -26,12 +26,12 @@ type Solver struct { } type Opts struct { - Control *bk.Client - Gateway bkgw.Client - Events chan *bk.SolveStatus - Auth *RegistryAuthProvider - Secrets session.Attachable - NoCache bool + Control *bk.Client + Gateway bkgw.Client + Events chan *bk.SolveStatus + Auth *RegistryAuthProvider + SecretsStore SecretsStore + NoCache bool } func New(opts Opts) Solver { @@ -61,6 +61,10 @@ func invalidateCache(def *llb.Definition) error { return nil } +func (s Solver) GetOptions() Opts { + return s.opts +} + func (s Solver) NoCache() bool { return s.opts.NoCache } @@ -189,7 +193,7 @@ func (s Solver) Export(ctx context.Context, st llb.State, img *dockerfile2llb.Im Exports: []bk.ExportEntry{output}, Session: []session.Attachable{ s.opts.Auth, - s.opts.Secrets, + s.opts.SecretsStore.Secrets, NewDockerSocketProvider(), }, } diff --git a/stdlib/.dagger/env/docker-pull/values.yaml b/stdlib/.dagger/env/docker-pull/values.yaml index 5e7205d8..75138a21 100644 --- a/stdlib/.dagger/env/docker-pull/values.yaml +++ b/stdlib/.dagger/env/docker-pull/values.yaml @@ -3,7 +3,7 @@ plan: name: docker-pull inputs: ref: - text: docker.io/daggerio/ci-test:xtyzsocvpici@sha256:35fc94d52b4fa53c2caa38ff11e13182e6f88c651eb0846728d1007d931f0d3c + text: docker.io/daggerio/ci-test:pncdyzkdemof@sha256:b92cbbfef6b952befc38812cd88cf5c4c1012f6df2891595c226f56cc053334e sops: kms: [] gcp_kms: [] @@ -19,8 +19,8 @@ sops: SG1raUVNTzZIWDltV1pOS3hySHlJeWcKg3blmstOGcxtPww513+mAEA0MWOXwNAT 5ngRvG6MraW3g9dhIuUYOwjuJyz1Z07/DBEocSxnjSyw45ZCkM1/9Q== -----END AGE ENCRYPTED FILE----- - lastmodified: "2021-07-08T09:53:37Z" - mac: ENC[AES256_GCM,data:kcONOT/cxu39rCrWtMEwHnSZU0o752WyrLMckPp4AGhkQ0CVb7vnnNQ0lLSzsUQfvf0Ze09kFZYuhlGqZ6EPCJvOw0girrdBi09hU2a7Nm8CZd/ku9gP08YsGV3yx0PgIYFuVQRJ60hwQEIZI5neEGV9x2FPUedy9lYbKvvboSE=,iv:ofZ605QYbEbtWNgGxNkp1QbK/VHtwchpFs4GxBU9rIg=,tag:Mo+0nfe2GaJcXpIOCl/cew==,type:str] + lastmodified: "2021-08-31T10:10:02Z" + mac: ENC[AES256_GCM,data:30qNlAVLJunPEboTzeIxcsZ06LcLiDiXXJLVqHE328hcezcOYGsvhlYTiGEzxtAsv78Mwxw54oSbiFZmCKoew9bTZFUyb6FcFVk4GG8z2I8pn7FkZlcnEknWinVf9Tc/h5R/g4/BBGzsBf2dr4fx4ADewwO2z1Df/8wdup0PD4E=,iv:KJcMdpLCfSU1LvvPMXitSPzm0JPwrDWdLncdvVFngNk=,tag:X2/D+RhEnyizZHXJWYnmmg==,type:str] pgp: [] encrypted_suffix: secret version: 3.7.1 diff --git a/stdlib/.dagger/env/docker-push-invalid-creds/values.yaml b/stdlib/.dagger/env/docker-push-invalid-creds/values.yaml index 7784def0..d8df2319 100644 --- a/stdlib/.dagger/env/docker-push-invalid-creds/values.yaml +++ b/stdlib/.dagger/env/docker-push-invalid-creds/values.yaml @@ -3,7 +3,7 @@ plan: name: docker-push-invalid-creds inputs: TestRegistry.secret: - text: ENC[AES256_GCM,data:PckymCtA/Q==,iv:to7XhUUcZrWDga7uT4C067BRzHEzmTPDUNAEb2TpS/I=,tag:jUTk8uGd185hmIvi/IHpww==,type:str] + secret: ENC[AES256_GCM,data:+gCg3g==,iv:TVQBLFvC1T+xNSJdmhEz+0cciIpCbo6D+twwghUU0ik=,tag:R7SoByjnyj6Aupw1/6c+8w==,type:str] TestRegistry.username: text: invalid sops: @@ -21,8 +21,8 @@ sops: VC8wSTZvUE5UaDg2WE1CaGMzR3M1TEkK9v83AVI4lvFgjKCg8UmQrcxarlESWTfV 2cDdWgoH7ZqgXo5jFv2tn8qQWHKl8eTTeYUWn8GoNVPKrCroax2fiQ== -----END AGE ENCRYPTED FILE----- - lastmodified: "2021-07-08T09:53:54Z" - mac: ENC[AES256_GCM,data:hnVsqFM81iSA/VFPbwqtqw3jOB7H2+67VuXmKfU5fEf15D5WGLZi17HCfRJQ+Db8d0S8ICwFlzqemq+99GB0wf0QVGeOBfrLZ+/AW6Yhd7klhZZxtngXos0lcZreBWduiLkctS2lbx0aiRDBUrsKFcJmu0O9JbMkwC7Hj+nncBk=,iv:2PDO6MTSszlVwmEkAI5lI9cBoJW8JdL3Q+i+sQgtFAk=,tag:nW2OLjAhSot7VyolrXbV5Q==,type:str] + lastmodified: "2021-08-31T10:07:27Z" + mac: ENC[AES256_GCM,data:sdycrW51n0tHL76DroLAUR33Fis5Hixn6dQ7LofNoIcdAj334MTWIf0jxnbzrv4Dkm/MsU90asiGwQyHI56t8mBUqrLJmd8PBE/t6S4RghCAIlM3mcHB4iHsC8Sib2URn3wKztcIuobfU8e9IvZoW4X8R/QWc1jWNmIt8VGdwfw=,iv:g7ri14SRxhsd1SSibYzDig6mZRG7LJ+R6CPDNmNOAfI=,tag:wM1DVa3LL9zFcHKAJJjugg==,type:str] pgp: [] encrypted_suffix: secret version: 3.7.1 diff --git a/stdlib/dagger/op/op.cue b/stdlib/dagger/op/op.cue index 81adc6e5..a7671bbc 100644 --- a/stdlib/dagger/op/op.cue +++ b/stdlib/dagger/op/op.cue @@ -68,7 +68,7 @@ package op target: string username: string // FIXME: should be a #Secret (circular import) - secret: string | bytes + secret: _ @dagger(secret) } #FetchContainer: { diff --git a/stdlib/docker/docker.cue b/stdlib/docker/docker.cue index 8cacf6ef..d61c8b7b 100644 --- a/stdlib/docker/docker.cue +++ b/stdlib/docker/docker.cue @@ -8,7 +8,7 @@ import ( // Build a Docker image from source, using included Dockerfile #Build: { - source: dagger.#Artifact @dagger(input) + source: dagger.#Input & {dagger.#Artifact} #up: [ op.#DockerBuild & { @@ -21,7 +21,7 @@ import ( // Pull a docker container #Pull: { // Remote ref (example: "index.docker.io/alpine:latest") - from: string @dagger(input) + from: dagger.#Input & {string} #up: [ op.#FetchContainer & {ref: from}, @@ -31,18 +31,18 @@ import ( // Push a docker image to a remote registry #Push: { // Remote target (example: "index.docker.io/alpine:latest") - target: string @dagger(input) + target: dagger.#Input & {string} // Image source - source: dagger.#Artifact @dagger(input) + source: dagger.#Input & {dagger.#Artifact} // Registry auth auth?: { // Username - username: string @dagger(input) + username: dagger.#Input & {string} // Password or secret - secret: string @dagger(input) + secret: dagger.#Input & {dagger.#Secret | string} } push: #up: [ @@ -72,7 +72,7 @@ import ( source: "/image_ref" }, ] - } @dagger(output) + } & dagger.#Output // Image digest digest: { @@ -85,43 +85,43 @@ import ( source: "/image_digest" }, ] - } @dagger(output) + } & dagger.#Output } #Run: { // Connect to a remote SSH server ssh: { // ssh host - host: string @dagger(input) + host: dagger.#Input & {string} // ssh user - user: string @dagger(input) + user: dagger.#Input & {string} // ssh port - port: *22 | int @dagger(input) + port: dagger.#Input & {*22 | int} // private key - key: dagger.#Secret @dagger(input) + key: dagger.#Input & {dagger.#Secret} // fingerprint - fingerprint?: string @dagger(input) + fingerprint?: dagger.#Input & {string} // ssh key passphrase - keyPassphrase?: dagger.#Secret @dagger(input) + keyPassphrase?: dagger.#Input & {dagger.#Secret} } // Image reference (e.g: nginx:alpine) - ref: string @dagger(input) + ref: dagger.#Input & {string} // Container name - name?: string @dagger(input) + name?: dagger.#Input & {string} // Image registry registry?: { target: string username: string secret: dagger.#Secret - } @dagger(input) + } & dagger.#Input #command: #""" # Run detach container @@ -150,10 +150,10 @@ import ( // FIXME: incorporate into #Build #ImageFromDockerfile: { // Dockerfile passed as a string - dockerfile: string @dagger(input) + dockerfile: dagger.#Input & {string} // Build context - context: dagger.#Artifact @dagger(input) + context: dagger.#Input & {dagger.#Artifact} #up: [ op.#DockerBuild & { diff --git a/stdlib/docker/tests/push-invalid-creds/push.cue b/stdlib/docker/tests/push-invalid-creds/push.cue index 1c5ab6c0..eab359d2 100644 --- a/stdlib/docker/tests/push-invalid-creds/push.cue +++ b/stdlib/docker/tests/push-invalid-creds/push.cue @@ -1,12 +1,13 @@ package docker import ( + "alpha.dagger.io/dagger" "alpha.dagger.io/random" ) TestRegistry: { - username: string @dagger(input) - secret: string @dagger(input) + username: dagger.#Input & {string} + secret: dagger.#Input & {dagger.#Secret} } TestPush: { diff --git a/stdlib/docker/tests/push-multi-registry/push.cue b/stdlib/docker/tests/push-multi-registry/push.cue index 7b0891c5..53c14707 100644 --- a/stdlib/docker/tests/push-multi-registry/push.cue +++ b/stdlib/docker/tests/push-multi-registry/push.cue @@ -4,9 +4,7 @@ import ( "alpha.dagger.io/aws" "alpha.dagger.io/aws/ecr" "alpha.dagger.io/dagger" - "alpha.dagger.io/dagger/op" "alpha.dagger.io/random" - "alpha.dagger.io/alpine" ) // @@ -48,36 +46,10 @@ TestRemoteAWS: { } } -#TestGetSecret: { - secret: dagger.#Artifact - - out: { - string - - #up: [ - op.#Load & {from: alpine.#Image}, - - op.#Exec & { - always: true - args: ["sh", "-c", "cp /input/secret /secret"] - mount: "/input/secret": "secret": secret - }, - - op.#Export & { - source: "/secret" - }, - ] - } -} - TestRemoteDocker: { dockerConfig: { - username: string & dagger.#Input - secret: dagger.#Secret & dagger.#Input - } - - secret: #TestGetSecret & { - secret: dockerConfig.secret + username: dagger.#Input & {string} + secret: dagger.#Input & {dagger.#Secret} } target: "daggerio/ci-test:test-docker-\(TestResources.suffix.out)" @@ -87,7 +59,7 @@ TestRemoteDocker: { source: TestResources.image auth: { username: dockerConfig.username - "secret": secret.out + secret: dockerConfig.secret } } } diff --git a/stdlib/docker/tests/push/push.cue b/stdlib/docker/tests/push/push.cue index 83d7da71..7cd6d916 100644 --- a/stdlib/docker/tests/push/push.cue +++ b/stdlib/docker/tests/push/push.cue @@ -1,37 +1,13 @@ package docker import ( - "alpha.dagger.io/dagger/op" "alpha.dagger.io/dagger" - "alpha.dagger.io/alpine" "alpha.dagger.io/random" ) TestRegistry: { - username: string @dagger(input) - secret: dagger.#Secret @dagger(input) -} - -#TestGetSecret: { - secret: dagger.#Artifact - - out: { - string - - #up: [ - op.#Load & {from: alpine.#Image}, - - op.#Exec & { - always: true - args: ["sh", "-c", "cp /input/secret /secret"] - mount: "/input/secret": "secret": secret - }, - - op.#Export & { - source: "/secret" - }, - ] - } + username: dagger.#Input & {string} + secret: dagger.#Input & {dagger.#Secret} } TestPush: { @@ -41,10 +17,6 @@ TestPush: { target: "daggerio/ci-test:\(tag.out)" - secret: #TestGetSecret & { - secret: TestRegistry.secret - } - image: #ImageFromDockerfile & { dockerfile: """ FROM alpine @@ -58,7 +30,7 @@ TestPush: { source: image auth: { username: TestRegistry.username - "secret": secret.out + secret: TestRegistry.secret } } } diff --git a/tests/ops.bats b/tests/ops.bats index b139dc81..ab839a57 100644 --- a/tests/ops.bats +++ b/tests/ops.bats @@ -81,14 +81,8 @@ setup() { } @test "op.#PushContainer" { - skip_unless_secrets_available "$TESTDIR"/ops/push-container/inputs.yaml - - # ensure the tests fail without credentials - run "$DAGGER" compute "$TESTDIR"/ops/push-container/valid - assert_failure - - # check that they succeed with the credentials - run "$DAGGER" compute --input-yaml "$TESTDIR"/ops/push-container/inputs.yaml "$TESTDIR"/ops/push-container + dagger_new_with_env "$TESTDIR"/ops/push-container/ + run "$DAGGER" up -e push-container assert_success } diff --git a/tests/ops/push-container/.dagger/env/push-container/.gitignore b/tests/ops/push-container/.dagger/env/push-container/.gitignore new file mode 100644 index 00000000..01ec19b0 --- /dev/null +++ b/tests/ops/push-container/.dagger/env/push-container/.gitignore @@ -0,0 +1,2 @@ +# dagger state +state/** diff --git a/tests/ops/push-container/.dagger/env/push-container/values.yaml b/tests/ops/push-container/.dagger/env/push-container/values.yaml new file mode 100644 index 00000000..b32eee1c --- /dev/null +++ b/tests/ops/push-container/.dagger/env/push-container/values.yaml @@ -0,0 +1,28 @@ +plan: + package: . +name: push-container +inputs: + registry.secret: + secret: ENC[AES256_GCM,data:kZivIXveEoh3+GayI1Tnn6zVf3e38Hlsd2V/GoeJ5bbMOiGS,iv:am3fLZE39MkfFlTXF90olpx/gkp/g1Olkf3PHDsAcKk=,tag:holrnoNR4SqJuw1lYgnUGw==,type:str] + registry.username: + text: daggertest +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age1gxwmtwahzwdmrskhf90ppwlnze30lgpm056kuesrxzeuyclrwvpsupwtpk + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAyRzBHQkNGdGpuVWUzeGdl + WXhYeGVVeUdFbTZLYWt2enFuUmlHTC83NDBZClh1NSthd3dDdGlaQVVUY09WRmNN + cUVPZUY0U3kvZm8zUVZMMjNMMEZrNFEKLS0tIHZYUE8zTTUwUGJWcWtweEo2R09q + UVBXdTZSSHhKRGlpOGErd1ZYL0JKY3MKEcay8Bhy1Ap9Jt8gq/6bV/VnzlPSxqZk + bd2SuoUs7rMiabhdbApym0MmghqNrwA8xQQo4dCWnxPGDa3avKtTCg== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2021-08-30T15:05:57Z" + mac: ENC[AES256_GCM,data:bfTPWrvxKB9a6bc2CPC9vE4BSd/H0JNMx1Cj8JT7KIb82Eymby/B+MEBQTDsVSaILEK6JUgH7Awl/JZAw1MwKG8K8nSAoX74311lRXXnYUNaggXgJu+V4cfdCZuofivQyymsZITMVfABmmjRoZ4zqWiJvYvqdtb42abRMU3vIpA=,iv:WvBCkZXyxYEM4HRdSiCfHdcK/olJOdq2uJpFE2R9wDU=,tag:BemiMETEs1ZmfUUrUUZTjA==,type:str] + pgp: [] + encrypted_suffix: secret + version: 3.7.1 diff --git a/tests/ops/push-container/inputs.yaml b/tests/ops/push-container/inputs.yaml deleted file mode 100644 index 2c68689b..00000000 --- a/tests/ops/push-container/inputs.yaml +++ /dev/null @@ -1,23 +0,0 @@ -registry: - username: ENC[AES256_GCM,data:Yuv+E9dhGZnCxw==,iv:ezThCQJv+bVBf8SdfSa2HFoP+eu6IZMPl5xvMOGDcps=,tag:8+EeJfySzwMczqrzIEDy+w==,type:str] - secret: ENC[AES256_GCM,data:OcxwHjWcTdtyKRb7whgG/fzmIG/bpQoSlUVIIhyeEX31lGWh,iv:YAXcRzBoemmef5PBdAOBa5acNPo4BoKH7Ngud/CWYfA=,tag:M1M1hsqKP0TyQbkU5c6oGg==,type:str] -sops: - kms: [] - gcp_kms: [] - azure_kv: [] - hc_vault: [] - age: - - recipient: age1gxwmtwahzwdmrskhf90ppwlnze30lgpm056kuesrxzeuyclrwvpsupwtpk - enc: | - -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBOaE5NYkdtR0FiOWZTcW54 - UzRTL3lwQ3owV0QyWmYzVmQ1K0swa2xZK0RnClZSblRIQUxpUWNUdGJBMngwRlFT - RXI1aHJMUVVySVF2dzBLN1djZitSWlEKLS0tIGd6RWttckdQTVV1Qi9uWUEvQitR - ODEwdXlXSy8veWZkNUpNbWszMVE3M0EKSiQ0AVvySOUHg6RZkcbmpLTHSlnT2zw7 - Em+pRLYs7GXyilGvSwlRw5O+SrNNQU8Tr8/Yumif2Mks5r3TatDqdA== - -----END AGE ENCRYPTED FILE----- - lastmodified: "2021-05-28T20:47:36Z" - mac: ENC[AES256_GCM,data:tSOZ6GWrpwPkwCYdtN9/Ym9OXGDzLfXaTATBodaLVjxsVtjaFSxjN15gcjtcxU9KNiOo77fJuEgHgQTQmzHrjSBkvX0zgGoNGU1KCQ3XqRMzfjm1yBU7sWb7lCwjAUqzhERRwe9Vja9GkDSgT+B+CUIRDyqQa1jXg0HlQldhEr0=,iv:ZioCDF8NueNw9miTWxhYWvn1cDw9wUxzMIlp9b2UEgE=,tag:CM4mbhrYW83/ijHNRtIWBw==,type:str] - pgp: [] - unencrypted_suffix: _unencrypted - version: 3.7.1 diff --git a/tests/ops/push-container/main.cue b/tests/ops/push-container/main.cue index 2b84729b..ceb5362e 100644 --- a/tests/ops/push-container/main.cue +++ b/tests/ops/push-container/main.cue @@ -1,14 +1,15 @@ package main import ( + "alpha.dagger.io/dagger" "alpha.dagger.io/dagger/op" "alpha.dagger.io/alpine" "alpha.dagger.io/random" ) registry: { - username: string - secret: string + username: dagger.#Input & {string} + secret: dagger.#Input & {dagger.#Secret} } TestPushContainer: {