📜 ⬆️ ⬇️

Ansible Dynamic Inventory from DNS or how to waste time searching for standards

This article is about failure, designed to demonstrate how useful it is to talk about failures. I hope she will change the result to success thanks to the comments.

As it usually happens, a new problem appears, you are thinking about it and stop at some solution. Further, this decision needs to be realized and here the most interesting begins ...

I faced a big challenge to transfer the infrastructure of the company and its projects to automated management. Subsequently, long-term brain activity, it was consistently chosen to use ansible and jenkins as web interface to it. As far as understanding of all business processes and systems of servers and services, I have clearly seen the whole picture of IaC (Infrastructure as Code - infrastructure as code). After the pilot playbukov and roles, it was time to start a partial implementation, for ansibl have a great opportunity to dynamically collect lists of servers that we need to manage. For the storage of a large number of servers and all the necessary variables for them, I decided to use our own DNS servers in the first stages having gotten the idea from badoo (so that you guys have a hiccup).
')
When you wanted the best, but it turned out as always. Forward, down into the depths of google jungle.

DNS query security


Of course, the first thing that should worry about the choice of technology appropriate to the tasks is security. To guarantee the client request that the answer came precisely from our server, we plan to implement DNSSEC, but there is not enough time for everything. To get a list of the entire zone, an AXFR request is used; this is the standard function of the overwhelming majority of DNS servers that we use to replicate data between our DNS servers. But it’s not acceptable to give out all our zone to everyone, there are not many options to protect against the execution of illegitimate requests. Firstly, this is a server-side restriction on the internal IPv4 subnets we use. Secondly, it is TSIG or GSS-TSIG authentication. Configuring GSS-TSIG is longer due to the larger number of actions required, but perhaps in the future we will use it all the same. Consequently, the choice fell on TSIG, for which there is a quite simple RFC 2845 standard document.

TSIG standard guts


How TSIG authentication works, I will not tell it described in a document or in Russian in Google. In the RFC, we are informed about all the details, such as the format of a packet with a request to the DNS server, but the format of the key files is not written there, but there is an enumeration of hash algorithms based on which the authentication works:


MD5 has been subject to collisions for more than 10 years, and since there are options for more persistent hashes, let's look at them. You have probably already heard that sha1 is also subject to collisions, and because I am not afraid of additional work, and we do not expect a large number of calls to the DNS, then we will choose the most stable algorithm available, sha512. The algorithm is selected, now we will create a key and experiment with requests to the DNS server, for this we install the bind-utils package and execute the command:

dnssec-keygen -a HMAC-SHA512 -b 512 -n USER abracadabra.example.com 

We made the key, now we will insert the settings for it in our dns and return to the main topic of the story. We tested our queries and decided to switch to LDAP . We began to implement the dynamic ansible inventory on python. First we need to parse the key file, its format is as follows:

 abracadabra.example.com. IN KEY 512 3 165 qxkDE9ZBykFEk4VBNUnB5s+mvJDWhP2dHi4Gd0PeSHf4ckOSMTlThnXD oXz3Av5zcXhIgAKlVkJ7j/Ru4qzSFg== name class rrtype keysize protocol algorithm data 

Let's start from the end, our big HMAC-SHA512 did not fit into 512 bytes for the udp packet and the key string was separated by a space. Not terribly glue and we will send to the TCP.

Next, the algorithm here is incomprehensible tsiferki (these tsiferki and forced me to write an article), skip for now.

The protocol, that such, again not clear tsiferki in RFC nothing was told about it.

We analyze further and everything is clear: we specified 512 bytes when creating the key and here we see the length of our key, remember well (I did not need this information).

The type of resource record, we have the same DNS and we tell the DNS server that this is the key.

Resource record class; It is theoretically believed that DNS can be used not only with TCP / IP, but also with other types of networks, the code in the class field determines the type of network (useless legacy garbage).

Well, respectively, our name.

We are looking for, we are looking for


We have 2 incomprehensible fields, let's see. To begin with, I tried to figure out what the protocol identifier is. But except that there is a range from 1 to 250 and the number 3 in this range belongs to dnssec, I did not recognize anything.

Then I decided to look for the identifiers of the algorithms, there was more information here. I came across such a page on the IANA administration , there was

