Skip to content
Open
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
139 changes: 139 additions & 0 deletions .github/workflows/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
# GitHub Actions Workflows

This directory contains GitHub Actions workflows for automated infrastructure deployment and management.

## Terraform DigitalOcean Infrastructure Workflow

The `terraform-digitalocean.yml` workflow provides manual deployment of infrastructure to DigitalOcean using Terraform.

### Features

- **Manual Trigger**: Workflow can be triggered manually with customizable parameters
- **Multiple Environments**: Support for dev, staging, and production environments
- **Multiple Regions**: Support for all major DigitalOcean regions
- **Security Scanning**: Integrated Trivy vulnerability scanning
- **Plan Review**: Terraform plans are uploaded as artifacts and commented on issues
- **Comprehensive Logging**: Detailed logging and notification system

### Prerequisites

1. **DigitalOcean API Token**: You need a DigitalOcean API token with appropriate permissions
2. **GitHub Secrets**: Configure the following secrets in your GitHub repository:
- `DIGITALOCEAN_TOKEN`: Your DigitalOcean API token

### Setup Instructions

1. **Create DigitalOcean API Token**:
- Go to [DigitalOcean API Tokens](https://cloud.digitalocean.com/account/api/tokens)
- Click "Generate New Token"
- Give it a name (e.g., "GitHub Actions Terraform")
- Select "Write" scope
- Copy the token

2. **Add GitHub Secret**:
- Go to your GitHub repository
- Navigate to Settings → Secrets and variables → Actions
- Click "New repository secret"
- Name: `DIGITALOCEAN_TOKEN`
- Value: Paste your DigitalOcean API token

### Usage

1. **Trigger the Workflow**:
- Go to the "Actions" tab in your GitHub repository
- Select "Terraform DigitalOcean Infrastructure"
- Click "Run workflow"

2. **Configure Parameters**:
- **Environment**: Choose dev, staging, or prod
- **Action**: Choose plan, apply, or destroy
- **Region**: Select your preferred DigitalOcean region
- **Domain Name**: (Optional) Enter your domain for production

3. **Workflow Actions**:
- **Plan**: Creates a Terraform plan without applying changes
- **Apply**: Applies the Terraform configuration to create/update infrastructure
- **Destroy**: Removes all infrastructure (use with caution)

### Workflow Steps

1. **Checkout**: Downloads the repository code
2. **Setup Terraform**: Installs Terraform with the specified version
3. **Format Check**: Validates Terraform code formatting
4. **Init**: Initializes Terraform working directory
5. **Validate**: Validates Terraform configuration
6. **Plan**: Creates execution plan (for plan/apply actions)
7. **Apply/Destroy**: Executes Terraform commands
8. **Security Scan**: Runs Trivy vulnerability scanner
9. **Notify**: Provides status notifications

### Security Features

- **Secret Management**: Uses GitHub secrets for sensitive data
- **Vulnerability Scanning**: Integrated Trivy scanner for security issues
- **Plan Review**: Plans are saved as artifacts for review
- **Environment Isolation**: Separate configurations for different environments

### Supported DigitalOcean Regions

- `nyc1` - New York 1
- `nyc3` - New York 3
- `sfo2` - San Francisco 2
- `sfo3` - San Francisco 3
- `ams2` - Amsterdam 2
- `ams3` - Amsterdam 3
- `fra1` - Frankfurt 1
- `lon1` - London 1
- `sgp1` - Singapore 1
- `tor1` - Toronto 1

### Infrastructure Components

The workflow deploys the following DigitalOcean resources:

- **Container Registry**: For storing Docker images
- **App Platform**: For running containerized applications
- **Database Cluster**: PostgreSQL database (production only)
- **Load Balancer**: For traffic distribution (production only)
- **Firewall**: Security rules for network access
- **Spaces Bucket**: Object storage for logs
- **Monitoring**: CPU and memory alerts
- **Domain & DNS**: Custom domain configuration (production only)

### Troubleshooting

1. **Authentication Errors**:
- Verify your `DIGITALOCEAN_TOKEN` secret is correctly set
- Ensure the token has "Write" permissions

2. **Terraform Errors**:
- Check the workflow logs for detailed error messages
- Verify your Terraform configuration files are valid
- Ensure all required variables are provided

3. **Resource Limits**:
- Check your DigitalOcean account limits
- Verify you have sufficient credits/balance

### Best Practices

1. **Always Plan First**: Run a plan before applying changes
2. **Use Separate Environments**: Keep dev, staging, and prod isolated
3. **Review Changes**: Always review Terraform plans before applying
4. **Monitor Costs**: Keep track of DigitalOcean resource usage
5. **Backup State**: Consider using remote state storage for production

### Cost Optimization

- Use appropriate instance sizes for each environment
- Enable auto-scaling for production workloads
- Set up monitoring alerts for resource usage
- Regularly review and clean up unused resources

### Support

For issues or questions:
1. Check the workflow logs for error details
2. Review the Terraform configuration files
3. Consult the DigitalOcean documentation
4. Open an issue in the repository
189 changes: 189 additions & 0 deletions .github/workflows/terraform-digitalocean.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
name: Terraform DigitalOcean Infrastructure

on:
workflow_dispatch:
inputs:
environment:
description: 'Environment to deploy to'
required: true
default: 'dev'
type: choice
options:
- dev
- staging
- prod
action:
description: 'Terraform action to perform'
required: true
default: 'plan'
type: choice
options:
- plan
- apply
- destroy
region:
description: 'DigitalOcean region'
required: true
default: 'nyc1'
type: choice
options:
- nyc1
- nyc3
- sfo2
- sfo3
- ams2
- ams3
- fra1
- lon1
- sgp1
- tor1
domain_name:
description: 'Domain name (optional, for production)'
required: false
type: string
default: ''

env:
TF_VERSION: "1.5.0"
TF_WORKING_DIR: "./terraform"

jobs:
terraform:
name: 'Terraform'
runs-on: ubuntu-latest

defaults:
run:
working-directory: ${{ env.TF_WORKING_DIR }}

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: ${{ env.TF_VERSION }}

- name: Terraform Format Check
run: terraform fmt -check -recursive
if: ${{ github.event.inputs.action == 'plan' || github.event.inputs.action == 'apply' }}

- name: Terraform Init
run: terraform init
env:
TF_VAR_cloud_provider: "digitalocean"
TF_VAR_environment: ${{ github.event.inputs.environment }}
TF_VAR_region: ${{ github.event.inputs.region }}
TF_VAR_domain_name: ${{ github.event.inputs.domain_name }}

- name: Terraform Validate
run: terraform validate
if: ${{ github.event.inputs.action == 'plan' || github.event.inputs.action == 'apply' }}

- name: Terraform Plan
id: plan
run: |
terraform plan \
-var="cloud_provider=digitalocean" \
-var="environment=${{ github.event.inputs.environment }}" \
-var="region=${{ github.event.inputs.region }}" \
-var="domain_name=${{ github.event.inputs.domain_name }}" \
-out=tfplan
if: ${{ github.event.inputs.action == 'plan' || github.event.inputs.action == 'apply' }}

- name: Terraform Plan Status
if: steps.plan.outcome == 'failure'
run: exit 1

- name: Terraform Apply
if: ${{ github.event.inputs.action == 'apply' }}
run: terraform apply -auto-approve tfplan
env:
DIGITALOCEAN_TOKEN: ${{ secrets.DIGITALOCEAN_TOKEN }}

- name: Terraform Destroy
if: ${{ github.event.inputs.action == 'destroy' }}
run: terraform destroy -auto-approve
env:
DIGITALOCEAN_TOKEN: ${{ secrets.DIGITALOCEAN_TOKEN }}

- name: Upload Terraform Plan
uses: actions/upload-artifact@v4
if: ${{ github.event.inputs.action == 'plan' }}
with:
name: terraform-plan
path: ${{ env.TF_WORKING_DIR }}/tfplan

- name: Comment Plan Results
if: ${{ github.event.inputs.action == 'plan' }}
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const plan = fs.readFileSync('${{ env.TF_WORKING_DIR }}/tfplan', 'utf8');
const comment = `## Terraform Plan Results

**Environment:** ${{ github.event.inputs.environment }}
**Region:** ${{ github.event.inputs.region }}
**Action:** ${{ github.event.inputs.action }}

\`\`\`hcl
${plan}
\`\`\`
`;

github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: comment
});

security-scan:
name: 'Security Scan'
runs-on: ubuntu-latest
needs: terraform
if: ${{ github.event.inputs.action == 'apply' }}

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
format: 'sarif'
output: 'trivy-results.sarif'

- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: 'trivy-results.sarif'

notify:
name: 'Notify'
runs-on: ubuntu-latest
needs: [terraform, security-scan]
if: always()

steps:
- name: Notify on Success
if: ${{ needs.terraform.result == 'success' && needs.security-scan.result == 'success' }}
run: |
echo "✅ Terraform deployment completed successfully!"
echo "Environment: ${{ github.event.inputs.environment }}"
echo "Region: ${{ github.event.inputs.region }}"
echo "Action: ${{ github.event.inputs.action }}"

- name: Notify on Failure
if: ${{ needs.terraform.result == 'failure' || needs.security-scan.result == 'failure' }}
run: |
echo "❌ Terraform deployment failed!"
echo "Environment: ${{ github.event.inputs.environment }}"
echo "Region: ${{ github.event.inputs.region }}"
echo "Action: ${{ github.event.inputs.action }}"
exit 1
Loading