Compare commits
2 Commits
269545596a
...
4e913599cb
| Author | SHA1 | Date | |
|---|---|---|---|
|
4e913599cb
|
|||
|
043c379647
|
@@ -10,6 +10,10 @@ env:
|
|||||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
TF_VAR_aws_region: ${{ vars.TF_VAR_aws_region }}
|
TF_VAR_aws_region: ${{ vars.TF_VAR_aws_region }}
|
||||||
TF_VAR_site_domain: ${{ vars.TF_VAR_site_domain }}
|
TF_VAR_site_domain: ${{ vars.TF_VAR_site_domain }}
|
||||||
|
TF_VAR_project_name: ${{ vars.TF_VAR_project_name }}
|
||||||
|
TF_VAR_environment: ${{ vars.TF_VAR_environment }}
|
||||||
|
TF_VAR_tuffas_applier_role_arn: ${{ vars.TF_VAR_tuffas_applier_role_arn }}
|
||||||
|
TF_VAR_tfstate_backend_role_arn: ${{ vars.TF_VAR_tfstate_backend_role_arn }}
|
||||||
TF_PLUGIN_CACHE_DIR: ${{ github.workspace }}/.terraform.d/plugin-cache
|
TF_PLUGIN_CACHE_DIR: ${{ github.workspace }}/.terraform.d/plugin-cache
|
||||||
jobs:
|
jobs:
|
||||||
nix:
|
nix:
|
||||||
@@ -46,3 +50,7 @@ jobs:
|
|||||||
- name: Plan
|
- name: Plan
|
||||||
id: plan
|
id: plan
|
||||||
run: terraform plan -no-color -input=false
|
run: terraform plan -no-color -input=false
|
||||||
|
- name: Apply
|
||||||
|
id: apply
|
||||||
|
run: terraform apply -auto-approve -no-color -input=false
|
||||||
|
if: github.ref == 'refs/heads/master' && github.event_name == 'push'
|
||||||
|
|||||||
97
main.tf
97
main.tf
@@ -1,17 +1,28 @@
|
|||||||
provider "aws" {
|
provider "aws" {
|
||||||
region = var.aws_region
|
region = var.aws_region
|
||||||
assume_role {
|
assume_role {
|
||||||
role_arn = "arn:aws:iam::677425296084:role/tuffas-applier"
|
role_arn = var.tuffas_applier_role_arn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
provider "cloudflare" {
|
provider "cloudflare" {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
locals {
|
||||||
|
common_tags = {
|
||||||
|
Project = var.project_name
|
||||||
|
Environment = var.environment
|
||||||
|
ManagedBy = "terraform"
|
||||||
|
Domain = var.site_domain
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# block with type resource, uses provider's aws_s3_bucket resource type and names it site
|
# block with type resource, uses provider's aws_s3_bucket resource type and names it site
|
||||||
resource "aws_s3_bucket" "site" {
|
resource "aws_s3_bucket" "site" {
|
||||||
# presumably
|
# presumably
|
||||||
bucket = var.site_domain
|
bucket = var.site_domain
|
||||||
|
|
||||||
|
tags = local.common_tags
|
||||||
}
|
}
|
||||||
|
|
||||||
# necessary to allow public users to eventually hit the s3 bucket
|
# necessary to allow public users to eventually hit the s3 bucket
|
||||||
@@ -60,7 +71,7 @@ resource "aws_s3_bucket_acl" "site" {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Full permissions for the bucket, which allows anyone to access any object in the bucket
|
# Public read access for website objects only (not bucket itself)
|
||||||
resource "aws_s3_bucket_policy" "site" {
|
resource "aws_s3_bucket_policy" "site" {
|
||||||
bucket = aws_s3_bucket.site.id
|
bucket = aws_s3_bucket.site.id
|
||||||
|
|
||||||
@@ -72,10 +83,7 @@ resource "aws_s3_bucket_policy" "site" {
|
|||||||
Effect = "Allow"
|
Effect = "Allow"
|
||||||
Principal = "*"
|
Principal = "*"
|
||||||
Action = "s3:GetObject"
|
Action = "s3:GetObject"
|
||||||
Resource = [
|
Resource = "${aws_s3_bucket.site.arn}/*"
|
||||||
aws_s3_bucket.site.arn,
|
|
||||||
"${aws_s3_bucket.site.arn}/*",
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
@@ -115,6 +123,83 @@ resource "cloudflare_record" "www" {
|
|||||||
proxied = true
|
proxied = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# S3 bucket versioning for content protection
|
||||||
|
resource "aws_s3_bucket_versioning" "site" {
|
||||||
|
bucket = aws_s3_bucket.site.id
|
||||||
|
versioning_configuration {
|
||||||
|
status = "Enabled"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Access logging bucket for monitoring
|
||||||
|
# resource "aws_s3_bucket" "access_logs" {
|
||||||
|
# bucket = "${var.site_domain}-access-logs"
|
||||||
|
#
|
||||||
|
# tags = merge(local.common_tags, {
|
||||||
|
# Purpose = "access-logs"
|
||||||
|
# })
|
||||||
|
# }
|
||||||
|
|
||||||
|
# resource "aws_s3_bucket_public_access_block" "access_logs" {
|
||||||
|
# bucket = aws_s3_bucket.access_logs.id
|
||||||
|
#
|
||||||
|
# block_public_acls = true
|
||||||
|
# block_public_policy = true
|
||||||
|
# ignore_public_acls = true
|
||||||
|
# restrict_public_buckets = true
|
||||||
|
# }
|
||||||
|
|
||||||
|
# Enable access logging for the main site bucket
|
||||||
|
# resource "aws_s3_bucket_logging" "site" {
|
||||||
|
# bucket = aws_s3_bucket.site.id
|
||||||
|
#
|
||||||
|
# target_bucket = aws_s3_bucket.access_logs.id
|
||||||
|
# target_prefix = "access-logs/"
|
||||||
|
# }
|
||||||
|
|
||||||
|
# Lifecycle rules for cost management
|
||||||
|
resource "aws_s3_bucket_lifecycle_configuration" "site" {
|
||||||
|
bucket = aws_s3_bucket.site.id
|
||||||
|
|
||||||
|
rule {
|
||||||
|
id = "cleanup_old_versions"
|
||||||
|
status = "Enabled"
|
||||||
|
|
||||||
|
noncurrent_version_expiration {
|
||||||
|
noncurrent_days = 90
|
||||||
|
}
|
||||||
|
filter {
|
||||||
|
prefix = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rule {
|
||||||
|
id = "cleanup_incomplete_uploads"
|
||||||
|
status = "Enabled"
|
||||||
|
|
||||||
|
abort_incomplete_multipart_upload {
|
||||||
|
days_after_initiation = 7
|
||||||
|
}
|
||||||
|
filter {
|
||||||
|
prefix = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Lifecycle rules for access logs
|
||||||
|
# resource "aws_s3_bucket_lifecycle_configuration" "access_logs" {
|
||||||
|
# bucket = aws_s3_bucket.access_logs.id
|
||||||
|
#
|
||||||
|
# rule {
|
||||||
|
# id = "delete_old_logs"
|
||||||
|
# status = "Enabled"
|
||||||
|
#
|
||||||
|
# expiration {
|
||||||
|
# days = 90
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
|
||||||
resource "cloudflare_page_rule" "https" {
|
resource "cloudflare_page_rule" "https" {
|
||||||
zone_id = data.cloudflare_zones.domain.zones[0].id
|
zone_id = data.cloudflare_zones.domain.zones[0].id
|
||||||
target = "*.${var.site_domain}/*"
|
target = "*.${var.site_domain}/*"
|
||||||
|
|||||||
17
terraform.tfvars.example
Normal file
17
terraform.tfvars.example
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# Example Terraform variables file
|
||||||
|
# Copy this file to terraform.tfvars and update with your actual values
|
||||||
|
|
||||||
|
# AWS region where resources will be created
|
||||||
|
aws_region = "us-east-2"
|
||||||
|
|
||||||
|
# Your domain name (must be managed by Cloudflare)
|
||||||
|
site_domain = "example.com"
|
||||||
|
|
||||||
|
# Project name for resource tagging
|
||||||
|
project_name = "tuffas"
|
||||||
|
|
||||||
|
# Environment (dev, staging, prod)
|
||||||
|
environment = "prod"
|
||||||
|
|
||||||
|
# IAM role ARNs (update with your actual role ARNs)
|
||||||
|
tuffas_applier_role_arn = "arn:aws:iam::YOUR-ACCOUNT-ID:role/ROLE_NAME"
|
||||||
21
variables.tf
21
variables.tf
@@ -7,3 +7,24 @@ variable "site_domain" {
|
|||||||
type = string
|
type = string
|
||||||
description = "The domain name of the site"
|
description = "The domain name of the site"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
variable "tuffas_applier_role_arn" {
|
||||||
|
type = string
|
||||||
|
description = "IAM role ARN for Terraform to assume when applying changes"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "project_name" {
|
||||||
|
type = string
|
||||||
|
description = "Name of the project for resource tagging"
|
||||||
|
default = "tuffas"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "environment" {
|
||||||
|
type = string
|
||||||
|
description = "Environment name (e.g., dev, staging, prod)"
|
||||||
|
|
||||||
|
validation {
|
||||||
|
condition = contains(["dev", "staging", "prod"], var.environment)
|
||||||
|
error_message = "Environment must be one of: dev, staging, prod."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user