This sign
Number Description Mnemonic Zone
Signing
Trans.
Sec.
Reference
0Delete DSDELETENN[ RFC4034 ] [ RFC4398 ] [ RFC8078 ]
oneRSA / MD5 (deprecated, see 5)RSAMD5NY[ RFC3110 ] [ RFC4034 ]
2Diffie-hellmanDHNY[ RFC2539 ] [proposed standard]
3DSA / SHA1DSAYY[ RFC3755 ] [proposed standard] [ RFC2536 ] [proposed standard] [Federal Information Processing Standards Publication (FIPS PUB) 186,
Digital Signature Standard, 18 May 1994.] [Federal Information Processing Standards Publication (FIPS PUB) 180-1,
Secure Hash Standard, April 17, 1995.
(Supersedes FIPS PUB 180 dated 11 May 1993.)]
fourReserved[ RFC6725 ]
fiveRSA / SHA-1RSASHA1YY[ RFC3110 ] [ RFC4034 ]
6DSA-NSEC3-SHA1DSA-NSEC3-SHA1YY[ RFC5155 ] [proposed standard]
7RSASHA1-NSEC3-SHA1RSASHA1-NSEC3-SHA1YY[ RFC5155 ] [proposed standard]
eightRSA / SHA-256RSASHA256Y*[ RFC5702 ] [proposed standard]
9Reserved[ RFC6725 ]
tenRSA / SHA-512RSASHA512Y*[ RFC5702 ] [proposed standard]
elevenReserved[ RFC6725 ]
12GOST R 10.34-2001ECC-GOSTY*[ RFC5933 ] [standards track]
13ECDSA Curve P-256 with SHA-256ECDSAP256SHA256Y*[ RFC6605 ] [standards track]
14ECDSA Curve P-384 with SHA-384ECDSAP384SHA384Y*[ RFC6605 ] [standards track]
15Ed25519ED25519Y*[ RFC8080 ] [standards track]
sixteenEd448ED448Y*[ RFC8080 ] [standards track]
17-122Unassigned
123-251Reserved[ RFC4034 ] [ RFC6014 ]
252Reserved for Indirect KeysINDIRECTNN[ RFC4034 ] [proposed standard]
253private algorithmPRIVATEDNSYY[ RFC4034 ]
254private algorithm OIDPRIVATEOIDYY[ RFC4034 ]
255Reserved[ RFC4034 ] [proposed standard]


Well, we have part of the table of identifiers, but our tsiferka identifier 165 which is included in the reserved space. References in the table from this space lead to other standards that do not contain information about the identifiers of the algorithms. And then Ostap suffered ... I began to dive into these exorbitant cross-references, then to one standard, then to the second. As a result, I spat and went into the bind-utils source . There I found a list of defines

 /* DST algorithm codes */ #define DST_ALG_UNKNOWN 0 #define DST_ALG_RSAMD5 1 #define DST_ALG_RSA DST_ALG_RSAMD5 /*%< backwards compatibility */ #define DST_ALG_DH 2 #define DST_ALG_DSA 3 #define DST_ALG_ECC 4 #define DST_ALG_RSASHA1 5 #define DST_ALG_NSEC3DSA 6 #define DST_ALG_NSEC3RSASHA1 7 #define DST_ALG_RSASHA256 8 #define DST_ALG_RSASHA512 10 #define DST_ALG_ECCGOST 12 #define DST_ALG_ECDSA256 13 #define DST_ALG_ECDSA384 14 #define DST_ALG_HMACMD5 157 #define DST_ALG_GSSAPI 160 #define DST_ALG_HMACSHA1 161 /* XXXMPA */ #define DST_ALG_HMACSHA224 162 /* XXXMPA */ #define DST_ALG_HMACSHA256 163 /* XXXMPA */ #define DST_ALG_HMACSHA384 164 /* XXXMPA */ #define DST_ALG_HMACSHA512 165 /* XXXMPA */ #define DST_ALG_INDIRECT 252 #define DST_ALG_PRIVATE 254 #define DST_ALG_EXPAND 255 #define DST_MAX_ALGS 255 

and added a piece to your python code

 HashMap = { '160': 'gss-tsig', '157': 'HMAC-MD5.SIG-ALG.REG.INT', '161': 'hmac-sha1', '162': 'hmac-sha224', '163': 'hmac-sha256', '164': 'hmac-sha384', '165': 'hmac-sha512' } 

What is it all written about


For an AXFR query, I need only 3 fields from the key: the name, the algorithm, and the key itself. Actually, I solved my task, but I do not consider it a success.

On the whole, the narrative is probably not very clearly written, but the conclusion will be simple. If I am faced with such difficulties, then it will happen again in others. The standard 17 years ago made me spend more than a dozen hours searching for information to understand. Do not spend more than a couple of hours looking for standards, look at popular implementations and borrow information from there, the source is simpler and clearer. In the source code of popular projects, all this work has already been done by other people, save your time.

PS


Since I did not find most of the information, I would be very grateful for the links to the following materials that might be useful to me or other people:

  1. TSIG private key format

    TSIG
    Private-key-format: v1.3
    Algorithm: 165 (HMAC_SHA512)
    Key: qxkDE9ZBykFEk4VBNUnB5s+mvJDWhP2dHi4Gd0PeSHf4ckOSMTlThnXDoXz3Av5zcXhIgAKlVkJ7j/Ru4qzSFg==
    Bits: AAA=
    Created: 20170902233427
    Publish: 20170902233427
    Activate: 20170902233427

  2. The format of the key TSIG
  3. Complete table of protocol identifier lists
  4. The complete table of the list of algorithm identifiers

UPD


I messed up the spoiler with a private key, corrected.

Source: https://habr.com/ru/post/337008/


All Articles