Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions terraform/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ terraform.rc
# ========================================
*.tfplan
*tfplan*
plan.out

# ========================================
# SSH Keys and Certificates
Expand Down
44 changes: 0 additions & 44 deletions terraform/.terraform.lock.hcl

This file was deleted.

1 change: 1 addition & 0 deletions terraform/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ module "load_balancer" {
app_name = var.app_name
environment = var.environment
aws_region = var.aws_region
domain_name = var.domain_name
vpc_id = module.networking.vpc_id
public_subnets = module.networking.public_subnets
alb_security_group_id = module.networking.alb_security_group_id
Expand Down
158 changes: 87 additions & 71 deletions terraform/modules/bastion/user_data.sh
Original file line number Diff line number Diff line change
@@ -1,57 +1,90 @@
#!/bin/bash
yum update -y
set -euo pipefail

BOOTSTRAP_SCRIPT="/usr/local/bin/bastion-bootstrap.sh"
LOG_FILE="/var/log/bastion-bootstrap.log"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Remove unused LOG_FILE variable from outer script.

The outer script declares LOG_FILE at line 5 but never uses it—the same variable is re-declared and used inside the bootstrap script. This is dead code and should be removed.

Apply this diff:

 BOOTSTRAP_SCRIPT="/usr/local/bin/bastion-bootstrap.sh"
-LOG_FILE="/var/log/bastion-bootstrap.log"
 
 cat > "$BOOTSTRAP_SCRIPT" <<'SCRIPT'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
LOG_FILE="/var/log/bastion-bootstrap.log"
BOOTSTRAP_SCRIPT="/usr/local/bin/bastion-bootstrap.sh"
cat > "$BOOTSTRAP_SCRIPT" <<'SCRIPT'
🧰 Tools
🪛 Shellcheck (0.11.0)

[warning] 5-5: LOG_FILE appears unused. Verify use (or export if used externally).

(SC2034)

🤖 Prompt for AI Agents
In terraform/modules/bastion/user_data.sh around line 5, the script declares
LOG_FILE="/var/log/bastion-bootstrap.log" but that outer declaration is never
used because the bootstrap script re-declares LOG_FILE; remove this unused OUTER
LOG_FILE assignment (delete the line) so only the bootstrap-local LOG_FILE
remains, and run a quick grep to ensure no other references depend on the
removed variable.


cat > "$BOOTSTRAP_SCRIPT" <<'SCRIPT'
#!/bin/bash
set -euo pipefail

LOG_FILE="/var/log/bastion-bootstrap.log"
exec > >(tee -a "$LOG_FILE") 2>&1

timestamp() {
date -u +"%Y-%m-%dT%H:%M:%SZ"
}

log() {
echo "[$(timestamp)] $*"
}

retry() {
local attempts="$1"
local delay="$2"
shift 2

local n=1
until "$@"; do
if [ "$n" -ge "$attempts" ]; then
log "Command failed after $attempts attempts: $*"
return 1
fi
log "Command failed (attempt $n/$attempts): $*; retrying in $${delay}s"
n=$((n + 1))
sleep "$delay"
done
}

if [ -f /var/log/bastion-bootstrap.done ]; then
log "Bootstrap already completed; exiting"
exit 0
fi

log "Starting bastion bootstrap"

retry 5 30 yum update -y

%{ if install_mysql_client ~}
# Install MySQL client
yum install -y mysql
log "Installing MySQL client"
retry 5 30 yum install -y mysql
%{ endif ~}

%{ if install_redis_client ~}
# Install Redis client
amazon-linux-extras install -y redis6
log "Installing Redis client"
retry 5 30 amazon-linux-extras install -y redis6
%{ endif ~}

# Install useful tools
yum install -y htop nano vim curl wget git unzip jq

# ========================================
# Install AWS CLI v2
# ========================================
cd /tmp
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
./aws/install
rm -rf aws awscliv2.zip

# ========================================
# Install Terraform
# ========================================
log "Installing base utilities"
retry 5 30 yum install -y htop nano vim curl wget git unzip jq

log "Installing AWS CLI v2"
retry 5 30 bash -c 'cd /tmp && curl -sSL "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o awscliv2.zip'
retry 5 30 bash -c 'cd /tmp && unzip -o awscliv2.zip'
retry 5 30 bash -c 'cd /tmp && ./aws/install'
rm -rf /tmp/aws /tmp/awscliv2.zip

log "Installing Terraform"
TERRAFORM_VERSION="1.10.5"
cd /tmp
wget "https://releases.hashicorp.com/terraform/$${TERRAFORM_VERSION}/terraform_$${TERRAFORM_VERSION}_linux_amd64.zip"
unzip "terraform_$${TERRAFORM_VERSION}_linux_amd64.zip"
mv terraform /usr/local/bin/
rm "terraform_$${TERRAFORM_VERSION}_linux_amd64.zip"
retry 5 30 bash -c "cd /tmp && wget -q \"https://releases.hashicorp.com/terraform/$${TERRAFORM_VERSION}/terraform_$${TERRAFORM_VERSION}_linux_amd64.zip\""
retry 5 30 bash -c "cd /tmp && unzip -o \"terraform_$${TERRAFORM_VERSION}_linux_amd64.zip\""
mv /tmp/terraform /usr/local/bin/
rm -f /tmp/terraform_$${TERRAFORM_VERSION}_linux_amd64.zip
chmod +x /usr/local/bin/terraform

# ========================================
# Install Docker
# ========================================
amazon-linux-extras install -y docker
log "Installing Docker engine"
retry 5 30 amazon-linux-extras install -y docker
systemctl start docker
systemctl enable docker

# Add ec2-user to docker group
usermod -aG docker ec2-user

# Install Docker Compose
log "Installing Docker Compose"
DOCKER_COMPOSE_VERSION="2.34.1"
curl -L "https://github.com/docker/compose/releases/download/v$${DOCKER_COMPOSE_VERSION}/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
retry 5 30 curl -sSL "https://github.com/docker/compose/releases/download/v$${DOCKER_COMPOSE_VERSION}/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
ln -sf /usr/local/bin/docker-compose /usr/bin/docker-compose

# Create a welcome message
cat > /etc/motd << 'EOF'
cat > /etc/motd <<'MOTD'
=================================
Bastion Host
=================================
Expand All @@ -67,74 +100,57 @@ Installed Tools:

Use SSH tunneling to connect to private resources.
=================================
EOF
MOTD

%{ if setup_mysql_user ~}
# ========================================
# Setup MySQL Application User
# ========================================
echo "Setting up MySQL application user..." >> /var/log/bastion-setup.log

# Wait for instance profile and AWS CLI to be ready
log "Configuring MySQL users"
sleep 30

# Get the master password from Secrets Manager
MASTER_PASSWORD=$(aws secretsmanager get-secret-value \
--secret-id "${rds_master_password_secret_arn}" \
--region "${aws_region}" \
--query 'SecretString' \
--output text | jq -r '.password')

if [ -z "$MASTER_PASSWORD" ]; then
echo "ERROR: Failed to retrieve master password from Secrets Manager" >> /var/log/bastion-setup.log
log "ERROR: Failed to retrieve master password from Secrets Manager"
exit 1
fi

# Wait for RDS to be available
echo "Waiting for RDS to be available..." >> /var/log/bastion-setup.log
for i in {1..30}; do
for i in $(seq 1 30); do
if mysql -h "${rds_endpoint}" -u "${rds_master_username}" -p"$MASTER_PASSWORD" -e "SELECT 1;" 2>/dev/null; then
echo "RDS is ready" >> /var/log/bastion-setup.log
log "RDS is ready"
break
fi
echo "Waiting for RDS... attempt $i/30" >> /var/log/bastion-setup.log
log "Waiting for RDS... attempt $i/30"
sleep 10
done

# Create application database user with limited privileges
echo "Creating application user '${app_db_username}'..." >> /var/log/bastion-setup.log

mysql -h "${rds_endpoint}" -u "${rds_master_username}" -p"$MASTER_PASSWORD" <<MYSQL_SCRIPT
-- Create the application user if it doesn't exist
CREATE USER IF NOT EXISTS '${app_db_username}'@'%' IDENTIFIED BY '${app_db_password}';

-- Grant necessary privileges for Laravel (migrations, CRUD operations)
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER,
CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW,
SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, TRIGGER, REFERENCES
ON \`${rds_database_name}\`.* TO '${app_db_username}'@'%';

-- Create read-only reporting user
CREATE USER IF NOT EXISTS 'reporting'@'%' IDENTIFIED BY '${db_reporting_password}';

-- Grant read-only privileges for reporting
GRANT SELECT, SHOW VIEW ON \`${rds_database_name}\`.* TO 'reporting'@'%';

-- Flush privileges
FLUSH PRIVILEGES;

-- Verify users were created
SELECT User, Host FROM mysql.user WHERE User IN ('${app_db_username}', 'reporting');
MYSQL_SCRIPT

if [ $? -eq 0 ]; then
echo "MySQL application and reporting users created successfully" >> /var/log/bastion-setup.log
MYSQL_EXIT_CODE=$?
unset MASTER_PASSWORD

if [ "$MYSQL_EXIT_CODE" -eq 0 ]; then
log "MySQL application and reporting users created successfully"
else
echo "ERROR: Failed to create MySQL users" >> /var/log/bastion-setup.log
log "ERROR: Failed to create MySQL users"
fi

# Clear the password from memory
unset MASTER_PASSWORD
%{ endif ~}

echo "Bastion host setup completed" > /var/log/bastion-setup.log
touch /var/log/bastion-bootstrap.done
log "Bastion bootstrap completed"
SCRIPT

chmod +x "$BOOTSTRAP_SCRIPT"
nohup "$BOOTSTRAP_SCRIPT" >/dev/null 2>&1 &
9 changes: 9 additions & 0 deletions terraform/modules/compute/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,15 @@ resource "aws_ecs_service" "main" {
container_port = 80
}

# Deployment configuration to minimize ENI requirements during rolling updates
deployment_minimum_healthy_percent = 50
deployment_maximum_percent = 100

deployment_circuit_breaker {
enable = true
rollback = true
}

# Give Laravel time to boot before health checks start
health_check_grace_period_seconds = 120

Expand Down
13 changes: 13 additions & 0 deletions terraform/modules/dns/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,19 @@ resource "aws_route53_record" "wildcard" {
}
}

# WWW subdomain A record (for www to non-www redirect)
resource "aws_route53_record" "www" {
zone_id = var.route53_zone_id
name = "www.${var.domain_name}"
type = "A"

alias {
name = var.alb_dns_name
zone_id = var.alb_zone_id
evaluate_target_health = true
}
}

# DMARC record (only created if dmarc_record is set)
resource "aws_route53_record" "dmarc" {
count = var.dmarc_record != "" ? 1 : 0
Expand Down
Loading