Aquarion
Aquarion

Reputation: 591

in Ansible, is there a way to stop multiple value TXT records always being marked as changed?

So I have this ansible task:

- name: google._domainkey.ludoistic.com. - TXT
  route53:
      overwrite: true
      command: "create"
      zone: "ludoistic.com"
      record: "google._domainkey.ludoistic.com."
      type: "TXT"
      ttl: "300"
      value: '"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAup2hbfv7PQuI+z8j634065jEtT",
      "eW4km3D7Vnt+tVQt+76mBp18mAb5C+xl70KS6LUEtYmrBe3fo6QbElQ96BZ4KnNJTo62NBfEkO2i/AuIO91ksKaL01En5wrH",
      "B6oo9JYhJ231eDZ01af6eBkrI9dy5wYSlU1wYwpIvk/DDA9HvmTMMGv87VOQYiEfEDfdWJq8ZRxUj+sKCDQAono7dmC/vHFG",
      "GkQ7/pFa+EqO4e2MFn22SmnXhLW1aGShJ3PSGvplyxZ3JHQiUO6bBi4ZoUtUZc1MOLRZjKMch/cXbkB+f/XUVNH9r0uOaZHt",
      "LXH+zwikjUVFStCdgtzyqOF2tVSwIDAQAB"'
      aws_access_key: '{{istic_aws_key}}'
      aws_secret_key: '{{istic_aws_secret}}'
  tags:
      - ludoistic

But when this task is executed, it's always a change. Is there a way to reformat this so ansible doesn't think it's changed when it hasn't?

Upvotes: 1

Views: 440

Answers (3)

Aquarion
Aquarion

Reputation: 591

Okay, I solved this, with credit going to β.εηοιτ.βε below who got me towards the right answer

The text record was being created as an array, so was coming back with four separate non-ordered answers when it went into DNS. It does have to be four seperate pieces because DNS can only cope with 255 characters per record - https://aws.amazon.com/premiumsupport/knowledge-center/route53-resolve-dkim-text-record-error/

The solution to this turns out to be to use space-separated double-quoted DNS records within a large single-quoted ansible value, thus:

- name: google._domainkey.ludoistic.com. - TXT
  route53:
      overwrite: true
      command: "create"
      zone: "ludoistic.com"
      record: "google._domainkey.ludoistic.com."
      type: "TXT"
      ttl: "300"
      value: '"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAup2hbfv7PQuI+z8j634065jEtT" "eW4km3D7Vnt+tVQt+76mBp18mAb5C+xl70KS6LUEtYmrBe3fo6QbElQ96BZ4KnNJTo62NBfEkO2i/AuIO91ksKaL01En5wrH" "B6oo9JYhJ231eDZ01af6eBkrI9dy5wYSlU1wYwpIvk/DDA9HvmTMMGv87VOQYiEfEDfdWJq8ZRxUj+sKCDQAono7dmC/vHFG" "GkQ7/pFa+EqO4e2MFn22SmnXhLW1aGShJ3PSGvplyxZ3JHQiUO6bBi4ZoUtUZc1MOLRZjKMch/cXbkB+f/XUVNH9r0uOaZHt" "LXH+zwikjUVFStCdgtzyqOF2tVSwIDAQAB"'
      aws_access_key: '{{istic_aws_key}}'
      aws_secret_key: '{{istic_aws_secret}}'
  tags:
      - ludoistic

Upvotes: 1

β.εηοιτ.βε
β.εηοιτ.βε

Reputation: 39294

In your case, mind that your DKIM record is all wrong.

Look at the result of you DNS record, while setting it with your actual playbook:

dig  google._domainkey.ludoistic.com TXT  
; <<>> DiG 9.10.6 <<>> google._domainkey.ludoistic.com TXT 
;; global options: +cmd 
;; Got answer: 
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 31974 
;; flags: qr rd ra; QUERY: 1, ANSWER: 5, AUTHORITY: 4, ADDITIONAL: 1

