Corp/ops/deploy/install-corp-runner-access

191 lines
6.1 KiB
Bash
Executable File

#!/usr/bin/env bash
set -Eeuo pipefail
if [[ ${EUID} -ne 0 ]]; then
echo "Run this installer with sudo." >&2
exit 1
fi
readonly SOURCE_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
readonly PUBLIC_KEY_FILE="${1:-}"
readonly NGINX_LINK="/etc/nginx/sites-enabled/eusrr"
readonly UPSTREAM_FILE="/etc/nginx/conf.d/eusrr-active-upstreams.conf"
if [[ -z ${PUBLIC_KEY_FILE} || ! -f ${PUBLIC_KEY_FILE} ]]; then
echo "Usage: $0 /path/to/gitea-runner.pub" >&2
exit 2
fi
if ! id deploy >/dev/null 2>&1; then
echo "The deploy system account does not exist." >&2
exit 3
fi
if [[ ! -d ${SOURCE_DIR}/systemd ]]; then
echo "Systemd templates are missing from ${SOURCE_DIR}." >&2
exit 4
fi
read -r key_type key_body _ <"${PUBLIC_KEY_FILE}"
if [[ ${key_type} != "ssh-ed25519" || -z ${key_body:-} ]]; then
echo "Expected an Ed25519 public key." >&2
exit 5
fi
nginx_config="$(readlink -f "${NGINX_LINK}")"
nginx_backup="${nginx_config}.bak.blue-green.$(date -u +%Y%m%dT%H%M%SZ)"
cp -a "${nginx_config}" "${nginx_backup}"
upstream_existed=0
upstream_backup=""
if [[ -f ${UPSTREAM_FILE} ]]; then
upstream_existed=1
upstream_backup="${UPSTREAM_FILE}.bak.$(date -u +%Y%m%dT%H%M%SZ)"
cp -a "${UPSTREAM_FILE}" "${upstream_backup}"
fi
install_complete=0
temporary_files=()
cleanup() {
local status=$?
for file in "${temporary_files[@]:-}"; do
[[ -n ${file} ]] && rm -f "${file}"
done
if [[ ${install_complete} -eq 0 ]]; then
cp -a "${nginx_backup}" "${nginx_config}"
if [[ ${upstream_existed} -eq 1 ]]; then
cp -a "${upstream_backup}" "${UPSTREAM_FILE}"
else
rm -f "${UPSTREAM_FILE}"
fi
nginx -t >/dev/null 2>&1 && systemctl reload nginx || true
fi
exit "${status}"
}
trap cleanup EXIT
install -o root -g root -m 0755 "${SOURCE_DIR}/eusrr-deploy" /usr/local/sbin/eusrr-deploy
install -o root -g root -m 0755 "${SOURCE_DIR}/eusrr-deploy-ssh" /usr/local/sbin/eusrr-deploy-ssh
for unit in "${SOURCE_DIR}"/systemd/*.service; do
install -o root -g root -m 0644 "${unit}" "/etc/systemd/system/$(basename "${unit}")"
done
install -d -o deploy -g eusrr -m 2775 /srv/eusrr-releases /srv/eusrr-slots
install -d -o deploy -g www-data -m 0755 /srv/eusrr-shared /srv/eusrr-shared/next-static
if [[ -d /srv/eusrr/frontend/.next/static ]]; then
rsync -a /srv/eusrr/frontend/.next/static/ /srv/eusrr-shared/next-static/
fi
chown -R deploy:www-data /srv/eusrr-shared
find /srv/eusrr-shared -type d -exec chmod 0755 {} +
find /srv/eusrr-shared -type f -exec chmod 0644 {} +
ln -sfn /srv/eusrr /srv/eusrr-current.new
mv -Tf /srv/eusrr-current.new /srv/eusrr-current
if [[ ! -f ${UPSTREAM_FILE} ]]; then
cat >"${UPSTREAM_FILE}" <<'EOF'
upstream eusrr_backend {
server 127.0.0.1:9000;
keepalive 32;
}
upstream eusrr_frontend {
server 127.0.0.1:3000;
keepalive 32;
}
EOF
chmod 0644 "${UPSTREAM_FILE}"
fi
NGINX_CONFIG="${nginx_config}" python3 <<'PY'
import os
import re
from pathlib import Path
path = Path(os.environ["NGINX_CONFIG"])
text = path.read_text(encoding="utf-8")
next_static = re.compile(
r"^ location /_next/static/ \{\n.*?^ \}",
flags=re.MULTILINE | re.DOTALL,
)
replacement = """ location /_next/static/ {
alias /srv/eusrr-shared/next-static/;
autoindex off;
expires 365d;
add_header Cache-Control \"public, immutable\";
}"""
text, static_blocks = next_static.subn(replacement, text)
if static_blocks not in (0, 2):
raise SystemExit(f"Expected zero or two Next.js static blocks, found {static_blocks}")
text = text.replace("proxy_pass http://127.0.0.1:9000;", "proxy_pass http://eusrr_backend;")
text = text.replace("proxy_pass http://127.0.0.1:3000;", "proxy_pass http://eusrr_frontend;")
text = text.replace(
"alias /srv/eusrr/backend/staticfiles/;",
"alias /srv/eusrr-current/backend/staticfiles/;",
)
required = (
"proxy_pass http://eusrr_backend;",
"proxy_pass http://eusrr_frontend;",
"alias /srv/eusrr-shared/next-static/;",
"alias /srv/eusrr-current/backend/staticfiles/;",
)
for marker in required:
if marker not in text:
raise SystemExit(f"Nginx transformation marker is missing: {marker}")
if "proxy_pass http://127.0.0.1:9000;" in text or "proxy_pass http://127.0.0.1:3000;" in text:
raise SystemExit("Legacy direct upstreams remain in Nginx configuration")
path.write_text(text, encoding="utf-8")
PY
install -d -o root -g root -m 0755 /etc/eusrr/slots /var/lib/eusrr-deploy
cat >/etc/eusrr/slots/blue.env <<'EOF'
BACKEND_PORT=9001
PORT=3001
HOSTNAME=127.0.0.1
EOF
cat >/etc/eusrr/slots/green.env <<'EOF'
BACKEND_PORT=9002
PORT=3002
HOSTNAME=127.0.0.1
EOF
chmod 0644 /etc/eusrr/slots/blue.env /etc/eusrr/slots/green.env
if [[ ! -f /var/lib/eusrr-deploy/active-slot ]]; then
printf '%s\n' legacy >/var/lib/eusrr-deploy/active-slot
fi
install -d -o deploy -g deploy -m 0755 /var/log/celery
install -d -o deploy -g deploy -m 0700 /var/backups/eusrr/deploy
touch /var/log/eusrr-deploy.log
chown root:root /var/log/eusrr-deploy.log
chmod 0600 /var/log/eusrr-deploy.log
sudoers_tmp="$(mktemp)"
temporary_files+=("${sudoers_tmp}")
printf '%s\n' 'deploy ALL=(root) NOPASSWD: /usr/local/sbin/eusrr-deploy *' >"${sudoers_tmp}"
chmod 0440 "${sudoers_tmp}"
visudo -cf "${sudoers_tmp}" >/dev/null
install -o root -g root -m 0440 "${sudoers_tmp}" /etc/sudoers.d/eusrr-deploy
deploy_home="$(getent passwd deploy | cut -d: -f6)"
install -d -o deploy -g deploy -m 0700 "${deploy_home}/.ssh"
authorized_keys="${deploy_home}/.ssh/authorized_keys"
touch "${authorized_keys}"
chown deploy:deploy "${authorized_keys}"
chmod 0600 "${authorized_keys}"
filtered_keys="$(mktemp)"
temporary_files+=("${filtered_keys}")
grep -v ' eusrr-gitea-runner$' "${authorized_keys}" >"${filtered_keys}" || true
printf '%s %s %s %s\n' \
'command="/usr/local/sbin/eusrr-deploy-ssh",restrict' \
"${key_type}" "${key_body}" 'eusrr-gitea-runner' >>"${filtered_keys}"
install -o deploy -g deploy -m 0600 "${filtered_keys}" "${authorized_keys}"
systemctl daemon-reload
nginx -t
systemctl reload nginx
sudo -u deploy sudo -n /usr/local/sbin/eusrr-deploy --self-test
install_complete=1
echo "Restricted blue-green Gitea deployment installed successfully."