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
13 changes: 13 additions & 0 deletions .checkov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
block-list-secret-scan: []
compact: true
directory:
- .
download-external-modules: false
evaluate-variables: true
framework:
- all
output:
- cli
quiet: true
soft-fail: true
summary-position: top
19 changes: 19 additions & 0 deletions .github/workflows/opentofu.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: OpenTofu

on:
pull_request:
branches:
- main
push:
branches:
- main

permissions:
contents: read
pull-requests: write

jobs:
opentofu:
uses: makeitworkcloud/shared-workflows/.github/workflows/opentofu.yml@main
secrets:
SOPS_AGE_KEY: ${{ secrets.SOPS_AGE_KEY }}
16 changes: 16 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# vim swap files
**/*.sw[po]

# don't commit terraform state or lock. the repo code is the only state we care about.
# the provider state cache is auto-upgraded by default to ensure compatibility with upstream cloud provider APIs
**/.terraform.lock.hcl
**/.terraform

# IDE Folders
**/.vscode

# Mac Finder cache
**/.DS_Store

# Plan output
plan-output.txt
36 changes: 36 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: check-case-conflict
- id: check-merge-conflict
- id: check-symlinks
- id: check-vcs-permalinks
- id: destroyed-symlinks
- id: detect-private-key
- id: mixed-line-ending
- id: trailing-whitespace
- repo: https://github.com/antonbabenko/pre-commit-terraform
rev: v1.104.0
hooks:
- id: terraform_validate
args:
- --hook-config=--retry-once-with-cleanup=true
- --args=-no-color
- --tf-init-args=-reconfigure
- --tf-init-args=-upgrade
- id: terraform_tflint
args:
- --args=--minimum-failure-severity=error
- --args=--config=__GIT_WORKING_DIR__/.tflint.hcl
- id: terraform_checkov
args:
- --args=--config-file __GIT_WORKING_DIR__/.checkov.yml
- id: terraform_fmt
args:
- --args=-no-color
- --args=-diff
- --args=-recursive
- id: terraform_docs
args:
- --args=--config=.terraform-docs.yml
3 changes: 3 additions & 0 deletions .sops.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
creation_rules:
- age: age152ek83tm4fj5u70r3fecytn4kg7c5xca24erjchxexx4pfqg6das7q763l
18 changes: 18 additions & 0 deletions .terraform-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
formatter: "markdown"

output:
file: "README.md"
mode: replace

settings:
color: false
lockfile: false

sort:
enabled: true
by: name

# recursive can't be enabled until this bug is fixed:
# https://github.com/terraform-docs/terraform-docs/issues/654
recursive:
enabled: false
12 changes: 12 additions & 0 deletions .tflint.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
plugin "terraform" {
enabled = true
preset = "recommended"
}

rule "terraform_required_providers" {
enabled = false
}

rule "terraform_required_version" {
enabled = false
}
79 changes: 79 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
SHELL := /bin/bash
TERRAFORM := $(shell which tofu)
S3_REGION := $(shell sops decrypt secrets/secrets.yaml | grep ^s3_region | cut -d ' ' -f 2)
S3_BUCKET := $(shell sops decrypt secrets/secrets.yaml | grep ^s3_bucket | cut -d ' ' -f 2)
S3_KEY := $(shell sops decrypt secrets/secrets.yaml | grep ^s3_key | cut -d ' ' -f 2)
S3_ACCESS_KEY := $(shell sops decrypt secrets/secrets.yaml | grep ^s3_access_key | cut -d ' ' -f 2)
S3_SECRET_KEY := $(shell sops decrypt secrets/secrets.yaml | grep ^s3_secret_key | cut -d ' ' -f 2)

.PHONY: help init plan apply migrate test pre-commit-check-deps pre-commit-install-hooks argcd-login

help:
@echo "General targets"
@echo "----------------"
@echo
@echo "\thelp: show this help text"
@echo "\tclean: removes all .terraform directories"
@echo
@echo "Terraform targets"
@echo "-----------------"
@echo
@echo "\tinit: run 'terraform init'"
@echo "\ttest: run pre-commmit checks"
@echo "\tplan: run 'terraform plan'"
@echo "\tapply: run 'terraform apply'"
@echo "\tmigrate; run terraform init -migrate-state"
@echo
@echo "One-time repo init targets"
@echo "--------------------------"
@echo
@echo "\tpre-commit-install-hooks: install pre-commit hooks"
@echo "\tpre-commit-check-deps: check pre-commit dependencies"
@echo

clean:
@find . -name .terraform -type d | xargs -I {} rm -rf {}

init: clean .terraform/terraform.tfstate

.terraform/terraform.tfstate:
@${TERRAFORM} init -reconfigure -upgrade -input=false -backend-config="key=${S3_KEY}" -backend-config="bucket=${S3_BUCKET}" -backend-config="region=${S3_REGION}" -backend-config="access_key=${S3_ACCESS_KEY}" -backend-config="secret_key=${S3_SECRET_KEY}"

plan: init .terraform/plan

.terraform/plan:
@${TERRAFORM} plan -compact-warnings -no-color -out tfplan.bin
@${TERRAFORM} show -no-color tfplan.bin | tee plan-output.txt
@rm -f tfplan.bin

apply: init .terraform/apply

.terraform/apply:
@${TERRAFORM} apply -auto-approve -compact-warnings

