diff --git a/infra/activate_release.sh b/infra/activate_release.sh index ceb1b190..828e1cb5 100755 --- a/infra/activate_release.sh +++ b/infra/activate_release.sh @@ -10,24 +10,31 @@ if [[ ! "${1:-}" =~ ^[0-9a-f]{40}$ ]]; then exit 64 fi +# deploy.sh uploads into a private per-deploy directory; /tmp is the older layout. +upload_dir="${TIN_LITE_UPLOAD_DIR:-/tmp}" +if [[ "${upload_dir}" != /tmp && ! "${upload_dir}" =~ ^/tmp/tin-deploy\.[A-Za-z0-9]{10}$ ]]; then + echo "TIN_LITE_UPLOAD_DIR must be /tmp or a deploy directory under it" >&2 + exit 64 +fi + cleanup() { - rm -f /tmp/tin-lite-github-app.pem + rm -f "${upload_dir}/tin-lite-github-app.pem" } trap cleanup EXIT release_sha="$1" release_dir="/opt/tin-lite/releases/${release_sha}" install -d -m 750 -o tinlite -g tinlite "${release_dir}" -tar -xzf /tmp/tin-lite-release.tar.gz -C "${release_dir}" -if [[ -f /tmp/tin-lite-github-app.pem ]]; then +tar -xzf "${upload_dir}/tin-lite-release.tar.gz" -C "${release_dir}" +if [[ -f "${upload_dir}/tin-lite-github-app.pem" ]]; then install -m 640 -o root -g tinlite \ - /tmp/tin-lite-github-app.pem /etc/tin-lite/github-app.pem + "${upload_dir}/tin-lite-github-app.pem" /etc/tin-lite/github-app.pem sed -i \ 's#^TIN_LITE_GITHUB_APP_PRIVATE_KEY_PATH=.*#TIN_LITE_GITHUB_APP_PRIVATE_KEY_PATH=/etc/tin-lite/github-app.pem#' \ - /tmp/tin-lite.env + "${upload_dir}/tin-lite.env" fi # An uploaded .env wins; otherwise the release env kept on the host (staging) is used. -release_env=/tmp/tin-lite.env +release_env="${upload_dir}/tin-lite.env" if [[ ! -f "${release_env}" ]]; then release_env=/etc/tin-lite/release.env fi @@ -53,4 +60,4 @@ ln -sfn "${release_dir}" /opt/tin-lite/current systemctl enable tin-lite-switchboard systemctl restart tin-lite-switchboard -rm -f /tmp/tin-lite-release.tar.gz /tmp/tin-lite.env +rm -f "${upload_dir}/tin-lite-release.tar.gz" "${upload_dir}/tin-lite.env" diff --git a/infra/deploy.sh b/infra/deploy.sh index 6738f27f..9f157a49 100755 --- a/infra/deploy.sh +++ b/infra/deploy.sh @@ -66,6 +66,16 @@ temporary_dir="$(mktemp -d)" trap 'rm -rf "${temporary_dir}"' EXIT git archive --format=tar.gz --output="${temporary_dir}/tin-lite-release.tar.gz" HEAD +# Each deploy uploads into its own private directory, so deploys by different people (or +# by CI) never collide on files another account left in /tmp. +upload_dir="$(gcloud compute ssh "${instance}" \ + --project "${TIN_LITE_GCP_PROJECT}" --zone "${zone}" --quiet \ + --command='mktemp -d /tmp/tin-deploy.XXXXXXXXXX' | tr -d '\r')" +if [[ ! "${upload_dir}" =~ ^/tmp/tin-deploy\.[A-Za-z0-9]{10}$ ]]; then + echo "could not create a private upload directory on ${instance}" >&2 + exit 70 +fi + release_files=("${temporary_dir}/tin-lite-release.tar.gz") if [[ "${upload_env}" == "1" ]]; then release_files+=(.env) @@ -77,18 +87,18 @@ gcloud compute scp \ infra/proxy_policy.py \ src/tin_lite/proxy_grants.py \ infra/activate_release.sh \ - "${instance}:/tmp/" \ + "${instance}:${upload_dir}/" \ --project "${TIN_LITE_GCP_PROJECT}" --zone "${zone}" --quiet if [[ -n "${github_private_key_path}" ]]; then gcloud compute scp \ "${github_private_key_path}" \ - "${instance}:/tmp/tin-lite-github-app.pem" \ + "${instance}:${upload_dir}/tin-lite-github-app.pem" \ --project "${TIN_LITE_GCP_PROJECT}" --zone "${zone}" --quiet gcloud compute ssh "${instance}" \ --project "${TIN_LITE_GCP_PROJECT}" --zone "${zone}" --quiet \ - --command="sudo chown root:root /tmp/tin-lite-github-app.pem && \ -sudo chmod 600 /tmp/tin-lite-github-app.pem" + --command="sudo chown root:root ${upload_dir}/tin-lite-github-app.pem && \ +sudo chmod 600 ${upload_dir}/tin-lite-github-app.pem" fi static_ip="${TIN_LITE_STATIC_IP:-}" @@ -107,12 +117,13 @@ if [[ ! "${product_host}" =~ ^[a-zA-Z0-9.-]+$ ]]; then fi move_env="" if [[ "${upload_env}" == "1" ]]; then - move_env="sudo mv /tmp/.env /tmp/tin-lite.env && " + move_env="mv ${upload_dir}/.env ${upload_dir}/tin-lite.env && " fi gcloud compute ssh "${instance}" \ --project "${TIN_LITE_GCP_PROJECT}" --zone "${zone}" --quiet \ - --command="sudo env TIN_LITE_STATIC_IP=${static_ip} TIN_LITE_PRODUCT_HOST=${product_host} bash /tmp/install_switchboard.sh && \ -${move_env}sudo env TIN_LITE_RUN_MIGRATIONS=${run_migrations} bash /tmp/activate_release.sh ${release_sha}" + --command="sudo env TIN_LITE_STATIC_IP=${static_ip} TIN_LITE_PRODUCT_HOST=${product_host} bash ${upload_dir}/install_switchboard.sh && \ +${move_env}sudo env TIN_LITE_UPLOAD_DIR=${upload_dir} TIN_LITE_RUN_MIGRATIONS=${run_migrations} bash ${upload_dir}/activate_release.sh ${release_sha}; \ +status=\$?; sudo rm -rf ${upload_dir}; exit \$status" public_host="tin-lite-switchboard.${static_ip//./-}.sslip.io" curl --http1.1 --fail --silent --show-error --retry "${health_retries}" --retry-all-errors --retry-delay 3 \ diff --git a/tests/test_secret_fences.py b/tests/test_secret_fences.py index 91b1660a..c53543c7 100644 --- a/tests/test_secret_fences.py +++ b/tests/test_secret_fences.py @@ -52,8 +52,10 @@ def test_github_private_key_is_installed_as_host_state_not_release_state() -> No activate = (ROOT / "infra" / "activate_release.sh").read_text() assert 'openssl pkey -in "${github_private_key_path}" -check -noout' in deploy - assert '"${instance}:/tmp/tin-lite-github-app.pem"' in deploy - assert "sudo chmod 600 /tmp/tin-lite-github-app.pem" in deploy + assert '"${instance}:${upload_dir}/tin-lite-github-app.pem"' in deploy + assert "sudo chmod 600 ${upload_dir}/tin-lite-github-app.pem" in deploy + assert "mktemp -d /tmp/tin-deploy.XXXXXXXXXX" in deploy + assert "sudo rm -rf ${upload_dir}" in deploy assert "install -m 640 -o root -g tinlite" in activate assert "/etc/tin-lite/github-app.pem" in activate assert "TIN_LITE_GITHUB_APP_PRIVATE_KEY_PATH=/etc/tin-lite/github-app.pem" in activate