Skip to content

Commit

Permalink
Add CA auth. header in AUTH_TOKEN is set
Browse files Browse the repository at this point in the history
  • Loading branch information
ab77 committed Feb 20, 2025
1 parent 1c88ee3 commit 9da5c29
Showing 1 changed file with 53 additions and 53 deletions.
106 changes: 53 additions & 53 deletions entry.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,48 +13,53 @@ fi

AWS_S3_ENDPOINT=${AWS_S3_ENDPOINT:-https://s3.amazonaws.com}
AWS_REGION=${AWS_REGION:-us-east-1}
# shellcheck disable=SC2034
AWS_DEFAULT_REGION=${AWS_REGION}
CERTS=${CERTS:-/certs}
EXPORT_CERT_CHAIN_PATH=${EXPORT_CERT_CHAIN_PATH:-${CERTS}/export/chain.pem}
SUBJECT_ALTERNATE_NAMES=${SUBJECT_ALTERNATE_NAMES:-*,*.devices,*.s3,*.img}
SSH_KEY_NAMES=${SSH_KEY_NAMES:-devices,git,proxy}
ca_http_url=${CA_HTTP_URL:-http://balena-ca:8888}
dns_cloudflare_propagation_seconds=${DNS_CLOUDFLARE_PROPAGATION_SECONDS:-60}
attempts=${ATTEMPTS:-3}
timeout=${TIMEOUT:-60}
cert_seconds_until_expiry=${CERT_SECONDS_UNTIL_EXPIRY:-604800} # 7 days

# shellcheck disable=SC2034
country=${COUNTRY:-US}
# shellcheck disable=SC2034
state=${STATE:-Washington}
# shellcheck disable=SC2034
locality_name=${LOCALITY_NAME:-Seattle}
# shellcheck disable=SC2034
org=${ORG:-balena}
# shellcheck disable=SC2034
org_unit=${ORG_UNIT:-balenaCloud}
# shellcheck disable=SC2034
key_algo=${KEY_ALGO:-ecdsa}
# shellcheck disable=SC2034
key_size=${KEY_SIZE:-256}
CA_HTTP_URL=${CA_HTTP_URL:-http://balena-ca:8888}
DNS_CLOUDFLARE_PROPAGATION_SECONDS=${DNS_CLOUDFLARE_PROPAGATION_SECONDS:-60}
ATTEMPTS=${ATTEMPTS:-3}
TIMEOUT=${TIMEOUT:-60}
CERT_SECONDS_UNTIL_EXPIRY=${CERT_SECONDS_UNTIL_EXPIRY:-604800} # 7 days
COUNTRY=${COUNTRY:-US}
STATE=${STATE:-Washington}
LOCALITY_NAME=${LOCALITY_NAME:-Seattle}
ORG=${ORG:-balena}
ORG_UNIT=${ORG_UNIT:-balenaCloud}
KEY_ALGO=${KEY_ALGO:-ecdsa}
KEY_SIZE=${KEY_SIZE:-256}

function cleanup() {
remove_update_lock
sleep $(( (RANDOM % 5) + 5))s
}
trap 'cleanup' EXIT

curl_with_opts() {
curl --silent --retry "${ATTEMPTS}" --fail "$@"
}

curl_with_auth_opts() {
if [[ -n "${AUTH_TOKEN:-}" ]]; then
curl --silent --retry "${ATTEMPTS}" --fail -H "Authorization: Bearer ${AUTH_TOKEN}" "$@"
else
curl --silent --retry "${ATTEMPTS}" --fail "$@"
fi
}

# https://coderwall.com/p/--eiqg/exponential-backoff-in-bash
# https://letsencrypt.org/docs/integration-guide/#retrying-failures
# https://letsencrypt.ORG/docs/integration-guide/#retrying-failures
function with_backoff() {
local max_attempts=${attempts-5}
local timeout=${timeout-1}
local max_attempts=${ATTEMPTS-5}
local timeout=${TIMEOUT-1}
local attempt=0
local exitCode=0

set +e
while [[ $attempt < $max_attempts ]]
while [[ $attempt -lt $max_attempts ]]
do
"$@"
exitCode=$?
Expand All @@ -64,8 +69,8 @@ function with_backoff() {
break
fi

echo "Failure! Retrying in $timeout.." 1>&2
sleep "$timeout"
echo "Failure! Retrying in $TIMEOUT.." 1>&2
sleep "$TIMEOUT"
attempt=$(( attempt + 1 ))
timeout=$(( timeout * 2 ))
done
Expand Down Expand Up @@ -147,7 +152,7 @@ function get_acme_email {
[[ -n "${balena_device_uuid}" ]] || return

# shellcheck disable=SC2153
acme_email="$(curl --retry "${attempts}" --fail "${BALENA_API_URL}/user/v1/whoami" \
acme_email="$(curl_with_opts "${BALENA_API_URL}/user/v1/whoami" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $(get_env_var_value "${balena_device_uuid}" API_TOKEN)" \
--compressed | jq -r '.email')"
Expand All @@ -170,13 +175,13 @@ function get_env_var_value {
balena_device_uuid="${1}"
[[ -n "${balena_device_uuid}" ]] || return

balena_device_id="$(curl --retry "${attempts}" --fail \
balena_device_id="$(curl_with_opts \
"${BALENA_API_URL}/v6/device?\$filter=uuid%20eq%20'${balena_device_uuid}'" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${BALENA_API_KEY}" \
--compressed | jq -r .d[].id)"

varval="$(curl --retry "${attempts}" --fail \
varval="$(curl_with_opts \
"${BALENA_API_URL}/v6/device_service_environment_variable?\$filter=service_install/device%20eq%20${balena_device_id}" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${BALENA_API_KEY}" \
Expand Down Expand Up @@ -207,7 +212,7 @@ function cloudflare_issue_public_cert {
# shellcheck disable=SC2086
with_backoff certbot certonly --agree-tos --non-interactive --verbose --expand \
--dns-cloudflare \
--dns-cloudflare-propagation-seconds "${dns_cloudflare_propagation_seconds}" \
--dns-cloudflare-propagation-seconds "${DNS_CLOUDFLARE_PROPAGATION_SECONDS}" \
--dns-cloudflare-credentials ~/.secrets/certbot/cloudflare.ini \
--cert-name "${dns_tld}" \
-m "$(get_acme_email ${balena_device_uuid})" \
Expand Down Expand Up @@ -258,7 +263,7 @@ function backup_certs_to_s3 {
dns_tld="${1}"

if [[ -n $AWS_S3_BUCKET ]]; then
tar -cpvzf "/tmp/${dns_tld}.tgz" --exclude='accounts' --exclude='renewal-hooks' *
tar -cpvzf "/tmp/${dns_tld}.tgz" --exclude='accounts' --exclude='renewal-hooks' ./*
(s3_init && mcli cp --recursive "/tmp/${dns_tld}.tgz" "s3/${AWS_S3_BUCKET}/") || true
rm -f "/tmp/${dns_tld}.tgz"
fi
Expand Down Expand Up @@ -293,6 +298,8 @@ function issue_public_certs {
if ! [[ $dns_tld =~ ^.*\.local\.? ]]; then
restore_certs_from_s3 "${dns_tld}"

# shellcheck disable=SC2012
# shellcheck disable=SC2086
current="$(ls -dt live/${dns_tld}* | head -n1)"

# only attempt to renew if the certificate is near expiry
Expand All @@ -304,8 +311,8 @@ function issue_public_certs {
fi

# refresh link to the latest certificate set
# https://community.letsencrypt.org/t/prevent-0001-xxxx-certificate-suffixes/66802/3
# https://community.letsencrypt.org/t/re-prevent-0001-xxxx-certificate-suffixes/83824
# https://community.letsencrypt.ORG/t/prevent-0001-xxxx-certificate-suffixes/66802/3
# https://community.letsencrypt.ORG/t/re-prevent-0001-xxxx-certificate-suffixes/83824
# shellcheck disable=SC2012
# shellcheck disable=SC2086
if [[ -d live ]]; then
Expand Down Expand Up @@ -363,11 +370,7 @@ function issue_private_certs {

if ! [[ -s "${CERTS}/private/${common_name}.pem" ]]; then
cat < "${tmprequest}" | jq -r

response="$(curl --retry "${attempts}" --fail \
"${ca_http_url}/api/v1/cfssl/newcert" \
--data @"${tmprequest}")"

response="$(curl_with_auth_opts "${CA_HTTP_URL}/api/v1/cfssl/newcert" --data @"${tmprequest}")"
echo "${response}" | jq -r '.result.certificate' > "${CERTS}/private/${common_name}.pem"
echo "${response}" | jq -r '.result.private_key' > "${CERTS}/private/${common_name}.key"
chmod 0600 "${CERTS}/private/${common_name}.key"
Expand All @@ -391,11 +394,7 @@ function issue_private_keys {

if ! [[ -s "${CERTS}/private/${common_name}.key" ]]; then
cat < "${tmprequest}" | jq -r

response="$(curl --retry "${attempts}" --fail \
"${ca_http_url}/api/v1/cfssl/newkey" \
--data @"${tmprequest}")"

response="$(curl_with_auth_opts "${CA_HTTP_URL}/api/v1/cfssl/newkey" --data @"${tmprequest}")"
echo "${response}" | jq -r '.result.private_key' > "${CERTS}/private/${common_name}.key"
chmod 0600 "${CERTS}/private/${common_name}.key"
fi
Expand Down Expand Up @@ -462,7 +461,7 @@ function surface_resolved_cert_chain {
server_ca="$(get_cert_subject "${CERTS}/server-ca.pem" | awk -F'subject=' '{print $2}')"

custom_cert=1
if [[ "$cert_issuer" =~ "$server_ca" ]]; then
if [[ "$cert_issuer" =~ $server_ca ]]; then
custom_cert=0
fi

Expand Down Expand Up @@ -570,7 +569,7 @@ function get_server_ca {

# shellcheck disable=SC2153
if ! [[ -s "${CERTS}/private/server-ca.${tld}.pem" ]]; then
curl --retry "${attempts}" --fail "${ca_http_url}/api/v1/cfssl/info" \
curl_with_auth_opts "${CA_HTTP_URL}/api/v1/cfssl/info" \
--data '{"label": "primary"}' \
| jq -r '.result.certificate' > "${CERTS}/private/server-ca.${tld}.pem"
fi
Expand All @@ -583,7 +582,7 @@ function get_root_ca {

# shellcheck disable=SC2153
if ! [[ -s "${CERTS}/private/root-ca.${tld}.pem" ]]; then
curl --retry "${attempts}" --fail "${ca_http_url}/api/v1/cfssl/bundle" \
curl_with_auth_opts "${CA_HTTP_URL}/api/v1/cfssl/bundle" \
--data "{\"certificate\": \"$(cat < "${CERTS}/private/server-ca.${tld}.pem" | awk '{printf "%s\\n", $0}')\"}" \
| jq -r '.result.root' > "${CERTS}/private/root-ca.${tld}.pem"
fi
Expand All @@ -601,10 +600,10 @@ function check_cert_expiry() {
[[ -e $1 ]] || return 1

expiry_check="$(openssl x509 -noout \
-checkend "${cert_seconds_until_expiry}" \
-checkend "${CERT_SECONDS_UNTIL_EXPIRY}" \
-in "$1")"

echo "$1 ${expiry_check} in $(( cert_seconds_until_expiry / 60 / 60 / 24 )) days"
echo "$1 ${expiry_check} in $(( CERT_SECONDS_UNTIL_EXPIRY / 60 / 60 / 24 )) days"
printf '\t%s\n\t%s\n' "$(get_cert_subject "$1")" "$(get_cert_issuer "$1")"

if ! [[ "${expiry_check}" =~ 'will not expire' ]]; then
Expand All @@ -618,7 +617,7 @@ function get_cert_issuer() {
local cert
cert=$1

cat <${cert} | openssl x509 -noout -issuer
cat <"${cert}" | openssl x509 -noout -issuer
}
export -f get_cert_issuer

Expand All @@ -627,10 +626,11 @@ function get_cert_subject() {
local cert
cert=$1

cat <${cert} | openssl x509 -noout -subject
cat <"${cert}" | openssl x509 -noout -subject
}
export -f get_cert_subject

# shellcheck disable=SC2016
function check_self_signed_certs_expiry() {
find "${CERTS}/private" -type f -name '*.pem' ! -name 'dhparam.*' \
-exec /bin/bash -c 'check_cert_expiry "$0"' {} \;
Expand All @@ -648,11 +648,11 @@ function resolve_templates() {

function set_update_lock {
if [[ -n $BALENA_SUPERVISOR_ADDRESS ]] && [[ -n $BALENA_SUPERVISOR_API_KEY ]]; then
while [[ $(curl --silent --retry "${attempts}" --fail \
while [[ $(curl_with_opts \
"${BALENA_SUPERVISOR_ADDRESS}/v1/device?apikey=${BALENA_SUPERVISOR_API_KEY}" \
-H "Content-Type: application/json" | jq -r '.update_pending') == 'true' ]]; do

curl --silent --retry "${attempts}" --fail \
curl_with_opts \
"${BALENA_SUPERVISOR_ADDRESS}/v1/device?apikey=${BALENA_SUPERVISOR_API_KEY}" \
-H "Content-Type: application/json" | jq -r

Expand All @@ -673,7 +673,7 @@ rm -f "${CERTS}/.ready"

mkdir -p "${CERTS}/public" "${CERTS}/private" "$(dirname "${EXPORT_CERT_CHAIN_PATH}")"

while ! curl -I --fail "${ca_http_url}"; do sleep "$((RANDOM%10+1))s"; done
while ! curl_with_auth_opts "${CA_HTTP_URL}"; do printf '.'; sleep "$((RANDOM%10+1))s"; done

get_server_ca "${TLD}"
get_root_ca "${TLD}"
Expand Down

0 comments on commit 9da5c29

Please sign in to comment.