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
4 changes: 2 additions & 2 deletions .devcontainer/onCreate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://
sudo apt update
sudo apt-get install -y terraform

# Install Azure CLI
# Install AWS CLI
# TODO move this into base image
sudo apt-get install -y azure-cli
sudo apt-get install -y awscli
131 changes: 47 additions & 84 deletions .github/workflows/build_deploy_and_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,76 +69,32 @@ jobs:
build_for_aws:
name: Build for AWS
runs-on: ubuntu-latest
if: false
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub container registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ github.token }}
- name: Lowercase the repo name and username
run: echo "REPO=${GITHUB_REPOSITORY,,}" >>${GITHUB_ENV}
- name: Build and push container image to registry
uses: docker/build-push-action@v6
with:
push: true
tags: |
ghcr.io/${{ env.REPO }}-aws:${{ github.sha }}
ghcr.io/${{ env.REPO }}-aws:latest
file: ./Dockerfile
build-args: |
MYSQL_HOST=${{ vars.AWS_MYSQL_HOST }}
MYSQL_TCP_PORT=${{ vars.AWS_MYSQL_TCP_PORT }}
MYSQL_USER=${{ vars.AWS_MYSQL_USER }}
MYSQL_PASSWORD=${{ secrets.AWS_MYSQL_PASSWORD }}
MYSQL_DATABASE=${{ vars.AWS_MYSQL_DATABASE }}
REDIS_HOST=${{ vars.AWS_REDIS_HOST }}
REDIS_AUTH=${{ secrets.AWS_REDIS_AUTH }}
HASH_SALT=${{ secrets.AWS_HASH_SALT }}

build_for_azure:
name: Build for Azure
runs-on: ubuntu-latest
if: github.ref_name == 'main'
permissions:
contents: read
packages: write
id-token: write
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub container registry
uses: docker/login-action@v3
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ vars.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
- name: Log in to Amazon ECR
uses: aws-actions/amazon-ecr-login@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ github.token }}
- name: Lowercase the repo name and username
run: echo "REPO=${GITHUB_REPOSITORY,,}" >>${GITHUB_ENV}
- name: Build and push container image to registry
mask-password: 'true'
- name: Build and push container image to ECR
uses: docker/build-push-action@v6
with:
push: true
tags: |
ghcr.io/${{ env.REPO }}-azure:${{ github.sha }}
ghcr.io/${{ env.REPO }}-azure:latest
${{ vars.ECR_REPOSITORY_URL }}:${{ github.sha }}
${{ vars.ECR_REPOSITORY_URL }}:latest
file: ./Dockerfile
build-args: |
MYSQL_HOST=${{ vars.AZURE_MYSQL_HOST }}
MYSQL_TCP_PORT=${{ vars.AZURE_MYSQL_TCP_PORT }}
MYSQL_USER=${{ vars.AZURE_MYSQL_USER }}
MYSQL_PASSWORD=${{ secrets.AZURE_MYSQL_PASSWORD }}
MYSQL_DATABASE=${{ vars.AZURE_MYSQL_DATABASE }}
REDIS_HOST=${{ vars.AZURE_REDIS_HOST }}
REDIS_AUTH=${{ secrets.AZURE_REDIS_AUTH }}
HASH_SALT=${{ secrets.AZURE_HASH_SALT }}

lint:
name: Check lint
Expand Down Expand Up @@ -312,36 +268,43 @@ jobs:
if: github.ref_name == 'main'
runs-on: ubuntu-latest
needs: [build_for_aws]
permissions:
contents: read
steps:
- name: Deploy to AWS
run: echo "Hello, world!"

