Creating DNS Records
Technical Background
DNS (Domain Name System) maps hostnames to IP addresses and provides aliases for easier access.
In this exercise, we use Terraform to:
- Create
A
records pointing to a fixed IP (1.2.3.4
). - Create
CNAME
alias records referencing the canonical hostname. - Ensure flexibility via variables and enforce configuration correctness through validation rules.
Reasons to use Terraform for DNS:
- Automation: Avoid manual
nsupdate
commands. - Reusability: Define variables for domain, canonical host, and aliases.
- Validation: Prevent alias conflicts (e.g., duplicate aliases or alias identical to canonical host).
Solution
Prerequisits
Create the same files and folder structure as done before in exercise 18 Enhancing The Web Server.
Configure DNS Provider
- Add required DNS provider to
KnownHostsByModule/providers.tf
:
terraform {
required_providers {
hcloud = {
source = "hetznercloud/hcloud"
}
dns = {
source = "hashicorp/dns"
version = "~> 3.0"
}
}
required_version = ">= 0.13"
}
- Define the DNS provider in
KnownHostsByModule/providers.tf
:
provider "dns" {
update {
server = "ns1.sdi.hdm-stuttgart.cloud"
key_name = "gXY.key."
key_algorithm = "hmac-sha512"
key_secret = var.dns_secret
}
}
Add DNS Secret
- Store your yout DNS Secret inside your
secrets.auto.tfvars
:
dns_secret = "<your-dns-secret>"
Warning
Make your it's always in a file that is version-controlled and published to the internet.
- Create
dns_secret
variable in/KnownHostsByModule/variables.tf
:
variable "dns_secret" {
type = string
sensitive = true
}
Define Input Variables
- Create these variables in
/KnownHostsByModule/variables.tf
:
variable "dns_zone" {
type = string
description = "DNS zone (must end with a dot)"
validation {
condition = can(regex("\\.$", var.dns_zone))
error_message = "dnsZone must end with a dot (e.g., g12.sdi.hdm-stuttgart.cloud.)"
}
}
variable "server_ip" {
type = string
description = "IPv4 address of the server"
}
variable "server_name" {
type = string
description = "Canonical server name"
}
variable "server_aliases" {
type = list(string)
description = "A list of aliases (CNAMEs) pointing to the server"
validation {
error_message = "Aliases must be unique and must not match the canonical server name."
condition = length(distinct(var.server_aliases)) == length(var.serverAliases) && !contains(var.serverAliases, var.serverName)
}
}
Note
The validation attributes stops DNS update failures.
- Create
/KnownHostsByModule/config.auto.tfvars
and configure the variables:
server_ip = "1.2.3.4"
dns_zone = "g11.sdi.hdm-stuttgart.cloud."
server_name = "workhorse"
server_aliases = ["www", "mail"]
Warning
Put config.auto.tfvars
in your .gitignore
if it contains sensitive or environment-specific data, such as:
- API keys (dns_secret via environment variables, if accidentally written in the file)
- Server IP addresses that are temporary or private
- Group-specific DNS zones (if not intended for public)
Create DNS Records
- Create
/KnownHostsByModule/dns-records.tf
containing:
resource "dns_a_record_set" "canonical" {
zone = var.dns_zone
name = var.server_name
addresses = [var.server_ip]
ttl = 10
}
resource "dns_a_record_set" "root" {
zone = var.dns_zone
name = var.server_name
addresses = [var.server_ip]
ttl = 10
}
resource "dns_a_record_set" "aliases" {
count = length(var.server_aliases)
zone = var.dns_zone
name = var.server_aliases[count.index]
addresses = [var.server_ip]
ttl = 10
}
Warning
Duplicated names will cause Terraform to crash
- Add output to
/KnownHostsByModule/outputs.tf
:
output "server_fqdn" {
description = "Fully qualified domain name of the canonical server"
value = "${var.server_name}.${var.dns_zone}"
}
output "alias_fqdns" {
description = "All alias FQDNs"
value = [
for alias in var.server_aliases : "${alias}.${var.dns_zone}"
]
}
Deploy and Verify
- Initialize and apply Terraform inside
/KnownHostsByModule
:
terraform init
terraform apply
- Verify with
dig
:
dig +noall +answer @ns1.hdm-stuttgart.cloud AXFR gxy.sdi.hdm-stuttgart.cloud
Success
Expected Output:
gxy.sdi.hdm-stuttgart.cloud. 10 IN A 1.2.3.4
workhorse.gxy.sdi.hdm-stuttgart.cloud. 10 IN A 1.2.3.4
www.gxy.sdi.hdm-stuttgart.cloud. 10 IN CNAME workhorse.gxy.sdi.hdm-stuttgart.cloud.
mail.gxy.sdi.hdm-stuttgart.cloud. 10 IN CNAME workhorse.gxy.sdi.hdm-stuttgart.cloud.
Note
Changes might not appear immediately if DNS caches are still valid.