From 4b6315e2fc096c46d57c85fcd234e3c2924099ff Mon Sep 17 00:00:00 2001 From: Tom Chauveau Date: Fri, 21 May 2021 17:18:30 +0200 Subject: [PATCH] Handle fingerprint option for auth Signed-off-by: Tom Chauveau --- stdlib/docker/client.cue | 46 +++------- stdlib/docker/docker.cue | 90 +++++++++++++------ tests/stdlib.bats | 19 +++- tests/stdlib/docker/run/key.yaml | 6 +- .../docker/run/passphrase/passphrase.cue | 20 +++++ tests/stdlib/docker/run/passphrase/random.cue | 20 +++++ tests/stdlib/docker/run/protected-key.yaml | 33 +++++++ tests/stdlib/docker/run/simple/random.cue | 20 +++++ tests/stdlib/docker/run/simple/simple.cue | 30 ++----- .../docker/run/wrong-passphrase/random.cue | 20 +++++ .../run/wrong-passphrase/wrong-password.cue | 20 +++++ 11 files changed, 231 insertions(+), 93 deletions(-) create mode 100644 tests/stdlib/docker/run/passphrase/passphrase.cue create mode 100644 tests/stdlib/docker/run/passphrase/random.cue create mode 100644 tests/stdlib/docker/run/protected-key.yaml create mode 100644 tests/stdlib/docker/run/simple/random.cue create mode 100644 tests/stdlib/docker/run/wrong-passphrase/random.cue create mode 100644 tests/stdlib/docker/run/wrong-passphrase/wrong-password.cue diff --git a/stdlib/docker/client.cue b/stdlib/docker/client.cue index 801c8b18..35621e67 100644 --- a/stdlib/docker/client.cue +++ b/stdlib/docker/client.cue @@ -5,38 +5,14 @@ import ( "dagger.io/alpine" ) -#Client: { - // Docker CLI version - version: *"20.10.6" | string - - #Code: #""" - curl -fsSL https://download.docker.com/linux/static/stable/x86_64/docker-\#(version).tgz | tar zxvf - --strip 1 -C /usr/bin docker/docker - """# - - #up: [ - op.#Load & { - from: alpine.#Image & { - package: bash: true - package: jq: true - package: curl: true - package: "openssh-client": true - } - }, - - op.#WriteFile & { - content: #Code - dest: "/entrypoint.sh" - }, - - op.#Exec & { - args: [ - "/bin/sh", - "--noprofile", - "--norc", - "-eo", - "pipefail", - "/entrypoint.sh", - ] - }, - ] -} +#Client: #up: [ + op.#Load & { + from: alpine.#Image & { + package: bash: true + package: jq: true + package: curl: true + package: "openssh-client": true + package: "docker-cli": true + } + }, +] diff --git a/stdlib/docker/docker.cue b/stdlib/docker/docker.cue index aca06a1e..fcb2377b 100644 --- a/stdlib/docker/docker.cue +++ b/stdlib/docker/docker.cue @@ -43,51 +43,72 @@ import ( #Run: { // Remote host - host: string + host: string @dagger(input) // Remote user - user: string + user: string @dagger(input) // Ssh remote port - port: *22 | int + port: *22 | int @dagger(input) // Ssh private key - key: dagger.#Artifact + key: dagger.#Artifact @dagger(input) + + // User fingerprint + fingerprint?: string @dagger(input) // Ssh passphrase - passphrase?: string + passphrase?: string @dagger(input) // Image reference (e.g: nginx:alpine) - ref: string + ref: string @dagger(input) // Container name - name?: string + name?: string @dagger(input) // Image registry registry?: { target: string username: string secret: dagger.#Secret - } + } @dagger(input) #code: #""" - # Add host to known hosts - ssh -i /key -o "UserKnownHostsFile $HOME/.ssh/known_hosts" -o "StrictHostKeyChecking accept-new" -p \#(port) \#(user)@\#(host) /bin/true > /dev/null 2>&1 + export DOCKER_HOST="ssh://$DOCKER_USERNAME@$DOCKER_HOSTNAME:\#(port)" - # Start ssh-agent - eval $(ssh-agent) > /dev/null 2>&1 + # Start ssh-agent + eval $(ssh-agent) > /dev/null - # Add key - ssh-add /key > /dev/null 2>&1 + # Add key + message="$(ssh-keygen -y -f /key < /dev/null 2>&1)" || { + >&2 echo "$message" + exit 1 + } - # Run detach container - OPTS="" + ssh-add /key > /dev/null + if [ "$?" != 0 ]; then + exit 1 + fi - if [ ! -z $CONTAINER_NAME ]; then - OPTS="$OPTS --name $CONTAINER_NAME" - fi + if [[ ! -z $FINGERPRINT ]]; then + mkdir -p "$HOME"/.ssh - docker container run -d $OPTS \#(ref) + # Add user's fingerprint to known hosts + echo "$FINGERPRINT" >> "$HOME"/.ssh/known_hosts + else + # Add host to known hosts + ssh -i /key -o "UserKnownHostsFile "$HOME"/.ssh/known_hosts" -o "StrictHostKeyChecking accept-new" -p \#(port) "$DOCKER_USERNAME"@"$DOCKER_HOSTNAME" /bin/true > /dev/null 2>&1 + fi + + + # Run detach container + OPTS="" + + if [ ! -z "$CONTAINER_NAME" ]; then + OPTS="$OPTS --name $CONTAINER_NAME" + fi + + docker container run -d $OPTS \#(ref) """# #up: [ @@ -96,7 +117,7 @@ import ( op.#WriteFile & { content: key dest: "/key" - mode: 0o600 + mode: 0o400 }, if registry != _|_ { @@ -105,11 +126,20 @@ import ( if passphrase != _|_ { op.#WriteFile & { - content: #""" - #!/bin/sh - echo '\#(passphrase)' - """# + content: passphrase dest: "/passphrase" + mode: 0o400 + } + }, + + if passphrase != _|_ { + op.#WriteFile & { + content: #""" + #!/bin/bash + cat /passphrase + """# + dest: "/get_passphrase" + mode: 0o500 } }, @@ -129,14 +159,18 @@ import ( "/entrypoint.sh", ] env: { - DOCKER_HOST: "ssh://\(user)@\(host):\(port)" + DOCKER_HOSTNAME: host + DOCKER_USERNAME: user if passphrase != _|_ { - SSH_ASKPASS: "/passphrase" - DISPLAY: "" + SSH_ASKPASS: "/get_passphrase" + DISPLAY: "1" } if name != _|_ { CONTAINER_NAME: name } + if fingerprint != _|_ { + FINGERPRINT: fingerprint + } } }, ] diff --git a/tests/stdlib.bats b/tests/stdlib.bats index 0944e0b2..b24337a4 100644 --- a/tests/stdlib.bats +++ b/tests/stdlib.bats @@ -72,15 +72,15 @@ setup() { "$DAGGER" compute "$TESTDIR"/stdlib/gcp/gcr --input-yaml "$TESTDIR"/stdlib/gcp/inputs.yaml } -@test "stdlib: docker-build" { +@test "stdlib: docker: build" { "$DAGGER" compute "$TESTDIR"/stdlib/docker/build/ --input-dir source="$TESTDIR"/stdlib/docker/build } -@test "stdlib: docker-dockerfile" { +@test "stdlib: docker: dockerfile" { "$DAGGER" compute "$TESTDIR"/stdlib/docker/dockerfile/ --input-dir source="$TESTDIR"/stdlib/docker/dockerfile/testdata } -@test "stdlib: docker-push-and-pull" { +@test "stdlib: docker: push-and-pull" { skip_unless_secrets_available "$TESTDIR"/stdlib/docker/push-pull/inputs.yaml # check that they succeed with the credentials @@ -88,11 +88,22 @@ setup() { assert_success } -@test "stdlib: docker run" { +@test "stdlib: docker: run" { skip_unless_secrets_available "$TESTDIR"/stdlib/docker/run/key.yaml + # Simple run run "$DAGGER" compute --input-yaml "$TESTDIR"/stdlib/docker/run/key.yaml "$TESTDIR"/stdlib/docker/run/simple/ assert_success + + # Handle key with passphrase + skip_unless_secrets_available "$TESTDIR"/stdlib/docker/run/protected-key.yaml + + # Fail if invalid password + run "$DAGGER" compute --input-yaml "$TESTDIR"/stdlib/docker/run/protected-key.yaml "$TESTDIR"/stdlib/docker/run/wrrong-passphrase/ + assert_failure + + run "$DAGGER" compute --input-yaml "$TESTDIR"/stdlib/docker/run/protected-key.yaml "$TESTDIR"/stdlib/docker/run/passphrase/ + assert_success } @test "stdlib: terraform" { diff --git a/tests/stdlib/docker/run/key.yaml b/tests/stdlib/docker/run/key.yaml index 32719be8..7a2ed888 100644 --- a/tests/stdlib/docker/run/key.yaml +++ b/tests/stdlib/docker/run/key.yaml @@ -1,11 +1,13 @@ key: ENC[AES256_GCM,data:WVwwHYqXbaMtZu3bMbNrwhexIsfUHRaocq+6yvS55I+9BI2T9X2xvFz7IiMC+1gY9tcVkq4Fs0/bIOjDpjQ14GPNxxnbhtzyp7nFI7EnrSWCwRnHjmc+2fMcpdRFRDaYvZt+aHA9x874nCOT5DQLniKTwi8WAKMcKVuMg6g+gHVXtrFEG0d+1pJuypRannXgOlt2TgpNO9VhZFFivJbJ5fATX0xMuctBEV6CVR2gBqx62Zqz1C/znDv+BiEYHntFeXntb/n0gIL2gmTAcQbBMC5e0i8LmqmZkbCgs3GwiImNEnjaSQf97DsrfzSOEAPpz0hCo7EIF9gQHimNads/WYDvSvvH4MD1ReLBtQD22jO3JFxFrTyimAKKd0IqdMsh+S2ZqxeG8tt2yq0dEYWUdVxPpr5fgmlsfHuBE+qbPE+s2QvWvgFo3ZIaxvcKe1NSVLrNh2u666uUJK2/wetzLllYomkqvqmJxUtJHtyQg+cDOErKomFXXbeSoMw9/xnTpR5oHj7icAqehYilAm71cKWA1qpuUtbhYe8Z,iv:b3AG6AWe/Rw26R1ZPHvTGoONpjQMdf/OWLoazyySRig=,tag:lv413iPTOejZwPdUDGUsAw==,type:str] +passphrase: ENC[AES256_GCM,data:6yw78pBY2B4=,iv:vdBWBE02qSyGmqyDeSM/4DP1QhKKFn9D1bCdP+oKic4=,tag:cg/WzydFf+IXflxW7v0BRA==,type:str] +user: ENC[AES256_GCM,data:L3sBCudP5iA=,iv:gupZZbW9kMxC+LpAV6+S2TankSnRTbCg87Rq10U50bo=,tag:0uPJtM0qrQkq+3p7yQOmKA==,type:str] sops: kms: [] gcp_kms: [] azure_kv: [] hc_vault: [] - lastmodified: '2021-05-21T13:38:51Z' - mac: ENC[AES256_GCM,data:RqXtx/iwDw0y35cJV7JHxRF8fZHW/E8KFf0akDZSjHn3N71pCnzA+gNh8gyiFb4PDlSKSMSt58TdaVQMAClkdKMvrihlYexaTE3BHTT1PSL9mIsfQw7GEmiaAh/bsitlFrEcLEoxYxeP8tjTFiIQ8tEDjGqp4uqbYCDpxODVfVw=,iv:CIqIwCAcdGl4Sid4h58u7vV+JdBkGVVnYtkSz9lhrgI=,tag:r+VrlOwJtwJ97SjecM5PNQ==,type:str] + lastmodified: '2021-05-28T15:55:50Z' + mac: ENC[AES256_GCM,data:ZRHdrBWlnjy/AMpl2X9jInUMZdSbvdWYQTRKItNAU2gjz3baCJtGdbFb4hE7bwFPxkuv4EvzongTmUmzs9dBlmZhDIwbqeo54C37Purbi6q1CLE2wSYPdSxpP6LkJDbM4QBQ0smX3jf12K4UqPmI3e46YJtEDgtS5pNPrSGXBn0=,iv:ycQ4add4ih0nuQxBCbe5fsvMfBizX/mA7eWKBn3azBE=,tag:dF7PfbJKxMOiTBKH5VJJQA==,type:str] pgp: - created_at: '2021-03-18T22:59:59Z' enc: | diff --git a/tests/stdlib/docker/run/passphrase/passphrase.cue b/tests/stdlib/docker/run/passphrase/passphrase.cue new file mode 100644 index 00000000..99f01efa --- /dev/null +++ b/tests/stdlib/docker/run/passphrase/passphrase.cue @@ -0,0 +1,20 @@ +package docker + +import ( + "dagger.io/docker" + "dagger.io/dagger" +) + +// Run with --input-file key=$HOME/.ssh/ +key: dagger.#Artifact +passphrase: dagger.#Secret +user: dagger.#Secret + +TestRun: run: docker.#Run & { + host: "143.198.64.230" + ref: "nginx:alpine" + "user": user + "passphrase": passphrase + name: "daggerci-test-simple-\(random)" + "key": key +} diff --git a/tests/stdlib/docker/run/passphrase/random.cue b/tests/stdlib/docker/run/passphrase/random.cue new file mode 100644 index 00000000..bd7acb33 --- /dev/null +++ b/tests/stdlib/docker/run/passphrase/random.cue @@ -0,0 +1,20 @@ +package docker + +import ( + "dagger.io/dagger/op" + "dagger.io/alpine" +) + +random: { + string + #up: [ + op.#Load & {from: alpine.#Image}, + op.#Exec & { + always: true + args: ["sh", "-c", "cat /dev/urandom | tr -dc 'a-z' | fold -w 10 | head -n 1 | tr -d '\n' > /rand"] + }, + op.#Export & { + source: "/rand" + }, + ] +} diff --git a/tests/stdlib/docker/run/protected-key.yaml b/tests/stdlib/docker/run/protected-key.yaml new file mode 100644 index 00000000..35be110f --- /dev/null +++ b/tests/stdlib/docker/run/protected-key.yaml @@ -0,0 +1,33 @@ +key: ENC[AES256_GCM,data:YrLeVqoLuzcEIK6FYCGiP9DhuMAlYU3o9UX6VcensCVAA9+Ix2Y7asBp1iqRpvHLEpT8AYe7Hb+PLuyvRjyY2dKW86BecxBUyX39rc5WWB5CK8nS1jR7qdRljcJca9Pw1jKiPmSht5wtVkJQtVORsHNVQipzj6ouGVBqkw0gPPvp9Ywfrgxw+sOhdkU7FrjmoAZygQ2fbTQM7q6QhpLh1MWXw532eoIRarrxO29T6/CPl5Z17jSd9OIlKVV4iwqWrzovU857oqd9MpU+aj/dVubq497/krnStNeWnUkHyJp+IwX0hO1T5E6uj08prXw8wSTWpdtsfTChfKNDvAgshTmHN8g0bw0qmbUmdDxBSUFRUI95iOJSPLxStIobajK5W1foHbEqgiTm2Ki6ugkBaOL7v+wNhlkFXOfZrbKDBz9CCndFyzig+wXAGT+MovgwgF1S7m1av/8TGkpmxCuUPjfEmNttrwy8xACH/A/WxMoOQhFZ4Q2LUTQdtptvi32WudUMmUZdcI+VJ9TgQVSng1mPOx7yCDgIeym9vKTqZ2DHLgkKtmO+xpZfQHaifcRolJGYINatZPPYQs7kIunwPQH7pZazld45z6Lt7xXQ9/8=,iv:ac0ij8s482TzLHxNTkbr/i5O9t5NL8IMzdQS6rfmwRQ=,tag:Mew5sRiCTDavwD7GKZK/qw==,type:str] +passphrase: ENC[AES256_GCM,data:6yw78pBY2B4=,iv:vdBWBE02qSyGmqyDeSM/4DP1QhKKFn9D1bCdP+oKic4=,tag:cg/WzydFf+IXflxW7v0BRA==,type:str] +user: ENC[AES256_GCM,data:L3sBCudP5iA=,iv:gupZZbW9kMxC+LpAV6+S2TankSnRTbCg87Rq10U50bo=,tag:0uPJtM0qrQkq+3p7yQOmKA==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + lastmodified: '2021-05-28T16:13:38Z' + mac: ENC[AES256_GCM,data:v4aC/yw20M2GnIktqxoGJCD4T4ViBivzMsBawNgBLTytRGI7s+QGEzdmfoF+dqA3Vdkzf0WKmoiUQ2bcbTjMx2sqvAiiavUz2/iOKdALpn2f13PHeJDBB8A9rnIdidhNadWm6rICIdlxuSmx3tCGIHcM7BY0XJvK3cr6q/3b+jE=,iv:j0J0gwpOGcDtItloYo1mbjfGJloioM1IanjqKwnOIA8=,tag:qPciC7z1fF3mNl+Zx7Fx4A==,type:str] + pgp: + - created_at: '2021-03-18T22:59:59Z' + enc: | + -----BEGIN PGP MESSAGE----- + + hQIMAzqVY590vudzAQ//etnfnpfCo9rAkctR+Fwg/7VdVL3Rov+6gnyjUnoN1BS1 + 8jnBF/86AZ7uK89dTcTZCsK1hKPxeYg1kJTKpA+zfDORupzTWcMrRyjwNk5wQ2Vg + N1adUwFsBQpk8WptpsU/ro6+3yH+Nn35begs6hP2fH/EQ9XOxw5gY0kp0AFjGaKJ + tRZVrr3f2hpLESo6LILRO97UXZiGcwTn5onslECL92260cU1nqEQp+ESK7XrdYIG + 99oM3eXEraKw4WuQDaDE6U135aUl6vIJWD1JZzyr3RW3+5O9pn5rpN3Wc0TbDR6+ + 9Fs/TjuA1h5eJzbt+lkA74BtxPOBv9O7HJnWJpXjiG0VUGHdFXoq5Tr5Ol68RQxa + BWe7IfTO6FHN0xOl1dY7cn5jtf+xlFjL86s9OkrJUFa9lbQx8L/QPCeA2Xiu4tpW + +wTSel13k8Uv/JSGgLwSohW6N4XTQYdxPkO+a1V08adwFBXaGgqxfg0rNehcS5fp + y3TEq84cOlBsaI+rYpnOTPEajtYWfTe8WFf+lBOn1vZ9EiupjZtefGX2MIWPXoaK + kVBgRvzjp4/BY68yRvdi5sZFd2nakl+DOXzouuFbzsOkxL3o9FA9aCVsXtFqqzSG + Hvq4ZJ5ivXf6vQf+s7Tgc4qxW2CQwIPZVkHhQossrWgtkQ4WDAyzfhF0YuhEnpLS + XgGNLr82LMVmempaJd7GfAR2nwGnLUTYny1KoiW/1ie6DPwLZBX/UxPOplaS5wYH + Xd3gV3smg5xZ7/rfvzKTzJ1a5yH6D3xI05UtnUWdqojONcXS9NS+P7RArngJwSs= + =m0OS + -----END PGP MESSAGE----- + fp: 6CB37404020B5F0A0B41B5BB225EBAB0B936AC65 + unencrypted_suffix: _unencrypted + version: 3.7.1 diff --git a/tests/stdlib/docker/run/simple/random.cue b/tests/stdlib/docker/run/simple/random.cue new file mode 100644 index 00000000..bd7acb33 --- /dev/null +++ b/tests/stdlib/docker/run/simple/random.cue @@ -0,0 +1,20 @@ +package docker + +import ( + "dagger.io/dagger/op" + "dagger.io/alpine" +) + +random: { + string + #up: [ + op.#Load & {from: alpine.#Image}, + op.#Exec & { + always: true + args: ["sh", "-c", "cat /dev/urandom | tr -dc 'a-z' | fold -w 10 | head -n 1 | tr -d '\n' > /rand"] + }, + op.#Export & { + source: "/rand" + }, + ] +} diff --git a/tests/stdlib/docker/run/simple/simple.cue b/tests/stdlib/docker/run/simple/simple.cue index 218fd7c5..1f45c1ae 100644 --- a/tests/stdlib/docker/run/simple/simple.cue +++ b/tests/stdlib/docker/run/simple/simple.cue @@ -3,33 +3,15 @@ package docker import ( "dagger.io/docker" "dagger.io/dagger" - "dagger.io/dagger/op" - "dagger.io/alpine" ) // Run with --input-file key=$HOME/.ssh/ key: dagger.#Artifact -TestRun: { - random: { - string - #up: [ - op.#Load & {from: alpine.#Image}, - op.#Exec & { - always: true - args: ["sh", "-c", "cat /dev/urandom | tr -dc 'a-z' | fold -w 10 | head -n 1 | tr -d '\n' > /rand"] - }, - op.#Export & { - source: "/rand" - }, - ] - } - - run: docker.#Run & { - host: "143.198.64.230" - ref: "nginx:alpine" - user: "root" - name: "daggerci-test-simple-\(random)" - "key": key - } +TestRun: run: docker.#Run & { + host: "143.198.64.230" + ref: "nginx:alpine" + user: "root" + name: "daggerci-test-simple-\(random)" + "key": key } diff --git a/tests/stdlib/docker/run/wrong-passphrase/random.cue b/tests/stdlib/docker/run/wrong-passphrase/random.cue new file mode 100644 index 00000000..bd7acb33 --- /dev/null +++ b/tests/stdlib/docker/run/wrong-passphrase/random.cue @@ -0,0 +1,20 @@ +package docker + +import ( + "dagger.io/dagger/op" + "dagger.io/alpine" +) + +random: { + string + #up: [ + op.#Load & {from: alpine.#Image}, + op.#Exec & { + always: true + args: ["sh", "-c", "cat /dev/urandom | tr -dc 'a-z' | fold -w 10 | head -n 1 | tr -d '\n' > /rand"] + }, + op.#Export & { + source: "/rand" + }, + ] +} diff --git a/tests/stdlib/docker/run/wrong-passphrase/wrong-password.cue b/tests/stdlib/docker/run/wrong-passphrase/wrong-password.cue new file mode 100644 index 00000000..6c7c5536 --- /dev/null +++ b/tests/stdlib/docker/run/wrong-passphrase/wrong-password.cue @@ -0,0 +1,20 @@ +package docker + +import ( + "dagger.io/docker" + "dagger.io/dagger" +) + +// Run with --input-file key=$HOME/.ssh/ +key: dagger.#Artifact +passphrase: dagger.#Secret +user: dagger.#Secret + +TestRun: run: docker.#Run & { + host: "143.198.64.230" + ref: "nginx:alpine" + "user": user + passphrase: "foobarbaz" + name: "daggerci-test-simple-\(random)" + "key": key +}