migrate:
@echo "First use -make init- using the old S3 backend, then run -make migrate- to use the new one."
@${TERRAFORM} init -migrate-state -backend-config="key=${S3_KEY}" -backend-config="bucket=${S3_BUCKET}" -backend-config="region=${S3_REGION}" -backend-config="access_key=${S3_ACCESS_KEY}" -backend-config="secret_key=${S3_SECRET_KEY}"

test: .git/hooks/pre-commit
@pre-commit run -a

DEPS_PRE_COMMIT=$(shell which pre-commit || echo "pre-commit not found")
DEPS_TERRAFORM_DOCS=$(shell which terraform-docs || echo "terraform-docs not found")
DEPS_TFLINT=$(shell which tflint || echo "tflint not found,")
DEPS_CHECKOV=$(shell which checkov || echo "checkov not found,")
DEPS_JQ=$(shell which jq || echo "jq not found,")
pre-commit-check-deps:
@echo "Checking for pre-commit and its dependencies:"
@echo " pre-commit: ${DEPS_PRE_COMMIT}"
@echo " terraform-docs: ${DEPS_TERRAFORM_DOCS}"
@echo " tflint: ${DEPS_TFLINT}"
@echo " checkov: ${DEPS_CHECKOV}"
@echo " jq: ${DEPS_JQ}"
@echo ""

pre-commit-install-hooks: .git/hooks/pre-commit

.git/hooks/pre-commit: pre-commit-check-deps
@pre-commit install --install-hooks

19 changes: 19 additions & 0 deletions aws-iam.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
resource "aws_iam_user" "admin" {
for_each = local.admin_users
name = each.value
force_destroy = false
tags = {
ManagedBy = "Terraform"
}
}

resource "aws_iam_user_policy_attachment" "admin_attach" {
for_each = local.admin_users
user = aws_iam_user.admin[each.key].name
policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"
}

resource "aws_iam_access_key" "admin_key" {
for_each = local.admin_users
user = aws_iam_user.admin[each.key].name
}
107 changes: 107 additions & 0 deletions aws-s3.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
resource "aws_s3_bucket" "private" {
for_each = local.s3_private_buckets
bucket = each.value

tags = {
ManagedBy = "Terraform"
}

lifecycle {
prevent_destroy = true
}
}

resource "aws_s3_bucket" "public" {
for_each = local.s3_public_buckets
bucket = each.value

tags = {
ManagedBy = "Terraform"
}

lifecycle {
prevent_destroy = true
}
}

resource "aws_s3_bucket_public_access_block" "public" {
for_each = aws_s3_bucket.public
bucket = each.value.id
block_public_acls = false
block_public_policy = false
ignore_public_acls = false
restrict_public_buckets = false
}

resource "aws_s3_bucket_policy" "public" {
for_each = aws_s3_bucket.public

bucket = each.value.id

policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = "*"
Action = [
"s3:GetObject"
]
Resource = "${each.value.arn}/*"
}
]
})
}

resource "aws_s3_bucket" "web" {
for_each = local.s3_web_buckets
bucket = each.value

tags = {
ManagedBy = "Terraform"
}

lifecycle {
prevent_destroy = true
}
}

# Make "web" buckets publicly accessible
resource "aws_s3_bucket_public_access_block" "web" {
for_each = aws_s3_bucket.web
bucket = each.value.id
block_public_acls = false
block_public_policy = false
ignore_public_acls = false
restrict_public_buckets = false
}

resource "aws_s3_bucket_policy" "web" {
for_each = aws_s3_bucket.web

bucket = each.value.id

policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = "*"
Action = [
"s3:GetObject"
]
Resource = "${each.value.arn}/*"
}
]
})
}

resource "aws_s3_bucket_website_configuration" "web" {
for_each = aws_s3_bucket.web

bucket = each.value.id

index_document {
suffix = "index.html"
}
}
18 changes: 18 additions & 0 deletions main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
data "sops_file" "secret_vars" {
source_file = "${path.module}/secrets/secrets.yaml"
}

locals {
admin_users = toset(["svc-terraform-admin"])
s3_private_buckets = toset([
"mitw-tf-aws-infra",
"mitw-tf-cloudflare-infra",
"mitw-tf-github-repos",
"mitw-tf-libvirt-infra"
])
s3_public_buckets = toset([])
s3_web_buckets = toset([
"makeitwork.cloud",
"onion.makeitwork.cloud"
])
}
16 changes: 16 additions & 0 deletions outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
output "admin_access_keys" {
description = "Admin IAM user access keys"
value = { for user, key in aws_iam_access_key.admin_key : user => {
access_key_id = key.id
secret_access_key = key.secret
} }
sensitive = true
}

output "web_bucket_endpoints" {
value = {
for k, b in aws_s3_bucket.web :
k => aws_s3_bucket_website_configuration.web[k].website_endpoint
}
description = "Website endpoints for public web S3 buckets"
}
22 changes: 22 additions & 0 deletions providers.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
terraform {
required_version = "> 1.3"

backend "s3" {}

required_providers {
sops = {
source = "carlpett/sops"
}
aws = {
source = "hashicorp/aws"
}
}
}

provider "sops" {}

provider "aws" {
region = data.sops_file.secret_vars.data["s3_region"]
access_key = data.sops_file.secret_vars.data["s3_access_key"]
secret_key = data.sops_file.secret_vars.data["s3_secret_key"]
}
Loading