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

Add secrets support #366

Merged
merged 1 commit into from
Apr 23, 2024
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
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,22 @@ version is the image's digest.
{ "EMAIL": "me@yopmail.com", "HOW_MANY_THINGS": 1, "DO_THING": false }
```

* `secrets`: *Optional.* A map of Docker build-time secrets. These will be
available as mounted paths only during the docker build phase.

Secrets are not stored in any metadata or layers, so they are safe to use for
access tokens and the like during the build.

Example:

```yaml
secrets:
secret1:
env: BUILD_ID
secret2:
source: /a/secret/file.txt
```

* `cache`: *Optional.* Default `false`. When the `build` parameter is set,
first pull `image:tag` from the Docker registry (so as to use cached
intermediate images when building). This will cause the resource to fail
Expand Down
29 changes: 28 additions & 1 deletion assets/out
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ tag_prefix=$(jq -r '.params.tag_prefix // ""' < $payload)
additional_tags=$(jq -r '.params.additional_tags // ""' < $payload)
need_tag_as_latest=$(jq -r '.params.tag_as_latest // "false"' < $payload)
build_args=$(jq -r '.params.build_args // {}' < $payload)
secrets=$(jq -r '.params.secrets // {}' < $payload)
build_args_file=$(jq -r '.params.build_args_file // ""' < $payload)
labels=$(jq -r '.params.labels // {}' < $payload)
labels_file=$(jq -r '.params.labels_file // ""' < $payload)
Expand Down Expand Up @@ -215,6 +216,32 @@ elif [ -n "$build" ]; then
fi
fi

expanded_secrets=()

secret_keys=($(echo "$secrets" | jq -r 'keys | join(" ")'))
if [ "${#secret_keys[@]}" -gt 0 ]; then
# Force buildkit on
export DOCKER_BUILDKIT=1
for key in "${secret_keys[@]}"; do
value=$(echo "$secrets" | jq -r --arg "k" "$key" '.[$k]')
for var in BUILD_ID BUILD_NAME BUILD_JOB_NAME BUILD_PIPELINE_NAME BUILD_TEAM_NAME ATC_EXTERNAL_URL; do
value="${value//\$$var/${!var:-}}"
value="${value//\$\{$var\}/${!var:-}}"
done
secret="id=${key}"
sub=$(jq -r ".params.secrets.${key} // {}" < $payload)
sub_keys=($(echo "$sub" | jq -r 'keys | join(" ")'))
if [ "${#sub_keys[@]}" -gt 0 ]; then
expanded_secrets+=("--secret")
for key in "${sub_keys[@]}"; do
value=$(echo "$sub" | jq -r --arg "k" "$key" '.[$k]')
secret="${secret},${key}=${value}"
done
expanded_secrets+=("${secret}")
fi
done
fi

expanded_labels=()

label_keys=($(echo "$labels" | jq -r 'keys | join(" ")'))
Expand Down Expand Up @@ -261,7 +288,7 @@ elif [ -n "$build" ]; then
# NOTE: deactivate amazon-ecr-credential-helper so that builds go through with the DOCKER_BUILDKIT set
cp ~/.docker/config.json ~/.docker/config.json.bak
cat <<< "$(jq 'del(.credsStore)' ~/.docker/config.json)" > ~/.docker/config.json
docker build -t "${repository}:${tag_name}" "${target[@]}" "${expanded_build_args[@]}" "${expanded_labels[@]}" "${ssh_args[@]}" -f "$dockerfile" $cache_from "$build"
docker build -t "${repository}:${tag_name}" "${target[@]}" "${expanded_build_args[@]}" "${expanded_secrets[@]}" "${expanded_labels[@]}" "${ssh_args[@]}" -f "$dockerfile" $cache_from "$build"
mv ~/.docker/config.json.bak ~/.docker/config.json # This restores the credsStore: ecr-login to config.json if needed

elif [ -n "$load_file" ]; then
Expand Down
31 changes: 31 additions & 0 deletions tests/out_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,37 @@ var _ = Describe("Out", func() {
})
})

Context("when secrets are provided", func() {
It("passes the arguments correctly to the docker daemon", func() {
session := put(map[string]interface{}{
"source": map[string]interface{}{
"repository": "test",
},
"params": map[string]interface{}{
"build": "/docker-image-resource/tests/fixtures/build",
"secrets": map[string]interface{}{
"secret1": map[string]interface{}{
"env": "GITHUB_TOKEN",
},
"secret2": map[string]interface{}{
"source": "/a/file/path.txt",
},
"secret3": map[string]interface{}{
"source": "/a/file/path with a space in it.txt",
},
},
},
})

Expect(session.Err).To(gbytes.Say(dockerarg(`--secret`)))
Expect(session.Err).To(gbytes.Say(dockerarg(`id=secret1,env=GITHUB_TOKEN`)))
Expect(session.Err).To(gbytes.Say(dockerarg(`--secret`)))
Expect(session.Err).To(gbytes.Say(dockerarg(`id=secret2,source=/a/file/path.txt`)))
Expect(session.Err).To(gbytes.Say(dockerarg(`--secret`)))
Expect(session.Err).To(gbytes.Say(dockerarg(`id=secret3,source=/a/file/path with a space in it.txt`)))
})
})

Context("when labels are provided", func() {
It("passes the labels correctly to the docker daemon", func() {
session := put(map[string]interface{}{
Expand Down