Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Terraforming Cloudflare for DNS records #3391

Closed
Closed
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
58 changes: 58 additions & 0 deletions .github/workflows/terraform.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: 'Terraform'

on:
push:
branches: [ "main" ]
paths:
- terraform/**
pull_request:
paths:
- terraform/**

permissions:
contents: read

jobs:
terraform:
name: 'Terraform'
runs-on: ubuntu-latest
env:
working-directory: ./terraform

# Use the Bash shell regardless whether the GitHub Actions runner is ubuntu-latest, macos-latest, or windows-latest
defaults:
run:
shell: bash

steps:
# Checkout the repository to the GitHub Actions runner
- name: Checkout
uses: actions/checkout@v3

# Install the latest version of Terraform CLI and configure the Terraform CLI configuration file with a Terraform Cloud user API token
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
with:
cli_config_credentials_token: ${{ secrets.TF_API_TOKEN }}

# Initialize a new or existing Terraform working directory by creating initial files, loading any remote state, downloading modules, etc.
- name: Terraform Init
run: terraform init
working-directory: ${{ env.working-directory }}

# Checks that all Terraform configuration files adhere to a canonical format
- name: Terraform Format
run: terraform fmt -check
working-directory: ${{ env.working-directory }}

# Generates an execution plan for Terraform
- name: Terraform Plan
run: terraform plan -input=false
working-directory: ${{ env.working-directory }}

# On push to "main", build or change infrastructure according to Terraform configuration files
# Note: It is recommended to set up a required "strict" status check in your repository for "Terraform Cloud". See the documentation on "strict" required status checks for more information: https://help.github.com/en/github/administering-a-repository/types-of-required-status-checks
- name: Terraform Apply
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: terraform apply -auto-approve -input=false
working-directory: ${{ env.working-directory }}
34 changes: 34 additions & 0 deletions terraform/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Local .terraform directories
**/.terraform/*

# .tfstate files
*.tfstate
*.tfstate.*

# Crash log files
crash.log

# Ignore any .tfvars files that are generated automatically for each Terraform run. Most
# .tfvars files are managed as part of configuration and so should be included in
# version control.
#
# example.tfvars

# Ignore override files as they are usually used to override resources locally and so
# are not checked in
override.tf
override.tf.json
*_override.tf
*_override.tf.json

# Include override files you do wish to add to version control using negated pattern
#
# !example_override.tf

# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
# example: *tfplan*


# OTHER
*.env
IGNORE/
25 changes: 25 additions & 0 deletions terraform/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

70 changes: 70 additions & 0 deletions terraform/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Cloudflare Infrastructure

This folder manage Node.js Cloudflare settings using Terraform

### Contributing

To modify the Cloudflare settings, you must fork/clone this repository and submit a pull request with the changes. Any alterations made in the `main` branch will be deployed to the Cloudflare account automatically. So, the pull request is required to review the changes before they are deployed.

### Historical Context

Today, we use Terraform to manage DNS records in Cloudflare. Previously, we used the Cloudflare UI for this task. To begin using Terraform, we cloned the Cloudflare settings and migrated them as the initial Terraform state using the utility cf-terraforming. This step was completed only once, and the state was stored in Terraform Cloud.

Since the imported resources had non-human friendly names like "terraform_managed_resource_*," we cannot change their names to prevent recreation or updates of the resources. However, we can use our own naming conventions for new Terraform resources, and there is no need to run the cf-terraforming utility again.


### General overview

<img width="946" alt="Captura de pantalla 2023-06-29 a las 8 58 37" src="https://github.com/nodejs/build/assets/5110813/46d2715c-0d9d-4eb4-96a9-f6eac772936a">


**Green path**

This is the default way (and recommended) when we want to make any changes in Cloudflare once this PR is merged. Any user can create a PR and add/update/remove resources from Cloudflare. Once the PR is merged, the GitHub actions will notify this change directly to Terraform Cloud. Terraform Cloud will apply the changes in Cloudflare.

**Blue path**

Any user who has access to Terraform Cloud (can use or generate a token). This token can be used in the same way as the GitHub actions do in the green path. So, even if you don't have access to Cloudflare, when you trigger a new plan directly from Terraform Cloud, it will be applied as Terraform Cloud can authenticate against Cloudflare.

This option is quite interesting as it is the best way to import resources. For example, as @nschonni suggested with the firewall rules.

**Red path**

As far I know is what we do today, the user has write access to Cloudflare and can make changes via web UI or CLI. This option remains possible even when this PR is merged.

Only a few people in the org have this access level, which will be used, for example, to modify Cloudflare settings for items that are not covered with Terraform.


### How to review changes in a PR?

The terraform plan is generated automatically in the PR. You can review the changes in the `terraform plan` section in the PR.

There are two possible scenarios:
- No changes
- Changes required

When changes are required you can see the details in the `terraform plan` section. Here you have several isolated examples of the changes:
- [Add resource](https://github.com/UlisesGascon/poc-nodejs-cloudflare-terraform/pull/5)
UlisesGascon marked this conversation as resolved.
Show resolved Hide resolved
- [Update resource](https://github.com/UlisesGascon/poc-nodejs-cloudflare-terraform/pull/6)
- [Delete resource](https://github.com/UlisesGascon/poc-nodejs-cloudflare-terraform/pull/4)

Note that any change can combine several of the previous examples. For example, you can see a change that add a resource and update another one.

Once the PR is merged, the changes will be applied in the Cloudflare account via Github Action.

### Local development

#### IMPORTANT ⚠️
If you apply any plan in you local machine, you can trigger changes in the Cloudflare account. So, you must be careful with the changes you are applying in your local environment. In order to review/create changes you are not require to do local development as the github pipeline will generate a plan with the changes.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@UlisesGascon I would have thought you would need Cloudflare access for anything you do locally to have an effect?



#### Requirements
- Terraform version `Terraform v1.4.5` used to build this infrastructure. [How to install Terraform](https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli)
- You will need a `TF_API_TOKEN` in you environment with a valid Terraform cloud API Key. [How to create a Terraform cloud API Key](https://www.terraform.io/docs/cloud/users-teams-organizations/api-tokens.html#creating-an-api-token)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this is related to my question above. I assume we don't expect anybody to be doing this. Intead there should be a PR and the action which has the TF_API_TOKEN will apply any changes.



### Reference
- [Fireship | Terraform in 100 Seconds](https://www.youtube.com/watch?v=tomUWcQ0P3k)
- [Terraform Cheatsheet](https://acloudguru.com/blog/engineering/the-ultimate-terraform-cheatsheet)
- [Youtube | Automate Cloudflare with Terraform and GitHub Actions! - Terraform Tutorial for Beginners](https://www.youtube.com/watch?v=FmYvrxYvBP0)
- [Techno Tim Docs | Automate Cloudflare with Terraform and GitHub Actions! - Terraform Tutorial for Beginners](https://docs.technotim.live/posts/terraform-cloudflare-github/)
18 changes: 18 additions & 0 deletions terraform/cloudflare.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
terraform {
cloud {
organization = "nodejs"

workspaces {
name = "nodejs-cloudflare"
}
}
required_providers {
cloudflare = {
source = "cloudflare/cloudflare"
version = "~> 3.0"
}
}
}

provider "cloudflare" {
}
146 changes: 146 additions & 0 deletions terraform/dns_iojs_org.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
resource "cloudflare_record" "terraform_managed_resource_1913231cd4f209515037c1ffee5d4a27" {
name = "direct"
proxied = false
ttl = 1
type = "A"
value = "138.197.224.240"
zone_id = "8c96c2859d246364a9b78b2fee7bee49"
}

resource "cloudflare_record" "terraform_managed_resource_0f6b6757054fdba56c054cca6aecc9be" {
name = "iojs.org"
proxied = false
ttl = 1
type = "A"
value = "138.197.224.240"
zone_id = "8c96c2859d246364a9b78b2fee7bee49"
}

resource "cloudflare_record" "terraform_managed_resource_3e025abdebca0ae6576a71a2c26d2c1b" {
name = "www"
proxied = false
ttl = 1
type = "A"
value = "138.197.224.240"
zone_id = "8c96c2859d246364a9b78b2fee7bee49"
}

resource "cloudflare_record" "terraform_managed_resource_b33f8bbe47906fef181a1592437fd95a" {
name = "iojs.org"
proxied = true
ttl = 1
type = "AAAA"
value = "2604:a880:400:d1::a3c:f001"
zone_id = "8c96c2859d246364a9b78b2fee7bee49"
}

resource "cloudflare_record" "terraform_managed_resource_f356629b68819fd225bdd3394c12b560" {
name = "www"
proxied = true
ttl = 1
type = "AAAA"
value = "2604:a880:400:d1::a3c:f001"
zone_id = "8c96c2859d246364a9b78b2fee7bee49"
}

resource "cloudflare_record" "terraform_managed_resource_bddb08d52eb2227d0dc3e4f7ce056c8b" {
name = "_19b4f8a51243a804259af6d5b2490cbf"
proxied = false
ttl = 1
type = "CNAME"
value = "0fa21492b60cd77cef88dd04e54a6c9b.d5ddcd1a90d12402e4751fb51f52d610.w0936042001502710049.comodoca.com"
zone_id = "8c96c2859d246364a9b78b2fee7bee49"
}

resource "cloudflare_record" "terraform_managed_resource_ddd771da56ee034b1d3203b2c67bbfeb" {
name = "email.iojs.org"
proxied = false
ttl = 1
type = "CNAME"
value = "mailgun.org"
zone_id = "8c96c2859d246364a9b78b2fee7bee49"
}

resource "cloudflare_record" "terraform_managed_resource_1aad4db1f51e00a30cb1d81e5150e32c" {
name = "logos"
proxied = false
ttl = 1
type = "CNAME"
value = "iojs.org"
zone_id = "8c96c2859d246364a9b78b2fee7bee49"
}

resource "cloudflare_record" "terraform_managed_resource_a78309035efe195a7a2607c3f52e7f15" {
name = "new-nodejs"
proxied = false
ttl = 1
type = "CNAME"
value = "www.iojs.org"
zone_id = "8c96c2859d246364a9b78b2fee7bee49"
}

resource "cloudflare_record" "terraform_managed_resource_e146702ef04508a564c99f69e84e78e7" {
name = "roadmap"
proxied = false
ttl = 1
type = "CNAME"
value = "iojs.org"
zone_id = "8c96c2859d246364a9b78b2fee7bee49"
}

resource "cloudflare_record" "terraform_managed_resource_78ef7407c3d14a5c679084b035abe76b" {
name = "iojs.org"
priority = 10
proxied = false
ttl = 1
type = "MX"
value = "mxb.mailgun.org"
zone_id = "8c96c2859d246364a9b78b2fee7bee49"
}

resource "cloudflare_record" "terraform_managed_resource_73d56ede702145a55657302ed70a4def" {
name = "iojs.org"
priority = 10
proxied = false
ttl = 1
type = "MX"
value = "mxa.mailgun.org"
zone_id = "8c96c2859d246364a9b78b2fee7bee49"
}

resource "cloudflare_record" "terraform_managed_resource_fe6cb302ca689b99a71a55c503ddba72" {
name = "_dmarc"
proxied = false
ttl = 1
type = "TXT"
value = "v=DMARC1; p=reject; rua=mailto:[email protected]; ruf=mailto:[email protected]; sp=reject; ri=86400"
zone_id = "8c96c2859d246364a9b78b2fee7bee49"
}

resource "cloudflare_record" "terraform_managed_resource_a586614f723184920a970d2967a5b0f8" {
name = "iojs.org"
proxied = false
ttl = 1
type = "TXT"
value = "\"google-site-verification=sLdkuluh-xi3YZs_Uhobiw1XA_Wjalt8D8O_2jiwudg\""
zone_id = "8c96c2859d246364a9b78b2fee7bee49"
}

resource "cloudflare_record" "terraform_managed_resource_1d4e8509d885efb04761863b0493cbfc" {
name = "iojs.org"
proxied = false
ttl = 1
type = "TXT"
value = "\"v=spf1 include:mailgun.org ~all\""
zone_id = "8c96c2859d246364a9b78b2fee7bee49"
}

resource "cloudflare_record" "terraform_managed_resource_8966613ab75b29a56f3c787f8bb10e56" {
name = "mailo._domainkey"
proxied = false
ttl = 1
type = "TXT"
value = "\"k=rsa\\; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBvSPBv8CLasvSnADi672NJNMa2hK0CTuTIpzCLIz1hfZKcFybimLDvMGFTAhxG3SnQOT9Torm4Ep16kIxjl6c2ms1fmoZr7e0iia4l45vO0/mYs3sZJIOlGDh1r0Vwr6aOB5eJL3D41+HPfdw236mTX+v+W6swQNCHrlXZeIoTQIDAQAB\""
zone_id = "8c96c2859d246364a9b78b2fee7bee49"
}

Loading