;; OPT PSEUDOSECTION: 
; EDNS: version: 0, flags:; udp: 4096 
;; QUESTION SECTION: 
;google._domainkey.ludoistic.com. IN  TXT

;; ANSWER SECTION: 
google._domainkey.ludoistic.com. 300 IN   TXT "B6oo9JYhJ231eDZ01af6eBkrI9dy5wYSlU1wYwpIvk/DDA9HvmTMMGv87VOQYiEfEDfdWJq8ZRxUj+sKCDQAono7dmC/vHFG"
google._domainkey.ludoistic.com. 300 IN   TXT "GkQ7/pFa+EqO4e2MFn22SmnXhLW1aGShJ3PSGvplyxZ3JHQiUO6bBi4ZoUtUZc1MOLRZjKMch/cXbkB+f/XUVNH9r0uOaZHt"
google._domainkey.ludoistic.com. 300 IN   TXT "LXH+zwikjUVFStCdgtzyqOF2tVSwIDAQAB"
google._domainkey.ludoistic.com. 300 IN   TXT "eW4km3D7Vnt+tVQt+76mBp18mAb5C+xl70KS6LUEtYmrBe3fo6QbElQ96BZ4KnNJTo62NBfEkO2i/AuIO91ksKaL01En5wrH"
google._domainkey.ludoistic.com. 300 IN   TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAup2hbfv7PQuI+z8j634065jEtT"

;; AUTHORITY SECTION:
ludoistic.com.        172800  IN  NS  ns-1058.awsdns-04.org.
ludoistic.com.        172800  IN  NS  ns-1761.awsdns-28.co.uk.
ludoistic.com.        172800  IN  NS  ns-333.awsdns-41.com.
ludoistic.com.        172800  IN  NS  ns-957.awsdns-55.net.

;; Query time: 49 msec 
;; SERVER: 192.168.1.1#53(192.168.1.1) 
;; WHEN: Sat Jun 20 10:06:36 CEST 2020 
;; MSG SIZE  rcvd: 672

See the multiples lines in the authoritative ANSWER SECTION?

Now compare this to SO's DKIM:

dig  google._domainkey.stackoverflow.com TXT
; <<>> DiG 9.10.6 <<>> google._domainkey.stackoverflow.com TXT
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 33678
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 4, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;google._domainkey.stackoverflow.com. IN  TXT

;; ANSWER SECTION:
google._domainkey.stackoverflow.com. 300 IN TXT   "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCbf2b+8IwDGfgu5u/9kY4d3Corv9C2UtQyLWqHer1vNmWprWnjHDNWwE7nL943WOdDSGGhwKrprrFbCJrHsZ8Yz+UR52zeySiwJi7eIoVl6SDa6DXSlh2bYKwgJUuCF5blhY8weRwpf0wAKK8i9TmZbx+5vBZ2tAGAa1MW6VkFDwIDAQAB"

;; AUTHORITY SECTION:
stackoverflow.com.    99395   IN  NS  ns-1033.awsdns-01.org.
stackoverflow.com.    99395   IN  NS  ns-358.awsdns-44.com.
stackoverflow.com.    99395   IN  NS  ns-cloud-e1.googledomains.com.
stackoverflow.com.    99395   IN  NS  ns-cloud-e2.googledomains.com.

;; Query time: 105 msec
;; SERVER: 192.168.1.1#53(192.168.1.1)
;; WHEN: Sat Jun 20 10:05:47 CEST 2020
;; MSG SIZE  rcvd: 443

See how this DKIM is a single line and not multiple ones compared to yours?
Now this happens because, as pointed in road53 module documentation, value will be considered as array, and so create multiple records either if you pass an actual YAML array or if you have a comma separated list of value, as you have currently.

