V9.14.008.2026.06.04
🛡️ Retrieve DNSSEC status of coresecret.dev. / 🛡️ Retrieve DNSSEC status of coresecret.dev. (push) Has been cancelled
🛡️ Shell Script Linting / 🛡️ Shell Script Linting (push) Has been cancelled
💙 Generating a PUBLIC Live ISO. / 💙 Generating a PUBLIC Live ISO. (push) Has been cancelled
🔐 Generating a Private Live ISO TRIXIE. / 🔐 Generating a Private Live ISO TRIXIE. (push) Has been cancelled
🛡️ Retrieve DNSSEC status of coresecret.dev. / 🛡️ Retrieve DNSSEC status of coresecret.dev. (push) Has been cancelled
🛡️ Shell Script Linting / 🛡️ Shell Script Linting (push) Has been cancelled
💙 Generating a PUBLIC Live ISO. / 💙 Generating a PUBLIC Live ISO. (push) Has been cancelled
🔐 Generating a Private Live ISO TRIXIE. / 🔐 Generating a Private Live ISO TRIXIE. (push) Has been cancelled
Signed-off-by: Marc S. Weidner <msw@coresecret.dev>
This commit is contained in:
@@ -11,47 +11,307 @@
|
||||
# SPDX-Security-Contact: security@coresecret.eu
|
||||
set -Ceuo pipefail
|
||||
|
||||
printf "\e[95m++++ ++++ ++++ ++++ ++++ ++++ ++ 🧪 '%s' starting ... \e[0m\n" "${0}"
|
||||
printf "\e[95m🧪 '%s' starting ... \e[0m\n" "${0}"
|
||||
|
||||
[[ -r /root/ciss_xdg_tmp.sh ]] && . /root/ciss_xdg_tmp.sh
|
||||
export DEBIAN_FRONTEND="noninteractive"
|
||||
export INITRD="No"
|
||||
|
||||
SOPS_VER="v3.13.0"
|
||||
ARCH="$(dpkg --print-architecture)"
|
||||
case "${ARCH}" in
|
||||
amd64) SOPS_FILE="sops-${SOPS_VER}.linux.amd64" ;;
|
||||
arm64) SOPS_FILE="sops-${SOPS_VER}.linux.arm64" ;;
|
||||
*) echo "Unsupported arch: ${ARCH}" >&2; exit 1 ;;
|
||||
esac
|
||||
declare SOPS_COSIGN_CERTIFICATE_IDENTITY_REGEXP="https://github.com/getsops"
|
||||
declare SOPS_COSIGN_CERTIFICATE_OIDC_ISSUER="https://token.actions.githubusercontent.com"
|
||||
|
||||
cd /tmp
|
||||
#######################################
|
||||
# Print a fatal error and abort the hook.
|
||||
# Globals:
|
||||
# None
|
||||
# Arguments:
|
||||
# 1: Message string
|
||||
# Returns:
|
||||
# None
|
||||
#######################################
|
||||
die() {
|
||||
declare message="$1"
|
||||
printf "\e[91m❌ ERROR: %s \e[0m\n" "${message}" >&2
|
||||
exit 43
|
||||
}
|
||||
|
||||
curl -fsSLO "https://github.com/getsops/sops/releases/download/${SOPS_VER}/${SOPS_FILE}"
|
||||
curl -fsSLO "https://github.com/getsops/sops/releases/download/${SOPS_VER}/sops-${SOPS_VER}.checksums.txt"
|
||||
curl -fsSLO "https://github.com/getsops/sops/releases/download/${SOPS_VER}/sops-${SOPS_VER}.checksums.pem"
|
||||
curl -fsSLO "https://github.com/getsops/sops/releases/download/${SOPS_VER}/sops-${SOPS_VER}.checksums.sig"
|
||||
#######################################
|
||||
# Require an executable tool.
|
||||
# Globals:
|
||||
# None
|
||||
# Arguments:
|
||||
# 1: Tool name
|
||||
# Returns:
|
||||
# 0: on success
|
||||
#######################################
|
||||
require_tool() {
|
||||
declare tool_name="$1"
|
||||
|
||||
cosign verify-blob "sops-${SOPS_VER}.checksums.txt" \
|
||||
--certificate "sops-${SOPS_VER}.checksums.pem" \
|
||||
--signature "sops-${SOPS_VER}.checksums.sig" \
|
||||
--certificate-identity-regexp="https://github.com/getsops" \
|
||||
--certificate-oidc-issuer="https://token.actions.githubusercontent.com"
|
||||
command -v "${tool_name}" >/dev/null 2>&1 || die "Required tool not found: ${tool_name}"
|
||||
|
||||
sha256sum -c "sops-${SOPS_VER}.checksums.txt" --ignore-missing
|
||||
return 0
|
||||
}
|
||||
|
||||
install -m 0755 "${SOPS_FILE}" /usr/local/bin/sops
|
||||
sops --version --check-for-updates >| /root/.ciss/cdlb/log/sops.log
|
||||
age --version >| /root/.ciss/cdlb/log/age.log
|
||||
#######################################
|
||||
# Validate and normalize a SOPS semantic version.
|
||||
# Globals:
|
||||
# None
|
||||
# Arguments:
|
||||
# 1: SOPS version string
|
||||
# Outputs:
|
||||
# Normalized bare semantic version
|
||||
# Returns:
|
||||
# 0: on success
|
||||
#######################################
|
||||
normalize_sops_version() {
|
||||
declare sops_version="${1#v}"
|
||||
|
||||
rm -f "/tmp/${SOPS_FILE}"
|
||||
rm -f "/tmp/sops-${SOPS_VER}.checksums.txt"
|
||||
rm -f "/tmp/sops-${SOPS_VER}.checksums.pem"
|
||||
rm -f "/tmp/sops-${SOPS_VER}.checksums.sig"
|
||||
[[ "${sops_version}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || \
|
||||
die "Invalid SOPS version '${1}'. Expected '<MAJOR>.<MINOR>.<PATCH>' without prerelease metadata."
|
||||
|
||||
chmod 0400 /root/.config/sops/age/keys.txt
|
||||
printf '%s' "${sops_version}"
|
||||
|
||||
printf "\e[92m++++ ++++ ++++ ++++ ++++ ++++ ++ ✅ '%s' applied successfully. \e[0m\n" "${0}"
|
||||
return 0
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Download a mandatory release asset.
|
||||
# Globals:
|
||||
# None
|
||||
# Arguments:
|
||||
# 1: Asset URL
|
||||
# 2: Target filename
|
||||
# Returns:
|
||||
# 0: on success
|
||||
#######################################
|
||||
download_required_asset() {
|
||||
declare asset_url="$1"
|
||||
declare target_file="$2"
|
||||
|
||||
if ! curl -fsSLo "${target_file}" "${asset_url}"; then
|
||||
die "Failed to download required SOPS asset '${target_file}' from '${asset_url}'."
|
||||
fi
|
||||
|
||||
[[ -s "${target_file}" ]] || die "Downloaded SOPS asset is empty: ${target_file}"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Download an optional release asset and distinguish absence from download errors.
|
||||
# Globals:
|
||||
# None
|
||||
# Arguments:
|
||||
# 1: Asset URL
|
||||
# 2: Target filename
|
||||
# Returns:
|
||||
# 0: asset was downloaded
|
||||
# 1: asset is absent upstream
|
||||
#######################################
|
||||
download_optional_asset() {
|
||||
declare asset_url="$1"
|
||||
declare target_file="$2"
|
||||
declare http_code=""
|
||||
|
||||
if ! http_code=$(curl -sSLo "${target_file}" -w '%{http_code}' "${asset_url}"); then
|
||||
rm -f -- "${target_file}"
|
||||
die "Failed to query optional SOPS asset '${target_file}' from '${asset_url}'."
|
||||
fi
|
||||
|
||||
case "${http_code}" in
|
||||
200)
|
||||
[[ -s "${target_file}" ]] || die "Optional SOPS asset is empty after HTTP 200: ${target_file}"
|
||||
return 0
|
||||
;;
|
||||
404)
|
||||
rm -f -- "${target_file}"
|
||||
return 1
|
||||
;;
|
||||
*)
|
||||
rm -f -- "${target_file}"
|
||||
die "Unexpected HTTP status ${http_code} for optional SOPS asset '${target_file}' from '${asset_url}'."
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Verify the SOPS checksums file with Cosign.
|
||||
# Globals:
|
||||
# SOPS_COSIGN_CERTIFICATE_IDENTITY_REGEXP
|
||||
# SOPS_COSIGN_CERTIFICATE_OIDC_ISSUER
|
||||
# Arguments:
|
||||
# 1: Checksums filename
|
||||
# 2: Bundle filename
|
||||
# 3: Certificate filename
|
||||
# 4: Signature filename
|
||||
# Returns:
|
||||
# 0: on success
|
||||
#######################################
|
||||
verify_sops_checksums_signature() {
|
||||
declare checksums_file="$1"
|
||||
declare bundle_file="$2"
|
||||
declare certificate_file="$3"
|
||||
declare signature_file="$4"
|
||||
|
||||
if [[ -f "${bundle_file}" ]]; then
|
||||
printf "\e[95m[INFO] Verifying SOPS checksums with Cosign bundle: %s \e[0m\n" "${bundle_file}"
|
||||
cosign verify-blob "${checksums_file}" \
|
||||
--bundle "${bundle_file}" \
|
||||
--certificate-identity-regexp="${SOPS_COSIGN_CERTIFICATE_IDENTITY_REGEXP}" \
|
||||
--certificate-oidc-issuer="${SOPS_COSIGN_CERTIFICATE_OIDC_ISSUER}" || \
|
||||
die "SOPS checksum signature verification failed in bundle mode for '${checksums_file}' using '${bundle_file}'."
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ -f "${certificate_file}" && -f "${signature_file}" ]]; then
|
||||
printf "\e[95m[INFO] Verifying SOPS checksums with Cosign split certificate/signature: %s %s \e[0m\n" "${certificate_file}" "${signature_file}"
|
||||
cosign verify-blob "${checksums_file}" \
|
||||
--certificate "${certificate_file}" \
|
||||
--signature "${signature_file}" \
|
||||
--certificate-identity-regexp="${SOPS_COSIGN_CERTIFICATE_IDENTITY_REGEXP}" \
|
||||
--certificate-oidc-issuer="${SOPS_COSIGN_CERTIFICATE_OIDC_ISSUER}" || \
|
||||
die "SOPS checksum signature verification failed in legacy split mode for '${checksums_file}' using '${certificate_file}' and '${signature_file}'."
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ -f "${certificate_file}" || -f "${signature_file}" ]]; then
|
||||
die "Incomplete legacy SOPS signature layout for '${checksums_file}'. Expected both '${certificate_file}' and '${signature_file}'."
|
||||
fi
|
||||
|
||||
die "No supported SOPS checksum signature layout found for '${checksums_file}'. Expected bundle or split certificate/signature assets."
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Verify the SOPS artifact checksum and ensure the expected artifact was covered.
|
||||
# Globals:
|
||||
# None
|
||||
# Arguments:
|
||||
# 1: Checksums filename
|
||||
# 2: Artifact filename
|
||||
# Returns:
|
||||
# 0: on success
|
||||
#######################################
|
||||
verify_sops_artifact_checksum() {
|
||||
declare checksums_file="$1"
|
||||
declare artifact_file="$2"
|
||||
declare checksum_output=""
|
||||
|
||||
if ! checksum_output=$(sha256sum -c "${checksums_file}" --ignore-missing 2>&1); then
|
||||
printf '%s\n' "${checksum_output}" >&2
|
||||
die "SOPS artifact checksum verification failed for '${artifact_file}' using '${checksums_file}'."
|
||||
fi
|
||||
|
||||
printf '%s\n' "${checksum_output}"
|
||||
|
||||
if ! grep -Fxq "${artifact_file}: OK" <<< "${checksum_output}" && \
|
||||
! grep -Fxq "./${artifact_file}: OK" <<< "${checksum_output}"; then
|
||||
die "SOPS checksum verification did not cover expected artifact '${artifact_file}' from '${checksums_file}'."
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Install SOPS from an upstream GitHub release after signature and checksum verification.
|
||||
# Globals:
|
||||
# CISS_SOPS_VERSION
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# 0: on success
|
||||
#######################################
|
||||
main() {
|
||||
require_tool curl
|
||||
require_tool cosign
|
||||
require_tool sha256sum
|
||||
|
||||
declare sops_env="/root/sops.env"
|
||||
[[ -r "${sops_env}" ]] || die "Missing SOPS environment file: ${sops_env}"
|
||||
|
||||
# shellcheck disable=SC1090
|
||||
. "${sops_env}"
|
||||
|
||||
declare ciss_sops_version
|
||||
ciss_sops_version=$(normalize_sops_version "${CISS_SOPS_VERSION:?CISS_SOPS_VERSION is not set}")
|
||||
|
||||
declare architecture
|
||||
architecture="$(dpkg --print-architecture)"
|
||||
|
||||
declare sops_tag="v${ciss_sops_version}"
|
||||
declare sops_file=""
|
||||
case "${architecture}" in
|
||||
amd64)
|
||||
sops_file="sops-${sops_tag}.linux.amd64"
|
||||
;;
|
||||
arm64)
|
||||
sops_file="sops-${sops_tag}.linux.arm64"
|
||||
;;
|
||||
*)
|
||||
die "Unsupported architecture '${architecture}' for SOPS version '${ciss_sops_version}'. Expected amd64 or arm64."
|
||||
;;
|
||||
esac
|
||||
|
||||
declare release_base_url="https://github.com/getsops/sops/releases/download/${sops_tag}"
|
||||
declare checksums_file="sops-${sops_tag}.checksums.txt"
|
||||
declare bundle_file="sops-${sops_tag}.checksums.sigstore.json"
|
||||
declare certificate_file="sops-${sops_tag}.checksums.pem"
|
||||
declare signature_file="sops-${sops_tag}.checksums.sig"
|
||||
declare bundle_available="false"
|
||||
declare certificate_available="false"
|
||||
declare signature_available="false"
|
||||
|
||||
cd /tmp
|
||||
|
||||
printf "\e[95m[INFO] Downloading SOPS %s asset: %s \e[0m\n" "${ciss_sops_version}" "${sops_file}"
|
||||
download_required_asset "${release_base_url}/${sops_file}" "${sops_file}"
|
||||
download_required_asset "${release_base_url}/${checksums_file}" "${checksums_file}"
|
||||
|
||||
# shellcheck disable=SC2310
|
||||
if download_optional_asset "${release_base_url}/${bundle_file}" "${bundle_file}"; then
|
||||
bundle_available="true"
|
||||
fi
|
||||
|
||||
if [[ "${bundle_available}" == "false" ]]; then
|
||||
# shellcheck disable=SC2310
|
||||
if download_optional_asset "${release_base_url}/${certificate_file}" "${certificate_file}"; then
|
||||
certificate_available="true"
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2310
|
||||
if download_optional_asset "${release_base_url}/${signature_file}" "${signature_file}"; then
|
||||
signature_available="true"
|
||||
fi
|
||||
|
||||
if [[ "${certificate_available}" != "${signature_available}" ]]; then
|
||||
die "Incomplete legacy SOPS signature assets for version '${ciss_sops_version}'. Expected both '${certificate_file}' and '${signature_file}'."
|
||||
fi
|
||||
fi
|
||||
|
||||
verify_sops_checksums_signature "${checksums_file}" "${bundle_file}" "${certificate_file}" "${signature_file}"
|
||||
verify_sops_artifact_checksum "${checksums_file}" "${sops_file}"
|
||||
|
||||
install -m 0755 "${sops_file}" /usr/local/bin/sops
|
||||
sops --version >| /root/.ciss/cdlb/log/sops.log
|
||||
age --version >| /root/.ciss/cdlb/log/age.log
|
||||
|
||||
rm -f -- "/tmp/${sops_file}"
|
||||
rm -f -- "/tmp/${checksums_file}"
|
||||
rm -f -- "/tmp/${bundle_file}"
|
||||
rm -f -- "/tmp/${certificate_file}"
|
||||
rm -f -- "/tmp/${signature_file}"
|
||||
|
||||
if [[ -f /root/.config/sops/age/keys.txt ]]; then
|
||||
chmod 0400 /root/.config/sops/age/keys.txt
|
||||
fi
|
||||
|
||||
printf "\e[92m✅ '%s' applied successfully. \e[0m\n" "${0}"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
if [[ "${CISS_SOPS_TEST_MODE:-false}" != "true" ]]; then
|
||||
main "$@"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
exit 0
|
||||
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh
|
||||
|
||||
Reference in New Issue
Block a user