aboutsummaryrefslogtreecommitdiff
path: root/content/blog/terraform
diff options
context:
space:
mode:
Diffstat (limited to 'content/blog/terraform')
-rw-r--r--content/blog/terraform/caa.md20
-rw-r--r--content/blog/terraform/email-dns-unused-zone.md104
2 files changed, 114 insertions, 10 deletions
diff --git a/content/blog/terraform/caa.md b/content/blog/terraform/caa.md
index 2f3f9ad..defcd6a 100644
--- a/content/blog/terraform/caa.md
+++ b/content/blog/terraform/caa.md
@@ -7,15 +7,15 @@ tags:
- terraform
---
-# Introduction
+## Introduction
Certification Authority Authorization (CAA) are a type of DNS records that allows the owner of a domain to restrict which Certificate Authority (CA) can emit a certificate for the domain. This is a protection mechanism that is easy to setup and that has absolutely no drawbacks.
One good reason to use CAA records in our modern world of servers running in the cloud is that when you decommission or change a server you very often lose access to its IP address and get a new one. If you mess up cleaning the old IP address from your DNS records and have no CAA records, someone who grabs it could then start issuing certificates for your domain.
-# CAA records
+## CAA records
-## Basics
+### Basics
CAA record can be queried with your favorite DNS lookup utility (`dig`, `drill`, `nslookup`, etc). A basic example looks like this:
```
@@ -26,7 +26,7 @@ $ dig +short CAA adyxax.org
In this example, letsencrypt is authorized to issue both standard and wildcard certificates for the adyxax.org domain.
-## Getting notified of wrongful attempts
+### Getting notified of wrongful attempts
There are several bits of syntax in the RFC that can be of interest, especially if you want to be notified when someone tries to issue a certificate from an unauthorized CA:
@@ -37,7 +37,7 @@ $ dig +short CAA adyxax.org
0 issuewild "letsencrypt.org"
```
-## Securing a domain even further
+### Securing a domain even further
There are other extensions that allow domain owners to restrict even more things like which certificate validation method can be used. Just keep in mind that these extensions will vary from CA to CA and you will need to read the documentation of your CA of choice. A letsencrypt locked down certificate issuance to a specific account ID with a specific validation method looks like this:
@@ -49,15 +49,15 @@ $ dig +short CAA adyxax.org
With this configuration, I can be pretty sure only I will be able to generate a (wildcard, other types are not authorized) certificate for my domain.
-## Caveat
+### Caveat
Note that some DNS providers that offer hosting services will sometimes provision invisible CAA records on your behalf and it might not be obvious this is happening. For example if your domain is hosted on Cloudflare and you use their `pages` service, they will add CAA records to issue their certificates. You will be able to see these records using your lookup tool, but not if you look at your Cloudflare dashboard.
-# Opentofu code
+## Opentofu code
The following code examples will first feature a standard version (suitable for AWS, GCP and other providers), and one for Cloudflare. Cloudflare records are built different than other providers I know of because the Cloudflare terraform provider does some validation by itself while others simply rely on their APIs. Another important difference is that terraform resources use a list of records as input, while Cloudflare forces you to create one resource per value you need for a record. Yes this will clutter your terraform states!
-## Basic
+### Basic
Here is a simple definition for multiple zones managed the same way on AWS:
```hcl
@@ -133,7 +133,7 @@ resource "cloudflare_record" "caa" {
}
```
-## Advanced
+### Advanced
Here is a more advanced definition that handles zones that have different needs than others, as well as CAs that have multiple signing domains like AWS does:
```hcl
@@ -236,6 +236,6 @@ resource "cloudflare_record" "caa" {
}
```
-# Conclusion
+## Conclusion
I hope I showed you that CAA records are both useful and accessible. Please start protecting your domains with CAA records now!
diff --git a/content/blog/terraform/email-dns-unused-zone.md b/content/blog/terraform/email-dns-unused-zone.md
new file mode 100644
index 0000000..cc8dc77
--- /dev/null
+++ b/content/blog/terraform/email-dns-unused-zone.md
@@ -0,0 +1,104 @@
+---
+title: Email DNS records for zones that do not send emails
+description: Automated with terraform/opentofu
+date: 2024-09-03
+tags:
+- cloudflare
+- DNS
+- opentofu
+- terraform
+---
+
+## Introduction
+
+There are multiple DNS records one needs to configure in order to setup and securely use a domain to send or receive emails: MX, DKIM, DMARC and SPF.
+
+An often overlooked fact is that you also need to configure some of these records even if you do not intend to use a domain to send emails. If you do not, scammers will spoof your domain to send fraudulent emails and your domain's reputation will suffer.
+
+## DNS email records you need
+
+### SPF
+
+The most important and only required record you need is a TXT record on the apex of your domain that advertises the fact that no server can send emails from your domain:
+```
+"v=spf1 -all"
+```
+
+### MX
+
+If you do not intend to ever send emails, you certainly do not intend to receive emails either. Therefore you should consider removing all MX records on your zone. Oftentimes your registrar will provision some pointing to a free email infrastructure that they provide along with your domain.
+
+### DKIM
+
+You do not need DKIM records if you are not sending emails.
+
+### DMARC
+
+While not strictly necessary, I strongly recommend to set a DMARC record that instructs the world to explicitly reject all emails not matching the SPF policy:
+
+```
+"v=DMARC1;p=reject;sp=reject;pct=100"
+```
+
+## Terraform / OpenTofu code
+
+### Zones
+
+I use a map of simple objects to specify email profiles for my DNS zones:
+``` hcl
+locals {
+ zones = {
+ "adyxax.eu" = { emails = "adyxax" }
+ "adyxax.org" = { emails = "adyxax" }
+ "anne-so-et-julien.fr" = { emails = "no" }
+ }
+}
+
+data "cloudflare_zone" "main" {
+ for_each = local.zones
+
+ name = each.key
+}
+```
+
+### SPF
+
+Then I map each profile to spf records:
+``` hcl
+locals {
+ spf = {
+ "adyxax" = "v=spf1 mx -all"
+ "no" = "v=spf1 -all"
+ }
+}
+
+resource "cloudflare_record" "spf" {
+ for_each = local.zones
+
+ name = "@"
+ type = "TXT"
+ value = local.spf[each.value.emails]
+ zone_id = data.cloudflare_zone.main[each.key].id
+}
+```
+
+### DMARC
+
+The same mapping system we had for spf can be used here too, but I choose to keep things simple and in the scope of this article. My real setup has some clever tricks to make dmarc notifications work centralized to a single domain that will be the subject another post:
+
+``` hcl
+resource "cloudflare_record" "dmarc" {
+ for_each = { for name, info in local.zones :
+ name => info if info.emails == "no"
+ }
+
+ name = "@"
+ type = "TXT"
+ value = "v=DMARC1;p=reject;sp=reject;pct=100"
+ zone_id = data.cloudflare_zone.main[each.key].id
+}
+```
+
+## Conclusion
+
+Please keep your email DNS records tight and secure!