Skip to content

Commit

Permalink
Validate with cosign / ditch codenotary-v1 (#171)
Browse files Browse the repository at this point in the history
  • Loading branch information
pvizeli committed Jun 23, 2023
1 parent 182db11 commit 5bcd370
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 59 deletions.
3 changes: 3 additions & 0 deletions build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ build_from:
codenotary:
signer: notary@home-assistant.io
base_image: notary@home-assistant.io
cosign:
base_identity: https://github.com/home-assistant/docker-base/.*
identity: https://github.com/home-assistant/builder/.*
args:
CAS_VERSION: "1.0.1"
YQ_VERSION: "v4.13.2"
Expand Down
122 changes: 63 additions & 59 deletions builder.sh
Original file line number Diff line number Diff line change
Expand Up @@ -215,14 +215,17 @@ function run_build() {
local docker_cli=("${!7}")
local docker_tags=("${!8}")
local shadow_repository=${9}
local codenotary_base=${10}
local codenotary_sign=${11}

local push_images=()
local cache_tag="latest"
local metadata
local release="${version}"
local dockerfile="${build_dir}/Dockerfile"
local cosign_base_identity=
local cosign_base_issuer=
local cosign_identity=
local cosign_issuer=
local codenotary_sign=

# Overwrites
if bashio::var.has_value "${DOCKER_HUB}"; then repository="${DOCKER_HUB@L}"; fi
Expand All @@ -243,6 +246,17 @@ function run_build() {
*) bashio::exit.nok "Recived unknown architecture ${build_arch}" ;;
esac

# Read build.json / cosign
if bashio::fs.file_exists "/tmp/build_config/build.json"; then
cosign_base_identity="$(jq --raw-output '.cosign.base_identity // empty' "/tmp/build_config/build.json")"
cosign_base_issuer="$(jq --raw-output '.cosign.base_issuer // "https://token.actions.githubusercontent.com"' "/tmp/build_config/build.json")"
cosign_identity="$(jq --raw-output '.cosign.identity // empty' "/tmp/build_config/build.json")"
cosign_issuer="$(jq --raw-output '.cosign.issuer // "https://token.actions.githubusercontent.com"' "/tmp/build_config/build.json")"

# remove later
codenotary_sign="$(jq --raw-output '.codenotary.signer // empty' "/tmp/build_config/build.json")"
fi

# Adjust Qemu CPU
if bashio::var.equals "${build_arch}" armhf; then
docker_cli+=("--build-arg" "QEMU_CPU=arm1176")
Expand Down Expand Up @@ -273,7 +287,7 @@ function run_build() {

if \
docker image inspect "${repository}/${image}:${cache_tag}" > /dev/null 2>&1 \
&& codenotary_validate "${codenotary_sign}" "${repository}/${image}:${cache_tag}" "false" "${docker_platform}" \
&& cosign_validate "${cosign_issuer}" "${cosign_identity}" "${repository}/${image}:${cache_tag}" "${docker_platform}" "false" \
; then
docker_cli+=("--cache-from" "${repository}/${image}:${cache_tag}")
else
Expand All @@ -291,7 +305,7 @@ function run_build() {
docker_cli+=("--label" "org.opencontainers.image.version=${release}")

# Validate the base image
if ! codenotary_validate "${codenotary_base}" "${build_from}" "true" "${docker_platform}"; then
if ! cosign_validate "${cosign_base_issuer}" "${cosign_base_identity}" "${build_from}" "${docker_platform}" "true"; then
bashio::exit.nok "Invalid base image ${build_from}"
fi

Expand Down Expand Up @@ -411,8 +425,6 @@ function build_base() {
local shadow_repository=
local raw_image=
local args=
local codenotary_base=
local codenotary_sign=
local docker_cli=()
local docker_tags=()

Expand All @@ -423,8 +435,6 @@ function build_base() {
labels="$(jq --raw-output '.labels // empty | keys[]' "/tmp/build_config/build.json")"
raw_image="$(jq --raw-output '.image // empty' "/tmp/build_config/build.json")"
shadow_repository="$(jq --raw-output '.shadow_repository // empty' "/tmp/build_config/build.json")"
codenotary_base="$(jq --raw-output '.codenotary.base_image // empty' "/tmp/build_config/build.json")"
codenotary_sign="$(jq --raw-output '.codenotary.signer // empty' "/tmp/build_config/build.json")"
fi

# Set defaults build things
Expand Down Expand Up @@ -480,8 +490,7 @@ function build_base() {

# Start build
run_build "${TARGET}" "${repository}" "${image}" "${VERSION_BASE}" \
"${build_from}" "${build_arch}" docker_cli[@] docker_tags[@] "${shadow_repository}" \
"${codenotary_base}" "${codenotary_sign}"
"${build_from}" "${build_arch}" docker_cli[@] docker_tags[@] "${shadow_repository}"
}


Expand All @@ -498,8 +507,6 @@ function build_addon() {
local description=
local url=
local args=
local codenotary_base=
local codenotary_sign=
local docker_cli=()
local docker_tags=()

Expand All @@ -508,8 +515,6 @@ function build_addon() {
build_from="$(jq --raw-output ".build_from.$build_arch // empty" "/tmp/build_config/build.json")"
args="$(jq --raw-output '.args // empty | keys[]' "/tmp/build_config/build.json")"
shadow_repository="$(jq --raw-output '.shadow_repository // empty' "/tmp/build_config/build.json")"
codenotary_base="$(jq --raw-output '.codenotary.base_image // empty' "/tmp/build_config/build.json")"
codenotary_sign="$(jq --raw-output '.codenotary.signer // empty' "/tmp/build_config/build.json")"
fi

# Set defaults build things
Expand Down Expand Up @@ -562,8 +567,7 @@ function build_addon() {

# Start build
run_build "$TARGET" "$repository" "$image" "$version" \
"$build_from" "$build_arch" docker_cli[@] docker_tags[@] "${shadow_repository}" \
"${codenotary_base}" "${codenotary_sign}"
"$build_from" "$build_arch" docker_cli[@] docker_tags[@] "${shadow_repository}"
}


Expand All @@ -576,7 +580,6 @@ function build_generic() {
local shadow_repository=
local raw_image=
local args=
local codenotary_base=
local codenotary_sign=
local docker_cli=()
local docker_tags=()
Expand All @@ -588,7 +591,6 @@ function build_generic() {
labels="$(jq --raw-output '.labels // empty | keys[]' "/tmp/build_config/build.json")"
raw_image="$(jq --raw-output '.image // empty' "/tmp/build_config/build.json")"
shadow_repository="$(jq --raw-output '.shadow_repository // empty' "/tmp/build_config/build.json")"
codenotary_base="$(jq --raw-output '.codenotary.base_image // empty' "/tmp/build_config/build.json")"
codenotary_sign="$(jq --raw-output '.codenotary.signer // empty' "/tmp/build_config/build.json")"
fi

Expand Down Expand Up @@ -624,8 +626,7 @@ function build_generic() {

# Start build
run_build "$TARGET" "$repository" "$image" "$VERSION" \
"$build_from" "$build_arch" docker_cli[@] docker_tags[@] "${shadow_repository}" \
"${codenotary_base}" "${codenotary_sign}"
"$build_from" "$build_arch" docker_cli[@] docker_tags[@] "${shadow_repository}"
}


Expand All @@ -639,8 +640,6 @@ function build_machine() {
local raw_image=
local build_from=
local shadow_repository=
local codenotary_base=
local codenotary_sign=
local docker_cli=()
local docker_tags=()

Expand All @@ -651,8 +650,6 @@ function build_machine() {
labels="$(jq --raw-output '.labels // empty | keys[]' "/tmp/build_config/build.json")"
raw_image="$(jq --raw-output '.image // empty' "/tmp/build_config/build.json")"
shadow_repository="$(jq --raw-output '.shadow_repository // empty' "/tmp/build_config/build.json")"
codenotary_base="$(jq --raw-output '.codenotary.base_image // empty' "/tmp/build_config/build.json")"
codenotary_sign="$(jq --raw-output '.codenotary.signer // empty' "/tmp/build_config/build.json")"
fi

# Modify build_from
Expand Down Expand Up @@ -694,8 +691,7 @@ function build_machine() {

# Start build
run_build "${TARGET}" "${repository}" "${image}" "${VERSION}" \
"${build_from}" "${build_arch}" docker_cli[@] docker_tags[@] "${shadow_repository}" \
"${codenotary_base}" "${codenotary_sign}"
"${build_from}" "${build_arch}" docker_cli[@] docker_tags[@] "${shadow_repository}"
}


Expand Down Expand Up @@ -776,67 +772,75 @@ function codenotary_sign() {
bashio::log.info "Signed ${image} with ${trust} (cas)"
}

function codenotary_validate() {
local trust=$1
local image=$2
local pull=$3
local platform=$4
local success=false
#### Security cosign ####

if [ "$image" == "scratch" ]; then
bashio::log.info "Scratch image, skiping CodeNotary validation"
return 0
fi
function cosign_sign() {
local image=$1

if ! bashio::var.has_value "${trust}"; then
return 0
fi
local success=false

if bashio::var.true "${pull}"; then
bashio::log.info "Download image ${image} for CodeNotary validation"
docker pull "${image}" --platform "${platform}" > /dev/null 2>&1 || bashio::exit.nok "Can't pull image ${image}"
if bashio::var.false "${DOCKER_PUSH}" || bashio::var.false "${COSIGN}"; then
return 0
fi

for j in {1..15}; do
# shellcheck disable=SC1007
if CAS_API_KEY= cas authenticate --signerID "${trust}" --silent "docker://${image}" ; then

for j in {1..6}; do
if cosign sign --yes "${image}"; then
success=true
break
fi
sleep $((5 * j))
done

if bashio::var.false "${success}"; then
bashio::log.warning "Validation of ${image} fails!"
return 1
bashio::exit.nok "Failed to sign the image (cosign)"
fi
bashio::log.info "Image ${image} is trusted"
bashio::log.info "Signed ${image} with ${trust} (cosign)"
}


#### Security cosign ####

function cosign_sign() {
function cosign_verify() {
local image=$1
local issuer=$2
local identity=$3
local image=$4
local platform=$5
local pull=$6

local success=false

if bashio::var.false "${DOCKER_PUSH}" || bashio::var.false "${COSIGN}"; then
# Support scratch image
if [ "$image" == "scratch" ]; then
bashio::log.info "Scratch image, skiping validation (cosign)"
return 0
fi

for j in {1..15}; do
if cosign sign --yes "${image}"; then

# Nothing to validate against
if ! bashio::var.has_value "${issuer}" || ! bashio::var.has_value "${identity}" ; then
return 0
fi

# Pull image if needed
if bashio::var.true "${pull}"; then
bashio::log.info "Download image ${image} for cosign validation"
docker pull "${image}" --platform "${platform}" > /dev/null 2>&1 || bashio::exit.nok "Can't pull image ${image}"
fi

# validate image
for j in {1..6}; do
if cosign verify --certificate-oidc-issuer-regexp "${issuer}" --certificate-identity-regexp "${identity}" "${image}"; then
success=true
break
fi
sleep $((5 * j))
done

if bashio::var.false "${success}"; then
bashio::exit.nok "Failed to sign the image (cosign)"
bashio::log.warning "Validation of ${image} fails (cosign)!"
if bashio::var.true "${pull}"; then
docker rmi "${image}" > /dev/null 2>&1 || true
fi
return 1
fi
bashio::log.info "Signed ${image} with ${trust} (cosign)"
bashio::log.info "Image ${image} is trusted (cosign)"
}


Expand Down

0 comments on commit 5bcd370

Please sign in to comment.