2

I have 3 environments for my infrastructure. All of them the same, but with various sizes. I understand this is a good use case for Terraform workspaces. And indeed it works well in that regard. But please correct me if this is not the right way to go.

Now my only issue is with managing the DNS within the workspaces. I use the Google provider and that works by having 2 types of resources: a google_dns_managed_zone which represents the zone, and a google_dns_record_set type for each DNS record.
Note that the record set type needs to have a reference to the managed zone type.

With that in mind, I need to manage the DNS zone from the production environment. I can't share that resource in the other workspaces because I should be able to destroy the dev or staging workspace without destroying the DNS zone.
I try to solve that issue with count. I use it as a boolean as shown in the code below and find it pretty hackish but that's what I have found in the Terraform community. Any improvement is welcome.
That allows me to have the zone and the production records (like MX shown below as example) only present in the prod workspace.

But then I am stuck when it comes to managing record sets only in a specific workspace. I need that for example in the case of creating an nginx in the dev workspace and automatically create a DNS record set for it, like dev.example.com.
For that I need to access the managed zone resource. As shown below I use terraform_remote_state in order to access the resource from the prod workspace. To the extent of my understanding, that works with an output, which you can see below. When I select the prod workspace, I can indeed output the managed zone. And then if I select another workspace, using the remote state retrieves the managed zone from prod successfully. But my issue is that Terraform fails when it comes to the output line since it is only present in the prod workspace and does not exist in any other workspace and thus can't be outputted.

So it's a bit of a nonsense and I don't understand if there is a better way to achieve this. I did a fair bit of research and asked the community but could not find an answer to that. It seems to me that managing DNS is common to all infrastructures and should be pretty well covered. What am I doing wrong and how should it be done?

locals {
  environment="${terraform.workspace}"

  dns_zone_managers = {
    "dev"     = "0"
    "staging" = "0"
    "prod"    = "1"
}

  dns_zone_manager = "${lookup(local.dns_zone_managers, local.environment)}"
}

resource "google_dns_managed_zone" "base_zone" {                                                                                                                                               
  name     = "base_zone"                                                                                                                                                               
  dns_name = "example.com."                                                                                                                                                                    
  count = "${local.dns_zone_manager}"                                                                                                                                                          
}                                                                                                                                                                                              

resource "google_dns_record_set" "mx" {                                                                                                                                                        
  name = "${google_dns_managed_zone.base_zone.dns_name}"                                                                                                                                       
  managed_zone = "${google_dns_managed_zone.base_zone.name}"                                                                                                                                   
  type = "MX"                                                                                                                                                                                  
  ttl  = 300                                                                                                                                                                                   

  rrdatas = [                                                                                                                                                                                  
    "10 spool.mail.example.com.",                                                                                                                                                                
    "50 fb.mail.example.com."                                                                                                                                                                    
  ]                                                                                                                                                                                            
  count = "${local.dns_zone_manager}"                                                                                                                                                          
}

data "terraform_remote_state" "dns" {
    backend = "local"
    workspace = "prod"
}

output "dns_zone_name" {
  value = "${google_dns_managed_zone.base_zone.*.name[0]}"
}

Then I can introduce record sets in a specific workspace only, using count again and referring to the managed zone through the remote state like so:

resource "google_dns_record_set" "a" {
  name = "dev"
  managed_zone = "${data.terraform_remote_state.dns.dns_zone_name}"
  type = "A"
  ttl  = 300

  rrdatas = ["1.2.3.4"]
}
Layo
  • 677
  • 6
  • 16
Bastian
  • 5,625
  • 10
  • 44
  • 68
  • 2
    I've solved this in the past by creating a root terraform project for all root level resources like dns. Then the other project can import with terraform_remote_state. It is a good idea to segregate certain pieces of infrastructure to reduced the impact if something went wrong. For example dns, db, compute. So if a bad terraform configuration for compute was deployed it wouldn't affect critical infrastructure such as db an dns. As a bonus it makes managing root dns easier as you don't need need multiple environments. – Caleb Macdonald Black Mar 05 '19 at 01:00
  • thanks @CalebMacdonaldBlack , that sounds pretty interesting. Would you care to expand your comment into an answer? – Bastian Mar 05 '19 at 09:59
  • @Bastian take a look at https://stackoverflow.com/a/52608146/925829 – Ramil Amerzyanov May 31 '19 at 22:31

0 Answers0