253 lines
9.4 KiB
Bash
Executable File
253 lines
9.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
if [ "${EUID:-$(id -u)}" -ne 0 ]; then
|
|
exec sudo bash "$0" "$@"
|
|
fi
|
|
|
|
ROOT="/data/aios-gitops"
|
|
WORKSPACE="$ROOT/workspace"
|
|
LEGO_BIN="$ROOT/runtime/bin/lego"
|
|
LEGO_PATH="/etc/letsencrypt/lego-cnnetmkt"
|
|
LIVE_DIR="/etc/letsencrypt/live/cnnetmkt-wildcard"
|
|
ENV_FILE="/etc/letsencrypt/huaweicloud-cnnetmkt.env"
|
|
LOG="$ROOT/logs/cnnetmkt-wildcard-lego.log"
|
|
REPORT="$ROOT/artifacts/CNNETMKT_WILDCARD_CERT_STATUS.md"
|
|
TRACKED="$WORKSPACE/deploy/nginx/cnnetmkt-wildcard-certificate.md"
|
|
BACKUP_DIR="$ROOT/backups/nginx-wildcard-$(date +%Y%m%d-%H%M%S)"
|
|
EMAIL="admin@cnnetmkt.top"
|
|
CERT_NAME="cnnetmkt-wildcard"
|
|
LEGO_VERSION="v5.2.2"
|
|
LEGO_URL="https://github.com/go-acme/lego/releases/download/${LEGO_VERSION}/lego_${LEGO_VERSION}_linux_amd64.tar.gz"
|
|
mkdir -p "$ROOT/logs" "$ROOT/runtime/bin" "$ROOT/artifacts" "$WORKSPACE/deploy/nginx" "$BACKUP_DIR"
|
|
exec > >(tee -a "$LOG") 2>&1
|
|
|
|
redact() {
|
|
sed -E 's/(ACCESS_KEY_ID=).+/\1[REDACTED]/; s/(SECRET_ACCESS_KEY=).+/\1[REDACTED]/'
|
|
}
|
|
|
|
echo "== preflight =="
|
|
hostname
|
|
date -Is
|
|
test -s "$ENV_FILE"
|
|
sudo chmod 600 "$ENV_FILE"
|
|
sudo chown root:root "$ENV_FILE"
|
|
echo "env_file=$ENV_FILE"
|
|
sudo sed -n '1,20p' "$ENV_FILE" | redact
|
|
|
|
echo "== install lego =="
|
|
if [ ! -x "$LEGO_BIN" ]; then
|
|
tmp="$(mktemp -d)"
|
|
curl -fL --retry 3 --connect-timeout 30 -o "$tmp/lego.tar.gz" "$LEGO_URL"
|
|
tar -xzf "$tmp/lego.tar.gz" -C "$tmp"
|
|
install -m 0755 "$tmp/lego" "$LEGO_BIN"
|
|
rm -rf "$tmp"
|
|
fi
|
|
"$LEGO_BIN" --version
|
|
|
|
echo "== load env =="
|
|
set -a
|
|
# shellcheck disable=SC1090
|
|
. "$ENV_FILE"
|
|
set +a
|
|
: "${HUAWEICLOUD_ACCESS_KEY_ID:?missing access key id}"
|
|
: "${HUAWEICLOUD_SECRET_ACCESS_KEY:?missing secret access key}"
|
|
: "${HUAWEICLOUD_REGION:?missing huawei region}"
|
|
export HUAWEICLOUD_HTTP_TIMEOUT="${HUAWEICLOUD_HTTP_TIMEOUT:-30}"
|
|
export HUAWEICLOUD_PROPAGATION_TIMEOUT="${HUAWEICLOUD_PROPAGATION_TIMEOUT:-180}"
|
|
export HUAWEICLOUD_POLLING_INTERVAL="${HUAWEICLOUD_POLLING_INTERVAL:-5}"
|
|
export HUAWEICLOUD_TTL="${HUAWEICLOUD_TTL:-300}"
|
|
|
|
echo "== DNS state =="
|
|
for n in cnnetmkt.top g.cnnetmkt.top user.cnnetmkt.top portal.cnnetmkt.top; do
|
|
echo "-- $n"
|
|
dig +time=5 +tries=1 +short "$n" A || true
|
|
done
|
|
|
|
echo "== staging DNS-01 =="
|
|
STAGING_STATUS="failed"
|
|
if sudo --preserve-env=HUAWEICLOUD_ACCESS_KEY_ID,HUAWEICLOUD_SECRET_ACCESS_KEY,HUAWEICLOUD_REGION,HUAWEICLOUD_HTTP_TIMEOUT,HUAWEICLOUD_PROPAGATION_TIMEOUT,HUAWEICLOUD_POLLING_INTERVAL,HUAWEICLOUD_TTL \
|
|
"$LEGO_BIN" run --path "$LEGO_PATH-staging" --email "$EMAIL" --accept-tos \
|
|
--server "https://acme-staging-v02.api.letsencrypt.org/directory" \
|
|
--dns huaweicloud --dns.propagation.wait 120s --cert.name "$CERT_NAME" --domains "cnnetmkt.top" --domains "*.cnnetmkt.top"; then
|
|
STAGING_STATUS="ok"
|
|
fi
|
|
echo "staging_status=$STAGING_STATUS"
|
|
if [ "$STAGING_STATUS" != "ok" ]; then
|
|
echo "STAGING_DNS01_FAILED"
|
|
exit 20
|
|
fi
|
|
|
|
echo "== production DNS-01 =="
|
|
PROD_STATUS="failed"
|
|
if sudo --preserve-env=HUAWEICLOUD_ACCESS_KEY_ID,HUAWEICLOUD_SECRET_ACCESS_KEY,HUAWEICLOUD_REGION,HUAWEICLOUD_HTTP_TIMEOUT,HUAWEICLOUD_PROPAGATION_TIMEOUT,HUAWEICLOUD_POLLING_INTERVAL,HUAWEICLOUD_TTL \
|
|
"$LEGO_BIN" run --path "$LEGO_PATH" --email "$EMAIL" --accept-tos \
|
|
--dns huaweicloud --dns.propagation.wait 120s --cert.name "$CERT_NAME" --domains "cnnetmkt.top" --domains "*.cnnetmkt.top"; then
|
|
PROD_STATUS="issued"
|
|
else
|
|
sudo --preserve-env=HUAWEICLOUD_ACCESS_KEY_ID,HUAWEICLOUD_SECRET_ACCESS_KEY,HUAWEICLOUD_REGION,HUAWEICLOUD_HTTP_TIMEOUT,HUAWEICLOUD_PROPAGATION_TIMEOUT,HUAWEICLOUD_POLLING_INTERVAL,HUAWEICLOUD_TTL \
|
|
"$LEGO_BIN" run --path "$LEGO_PATH" --email "$EMAIL" --accept-tos \
|
|
--dns huaweicloud --dns.propagation.wait 120s --cert.name "$CERT_NAME" --domains "cnnetmkt.top" --domains "*.cnnetmkt.top" --renew-days 60 --renew-force
|
|
PROD_STATUS="renewed"
|
|
fi
|
|
|
|
echo "== install cert material =="
|
|
sudo mkdir -p "$LIVE_DIR"
|
|
cert_file="$(sudo find "$LEGO_PATH/certificates" -maxdepth 1 -type f -name '*.crt' ! -name '*.issuer.crt' | head -1)"
|
|
key_file="$(sudo find "$LEGO_PATH/certificates" -maxdepth 1 -type f -name '*.key' | head -1)"
|
|
issuer_file="$(sudo find "$LEGO_PATH/certificates" -maxdepth 1 -type f -name '*.issuer.crt' | head -1 || true)"
|
|
test -n "$cert_file"
|
|
test -n "$key_file"
|
|
sudo cp "$key_file" "$LIVE_DIR/privkey.pem"
|
|
if [ -n "${issuer_file:-}" ] && [ -f "$issuer_file" ]; then
|
|
sudo sh -c "cat '$cert_file' '$issuer_file' > '$LIVE_DIR/fullchain.pem'"
|
|
sudo cp "$issuer_file" "$LIVE_DIR/chain.pem"
|
|
else
|
|
sudo cp "$cert_file" "$LIVE_DIR/fullchain.pem"
|
|
fi
|
|
sudo chmod 644 "$LIVE_DIR/fullchain.pem" "$LIVE_DIR/chain.pem" 2>/dev/null || true
|
|
sudo chmod 600 "$LIVE_DIR/privkey.pem"
|
|
|
|
echo "== verify cert material =="
|
|
sudo openssl x509 -in "$LIVE_DIR/fullchain.pem" -noout -subject -issuer -dates -ext subjectAltName
|
|
|
|
echo "== patch nginx cert paths =="
|
|
sudo cp -a /etc/nginx/sites-available/aios-user-portal.conf "$BACKUP_DIR/aios-user-portal.conf"
|
|
sudo cp -a /etc/nginx/sites-available/g-cnnetmkt-gitea.conf "$BACKUP_DIR/g-cnnetmkt-gitea.conf" 2>/dev/null || true
|
|
sudo python3 - <<'PY'
|
|
from pathlib import Path
|
|
|
|
files = [
|
|
Path("/etc/nginx/sites-available/aios-user-portal.conf"),
|
|
Path("/etc/nginx/sites-available/g-cnnetmkt-gitea.conf"),
|
|
]
|
|
for path in files:
|
|
if not path.exists():
|
|
continue
|
|
text = path.read_text()
|
|
text = text.replace(
|
|
"/etc/letsencrypt/live/user.cnnetmkt.top/fullchain.pem",
|
|
"/etc/letsencrypt/live/cnnetmkt-wildcard/fullchain.pem",
|
|
)
|
|
text = text.replace(
|
|
"/etc/letsencrypt/live/user.cnnetmkt.top/privkey.pem",
|
|
"/etc/letsencrypt/live/cnnetmkt-wildcard/privkey.pem",
|
|
)
|
|
path.write_text(text)
|
|
PY
|
|
|
|
sudo nginx -t
|
|
sudo systemctl reload nginx
|
|
|
|
echo "== validation =="
|
|
for h in cnnetmkt.top g.cnnetmkt.top user.cnnetmkt.top portal.cnnetmkt.top; do
|
|
echo "-- $h cert"
|
|
echo | openssl s_client -connect 127.0.0.1:443 -servername "$h" 2>/dev/null \
|
|
| openssl x509 -noout -subject -issuer -dates -ext subjectAltName 2>/dev/null || true
|
|
echo "-- $h /"
|
|
curl -k -sS -D - -o /tmp/cnnetmkt-body --resolve "$h:443:127.0.0.1" "https://$h/" | sed -n '1,12p' || true
|
|
grep -ao '<title>[^<]*' /tmp/cnnetmkt-body 2>/dev/null | head -1 || true
|
|
echo "-- $h /git/"
|
|
curl -k -sS -D - -o /tmp/cnnetmkt-body --resolve "$h:443:127.0.0.1" "https://$h/git/" | sed -n '1,12p' || true
|
|
grep -ao '<title>[^<]*' /tmp/cnnetmkt-body 2>/dev/null | head -1 || true
|
|
done
|
|
|
|
echo "== write renewal helper =="
|
|
sudo tee /usr/local/sbin/renew-cnnetmkt-wildcard.sh >/dev/null <<'SH'
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
ROOT="/data/aios-gitops"
|
|
LEGO_BIN="$ROOT/runtime/bin/lego"
|
|
LEGO_PATH="/etc/letsencrypt/lego-cnnetmkt"
|
|
LIVE_DIR="/etc/letsencrypt/live/cnnetmkt-wildcard"
|
|
ENV_FILE="/etc/letsencrypt/huaweicloud-cnnetmkt.env"
|
|
set -a
|
|
. "$ENV_FILE"
|
|
set +a
|
|
sudo --preserve-env=HUAWEICLOUD_ACCESS_KEY_ID,HUAWEICLOUD_SECRET_ACCESS_KEY,HUAWEICLOUD_REGION,HUAWEICLOUD_HTTP_TIMEOUT,HUAWEICLOUD_PROPAGATION_TIMEOUT,HUAWEICLOUD_POLLING_INTERVAL,HUAWEICLOUD_TTL \
|
|
"$LEGO_BIN" run --path "$LEGO_PATH" --email "admin@cnnetmkt.top" --accept-tos \
|
|
--dns huaweicloud --dns.propagation.wait 120s --cert.name "cnnetmkt-wildcard" --domains "cnnetmkt.top" --domains "*.cnnetmkt.top" --renew-days 45
|
|
cert_file="$(find "$LEGO_PATH/certificates" -maxdepth 1 -type f -name '*.crt' ! -name '*.issuer.crt' | head -1)"
|
|
key_file="$(find "$LEGO_PATH/certificates" -maxdepth 1 -type f -name '*.key' | head -1)"
|
|
cp "$cert_file" "$LIVE_DIR/fullchain.pem"
|
|
cp "$key_file" "$LIVE_DIR/privkey.pem"
|
|
chmod 644 "$LIVE_DIR/fullchain.pem"
|
|
chmod 600 "$LIVE_DIR/privkey.pem"
|
|
nginx -t
|
|
systemctl reload nginx
|
|
SH
|
|
sudo chmod 700 /usr/local/sbin/renew-cnnetmkt-wildcard.sh
|
|
|
|
sudo tee /etc/systemd/system/cnnetmkt-wildcard-renew.service >/dev/null <<'UNIT'
|
|
[Unit]
|
|
Description=Renew cnnetmkt wildcard certificate via Huawei Cloud DNS
|
|
|
|
[Service]
|
|
Type=oneshot
|
|
ExecStart=/usr/local/sbin/renew-cnnetmkt-wildcard.sh
|
|
UNIT
|
|
|
|
sudo tee /etc/systemd/system/cnnetmkt-wildcard-renew.timer >/dev/null <<'UNIT'
|
|
[Unit]
|
|
Description=Daily cnnetmkt wildcard certificate renewal check
|
|
|
|
[Timer]
|
|
OnCalendar=daily
|
|
RandomizedDelaySec=2h
|
|
Persistent=true
|
|
|
|
[Install]
|
|
WantedBy=timers.target
|
|
UNIT
|
|
|
|
sudo systemctl daemon-reload
|
|
sudo systemctl enable --now cnnetmkt-wildcard-renew.timer
|
|
|
|
cat > "$TRACKED" <<EOF_TRACKED
|
|
# cnnetmkt wildcard certificate
|
|
|
|
generated_at=$(date -Is)
|
|
issuer=Let's Encrypt via lego DNS-01 Huawei Cloud
|
|
domains=cnnetmkt.top,*.cnnetmkt.top
|
|
live_dir=$LIVE_DIR
|
|
nginx_sites=/etc/nginx/sites-available/aios-user-portal.conf,/etc/nginx/sites-available/g-cnnetmkt-gitea.conf
|
|
renew_service=cnnetmkt-wildcard-renew.service
|
|
renew_timer=cnnetmkt-wildcard-renew.timer
|
|
secret_env=$ENV_FILE
|
|
backup_dir=$BACKUP_DIR
|
|
status=$PROD_STATUS
|
|
EOF_TRACKED
|
|
|
|
cat > "$REPORT" <<EOF_REPORT
|
|
# CNNETMKT wildcard certificate status
|
|
|
|
generated_at=$(date -Is)
|
|
status=$PROD_STATUS
|
|
staging_status=$STAGING_STATUS
|
|
dns_provider=huaweicloud
|
|
secret_storage=$ENV_FILE
|
|
certificate_live_dir=$LIVE_DIR
|
|
nginx_status=loaded
|
|
backup_dir=$BACKUP_DIR
|
|
renew_timer=cnnetmkt-wildcard-renew.timer
|
|
|
|
## certificate
|
|
|
|
$(sudo openssl x509 -in "$LIVE_DIR/fullchain.pem" -noout -subject -issuer -dates -ext subjectAltName)
|
|
|
|
## routes
|
|
|
|
- https://cnnetmkt.top/
|
|
- https://cnnetmkt.top/git/
|
|
- https://g.cnnetmkt.top/
|
|
- https://g.cnnetmkt.top/git/
|
|
- https://user.cnnetmkt.top/
|
|
EOF_REPORT
|
|
|
|
cd "$WORKSPACE"
|
|
chown -R aiman:aiman "$WORKSPACE/deploy/nginx" "$ROOT/artifacts" "$ROOT/logs"
|
|
runuser -u aiman -- git add deploy/nginx/cnnetmkt-wildcard-certificate.md
|
|
runuser -u aiman -- git commit -m "fix(ingress): switch cnnetmkt to wildcard certificate" || true
|
|
|
|
echo "CNNETMKT_WILDCARD_DONE status=$PROD_STATUS report=$REPORT"
|