The new value when creating a DNS record. YAML lists or multiple comma-spaced values are allowed for non-alias records.
When deleting a record all values for the record must be specified or Route53 will not delete it.

Source: https://docs.ansible.com/ansible/latest/modules/route53_module.html#parameter-value

The actual correct playbook task for your use case should be:

- name: google._domainkey.ludoistic.com. - TXT
  route53:
      overwrite: true
      command: "create"
      zone: "ludoistic.com"
      record: "google._domainkey.ludoistic.com."
      type: "TXT"
      ttl: "300"
      value: '"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAup2hbfv7PQuI+z8j634065jEtTeW4km3D7Vnt+tVQt+76mBp18mAb5C+xl70KS6LUEtYmrBe3fo6QbElQ96BZ4KnNJTo62NBfEkO2i/AuIO91ksKaL01En5wrHB6oo9JYhJ231eDZ01af6eBkrI9dy5wYSlU1wYwpIvk/DDA9HvmTMMGv87VOQYiEfEDfdWJq8ZRxUj+sKCDQAono7dmC/vHFGGkQ7/pFa+EqO4e2MFn22SmnXhLW1aGShJ3PSGvplyxZ3JHQiUO6bBi4ZoUtUZc1MOLRZjKMch/cXbkB+f/XUVNH9r0uOaZHtLXH+zwikjUVFStCdgtzyqOF2tVSwIDAQAB"'
      aws_access_key: '{{istic_aws_key}}'
      aws_secret_key: '{{istic_aws_secret}}'
  tags:
      - ludoistic

This will create you a unique DKIM TXT record, and eventually also fix your changed state issue because now, you will have a unique TXT and the matching mechanism of the route53 module will work.


Generally speaking, from what I understand reading both the documentation and the source code of the module, this seems to be happening because you are setting your TXT record in multiple separated tasks, when the module would consider and compare the existing TXT to your desired change in a whole.

So what I understand you are doing right now is:

- name: foo.example.org. - TXT
  route53:
      overwrite: true
      command: "create"
      zone: "example.org"
      record: "foo.example.org."
      type: "TXT"
      ttl: "300"
      value: 'bar'
      aws_access_key: '{{istic_aws_key}}'
      aws_secret_key: '{{istic_aws_secret}}'

- name: foo.example.org. - TXT
  route53:
      overwrite: true
      command: "create"
      zone: "example.org"
      record: "foo.example.org."
      type: "TXT"
      ttl: "300"
      value: 'bar bar'
      aws_access_key: '{{istic_aws_key}}'
      aws_secret_key: '{{istic_aws_secret}}'

And this will always be a change because the whole TXT record for foo.ludoistic.com. won't never match only a part of it.

What you should do instead, that should make the matching mechanism of the module work is to pass your value as an array in a single task.

So the two tasks above would become:

- name: foo.example.org. - TXT
  route53:
      overwrite: true
      command: "create"
      zone: "example.org"
      record: "foo.example.org."
      type: "TXT"
      ttl: "300"
      value: 
        - 'bar'
        - 'bar bar'
      aws_access_key: '{{istic_aws_key}}'
      aws_secret_key: '{{istic_aws_secret}}'

Upvotes: 1

Salim
Salim

Reputation: 418

I assume this is happening since you have overwrite set to true. This will probably execute every time and will therefore always give you a changed result.

A possible way to fix this is to execute only if the record does not exist or use changed_when. route53_info can be used to look up a record.


    - name: grab zone id
      route53_zone:
        zone: "ludoistic.com"
      register: AWSINFO

    - name: grab Route53 record information
      route53_info:
        type: TXT
        query: record_sets
        hosted_zone_id: "{{ AWSINFO.zone_id }}"
        start_record_name: "google._domainkey.ludoistic.com."
      register: RECORDS

   - name: add Route 53 record if it does not exist
     route53:
       overwrite: false
       # ...
     when: RECORDS.value != other_value_goes_here

Upvotes: 1

Related Questions