Some checks failed
Architecture Governance / architecture (push) Failing after 6m16s
Reconcile TLS, exact CORS, and backend proxying before release activation so every storefront uses its derived API host.
108 lines
3.6 KiB
Bash
Executable File
108 lines
3.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Configure api.<storefront-domain> as the TLS/CORS reverse proxy for one tenant.
|
|
# Idempotent. Run as root after both storefront and API DNS records resolve here.
|
|
|
|
set -euo pipefail
|
|
|
|
DOMAIN=""
|
|
EMAIL=""
|
|
UPSTREAM="https://127.0.0.1:445"
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--domain) DOMAIN="$2"; shift 2 ;;
|
|
--email) EMAIL="$2"; shift 2 ;;
|
|
--upstream) UPSTREAM="$2"; shift 2 ;;
|
|
*) echo "unknown argument: $1" >&2; exit 2 ;;
|
|
esac
|
|
done
|
|
|
|
[[ $EUID -eq 0 ]] || { echo "must run as root" >&2; exit 1; }
|
|
[[ "$DOMAIN" =~ ^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$ ]] || {
|
|
echo "--domain must be a valid lowercase hostname" >&2; exit 2;
|
|
}
|
|
[[ "$EMAIL" =~ ^[^[:space:]@]+@[^[:space:]@]+\.[^[:space:]@]+$ ]] || {
|
|
echo "--email must be valid" >&2; exit 2;
|
|
}
|
|
[[ "$UPSTREAM" =~ ^https?://[a-zA-Z0-9.:-]+$ ]] || {
|
|
echo "--upstream must be an http(s) origin without a path" >&2; exit 2;
|
|
}
|
|
|
|
API_DOMAIN="api.$DOMAIN"
|
|
CONF="/etc/nginx/sites-available/$API_DOMAIN"
|
|
|
|
echo "==> checking DNS for $API_DOMAIN"
|
|
getent hosts "$API_DOMAIN" >/dev/null || {
|
|
echo "ERROR: $API_DOMAIN does not resolve; create DNS before provisioning TLS" >&2
|
|
exit 1
|
|
}
|
|
|
|
cat > "$CONF" <<NGINX
|
|
# Managed by marketplaces configure-api-domain.sh. Manual edits are overwritten.
|
|
# Storefront $DOMAIN derives this API origin as https://$API_DOMAIN.
|
|
server {
|
|
listen 80;
|
|
listen [::]:80;
|
|
server_name $API_DOMAIN;
|
|
|
|
access_log /var/log/nginx/$API_DOMAIN.access.log;
|
|
error_log /var/log/nginx/$API_DOMAIN.error.log;
|
|
|
|
set \$cors_origin "";
|
|
if (\$http_origin = "https://$DOMAIN") { set \$cors_origin \$http_origin; }
|
|
|
|
add_header Access-Control-Allow-Origin \$cors_origin always;
|
|
add_header Access-Control-Allow-Credentials "true" always;
|
|
add_header Access-Control-Allow-Methods "GET, POST, PUT, PATCH, DELETE, OPTIONS" always;
|
|
add_header Access-Control-Allow-Headers "Authorization, Content-Type, AdminWebSessionID, X-Requested-With" always;
|
|
add_header Vary "Origin" always;
|
|
|
|
if (\$request_method = OPTIONS) { return 204; }
|
|
|
|
location / {
|
|
proxy_pass $UPSTREAM;
|
|
proxy_http_version 1.1;
|
|
# Keep the existing backend compatible: it already serves this tenant
|
|
# when the storefront Host reaches :445. The original public API host
|
|
# remains available in the trusted forwarding headers below.
|
|
proxy_set_header Host $DOMAIN;
|
|
proxy_set_header X-Forwarded-Host $API_DOMAIN;
|
|
proxy_set_header X-Storefront-Host $DOMAIN;
|
|
proxy_set_header X-Real-IP \$remote_addr;
|
|
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto https;
|
|
proxy_read_timeout 60s;
|
|
proxy_connect_timeout 10s;
|
|
|
|
proxy_ssl_server_name on;
|
|
proxy_ssl_name $DOMAIN;
|
|
}
|
|
}
|
|
NGINX
|
|
|
|
ln -sfn "$CONF" "/etc/nginx/sites-enabled/$API_DOMAIN"
|
|
nginx -t
|
|
|
|
certbot --nginx -d "$API_DOMAIN" \
|
|
--non-interactive --agree-tos --email "$EMAIL" \
|
|
--redirect --keep-until-expiring
|
|
|
|
nginx -t
|
|
systemctl reload nginx
|
|
|
|
echo "==> verifying https://$API_DOMAIN/bootstrap"
|
|
bootstrap_tmp="$(mktemp)"
|
|
trap 'rm -f "$bootstrap_tmp"' EXIT
|
|
content_type="$(curl --resolve "$API_DOMAIN:443:127.0.0.1" -fsS \
|
|
-o "$bootstrap_tmp" -w '%{content_type}' \
|
|
"https://$API_DOMAIN/bootstrap")"
|
|
[[ "$content_type" == application/json* ]] || {
|
|
echo "ERROR: $API_DOMAIN/bootstrap returned $content_type, expected application/json" >&2
|
|
exit 1
|
|
}
|
|
jq -e 'type == "object"' "$bootstrap_tmp" >/dev/null
|
|
rm -f "$bootstrap_tmp"
|
|
trap - EXIT
|
|
|
|
echo "configured: $DOMAIN -> https://$API_DOMAIN -> $UPSTREAM"
|