added infra
This commit is contained in:
27
infra/gcp/.gitignore
vendored
Normal file
27
infra/gcp/.gitignore
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
# Local .terraform directories
|
||||
.terraform/
|
||||
|
||||
# .tfstate files
|
||||
*.tfstate
|
||||
*.tfstate.*
|
||||
|
||||
# Crash log files
|
||||
crash.log
|
||||
|
||||
# Exclude all .tfvars files, which are likely to contain sensitive data, such as
|
||||
# password, private keys, and other secrets. These should not be part of version
|
||||
# control as they are data points which are potentially sensitive and subject
|
||||
# to change depending on the environment.
|
||||
*.tfvars
|
||||
*.tfvars.json
|
||||
|
||||
# Ignore override files as they are usually used for local testing and overriding
|
||||
# values locally
|
||||
override.tf
|
||||
override.tf.json
|
||||
*_override.tf
|
||||
*_override.tf.json
|
||||
|
||||
# Include the .terraform.lock.hcl file to ensure that the same provider versions
|
||||
# are used across all environments.
|
||||
# .terraform.lock.hcl
|
||||
22
infra/gcp/.terraform.lock.hcl
generated
Normal file
22
infra/gcp/.terraform.lock.hcl
generated
Normal file
@@ -0,0 +1,22 @@
|
||||
# This file is maintained automatically by "terraform init".
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.terraform.io/hashicorp/google" {
|
||||
version = "5.45.2"
|
||||
constraints = "~> 5.0"
|
||||
hashes = [
|
||||
"h1:iy2Q9VcnMu4z/bH3v/NmI/nEpgYY7bXgJmT/hVTAUS4=",
|
||||
"zh:0d09c8f20b556305192cdbe0efa6d333ceebba963a8ba91f9f1714b5a20c4b7a",
|
||||
"zh:117143fc91be407874568df416b938a6896f94cb873f26bba279cedab646a804",
|
||||
"zh:16ccf77d18dd2c5ef9c0625f9cf546ebdf3213c0a452f432204c69feed55081e",
|
||||
"zh:3e555cf22a570a4bd247964671f421ed7517970cd9765ceb46f335edc2c6f392",
|
||||
"zh:688bd5b05a75124da7ae6e885b2b92bd29f4261808b2b78bd5f51f525c1052ca",
|
||||
"zh:6db3ef37a05010d82900bfffb3261c59a0c247e0692049cb3eb8c2ef16c9d7bf",
|
||||
"zh:70316fde75f6a15d72749f66d994ccbdde5f5ed4311b6d06b99850f698c9bbf9",
|
||||
"zh:84b8e583771a4f2bd514e519d98ed7fd28dce5efe0634e973170e1cfb5556fb4",
|
||||
"zh:9d4b8ef0a9b6677935c604d94495042e68ff5489932cfd1ec41052e094a279d3",
|
||||
"zh:a2089dd9bd825c107b148dd12d6b286f71aa37dfd4ca9c35157f2dcba7bc19d8",
|
||||
"zh:f03d795c0fd9721e59839255ee7ba7414173017dc530b4ce566daf3802a0d6dd",
|
||||
"zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
|
||||
]
|
||||
}
|
||||
127
infra/gcp/CICD_PLAN.md
Normal file
127
infra/gcp/CICD_PLAN.md
Normal file
@@ -0,0 +1,127 @@
|
||||
# CI/CD Plan for GCP Terraform with Gitea
|
||||
|
||||
This document outlines a CI/CD plan for the GCP Terraform infrastructure using Gitea Actions.
|
||||
|
||||
## 1. Overview
|
||||
|
||||
The goal is to automate the process of validating, planning, and applying Terraform changes. This will ensure that all infrastructure changes are peer-reviewed, tested, and applied in a consistent and predictable manner.
|
||||
|
||||
We will use Gitea Actions, the built-in CI/CD solution in Gitea, to orchestrate the workflows.
|
||||
|
||||
## 2. Branching Strategy
|
||||
|
||||
We will use a simple GitFlow-like model:
|
||||
- **`main` branch:** Represents the production infrastructure. Direct pushes will be disallowed. Changes are merged via pull requests.
|
||||
- **Feature branches:** All changes are developed on feature branches (e.g., `feat/add-monitoring`, `fix/firewall-rules`).
|
||||
|
||||
## 3. Secrets Management
|
||||
|
||||
GCP credentials must be handled securely. We will use Gitea's encrypted secrets to store the GCP service account key.
|
||||
|
||||
1. **Create a GCP Service Account:** Create a dedicated service account in GCP with the necessary permissions to manage the infrastructure.
|
||||
2. **Generate a JSON Key:** Generate a JSON key for this service account.
|
||||
3. **Store the Key in Gitea:** Store the contents of the JSON key file as a repository secret in Gitea with the name `GCP_SA_KEY`.
|
||||
|
||||
## 4. Gitea Actions Workflow
|
||||
|
||||
We will create a single workflow file at `.gitea/workflows/terraform.yml`. This workflow will have two main jobs, triggered by different events.
|
||||
|
||||
### Workflow Triggers
|
||||
|
||||
- **On `pull_request` to `main`:** The workflow will run `terraform init`, `terraform validate`, and `terraform plan`. The output of the plan will be added as a comment to the pull request for review.
|
||||
- **On `push` to `main`:** After a pull request is merged, the workflow will run `terraform init` and `terraform apply` to deploy the changes to production. This step will require manual approval within Gitea Actions.
|
||||
|
||||
### Workflow Definition (`.gitea/workflows/terraform.yml`)
|
||||
|
||||
```yaml
|
||||
name: Terraform CI/CD
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
terraform-plan:
|
||||
if: github.event_name == 'pull_request'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Terraform
|
||||
uses: hashicorp/setup-terraform@v2
|
||||
with:
|
||||
terraform_version: 1.8.0
|
||||
|
||||
- name: Authenticate to GCP
|
||||
uses: google-github-actions/auth@v1
|
||||
with:
|
||||
credentials_json: ${{ secrets.GCP_SA_KEY }}
|
||||
|
||||
- name: Terraform Init
|
||||
run: terraform init
|
||||
|
||||
- name a: Terraform Validate
|
||||
run: terraform validate
|
||||
|
||||
- name: Terraform Plan
|
||||
id: plan
|
||||
run: terraform plan -no-color -out=tfplan
|
||||
|
||||
- name: Add Plan to PR
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
const output = `#### Terraform Plan 📖\n${{ steps.plan.outputs.stdout }}\n`
|
||||
github.rest.issues.createComment({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: output
|
||||
})
|
||||
|
||||
terraform-apply:
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||
runs-on: ubuntu-latest
|
||||
environment: production # This can be used to require manual approval
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Terraform
|
||||
uses: hashicorp/setup-terraform@v2
|
||||
with:
|
||||
terraform_version: 1.8.0
|
||||
|
||||
- name: Authenticate to GCP
|
||||
uses: google-github-actions/auth@v1
|
||||
with:
|
||||
credentials_json: ${{ secrets.GCP_SA_KEY }}
|
||||
|
||||
- name: Terraform Init
|
||||
run: terraform init
|
||||
|
||||
- name: Terraform Apply
|
||||
run: terraform apply -auto-approve tfplan
|
||||
|
||||
```
|
||||
|
||||
### 5. Manual Approval for Production
|
||||
|
||||
To protect the production environment, the `terraform-apply` job will be configured to require manual approval. In Gitea, you can protect the `main` branch and require reviews before merging. For the deployment, Gitea Actions can be configured with an `environment` that requires a manual approval from a specific team or user before the job runs.
|
||||
|
||||
## 6. Implementation Steps
|
||||
|
||||
1. **Create the `.gitea/workflows` directory.**
|
||||
2. **Create the `terraform.yml` file** with the content above.
|
||||
3. **Create a dedicated GCP service account** with appropriate IAM roles.
|
||||
4. **Generate a JSON key** for the service account.
|
||||
5. **Add the JSON key as a secret** named `GCP_SA_KEY` in the Gitea repository settings.
|
||||
6. **Protect the `main` branch** in Gitea to require pull requests and reviews.
|
||||
7. **(Optional) Configure an environment** in Gitea that requires manual approval for deployments.
|
||||
|
||||
This plan provides a solid foundation for automating the Terraform workflow in a safe and controlled manner.
|
||||
62
infra/gcp/README.md
Normal file
62
infra/gcp/README.md
Normal file
@@ -0,0 +1,62 @@
|
||||
# GCP Infrastructure for Sing For Hope
|
||||
|
||||
This directory contains Terraform configurations for deploying and managing Gitea and n8n instances on Google Cloud Platform (GCP).
|
||||
|
||||
## Services Deployed
|
||||
|
||||
* **Gitea**: A self-hosted Git service, accessible at `https://git.singforhope.cloud`.
|
||||
* **n8n**: A workflow automation tool, accessible at `https://n8n.singforhope.cloud`.
|
||||
|
||||
Both services are deployed on separate `e2-small` virtual machines, configured with Nginx as a reverse proxy and SSL/TLS certificates from Let's Encrypt.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before using these Terraform configurations, ensure you have the following:
|
||||
|
||||
* **GCP Project**: A Google Cloud Platform project with billing enabled.
|
||||
* **`gcloud` CLI**: The Google Cloud SDK installed and authenticated.
|
||||
* **Terraform CLI**: Terraform installed on your local machine.
|
||||
* **GCS Backend**: A Google Cloud Storage bucket named `tf-state-token-sfh` for Terraform state management.
|
||||
|
||||
## Usage
|
||||
|
||||
1. **Initialize Terraform**:
|
||||
Navigate to this directory in your terminal and initialize Terraform:
|
||||
```bash
|
||||
terraform init
|
||||
```
|
||||
|
||||
2. **Review the Plan**:
|
||||
Review the execution plan to understand what changes Terraform will make. Replace `sing-for-hope` with your actual GCP project ID.
|
||||
```bash
|
||||
terraform plan -var="project_id=sing-for-hope"
|
||||
```
|
||||
|
||||
3. **Apply the Configuration**:
|
||||
Apply the Terraform configuration to create or update the resources.
|
||||
```bash
|
||||
terraform apply -var="project_id=sing-for-hope"
|
||||
```
|
||||
You will be prompted to confirm the changes. Type `yes` to proceed.
|
||||
|
||||
## Resources Managed
|
||||
|
||||
The Terraform configuration in this directory manages the following GCP resources:
|
||||
|
||||
* **`google_dns_managed_zone.singforhope_cloud`**: The DNS managed zone for `singforhope.cloud`.
|
||||
* **`google_compute_instance.gitea_vm`**: The virtual machine instance for Gitea.
|
||||
* **`google_compute_instance.n8n_vm`**: The virtual machine instance for n8n.
|
||||
* **`google_dns_record_set.gitea`**: The A record for `git.singforhope.cloud`.
|
||||
* **`google_dns_record_set.n8n`**: The A record for `n8n.singforhope.cloud`.
|
||||
* **`google_compute_firewall.gitea_http`**: Firewall rule to allow traffic to Gitea on port 3000.
|
||||
* **`google_compute_firewall.http_allow`**: Firewall rule to allow HTTP traffic (port 80) to Gitea.
|
||||
* **`google_compute_firewall.https_allow`**: Firewall rule to allow HTTPS traffic (port 443) to Gitea.
|
||||
* **`google_compute_firewall.n8n_app_allow`**: Firewall rule to allow traffic to n8n on port 5678.
|
||||
* **`google_compute_firewall.n8n_http_allow`**: Firewall rule to allow HTTP traffic (port 80) to n8n.
|
||||
* **`google_compute_firewall.n8n_https_allow`**: Firewall rule to allow HTTPS traffic (port 443) to n8n.
|
||||
|
||||
## Important Notes
|
||||
|
||||
* The initial setup of Gitea and n8n (Docker installation, Nginx configuration, and Certbot SSL) was performed manually via `gcloud` commands. This Terraform configuration now manages the underlying infrastructure (VMs, DNS, Firewall rules) but does not re-run the application-level setup scripts.
|
||||
* The `metadata_startup_script` attribute for the VM instances is intentionally omitted from the Terraform configuration to prevent unintended re-provisioning of the VMs.
|
||||
* The `dnssec_config` for the managed zone is included as it is a required parameter.
|
||||
385
infra/gcp/REVIEW.md
Normal file
385
infra/gcp/REVIEW.md
Normal file
@@ -0,0 +1,385 @@
|
||||
# Infrastructure Review: GCP Terraform for Sing For Hope
|
||||
|
||||
**Review Date:** November 9, 2025
|
||||
**Reviewer:** Claude Code
|
||||
**Project:** GCP Infrastructure for Gitea and n8n
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
|
||||
This Terraform project manages GCP infrastructure for hosting Gitea (self-hosted Git) and n8n (workflow automation) on separate VM instances. While the code is clean and functional, it has several critical issues that limit production-readiness, particularly around security, data persistence, and infrastructure-as-code completeness.
|
||||
|
||||
**Overall Ratings:**
|
||||
- Production-Readiness: **4/10**
|
||||
- Code Quality: **6/10**
|
||||
- Documentation: **7/10**
|
||||
- Maintainability: **5/10**
|
||||
- Security: **3/10**
|
||||
|
||||
---
|
||||
|
||||
## Strengths
|
||||
|
||||
### 1. Clean Project Structure
|
||||
The project follows Terraform best practices with proper file organization:
|
||||
- Separate files for variables, outputs, and backend configuration
|
||||
- Clear naming conventions
|
||||
- Logical resource grouping
|
||||
|
||||
### 2. Good Documentation
|
||||
The README.md provides:
|
||||
- Clear service descriptions
|
||||
- Prerequisite checklist
|
||||
- Step-by-step usage instructions
|
||||
- Honest acknowledgment of manual setup steps
|
||||
|
||||
### 3. Remote State Management
|
||||
- Uses GCS backend for state storage
|
||||
- Prevents state conflicts in team environments
|
||||
- Enables state locking
|
||||
|
||||
### 4. DNS Security
|
||||
- DNSSEC enabled with appropriate configuration
|
||||
- Uses NSEC3 for non-existence proof
|
||||
- Proper key specifications for signing and zone signing
|
||||
|
||||
### 5. Sensible Defaults
|
||||
- Variables have reasonable default values
|
||||
- Machine type (e2-small) appropriate for small workloads
|
||||
- Standard region/zone selection
|
||||
|
||||
---
|
||||
|
||||
## Critical Issues
|
||||
|
||||
### 1. Hardcoded Service Account Email
|
||||
**Location:** `main.tf:53`, `main.tf:76`
|
||||
|
||||
```terraform
|
||||
service_account {
|
||||
email = "456409048169-compute@developer.gserviceaccount.com"
|
||||
scopes = [...]
|
||||
}
|
||||
```
|
||||
|
||||
**Impact:**
|
||||
- Code is not portable across projects
|
||||
- Violates infrastructure-as-code principles
|
||||
- Will fail if used in different GCP projects
|
||||
|
||||
**Fix:**
|
||||
Use Terraform data sources to dynamically fetch the default compute service account:
|
||||
```terraform
|
||||
data "google_compute_default_service_account" "default" {}
|
||||
|
||||
service_account {
|
||||
email = data.google_compute_default_service_account.default.email
|
||||
scopes = [...]
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Infrastructure Drift (Manual Configuration)
|
||||
**Location:** README.md notes manual setup of Docker, Nginx, Certbot
|
||||
|
||||
**Impact:**
|
||||
- Infrastructure cannot be reproduced from code alone
|
||||
- Disaster recovery requires manual intervention and documentation
|
||||
- Team members cannot spin up identical environments
|
||||
- Configuration changes aren't tracked in version control
|
||||
|
||||
**Fix:**
|
||||
- Add startup scripts to `metadata_startup_script` in VM resources
|
||||
- OR use Packer to create pre-configured VM images
|
||||
- OR use configuration management tools (Ansible, Cloud Init)
|
||||
|
||||
### 3. Security Vulnerabilities
|
||||
|
||||
#### a. Overly Permissive Firewall Rules
|
||||
**Location:** All firewall rules use `source_ranges = ["0.0.0.0/0"]`
|
||||
|
||||
**Issues:**
|
||||
- Gitea port 3000 exposed to the internet (`main.tf:82-93`)
|
||||
- n8n port 5678 exposed to the internet (`main.tf:121-132`)
|
||||
- These should only be accessible via reverse proxy (Nginx)
|
||||
|
||||
#### b. Using Default VPC
|
||||
**Location:** All resources use `network = "default"`
|
||||
|
||||
**Issues:**
|
||||
- Default network has permissive routing
|
||||
- No network segmentation
|
||||
- Shared with other project resources
|
||||
- Difficult to implement security best practices
|
||||
|
||||
#### c. No SSH Access Control
|
||||
- No explicit SSH firewall rules defined
|
||||
- Default GCP rules may be too permissive
|
||||
- No bastion host or IAP tunneling
|
||||
|
||||
### 4. No Data Persistence Strategy
|
||||
**Locations:** `main.tf:40-44`, `main.tf:64-68`
|
||||
|
||||
**Issues:**
|
||||
- Boot disks use default sizing
|
||||
- No separate data volumes for application data
|
||||
- Gitea repositories and n8n workflows stored on ephemeral boot disk
|
||||
- No backup configuration
|
||||
- Risk of data loss if VMs are recreated
|
||||
|
||||
**Impact:**
|
||||
Critical user data (Git repositories, workflow configurations) could be lost during infrastructure updates.
|
||||
|
||||
---
|
||||
|
||||
## Notable Gaps
|
||||
|
||||
### 5. Missing Startup Automation
|
||||
While intentionally omitted per README, this creates operational challenges:
|
||||
- New team members can't provision working infrastructure
|
||||
- Updates require manual SSH intervention
|
||||
- No automated application updates or patching
|
||||
|
||||
### 6. Outdated Operating System
|
||||
**Location:** `main.tf:42`, `main.tf:66`
|
||||
|
||||
Currently using `debian-cloud/debian-11` while Debian 12 is available and supported.
|
||||
|
||||
### 7. No Monitoring or Alerting
|
||||
Missing operational visibility:
|
||||
- No Cloud Monitoring dashboards
|
||||
- No alerting for VM health, disk usage, or service availability
|
||||
- No log aggregation configuration
|
||||
- No uptime checks for the applications
|
||||
|
||||
### 8. No High Availability or Auto-Healing
|
||||
Current setup has single points of failure:
|
||||
- Single VM per service
|
||||
- No managed instance groups
|
||||
- No auto-restart on failure
|
||||
- No health checks
|
||||
|
||||
### 9. DNS Configuration Gaps
|
||||
- Zone signing key uses 1024-bit RSA (should be 2048 bits)
|
||||
- No apex domain record defined (only subdomains)
|
||||
- TTL of 300 seconds is reasonable but not documented
|
||||
|
||||
### 10. Missing Cost Optimization
|
||||
- No committed use discounts
|
||||
- Could use preemptible VMs for non-production
|
||||
- No resource tagging for cost allocation
|
||||
- No budgets or billing alerts
|
||||
|
||||
---
|
||||
|
||||
## Detailed Recommendations
|
||||
|
||||
### High Priority (Do First)
|
||||
|
||||
1. **Fix Hardcoded Service Account**
|
||||
- Use data sources or variables
|
||||
- Ensures portability across projects
|
||||
|
||||
2. **Implement Application Provisioning**
|
||||
- Add startup scripts with idempotent configuration
|
||||
- Or create golden images with Packer
|
||||
- Document all manual steps taken
|
||||
|
||||
3. **Secure Firewall Rules**
|
||||
- Remove public access to ports 3000 and 5678
|
||||
- Restrict HTTP/HTTPS to CloudFlare IPs if using CDN
|
||||
- Add explicit SSH rules with IP allowlisting
|
||||
|
||||
4. **Create Custom VPC**
|
||||
- Separate network for these resources
|
||||
- Proper subnet configuration
|
||||
- Network tags for better organization
|
||||
|
||||
5. **Add Persistent Data Disks**
|
||||
```terraform
|
||||
resource "google_compute_disk" "gitea_data" {
|
||||
name = "gitea-data"
|
||||
size = 50
|
||||
type = "pd-standard"
|
||||
zone = var.zone
|
||||
}
|
||||
```
|
||||
|
||||
6. **Implement Backup Strategy**
|
||||
- Scheduled snapshots for data disks
|
||||
- Retention policies
|
||||
- Test restore procedures
|
||||
|
||||
### Medium Priority (Important but Not Urgent)
|
||||
|
||||
7. **Add Monitoring and Alerting**
|
||||
- Cloud Monitoring dashboards for VM metrics
|
||||
- Uptime checks for services
|
||||
- Alert policies for disk usage, CPU, memory
|
||||
- Email/Slack notifications
|
||||
|
||||
8. **Upgrade Operating System**
|
||||
- Change to `debian-cloud/debian-12`
|
||||
- Test application compatibility first
|
||||
|
||||
9. **Improve DNS Configuration**
|
||||
- Increase zone signing key to 2048 bits
|
||||
- Add apex domain record if needed
|
||||
- Consider lower TTL during migrations
|
||||
|
||||
10. **Add Lifecycle Management**
|
||||
```terraform
|
||||
lifecycle {
|
||||
prevent_destroy = true # For production
|
||||
ignore_changes = [metadata_startup_script]
|
||||
}
|
||||
```
|
||||
|
||||
11. **Implement Better Secrets Management**
|
||||
- Use Secret Manager for application secrets
|
||||
- Grant VMs access via service account
|
||||
- Avoid hardcoding credentials
|
||||
|
||||
12. **Add Resource Labels**
|
||||
```terraform
|
||||
labels = {
|
||||
environment = "production"
|
||||
service = "gitea"
|
||||
managed_by = "terraform"
|
||||
cost_center = "engineering"
|
||||
}
|
||||
```
|
||||
|
||||
### Low Priority (Nice to Have)
|
||||
|
||||
13. **Modularize Terraform Code**
|
||||
- Create reusable modules for VM + DNS pattern
|
||||
- Separate module for firewall rules
|
||||
- Easier to maintain and extend
|
||||
|
||||
14. **Add terraform.tfvars.example**
|
||||
- Document required variables
|
||||
- Provide example values
|
||||
- Help new team members get started
|
||||
|
||||
15. **Consider Terragrunt**
|
||||
- If planning multi-environment setup (dev/staging/prod)
|
||||
- DRY configuration management
|
||||
- Environment-specific overrides
|
||||
|
||||
16. **Implement CI/CD for Terraform**
|
||||
- Automated `terraform plan` on PRs
|
||||
- Automated `terraform apply` after merge
|
||||
- State locking verification
|
||||
|
||||
17. **Add Pre-commit Hooks**
|
||||
- Run `terraform fmt` automatically
|
||||
- Run `terraform validate`
|
||||
- Run security scanning (tfsec, checkov)
|
||||
|
||||
18. **Consider Managed Services**
|
||||
- Cloud Run for containerized apps (simpler than VMs)
|
||||
- Cloud SQL if databases are needed
|
||||
- Cloud Storage for artifacts/backups
|
||||
|
||||
---
|
||||
|
||||
## Security Recommendations Summary
|
||||
|
||||
### Immediate Actions Required:
|
||||
1. Close ports 3000 and 5678 to public internet
|
||||
2. Implement IP allowlisting for SSH access
|
||||
3. Create custom VPC with proper firewall rules
|
||||
4. Enable VPC Flow Logs for security monitoring
|
||||
5. Implement Cloud Armor for DDoS protection
|
||||
|
||||
### Additional Security Measures:
|
||||
- Enable OS Login for SSH key management
|
||||
- Use Identity-Aware Proxy (IAP) for VM access
|
||||
- Implement least-privilege service account permissions
|
||||
- Enable audit logging for all resources
|
||||
- Regular security scanning with Cloud Security Scanner
|
||||
- Implement Web Application Firewall (WAF) rules
|
||||
|
||||
---
|
||||
|
||||
## Data Protection Recommendations
|
||||
|
||||
### Backup Strategy:
|
||||
```terraform
|
||||
# Example snapshot schedule
|
||||
resource "google_compute_resource_policy" "daily_backup" {
|
||||
name = "daily-backup-policy"
|
||||
region = var.region
|
||||
|
||||
snapshot_schedule_policy {
|
||||
schedule {
|
||||
daily_schedule {
|
||||
days_in_cycle = 1
|
||||
start_time = "04:00"
|
||||
}
|
||||
}
|
||||
retention_policy {
|
||||
max_retention_days = 14
|
||||
on_source_disk_delete = "KEEP_AUTO_SNAPSHOTS"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Disaster Recovery Plan:
|
||||
1. Document manual setup steps in code-readable format (cloud-init)
|
||||
2. Test VM restoration from snapshots quarterly
|
||||
3. Maintain off-site backups of critical data
|
||||
4. Document RTO (Recovery Time Objective) and RPO (Recovery Point Objective)
|
||||
|
||||
---
|
||||
|
||||
## Estimated Effort for Improvements
|
||||
|
||||
| Priority | Task Category | Estimated Time |
|
||||
|----------|---------------|----------------|
|
||||
| High | Security fixes | 4-6 hours |
|
||||
| High | Data persistence | 2-3 hours |
|
||||
| High | Service account fix | 30 minutes |
|
||||
| High | Startup scripts | 4-8 hours |
|
||||
| Medium | Monitoring setup | 3-4 hours |
|
||||
| Medium | OS upgrade | 1-2 hours |
|
||||
| Low | Modularization | 6-8 hours |
|
||||
| Low | CI/CD pipeline | 4-6 hours |
|
||||
|
||||
**Total effort for high-priority items:** ~12-18 hours
|
||||
**Total effort for all recommendations:** ~30-40 hours
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
This infrastructure demonstrates a good starting point for managing cloud resources with Terraform. The code is readable, well-documented, and follows basic IaC principles. However, significant work is needed to make this production-ready.
|
||||
|
||||
The most critical issue is the **hybrid approach** where infrastructure is managed by Terraform but application configuration is manual. This creates a maintenance burden and makes disaster recovery difficult.
|
||||
|
||||
### Recommended Next Steps:
|
||||
1. Start with security fixes (firewall rules, custom VPC)
|
||||
2. Add persistent data disks and backups
|
||||
3. Automate application provisioning
|
||||
4. Implement monitoring and alerting
|
||||
5. Create runbooks for common operations
|
||||
|
||||
With these improvements, this infrastructure could achieve a production-readiness score of 8/10 and provide a solid foundation for the Sing For Hope organization's DevOps needs.
|
||||
|
||||
---
|
||||
|
||||
## Questions for Further Discussion
|
||||
|
||||
1. What is the expected traffic volume for these services?
|
||||
2. What are the RTO/RPO requirements for disaster recovery?
|
||||
3. Is high availability required, or is some downtime acceptable?
|
||||
4. What is the budget for infrastructure costs?
|
||||
5. Are there compliance requirements (HIPAA, SOC2, etc.)?
|
||||
6. Who will be responsible for ongoing maintenance?
|
||||
7. Are there plans to add more services to this infrastructure?
|
||||
|
||||
---
|
||||
|
||||
**Note:** This review is based on the code as of November 9, 2025. As infrastructure evolves, periodic reviews should be conducted to ensure continued alignment with best practices and organizational needs.
|
||||
6
infra/gcp/backend.tf
Normal file
6
infra/gcp/backend.tf
Normal file
@@ -0,0 +1,6 @@
|
||||
terraform {
|
||||
backend "gcs" {
|
||||
bucket = "tf-state-token-sfh" # Replace with your GCS bucket name
|
||||
prefix = "gcp"
|
||||
}
|
||||
}
|
||||
174
infra/gcp/main.tf
Normal file
174
infra/gcp/main.tf
Normal file
@@ -0,0 +1,174 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
google = {
|
||||
source = "hashicorp/google"
|
||||
version = "~> 5"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "google" {
|
||||
project = var.project_id
|
||||
}
|
||||
|
||||
resource "google_dns_managed_zone" "singforhope_cloud" {
|
||||
name = "singforhope-cloud"
|
||||
dns_name = "${var.domain_name}."
|
||||
|
||||
dnssec_config {
|
||||
state = "on"
|
||||
non_existence = "nsec3"
|
||||
default_key_specs {
|
||||
algorithm = "rsasha256"
|
||||
key_length = 2048
|
||||
key_type = "keySigning"
|
||||
}
|
||||
default_key_specs {
|
||||
algorithm = "rsasha256"
|
||||
key_length = 1024
|
||||
key_type = "zoneSigning"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_compute_instance" "gitea_vm" {
|
||||
name = "gitea-vm"
|
||||
machine_type = var.machine_type
|
||||
zone = var.zone
|
||||
tags = ["gitea"]
|
||||
|
||||
boot_disk {
|
||||
initialize_params {
|
||||
image = "debian-cloud/debian-11"
|
||||
}
|
||||
}
|
||||
|
||||
network_interface {
|
||||
network = "default"
|
||||
access_config {
|
||||
}
|
||||
}
|
||||
|
||||
service_account {
|
||||
email = "456409048169-compute@developer.gserviceaccount.com"
|
||||
scopes = ["https://www.googleapis.com/auth/devstorage.read_only", "https://www.googleapis.com/auth/logging.write", "https://www.googleapis.com/auth/monitoring.write", "https://www.googleapis.com/auth/pubsub", "https://www.googleapis.com/auth/service.management.readonly", "https://www.googleapis.com/auth/servicecontrol", "https://www.googleapis.com/auth/trace.append"]
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_compute_instance" "n8n_vm" {
|
||||
name = "n8n-vm"
|
||||
machine_type = var.machine_type
|
||||
zone = var.zone
|
||||
tags = ["n8n"]
|
||||
|
||||
boot_disk {
|
||||
initialize_params {
|
||||
image = "debian-cloud/debian-11"
|
||||
}
|
||||
}
|
||||
|
||||
network_interface {
|
||||
network = "default"
|
||||
access_config {
|
||||
}
|
||||
}
|
||||
|
||||
service_account {
|
||||
email = "456409048169-compute@developer.gserviceaccount.com"
|
||||
scopes = ["https://www.googleapis.com/auth/devstorage.read_only", "https://www.googleapis.com/auth/logging.write", "https://www.googleapis.com/auth/monitoring.write", "https://www.googleapis.com/auth/pubsub", "https://www.googleapis.com/auth/service.management.readonly", "https://www.googleapis.com/auth/servicecontrol", "https://www.googleapis.com/auth/trace.append"]
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_compute_firewall" "gitea_http" {
|
||||
name = "gitea-http"
|
||||
network = "default"
|
||||
|
||||
allow {
|
||||
protocol = "tcp"
|
||||
ports = ["3000"]
|
||||
}
|
||||
|
||||
source_ranges = ["0.0.0.0/0"]
|
||||
target_tags = ["gitea"]
|
||||
}
|
||||
|
||||
resource "google_compute_firewall" "http_allow" {
|
||||
name = "http-allow"
|
||||
network = "default"
|
||||
|
||||
allow {
|
||||
protocol = "tcp"
|
||||
ports = ["80"]
|
||||
}
|
||||
|
||||
source_ranges = ["0.0.0.0/0"]
|
||||
target_tags = ["gitea"]
|
||||
}
|
||||
|
||||
resource "google_compute_firewall" "https_allow" {
|
||||
name = "https-allow"
|
||||
network = "default"
|
||||
|
||||
allow {
|
||||
protocol = "tcp"
|
||||
ports = ["443"]
|
||||
}
|
||||
|
||||
source_ranges = ["0.0.0.0/0"]
|
||||
target_tags = ["gitea"]
|
||||
}
|
||||
|
||||
resource "google_compute_firewall" "n8n_app_allow" {
|
||||
name = "n8n-app-allow"
|
||||
network = "default"
|
||||
|
||||
allow {
|
||||
protocol = "tcp"
|
||||
ports = ["5678"]
|
||||
}
|
||||
|
||||
source_ranges = ["0.0.0.0/0"]
|
||||
target_tags = ["n8n"]
|
||||
}
|
||||
|
||||
resource "google_compute_firewall" "n8n_http_allow" {
|
||||
name = "n8n-http-allow"
|
||||
network = "default"
|
||||
|
||||
allow {
|
||||
protocol = "tcp"
|
||||
ports = ["80"]
|
||||
}
|
||||
|
||||
source_ranges = ["0.0.0.0/0"]
|
||||
target_tags = ["n8n"]
|
||||
}
|
||||
|
||||
resource "google_compute_firewall" "n8n_https_allow" {
|
||||
name = "n8n-https-allow"
|
||||
network = "default"
|
||||
|
||||
allow {
|
||||
protocol = "tcp"
|
||||
ports = ["443"]
|
||||
}
|
||||
|
||||
source_ranges = ["0.0.0.0/0"]
|
||||
target_tags = ["n8n"]
|
||||
}
|
||||
|
||||
resource "google_dns_record_set" "gitea" {
|
||||
name = "git.${var.domain_name}."
|
||||
type = "A"
|
||||
ttl = 300
|
||||
managed_zone = google_dns_managed_zone.singforhope_cloud.name
|
||||
rrdatas = [google_compute_instance.gitea_vm.network_interface[0].access_config[0].nat_ip]
|
||||
}
|
||||
|
||||
resource "google_dns_record_set" "n8n" {
|
||||
name = "n8n.${var.domain_name}."
|
||||
type = "A"
|
||||
ttl = 300
|
||||
managed_zone = google_dns_managed_zone.singforhope_cloud.name
|
||||
rrdatas = [google_compute_instance.n8n_vm.network_interface[0].access_config[0].nat_ip]
|
||||
}
|
||||
24
infra/gcp/outputs.tf
Normal file
24
infra/gcp/outputs.tf
Normal file
@@ -0,0 +1,24 @@
|
||||
output "gitea_vm_name" {
|
||||
description = "The name of the Gitea VM."
|
||||
value = google_compute_instance.gitea_vm.name
|
||||
}
|
||||
|
||||
output "gitea_vm_external_ip" {
|
||||
description = "The external IP address of the Gitea VM."
|
||||
value = google_compute_instance.gitea_vm.network_interface[0].access_config[0].nat_ip
|
||||
}
|
||||
|
||||
output "n8n_vm_name" {
|
||||
description = "The name of the n8n VM."
|
||||
value = google_compute_instance.n8n_vm.name
|
||||
}
|
||||
|
||||
output "n8n_vm_external_ip" {
|
||||
description = "The external IP address of the n8n VM."
|
||||
value = google_compute_instance.n8n_vm.network_interface[0].access_config[0].nat_ip
|
||||
}
|
||||
|
||||
output "dns_name_servers" {
|
||||
description = "The name servers for the DNS zone."
|
||||
value = google_dns_managed_zone.singforhope_cloud.name_servers
|
||||
}
|
||||
28
infra/gcp/variables.tf
Normal file
28
infra/gcp/variables.tf
Normal file
@@ -0,0 +1,28 @@
|
||||
variable "project_id" {
|
||||
description = "The GCP project ID."
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "region" {
|
||||
description = "The GCP region to deploy resources in."
|
||||
type = string
|
||||
default = "us-central1"
|
||||
}
|
||||
|
||||
variable "zone" {
|
||||
description = "The GCP zone to deploy resources in."
|
||||
type = string
|
||||
default = "us-central1-a"
|
||||
}
|
||||
|
||||
variable "domain_name" {
|
||||
description = "The domain name to configure DNS for."
|
||||
type = string
|
||||
default = "singforhope.cloud"
|
||||
}
|
||||
|
||||
variable "machine_type" {
|
||||
description = "The machine type for the VM."
|
||||
type = string
|
||||
default = "e2-small"
|
||||
}
|
||||
Reference in New Issue
Block a user