deploy_to_azure:
name: Deploy to Azure
if: github.ref_name == 'main'
runs-on: ubuntu-latest
needs: [build_for_azure]
environment:
name: 'Development'
url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
steps:
- name: Lowercase the repo name and username
run: echo "REPO=${GITHUB_REPOSITORY,,}" >>${GITHUB_ENV}
- name: Deploy to Azure Web App
id: deploy-to-webapp
uses: azure/webapps-deploy@v2
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
app-name: ${{ env.AZURE_WEBAPP_NAME }}
publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }}
images: 'ghcr.io/${{ env.REPO }}-azure:${{ github.sha }}'
- name: Drush deploy
aws-access-key-id: ${{ vars.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
- name: Update ECS service with new image
run: |
az webapp create-remote-connection \
--resource-group drupal-example-stirred-dove \
--name drupal-example-precious-seasnail \
--port 16385 &
sleep 30
sshpass -pDocker\! ssh root@127.0.0.1 -m hmac-sha1 -p 16385 -o "StrictHostKeyChecking no" /var/www/vendor/bin/drush deploy
# Get the current task definition
TASK_DEF=$(aws ecs describe-task-definition \
--task-definition ${{ vars.AWS_ECS_TASK_DEFINITION }} \
--region ${{ vars.AWS_REGION }} \
--query 'taskDefinition' --output json)

# Update the image in the task definition
NEW_TASK_DEF=$(echo "$TASK_DEF" | jq \
--arg IMAGE "${{ vars.ECR_REPOSITORY_URL }}:${{ github.sha }}" \
'.containerDefinitions[0].image = $IMAGE |
del(.taskDefinitionArn, .revision, .status, .requiresAttributes, .compatibilities, .registeredAt, .registeredBy)')

# Register the new task definition
NEW_TASK_DEF_ARN=$(aws ecs register-task-definition \
--region ${{ vars.AWS_REGION }} \
--cli-input-json "$(echo "$NEW_TASK_DEF" | jq -c .)" \
--query 'taskDefinition.taskDefinitionArn' \
--output text)

# Update the ECS service to use the new task definition
aws ecs update-service \
--cluster ${{ vars.AWS_ECS_CLUSTER }} \
--service ${{ vars.AWS_ECS_SERVICE }} \
--task-definition "$NEW_TASK_DEF_ARN" \
--region ${{ vars.AWS_REGION }} \
--force-new-deployment

e2e_test:
name: Feature tests
Expand Down
14 changes: 1 addition & 13 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
# check=skip=SecretsUsedInArgOrEnv

FROM ghcr.io/uceap/devcontainer-drupal:v2.3.0

# Install SSH server
Expand All @@ -12,23 +10,13 @@ RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
COPY docker-uceap-entrypoint /usr/local/bin/docker-uceap-entrypoint
ENTRYPOINT ["docker-uceap-entrypoint"]

ARG MYSQL_HOST
ARG MYSQL_TCP_PORT
ARG MYSQL_USER
ARG MYSQL_PASSWORD
ARG MYSQL_DATABASE
ARG REDIS_HOST
ARG REDIS_AUTH
ARG HASH_SALT

COPY build /var/www/build
COPY config /var/www/config
COPY composer.json /var/www/
COPY web /var/www/web

WORKDIR /var/www

RUN composer initialize-container && \
composer install --no-dev --no-interaction --no-progress --optimize-autoloader && \
RUN composer install --no-dev --no-interaction --no-progress --optimize-autoloader && \
sed -i 's-/var/www/html-/var/www/web-' /etc/apache2/sites-available/*.conf && \
sed -i 's/# Listen\s*80$/Listen 80/' /etc/apache2/ports.conf
4 changes: 4 additions & 0 deletions docker-uceap-entrypoint
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
#!/bin/sh
set -e

# Initialize Drupal container with runtime environment variables
# This runs at container startup with secrets from AWS Secrets Manager
cd /var/www && composer initialize-container

service ssh start

exec apache2-foreground
68 changes: 68 additions & 0 deletions terraform/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

86 changes: 86 additions & 0 deletions terraform/CIDR_ALLOCATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# CIDR Allocation Registry

## 10.0.0.0/8 - Internal Infrastructure Space

This document tracks IP address allocation for all internal applications and infrastructure.

## CIDR Block Allocation

| CIDR Block | Purpose | Status | Notes |
|-----------------|----------------------------------|----------|-------|
| 10.0.0.0/16 | Shared Services (Reserved) | Reserved | VPN, monitoring, shared infrastructure |
| 10.1.0.0/16 - 10.100.0.0/16 | Additional shared infrastructure | Reserved | Future use |
| 10.101.0.0/16 | drupal-example (app_number=101) | Active | Drupal CMS application |
| 10.102.0.0/16 | (Next app, app_number=102) | Available | |
| 10.103.0.0/16 | (Next app, app_number=103) | Available | |
| ... | ... | Available | |
| 10.254.0.0/16 | (Last app, app_number=254) | Available | |

## Application VPC Subnet Structure

Each application VPC uses a consistent internal structure for predictable IP allocation.

### Example: drupal-example (10.101.0.0/16)

| CIDR Block | Tier | AZ | Use Case | Hosts | Gateway |
|-----------------|----------|--------|----------------|-------|---------|
| 10.101.0.0/24 | Public | us-west-2a | ALB | ~254 | IGW |
| 10.101.1.0/24 | Public | us-west-2b | ALB (HA) | ~254 | IGW |
| 10.101.10.0/24 | Private | us-west-2a | ECS Tasks | ~254 | NAT-GW |
| 10.101.11.0/24 | Private | us-west-2b | ECS Tasks (HA) | ~254 | NAT-GW |
| 10.101.20.0/24 | Database | us-west-2a | RDS/Redis | ~254 | None |
| 10.101.21.0/24 | Database | us-west-2b | RDS/Redis (HA) | ~254 | None |

### Template for New Apps

When deploying a new application, use this template with your assigned `app_number`:

| CIDR Block | Tier | AZ | Use Case |
|---------------------|----------|--------|----------------|
| 10.{app_number}.0.0/24 | Public | AZ1 | Load Balancer |
| 10.{app_number}.1.0/24 | Public | AZ2 | Load Balancer |
| 10.{app_number}.10.0/24 | Private | AZ1 | Application |
| 10.{app_number}.11.0/24 | Private | AZ2 | Application |
| 10.{app_number}.20.0/24 | Database | AZ1 | Data Layer |
| 10.{app_number}.21.0/24 | Database | AZ2 | Data Layer |

## Network Tiers

### Public Tier (X.0.0/24, X.1.0/24)
- Internet-facing resources (ALB, NAT gateways)
- Ingress from internet allowed
- Routed through Internet Gateway

### Private Tier (X.10.0/24, X.11.0/24)
- Application compute (ECS tasks)
- No direct internet access
- Egress through NAT Gateway for outbound internet access
- Ingress only from ALB

### Database Tier (X.20.0/24, X.21.0/24)
- Data layer resources (RDS, ElastiCache)
- No internet access
- Ingress only from application tier
- No outbound internet access

## Deployment Instructions

To deploy a new application with this convention:

1. **Assign an app_number**: Choose a number between 101-254 (update this registry first)
2. **Update this registry**: Add the app and its status
3. **Deploy with Terraform**:
```bash
terraform apply -var="app_number=101" # For drupal-example
terraform apply -var="app_number=102" # For next app
```

4. **Verify CIDR blocks** in AWS console match expected values

## Benefits

- **Predictable**: Each app's CIDR space is deterministic and easy to calculate
- **Readable**: Simple numeric offsets (0, 1, 10, 11, 20, 21) are easy to remember
- **Scalable**: Supports up to 154 applications
- **Reserved**: Lower CIDR space (10.0-10.100) reserved for shared infrastructure
- **Non-overlapping**: Each app completely isolated in its own /16
Loading
Loading