- 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
209 lines
6 KiB
Bash
Executable file
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
|