diff --git a/.github/workflows/terraform.yml b/.github/workflows/terraform.yml new file mode 100644 index 0000000..6355177 --- /dev/null +++ b/.github/workflows/terraform.yml @@ -0,0 +1,152 @@ +name: 'Terraform' + +on: + push: + branches: + - master + pull_request: + branches: + - master + +env: + DIGITALOCEAN_TOKEN: ${{ secrets.DIGITALOCEAN_TOKEN }} + PRIVATE_SSH_KEY: ${{ secrets.PRIVATE_SSH_KEY }} + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + CLOUDFLARE_ZONE_ID: ${{ secrets.CLOUDFLARE_ZONE_ID }} + CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + CLOUDFLARE_DOMAIN: ${{ secrets.CLOUDFLARE_DOMAIN }} + KUBECONFIG: ${{ secrets.KUBECONFIG }} + +jobs: + terraform-plan: + name: 'Terraform Plan' + runs-on: ubuntu-latest + outputs: + tfplanExitCode: ${{ steps.tf-plan.outputs.exitcode }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Terraform + uses: hashicorp/setup-terraform@v3 + with: + terraform_wrapper: false + + - name: Write Kubeconfig to Disk + run: | + mkdir ~/.kube + echo "$KUBECONFIG" > ~/.kube/config + + - name: Terraform Init + working-directory: ./tf + run: terraform init + + - name: Terraform Format + working-directory: ./tf + run: terraform fmt -check + + - name: Terraform Plan + id: tf-plan + working-directory: ./tf + run: | + export exitcode=0 + terraform plan \ + -var "do_token=$DIGITALOCEAN_TOKEN" \ + -var "pvt_key=$PRIVATE_SSH_KEY" \ + -var "cloudflare_api_token=$CLOUDFLARE_API_TOKEN" \ + -var "cloudflare_zone_id=$CLOUDFLARE_ZONE_ID" \ + -var "cloudflare_account_id=$CLOUDFLARE_ACCOUNT_ID" \ + -var "cloudflare_domain=$CLOUDFLARE_DOMAIN" \ + -detailed-exitcode \ + -no-color \ + -out tfplan \ + || export exitcode=$? + + echo "exitcode=$exitcode" >> $GITHUB_OUTPUT + + if [ $exitcode -eq 1 ]; then + echo Terraform Plan Failed! + exit 1 + else + exit 0 + fi + + - name: Publish Terraform Plan + uses: actions/upload-artifact@v4 + with: + name: tfplan + path: tfplan + + - name: Create String Output + id: tf-plan-string + working-directory: ./tf + run: | + TERRAFORM_PLAN=$(terraform show -no-color tfplan) + + delimiter="$(openssl rand -hex 8)" + echo "summary<<${delimiter}" >> $GITHUB_OUTPUT + echo "## Terraform Plan Output" >> $GITHUB_OUTPUT + echo "
Click to expand" >> $GITHUB_OUTPUT + echo "" >> $GITHUB_OUTPUT + echo '```terraform' >> $GITHUB_OUTPUT + echo "$TERRAFORM_PLAN" >> $GITHUB_OUTPUT + echo '```' >> $GITHUB_OUTPUT + echo "
" >> $GITHUB_OUTPUT + echo "${delimiter}" >> $GITHUB_OUTPUT + + - name: Publish Terraform Plan to Task Summary + env: + SUMMARY: ${{ steps.tf-plan-string.outputs.summary }} + run: | + echo "$SUMMARY" >> $GITHUB_STEP_SUMMARY + + - name: Push Terraform Output to PR + if: github.ref != 'refs/heads/master' + uses: actions/github-script@v7 + env: + SUMMARY: "${{ steps.tf-plan-string.outputs.summary }}" + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const body = `${process.env.SUMMARY}`; + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: body + }) + + terraform-apply: + name: 'Terraform Apply' + if: github.ref == 'refs/heads/master' && needs.terraform-plan.outputs.tfplanExitCode == 2 + runs-on: ubuntu-latest + needs: [terraform-plan] + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Terraform + uses: hashicorp/setup-terraform@v3 + + - name: Terraform Init + working-directory: ./tf + run: terraform init + + - name: Download Terraform Plan + uses: actions/download-artifact@v4 + with: + name: tfplan + + - name: Terraform Apply + working-directory: ./tf + run: terraform apply \ + -var "do_token=$DIGITALOCEAN_TOKEN" \ + -var "pvt_key=$PRIVATE_SSH_KEY" \ + -var "cloudflare_api_token=$CLOUDFLARE_API_TOKEN" \ + -var "cloudflare_zone_id=$CLOUDFLARE_ZONE_ID" \ + -var "cloudflare_account_id=$CLOUDFLARE_ACCOUNT_ID" \ + -var "cloudflare_domain=$CLOUDFLARE_DOMAIN" \ + -auto-approve \ + tfplan diff --git a/tf/aws.tf b/tf/aws.tf new file mode 100644 index 0000000..d05730f --- /dev/null +++ b/tf/aws.tf @@ -0,0 +1,2 @@ +# variable "aws_access_key" {} +# variable "aws_secret_key" {} diff --git a/tf/cloudflare.tf b/tf/cloudflare.tf new file mode 100644 index 0000000..9a97bca --- /dev/null +++ b/tf/cloudflare.tf @@ -0,0 +1,271 @@ +variable "cloudflare_api_token" {} +variable "cloudflare_zone_id" {} +variable "cloudflare_account_id" {} +variable "cloudflare_domain" {} + +resource "cloudflare_record" "terraform_managed_resource_c777c536e462f6e23c88838db09ecc15" { + name = "akatsuki.gg" + proxied = true + ttl = 1 + type = "A" + value = "68.183.196.157" + zone_id = var.cloudflare_zone_id +} + +resource "cloudflare_record" "terraform_managed_resource_179f0b68cd0e7f97a07175291846cc1f" { + name = "a" + proxied = true + ttl = 1 + type = "CNAME" + value = "akatsuki.gg" + zone_id = var.cloudflare_zone_id +} + +resource "cloudflare_record" "terraform_managed_resource_7097f7485cca66490f13b70f7309453b" { + name = "air_conditioning" + proxied = true + ttl = 1 + type = "CNAME" + value = "akatsuki.gg" + zone_id = var.cloudflare_zone_id +} + +resource "cloudflare_record" "terraform_managed_resource_94b09abead16cf373a0e864a6a405253" { + name = "assets" + proxied = true + ttl = 1 + type = "CNAME" + value = "akatsuki.gg" + zone_id = var.cloudflare_zone_id +} + +resource "cloudflare_record" "terraform_managed_resource_6ee19f44bf87065363caee9d3c05a7a5" { + name = "b" + proxied = true + ttl = 1 + type = "CNAME" + value = "akatsuki.gg" + zone_id = var.cloudflare_zone_id +} + +resource "cloudflare_record" "terraform_managed_resource_fad0bd13cea5e0fb81469c735ecb612a" { + name = "beatmaps" + proxied = true + ttl = 1 + type = "CNAME" + value = "akatsuki.gg" + zone_id = var.cloudflare_zone_id +} + +resource "cloudflare_record" "terraform_managed_resource_716ef8ba0d0d3bf5ac99d7b86afa7477" { + name = "c" + proxied = true + ttl = 1 + type = "CNAME" + value = "akatsuki.gg" + zone_id = var.cloudflare_zone_id +} + +resource "cloudflare_record" "terraform_managed_resource_60590adccff06bef9cc8cd88cfcb7595" { + name = "difficulty" + proxied = true + ttl = 1 + type = "CNAME" + value = "akatsuki.gg" + zone_id = var.cloudflare_zone_id +} + +resource "cloudflare_record" "terraform_managed_resource_5f3fba0f5e45e88a9c153b6de0f2099e" { + name = "k8s2" + proxied = true + ttl = 1 + type = "CNAME" + value = "akatsuki.gg" + zone_id = var.cloudflare_zone_id +} + +resource "cloudflare_record" "terraform_managed_resource_ae7787c943c44985f691ef77f11fdbb3" { + name = "k8s" + proxied = true + ttl = 1 + type = "CNAME" + value = "akatsuki.gg" + zone_id = var.cloudflare_zone_id +} + +resource "cloudflare_record" "terraform_managed_resource_49009678a2c31101a4b0484428c5ee9e" { + name = "old" + proxied = true + ttl = 1 + type = "CNAME" + value = "akatsuki.gg" + zone_id = var.cloudflare_zone_id +} + +resource "cloudflare_record" "terraform_managed_resource_e5f9fa810f24478ec6212e2e5bd40542" { + name = "osu" + proxied = true + ttl = 1 + type = "CNAME" + value = "akatsuki.gg" + zone_id = var.cloudflare_zone_id +} + +resource "cloudflare_record" "terraform_managed_resource_e0d1427279c9900c22b897d7b33efd9c" { + name = "payments" + proxied = true + ttl = 1 + type = "CNAME" + value = "akatsuki.gg" + zone_id = var.cloudflare_zone_id +} + +resource "cloudflare_record" "terraform_managed_resource_f8963f0589aab4febc666e249e3b18a3" { + name = "performance" + proxied = true + ttl = 1 + type = "CNAME" + value = "akatsuki.gg" + zone_id = var.cloudflare_zone_id +} + +resource "cloudflare_record" "terraform_managed_resource_3d6cfd3fe505689a876871896cb5178c" { + name = "pypi2" + proxied = true + ttl = 1 + type = "CNAME" + value = "akatsuki.gg" + zone_id = var.cloudflare_zone_id +} + +resource "cloudflare_record" "terraform_managed_resource_09dffb3d0ed5812c62c6886c823fb0b1" { + name = "pypi" + proxied = true + ttl = 1 + type = "CNAME" + value = "akatsuki.gg" + zone_id = var.cloudflare_zone_id +} + +resource "cloudflare_record" "terraform_managed_resource_ac35937a3b1dd16002c34ff979c1c69c" { + name = "relax" + proxied = true + ttl = 1 + type = "CNAME" + value = "akatsuki.gg" + zone_id = var.cloudflare_zone_id +} + +resource "cloudflare_record" "terraform_managed_resource_e3e21a2cfcf8d367fb84fffd12881f8d" { + name = "rework" + proxied = true + ttl = 1 + type = "CNAME" + value = "akatsuki.gg" + zone_id = var.cloudflare_zone_id +} + +resource "cloudflare_record" "terraform_managed_resource_660b7bf2540aeb1d28590e866876ca44" { + name = "reworks" + proxied = true + ttl = 1 + type = "CNAME" + value = "akatsuki.gg" + zone_id = var.cloudflare_zone_id +} + +resource "cloudflare_record" "terraform_managed_resource_607a671bcc399aee897f192ffbf904e2" { + name = "s" + proxied = true + ttl = 1 + type = "CNAME" + value = "akatsuki.gg" + zone_id = var.cloudflare_zone_id +} + +resource "cloudflare_record" "terraform_managed_resource_615173b6009fc0169a1d8471d781d8b1" { + name = "vault2" + proxied = true + ttl = 1 + type = "CNAME" + value = "akatsuki.gg" + zone_id = var.cloudflare_zone_id +} + +resource "cloudflare_record" "terraform_managed_resource_4661649de0c6385b1bc5c4a10c33ba8f" { + name = "vault" + proxied = true + ttl = 1 + type = "CNAME" + value = "akatsuki.gg" + zone_id = var.cloudflare_zone_id +} + +resource "cloudflare_record" "terraform_managed_resource_d37fc100eb9a8a0eec2f25281d95a7b1" { + name = "www" + proxied = true + ttl = 1 + type = "CNAME" + value = "akatsuki.gg" + zone_id = var.cloudflare_zone_id +} + +resource "cloudflare_record" "terraform_managed_resource_cddb658c1a211af6540fc615cae450ca" { + name = "akatsuki.gg" + priority = 15 + proxied = false + ttl = 1 + type = "MX" + value = "3h5azgn53tixa3a2yxyqkgyethll22hdjl7jj5jshsfw2wpalkhq.mx-verification.google.com" + zone_id = var.cloudflare_zone_id +} + +resource "cloudflare_record" "terraform_managed_resource_bbe86d4aacefd3b9e041971237326ad3" { + name = "akatsuki.gg" + priority = 10 + proxied = false + ttl = 1 + type = "MX" + value = "alt4.aspmx.l.google.com" + zone_id = var.cloudflare_zone_id +} + +resource "cloudflare_record" "terraform_managed_resource_e053bc92f9485f547e1bab88cd49f63e" { + name = "akatsuki.gg" + priority = 10 + proxied = false + ttl = 1 + type = "MX" + value = "alt3.aspmx.l.google.com" + zone_id = var.cloudflare_zone_id +} + +resource "cloudflare_record" "terraform_managed_resource_ede7c6ea5f4e989e2f41010a704d8ccc" { + name = "akatsuki.gg" + priority = 5 + proxied = false + ttl = 1 + type = "MX" + value = "alt2.aspmx.l.google.com" + zone_id = var.cloudflare_zone_id +} + +resource "cloudflare_record" "terraform_managed_resource_18809f26ceae1650b15bd34708cf5209" { + name = "akatsuki.gg" + priority = 5 + proxied = false + ttl = 1 + type = "MX" + value = "alt1.aspmx.l.google.com" + zone_id = var.cloudflare_zone_id +} + +resource "cloudflare_record" "terraform_managed_resource_cc99f7278220097b3f5762ec3d8a964c" { + name = "akatsuki.gg" + priority = 1 + proxied = false + ttl = 1 + type = "MX" + value = "aspmx.l.google.com" + zone_id = var.cloudflare_zone_id +} diff --git a/tf/digitalocean.tf b/tf/digitalocean.tf new file mode 100644 index 0000000..be53bae --- /dev/null +++ b/tf/digitalocean.tf @@ -0,0 +1,102 @@ +variable "do_token" {} +variable "pvt_key" {} + +data "digitalocean_ssh_key" "cmyui_ssh_key" { + name = "cmyui desktop" +} + +resource "digitalocean_project" "akatsuki-production" { + name = "akatsuki-production" + description = null + purpose = "Web Application" + environment = "Production" + is_default = true +} + +resource "digitalocean_vpc" "akatsuki-production-vpc" { + region = "tor1" + name = "akatsuki-production" + description = null + ip_range = "10.118.0.0/20" +} + +resource "digitalocean_tag" "k8s-production" { + name = "k8s-production" +} + +resource "digitalocean_droplet" "infrastructure01-droplet" { + region = "tor1" + name = "infrastructure01.akatsuki.gg" + image = "ubuntu-23-10-x64" + size = "s-2vcpu-2gb" + backups = false + resize_disk = true + tags = [] + vpc_uuid = digitalocean_vpc.akatsuki-production-vpc.id +} + +resource "digitalocean_droplet" "k8s-master01-droplet" { + region = "tor1" + name = "k8s-master01.akatsuki.gg" + image = "140878882" + size = "s-2vcpu-2gb" + backups = false + resize_disk = true + tags = [digitalocean_tag.k8s-production.name] + vpc_uuid = digitalocean_vpc.akatsuki-production-vpc.id +} + +resource "digitalocean_droplet" "k8s-worker01-droplet" { + region = "tor1" + name = "k8s-worker01.akatsuki.gg" + image = "140878882" + size = "s-4vcpu-8gb-intel" + backups = false + resize_disk = true + tags = [digitalocean_tag.k8s-production.name] + vpc_uuid = digitalocean_vpc.akatsuki-production-vpc.id +} + +resource "digitalocean_droplet" "k8s-worker02-droplet" { + region = "tor1" + name = "k8s-worker02.akatsuki.gg" + image = "ubuntu-23-10-x64" + size = "s-4vcpu-8gb-intel" + backups = false + resize_disk = true + tags = [digitalocean_tag.k8s-production.name] + vpc_uuid = digitalocean_vpc.akatsuki-production-vpc.id +} + +resource "digitalocean_droplet" "k8s-worker04-droplet" { + region = "tor1" + name = "k8s-worker04.akatsuki.gg" + image = "ubuntu-23-10-x64" + size = "s-4vcpu-8gb-intel" + backups = false + resize_disk = true + tags = [digitalocean_tag.k8s-production.name] + vpc_uuid = digitalocean_vpc.akatsuki-production-vpc.id +} + +resource "digitalocean_droplet" "mysql-master01-droplet" { + region = "tor1" + name = "mysql-master01.akatsuki.gg" + image = "ubuntu-23-10-x64" + size = "s-4vcpu-8gb-intel" + backups = false + resize_disk = true + tags = [] + vpc_uuid = digitalocean_vpc.akatsuki-production-vpc.id +} + +resource "digitalocean_droplet" "rabbitmq-worker01-droplet" { + region = "tor1" + name = "rabbitmq-worker01.akatsuki.gg" + image = "ubuntu-23-10-x64" + size = "s-1vcpu-2gb" + backups = false + resize_disk = true + tags = [] + vpc_uuid = digitalocean_vpc.akatsuki-production-vpc.id +} diff --git a/tf/provider.tf b/tf/provider.tf new file mode 100644 index 0000000..719532f --- /dev/null +++ b/tf/provider.tf @@ -0,0 +1,46 @@ +terraform { + # backend "s3" { + # bucket = "akatsuki-terraform-state" + # key = "terraform.tfstate" + # region = "ca-central-1" + # } + backend "kubernetes" { + secret_suffix = "state" + config_path = "~/.kube/config" + } + + required_providers { + # aws = { + # source = "hashicorp/aws" + # version = "~> 5.0" + # } + digitalocean = { + source = "digitalocean/digitalocean" + version = "~> 2.0" + } + cloudflare = { + source = "cloudflare/cloudflare" + version = "~> 4" + } + } +} + +# provider "aws" { +# endpoints { +# s3 = "https://s3.ca-central-1.wasabisys.com" +# iam = "https://iam.wasabisys.com" +# sts = "https://sts.wasabisys.com" +# sso = "https://sso.wasabisys.com" +# } +# region = "ca-central-1" +# access_key = var.aws_access_key +# secret_key = var.aws_secret_key +# } + +provider "digitalocean" { + token = var.do_token +} + +provider "cloudflare" { + api_token = var.cloudflare_api_token +} diff --git a/tf/terraform.tfvars.sample b/tf/terraform.tfvars.sample new file mode 100644 index 0000000..7039d44 --- /dev/null +++ b/tf/terraform.tfvars.sample @@ -0,0 +1,10 @@ +do_token = "" +pvt_key = "/home/josh/.ssh/id_rsa" + +cloudflare_api_token = "" +cloudflare_zone_id = "" +cloudflare_account_id = "" +cloudflare_domain = "akatsuki.gg" + +aws_access_key = "" +aws_secret_key = ""