infra/setup
Jeremie Fraeys f0fd9b48d9
refactor(infra): update terraform and setup configurations
- Update terraform main.tf and variables.tf for infrastructure changes
- Modify stackscripts/essentials.sh provisioning
- Adjust setup script for deployment workflow

Note: Includes various infrastructure hardening and configuration updates
2026-03-06 14:27:53 -05:00

209 lines
6 KiB
Bash
Executable file

#! /usr/bin/env bash
set -euo pipefail
vault_args=()
temp_vault_pass_file=""
usage() {
cat <<'EOF'
Usage: ./setup [--no-ansible] [--no-terraform|--ansible-only] [--] [terraform <args>]
Defaults:
- Runs Terraform (plan/apply) in terraform/
- Generates Ansible inventory from Terraform outputs
- Runs Ansible playbooks
Options:
--no-ansible Run Terraform only (no Ansible).
--no-terraform Skip Terraform; requires existing inventory/hosts.yml.
--ansible-only Alias for --no-terraform.
--help Show this help.
Terraform passthrough:
./setup -- terraform <cmd> [args]
./setup -- <terraform-subcommand> [args]
EOF
}
cleanup() {
if [[ -n "${temp_vault_pass_file}" ]] && [[ -f "${temp_vault_pass_file}" ]]; then
rm -f "${temp_vault_pass_file}"
fi
}
trap cleanup EXIT
ansible_extra_args=()
terraform_apply_args=()
terraform_passthrough=()
run_ansible=true
run_terraform=true
if [[ "${1:-}" == "--help" ]] || [[ "${1:-}" == "-h" ]]; then
usage
exit 0
fi
if [[ "${1:-}" == "--no-ansible" ]]; then
run_ansible=false
shift
fi
if [[ "${1:-}" == "--no-terraform" ]] || [[ "${1:-}" == "--ansible-only" ]]; then
run_terraform=false
shift
fi
if [[ "${1:-}" == "--" ]]; then
shift
if [[ "${1:-}" == "terraform" ]]; then
shift
terraform_passthrough=("$@")
else
case "${1:-}" in
output|state|workspace|providers|version|validate|fmt|taint|untaint|graph|show|console|import)
terraform_passthrough=("$@")
;;
*)
terraform_apply_args=("$@")
;;
esac
fi
fi
if [[ -f ".env" ]]; then
set -a
source .env
set +a
fi
if [[ "${run_terraform}" == "true" ]]; then
if ! command -v terraform >/dev/null 2>&1; then
echo "terraform is required (install terraform or run with --no-terraform)" >&2
exit 2
fi
fi
if [[ "${run_ansible}" == "true" ]]; then
if ! command -v ansible-playbook >/dev/null 2>&1; then
echo "ansible-playbook is required (install ansible or run with --no-ansible)" >&2
exit 2
fi
fi
if [[ -f "secrets/vault.yml" ]]; then
if ! command -v ansible-vault >/dev/null 2>&1; then
echo "ansible-vault is required to read secrets/vault.yml" >&2
exit 2
fi
if [[ -f "secrets/.vault_pass" ]]; then
vault_args+=(--vault-password-file "secrets/.vault_pass")
elif [[ -f ".vault_pass" ]]; then
vault_args+=(--vault-password-file ".vault_pass")
else
read -rsp "Vault password: " vault_password
echo
temp_vault_pass_file=$(mktemp)
chmod 600 "${temp_vault_pass_file}"
printf '%s' "${vault_password}" > "${temp_vault_pass_file}"
unset vault_password
vault_args+=(--vault-password-file "${temp_vault_pass_file}")
fi
if (( ${#vault_args[@]} )); then
vault_plain=$(ansible-vault view secrets/vault.yml "${vault_args[@]}")
else
vault_plain=$(ansible-vault view secrets/vault.yml)
fi
while IFS= read -r line; do
[[ -z "${line}" ]] && continue
[[ "${line}" == "---" ]] && continue
[[ "${line}" != TF_VAR_*:* ]] && [[ "${line}" != CF_DNS_API_TOKEN:* ]] && [[ "${line}" != CF_ZONE_API_TOKEN:* ]] && [[ "${line}" != S3_ACCESS_KEY_ID:* ]] && [[ "${line}" != S3_SECRET_ACCESS_KEY:* ]] && continue
key="${line%%:*}"
value="${line#*:}"
value="${value# }"
[[ -z "${value}" ]] && continue
escaped=$(printf '%q' "${value}")
eval "export ${key}=${escaped}"
done <<< "${vault_plain}"
if [[ -z "${TF_VAR_cloudflare_api_token:-}" ]] && [[ -n "${CF_DNS_API_TOKEN:-}" ]]; then
export TF_VAR_cloudflare_api_token="${CF_DNS_API_TOKEN}"
fi
if [[ -z "${TF_VAR_cloudflare_zone_id:-}" ]] && [[ -n "${CF_ZONE_API_TOKEN:-}" ]]; then
export TF_VAR_cloudflare_zone_id="${CF_ZONE_API_TOKEN}"
fi
fi
if [[ "${run_terraform}" == "true" ]]; then
init_args=()
# Only add backend-config args if S3 backend variables are set
if [[ -n "${TF_VAR_tf_state_bucket:-}" ]] && [[ -n "${S3_ACCESS_KEY_ID:-}" ]]; then
init_args+=(-backend-config="bucket=${TF_VAR_tf_state_bucket}")
init_args+=(-backend-config="region=${TF_VAR_tf_state_region:-us-east-1}")
init_args+=(-backend-config="endpoint=${TF_VAR_tf_state_endpoint:-https://us-east-1.linodeobjects.com}")
init_args+=(-backend-config="access_key=${S3_ACCESS_KEY_ID}")
init_args+=(-backend-config="secret_key=${S3_SECRET_ACCESS_KEY}")
# Migrate state from local to S3
init_args+=(-migrate-state)
fi
terraform -chdir=terraform init ${init_args[@]+"${init_args[@]}"}
if (( ${#terraform_passthrough[@]} )); then
terraform -chdir=terraform "${terraform_passthrough[@]}"
exit 0
fi
if (( ${#terraform_apply_args[@]} )); then
terraform -chdir=terraform apply "${terraform_apply_args[@]}"
else
terraform -chdir=terraform plan -out=tfplan
terraform -chdir=terraform apply tfplan
fi
rm -f terraform/tfplan
web_ipv4=$(terraform -chdir=terraform output -raw web_ip)
web_ipv6=$(terraform -chdir=terraform output -raw web_ipv6)
services_ipv4=$(terraform -chdir=terraform output -raw services_ip)
ssh_user=${TF_VAR_user:-ansible}
mkdir -p inventory/host_vars
cat > inventory/hosts.yml <<EOF
all:
children:
web_hosts:
hosts:
web:
ansible_host: ${web_ipv4}
ansible_port: ${TF_VAR_ssh_port:-22}
ansible_user: ${ssh_user}
services_hosts:
hosts:
services:
ansible_host: ${services_ipv4}
ansible_port: ${TF_VAR_ssh_port:-22}
ansible_user: ${ssh_user}
EOF
cat > inventory/host_vars/web.yml <<EOF
public_ipv4: ${web_ipv4}
public_ipv6: ${web_ipv6%%/*}
EOF
else
if [[ ! -f inventory/hosts.yml ]]; then
echo "inventory/hosts.yml is missing; run without --no-terraform at least once to generate it" >&2
exit 2
fi
fi
if [[ "${run_ansible}" == "true" ]]; then
if [[ -n "${vault_args+x}" ]] && (( ${#vault_args[@]} )); then
ansible_extra_args=("${vault_args[@]}")
fi
ansible-playbook playbooks/services.yml ${ansible_extra_args[@]+"${ansible_extra_args[@]}"}
ansible-playbook playbooks/web.yml ${ansible_extra_args[@]+"${ansible_extra_args[@]}"}
fi