#!/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 </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 </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