mirror of
https://github.com/Sea-Haven-Industries/seahaven-site.git
synced 2026-09-30 06:33:16 +00:00
Some checks are pending
Deploy / deploy (push) Waiting to run
* feat(infra): add HCP Terraform for prod static hosting Greenfield S3+CloudFront+ACM+OIDC content-deploy role under /tf-managed/, with OOB mgmt DNS helper for ACM validation and apex alias cutover. * chore(security): suppress pre-existing js-yaml npm audit * feat(ci): retarget content deploy to seahaven-prod origin Point OIDC, S3 sync, and CloudFront invalidation at the HCP-managed prod hosting stack so GHA remains the content publish path after cutover.
143 lines
6.1 KiB
Bash
Executable file
143 lines
6.1 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
###############################################################################
|
|
# setup_seahaven_site_domain.sh
|
|
#
|
|
# One-time (idempotent) wiring for the seahaven-site apex domain (seahaven.com).
|
|
# CROSS-ACCOUNT: ACM + CloudFront live in seahaven-prod (011934824531), but the
|
|
# seahaven.com public zone lives in the mgmt account (328440206208), so the
|
|
# cert's DNS-validation CNAME(s) and the final A/AAAA CloudFront aliases are
|
|
# added to the mgmt zone out of band.
|
|
#
|
|
# Order of operations:
|
|
# 1. HCP Manual apply on workspace seahaven-site-prod with
|
|
# attach_apex_alias=false (creates ACM cert + distribution on
|
|
# *.cloudfront.net + origin + githubdeploy role).
|
|
# 2. ./scripts/setup_seahaven_site_domain.sh cert
|
|
# - reads ACM validation CNAMEs for seahaven.com in prod
|
|
# - upserts them in the mgmt seahaven.com zone
|
|
# - waits for ISSUED
|
|
# 3. Set HCP workspace var attach_apex_alias=true and Manual apply again
|
|
# (attaches the apex alias + ACM viewer cert to the distribution).
|
|
# 4. Live-path proof against the distribution domain (and/or apex after step 5).
|
|
# 5. ./scripts/setup_seahaven_site_domain.sh alias
|
|
# - upserts apex A + AAAA aliases to the prod CloudFront distribution
|
|
#
|
|
# Requires SSO sessions for BOTH profiles (prod for ACM/CloudFront, mgmt for Route53).
|
|
###############################################################################
|
|
set -euo pipefail
|
|
|
|
DOMAIN="seahaven.com"
|
|
REGION="us-east-1"
|
|
PROD_PROFILE="${PROD_PROFILE:-seahaven-prod}"
|
|
MGMT_PROFILE="${MGMT_PROFILE:-seahaven-mgmt}"
|
|
PROD_ACCOUNT="011934824531"
|
|
MGMT_ACCOUNT="328440206208"
|
|
ZONE_ID="Z06652411XKH89KTZD3XA" # seahaven.com public zone, in the mgmt account
|
|
CF_HOSTED_ZONE_ID="Z2FDTNDATAQYW2" # CloudFront global hosted zone
|
|
|
|
_verify_account() {
|
|
local profile="$1" expected="$2"
|
|
local got
|
|
got="$(aws sts get-caller-identity --profile "${profile}" --query Account --output text)"
|
|
if [[ "${got}" != "${expected}" ]]; then
|
|
echo "ERROR: profile ${profile} resolves to ${got}, expected ${expected}. Aborting." >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
_find_cert_arn() {
|
|
aws acm list-certificates --profile "${PROD_PROFILE}" --region "${REGION}" \
|
|
--query "CertificateSummaryList[?DomainName=='${DOMAIN}'].CertificateArn | [0]" \
|
|
--output text
|
|
}
|
|
|
|
cmd_cert() {
|
|
_verify_account "${PROD_PROFILE}" "${PROD_ACCOUNT}"
|
|
_verify_account "${MGMT_PROFILE}" "${MGMT_ACCOUNT}"
|
|
|
|
local cert_arn
|
|
cert_arn="$(_find_cert_arn)"
|
|
if [[ "${cert_arn}" == "None" || -z "${cert_arn}" ]]; then
|
|
echo "ERROR: no ACM cert for ${DOMAIN} in ${PROD_ACCOUNT}. HCP-apply seahaven-site-prod first." >&2
|
|
exit 1
|
|
fi
|
|
echo "==> Using cert ${cert_arn}"
|
|
|
|
echo "==> Reading DNS-validation record(s)"
|
|
local rec_count
|
|
rec_count="$(aws acm describe-certificate --profile "${PROD_PROFILE}" --region "${REGION}" \
|
|
--certificate-arn "${cert_arn}" \
|
|
--query "length(Certificate.DomainValidationOptions[].ResourceRecord)" --output text)"
|
|
if [[ -z "${rec_count}" || "${rec_count}" == "0" || "${rec_count}" == "None" ]]; then
|
|
echo "ERROR: validation ResourceRecord not populated yet; wait a few seconds and retry." >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "==> Upserting validation CNAME(s) in the mgmt seahaven.com zone"
|
|
local name value type
|
|
while IFS=$'\t' read -r name type value; do
|
|
[[ -z "${name}" || "${name}" == "None" ]] && continue
|
|
echo " ${name} (${type}) -> ${value}"
|
|
aws route53 change-resource-record-sets --profile "${MGMT_PROFILE}" \
|
|
--hosted-zone-id "${ZONE_ID}" --change-batch "$(cat <<JSON
|
|
{"Changes":[{"Action":"UPSERT","ResourceRecordSet":{
|
|
"Name":"${name}","Type":"${type}","TTL":300,
|
|
"ResourceRecords":[{"Value":"${value}"}]}}]}
|
|
JSON
|
|
)" >/dev/null
|
|
done < <(aws acm describe-certificate --profile "${PROD_PROFILE}" --region "${REGION}" \
|
|
--certificate-arn "${cert_arn}" \
|
|
--query "Certificate.DomainValidationOptions[].ResourceRecord.[Name,Type,Value]" \
|
|
--output text)
|
|
|
|
echo "==> Waiting for cert to reach ISSUED (can take a few minutes)"
|
|
aws acm wait certificate-validated --profile "${PROD_PROFILE}" --region "${REGION}" \
|
|
--certificate-arn "${cert_arn}"
|
|
|
|
echo "OK: cert ISSUED. Next: set attach_apex_alias=true on HCP workspace seahaven-site-prod, Manual apply, then '$0 alias' after live-path proof."
|
|
}
|
|
|
|
cmd_alias() {
|
|
_verify_account "${PROD_PROFILE}" "${PROD_ACCOUNT}"
|
|
_verify_account "${MGMT_PROFILE}" "${MGMT_ACCOUNT}"
|
|
|
|
echo "==> Finding CloudFront distribution with alias ${DOMAIN} (or comment seahaven-site-prod)"
|
|
local dist_id domain
|
|
dist_id="$(aws cloudfront list-distributions --profile "${PROD_PROFILE}" \
|
|
--query "DistributionList.Items[?Comment=='Sea Haven marketing site (seahaven-site-prod)'].Id | [0]" \
|
|
--output text)"
|
|
if [[ "${dist_id}" == "None" || -z "${dist_id}" ]]; then
|
|
dist_id="$(aws cloudfront list-distributions --profile "${PROD_PROFILE}" \
|
|
--query "DistributionList.Items[?contains(Aliases.Items, '${DOMAIN}')].Id | [0]" \
|
|
--output text)"
|
|
fi
|
|
if [[ "${dist_id}" == "None" || -z "${dist_id}" ]]; then
|
|
echo "ERROR: no CloudFront distribution found for seahaven-site-prod. HCP-apply first." >&2
|
|
exit 1
|
|
fi
|
|
domain="$(aws cloudfront get-distribution --profile "${PROD_PROFILE}" --id "${dist_id}" \
|
|
--query "Distribution.DomainName" --output text)"
|
|
echo " distribution ${dist_id} -> ${domain}"
|
|
|
|
echo "==> Upserting A + AAAA aliases ${DOMAIN} -> ${domain} in the mgmt zone"
|
|
aws route53 change-resource-record-sets --profile "${MGMT_PROFILE}" \
|
|
--hosted-zone-id "${ZONE_ID}" --change-batch "$(cat <<JSON
|
|
{"Changes":[
|
|
{"Action":"UPSERT","ResourceRecordSet":{
|
|
"Name":"${DOMAIN}","Type":"A",
|
|
"AliasTarget":{"DNSName":"${domain}","HostedZoneId":"${CF_HOSTED_ZONE_ID}","EvaluateTargetHealth":false}}},
|
|
{"Action":"UPSERT","ResourceRecordSet":{
|
|
"Name":"${DOMAIN}","Type":"AAAA",
|
|
"AliasTarget":{"DNSName":"${domain}","HostedZoneId":"${CF_HOSTED_ZONE_ID}","EvaluateTargetHealth":false}}}
|
|
]}
|
|
JSON
|
|
)" >/dev/null
|
|
|
|
echo "OK: apex aliases set. Verify: curl -sS -o /dev/null -w '%{http_code}\\n' https://${DOMAIN}/ (expect 200)."
|
|
}
|
|
|
|
case "${1:-}" in
|
|
cert) cmd_cert ;;
|
|
alias) cmd_alias ;;
|
|
*) echo "usage: $0 {cert|alias}" >&2; exit 2 ;;
|
|
esac
|