Alisson Machado
30 April 2018

Terraform: Gerenciando DNS com TSIG

Terraform é uma ferramenta da Hashicorp focada em Bootstrapping e inicialização de recursos, se fizermos uma comparação entre Puppet e Terraform por exemplo, o Puppet é responsável por gerenciar a configuração de uma infraestrutura que já existe, já o Terraform vai criar essa infraestrutura que será gerenciada pelo Puppet.


Nesse post vou mostrar como podemos gerenciar entradas de DNS através do Terraform usando o protocolo TSIG ( Transaction Signature ) que é documentando na RFC 2845 ( https://tools.ietf.org/html/rfc2845 ), isso permite que façamos atualizações dinâmicas no servidor de DNS de forma segura sem precisar logar no servidor.


Agora Hands On! O primeiro passo é subir uma máquina no Vagrant com o bind9 instalado:

# -*- mode: ruby -*-
# vi: set ft=ruby :

# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure("2") do |config|
  
  config.vm.provider "virtualbox" do |vb|
    vb.memory = "1024"
  end
  
  config.vm.define "bind9" do |node| 
    node.vm.box = "ubuntu/trusty64"
    node.vm.hostname = "dns-terraform"
    node.vm.network "public_network", bridge: "wlp4s0"
    node.vm.provision "shell", inline: <<-SHELL
      apt-get clean all
      apt-get update
      apt-get install -y bind9 dnsutils
    SHELL
  end

end


Esse Vagrantfile irá subir um servidor Ubuntu 16.04 já com o bind9 instalado, que é o servidor de DNS geralmente utilizado nos servidores Linux.


Após a inicialização da máquina, acesse o diretório /etc/bind:

$ vagrant ssh bind9
vagrant@dns-terraform:~$ sudo su -
root@dns-terraform:~# cd /etc/bind/


Veja os arquivos dentro do diretório:

root@dns-terraform:/etc/bind# ls
bind.keys  db.127  db.empty  db.root     named.conf.default-zones  named.conf.options  zones.rfc1918
db.0       db.255  db.local  named.conf  named.conf.local          rndc.key


O bind quando instalado automaticamente já cria uma chave chamada rndc.key, vamos ver o conteúdo dela:

root@dns-terraform:/etc/bind# cat rndc.key 
key "rndc-key" {
	algorithm hmac-md5;
	secret "oP+1ph0UYnWnL/D8QXNYSQ==";
};


Copie esse conteúdo e cole dentro de /etc/bind/named.conf.local.

root@dns-terraform:/etc/bind# cat named.conf.local 
//
// Do any local configuration here
//

// Consider adding the 1918 zones here, if they are not used in your
// organization
//include "/etc/bind/zones.rfc1918";


key "rndc-key" {
	algorithm hmac-md5;
	secret "oP+1ph0UYnWnL/D8QXNYSQ==";
};


Nesse passo criamos uma chave chamada rndc-key que vamos usar em breve. Agora precisamos criar uma zona de DNS.

root@dns-terraform:/etc/bind# cp /etc/bind/db.local /var/cache/bind/db.alissonmachado.com.br


Substitua o conteúdo localhost por alissonmachado.com.br.

root@dns-terraform:/etc/bind# sed -i "s/localhost/alissonmachado.com.br/g" /var/cache/bind/db.alissonmachado.com.br


A zona de DNS deve ficar da seguinte forma:

root@dns-terraform:/etc/bind# cat /var/cache/bind/db.alissonmachado.com.br
;
; BIND data file for local loopback interface
;
$TTL	604800
@	IN	SOA	alissonmachado.com.br. root.alissonmachado.com.br. (
			      2		; Serial
			 604800		; Refresh
			  86400		; Retry
			2419200		; Expire
			 604800 )	; Negative Cache TTL
;
@	IN	NS	alissonmachado.com.br.
@	IN	A	127.0.0.1
@	IN	AAAA	::1


Agora vamos editar de novo o named.conf.local e deixar da seguinte forma:

root@dns-terraform:/etc/bind# cat /etc/bind/named.conf.local 
//
// Do any local configuration here
//

// Consider adding the 1918 zones here, if they are not used in your
// organization
//include "/etc/bind/zones.rfc1918";


key "rndc-key" {
	algorithm hmac-md5;
	secret "oP+1ph0UYnWnL/D8QXNYSQ==";
};


zone "alissonmachado.com.br." {
	type master;
	file "/var/cache/bind/db.alissonmachado.com.br";
        allow-update { key rndc-key; };
};


Agora reinicie o bind.

root@dns-terraform:/etc/bind# service bind9 restart
 * Stopping domain name service... bind9                                                                                                  waiting for pid 3291 to die
                                                                                                                                   [ OK ]
 * Starting domain name service... bind9                                                                                           [ OK ] 
root@dns-terraform:/etc/bind# 


Para validar se o DNS está funcionando utilize o comando host:

root@dns-terraform:/etc/bind# host alissonmachado.com.br localhost
Using domain server:
Name: localhost
Address: 127.0.0.1#53
Aliases: 

alissonmachado.com.br has address 127.0.0.1


Está Ok! Agora vamos para o Terraform.


Para instalar o Terraform é só baixar o zip da documentação oficial. https://www.terraform.io/downloads.html Agora crie um arquivo chamado alisson_dns.tf com o seguinte conteúdo:

provider "dns" {
  update {
    server        = "10.100.0.171"
    key_name      = "rndc-key."
    key_algorithm = "hmac-md5"
    key_secret    = "oP+1ph0UYnWnL/D8QXNYSQ=="
  }
}

resource "dns_a_record_set" "teste" {
  zone = "alissonmachado.com.br."
  name = "hector"
  addresses = [
    "6.6.6.6"
  ]
  ttl = 300
}

resource "dns_a_record_set" "jorge" {
  zone = "alissonmachado.com.br."
  name = "jorge"
  addresses = [
    "10.10.10.10"
  ]
  ttl = 300
}


Com o arquivo criado, deixe o log do dns na tela para acompanhar a modificação:

root@dns-terraform:/etc/bind# tail -f /var/log/syslog 


Dentro do Terraform, utilizamos o provider DNS, que deve ser baixado antes de executar o Terraform, para isso na pasta onde vc criou o alisson_dns.tf, digite o comando terraform init.

$ terraform init

Initializing provider plugins...
- Checking for available provider plugins on https://releases.hashicorp.com...
- Downloading plugin for provider "dns" (1.0.0)...

The following providers do not have any version constraints in configuration,
so the latest version was installed.

To prevent automatic upgrades to new major versions that may contain breaking
changes, it is recommended to add version = "..." constraints to the
corresponding provider blocks in configuration, with the constraint strings
suggested below.

* provider.dns: version = "~> 1.0"

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If y


Agora o provider já foi instalado. Digite o comando terraform plan, ele irá mostrar o que será alterado no seu dns.

$ terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.


------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  + dns_a_record_set.jorge
      id:                   
      addresses.#:          "1"
      addresses.3258735021: "10.10.10.10"
      name:                 "jorge"
      ttl:                  "300"
      zone:                 "alissonmachado.com.br."

  + dns_a_record_set.teste
      id:                   
      addresses.#:          "1"
      addresses.3786324972: "6.6.6.6"
      name:                 "hector"
      ttl:                  "300"
      zone:                 "alissonmachado.com.br."


Plan: 2 to add, 0 to change, 0 to destroy.

------------------------------------------------------------------------
a chamada 
Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.


Veja que ele irá criar duas entradas de dns, uma chamada jorge apontando para o ip 10.10.10.10 e outra chamada hector apontando para o ip 6.6.6.6. Digite agora o comando terraform apply.

$ terraform apply

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  + dns_a_record_set.jorge
      id:                   
      addresses.#:          "1"
      addresses.3258735021: "10.10.10.10"
      name:                 "jorge"
      ttl:                  "300"
      zone:                 "alissonmachado.com.br."

  + dns_a_record_set.teste
      id:                   
      addresses.#:          "1"
      addresses.3786324972: "6.6.6.6"
      name:                 "hector"
      ttl:                  "300"
      zone:                 "alissonmachado.com.br."


Plan: 2 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

dns_a_record_set.teste: Creating...
  addresses.#:          "" => "1"
  addresses.3786324972: "" => "6.6.6.6"
  name:                 "" => "hector"
  ttl:                  "" => "300"
  zone:                 "" => "alissonmachado.com.br."
dns_a_record_set.jorge: Creating...
  addresses.#:          "" => "1"
  addresses.3258735021: "" => "10.10.10.10"
  name:                 "" => "jorge"
  ttl:                  "" => "300"
  zone:                 "" => "alissonmachado.com.br."
dns_a_record_set.jorge: Creation complete after 0s (ID: jorge.alissonmachado.com.br.)
dns_a_record_set.teste: Creation complete after 0s (ID: hector.alissonmachado.com.br.)


Veja que no final da execução do comando apareceu a mensagem Creation complete.


No log do bind apareceu a seguinte mensagem:

root@dns-terraform:/etc/bind# tail -f /var/log/syslog 
Apr 30 18:51:54 vagrant-ubuntu-trusty-64 named[3608]: client 10.100.0.185#53063/key rndc-key: updating zone 'alissonmachado.com.br/IN': adding an RR at 'jorge.alissonmachado.com.br' A
Apr 30 18:51:54 vagrant-ubuntu-trusty-64 named[3608]: client 10.100.0.185#47174/key rndc-key: signer "rndc-key" approved
Apr 30 18:51:54 vagrant-ubuntu-trusty-64 named[3608]: client 10.100.0.185#47174/key rndc-key: updating zone 'alissonmachado.com.br/IN': adding an RR at 'hector.alissonmachado.com.br' A


Agora se eu fizer uma consulta de DNS deve retornar os IPs cadastrados no terraform.

root@dns-terraform:/etc/bind# host jorge.alissonmachado.com.br localhost
Using domain server:
Name: localhost
Address: 127.0.0.1#53
Aliases: 

jorge.alissonmachado.com.br has address 10.10.10.10
root@dns-terraform:/etc/bind# host hector.alissonmachado.com.br localhost
Using domain server:
Name: localhost
Address: 127.0.0.1#53
Aliases: 

hector.alissonmachado.com.br has address 6.6.6.6


Dahora, é isso ae, valeuz!