AnalogJ / lexicon

Manipulate DNS records on various DNS providers in a standardized way.
MIT License
1.48k stars 306 forks source link

letsencrypt.sh + lexicon on DNSimple creates _acme-challenge.www.foo.net.foo.net #3

Closed cben closed 8 years ago

cben commented 8 years ago

Thanks for writing this library (and blog post) just in time, it helped me get Let's Encrypt certs a few days ago :-)

Using it with DNSimple I had to intervene in the code, as it was creating wrong domains: I'm controlling mathdown.net zone; for www.mathdown.net it created _acme-challenge.www.mathdown.net.mathdown.net, for mathdown.net it created _acme-challenge.mathdown.net.mathdown.net.

The command executed by the hook was:

lexicon dnsimple create www.mathdown.net TXT --name _acme-challenge.www.mathdown.net. --content IquLz5DkyqvV1f37rpP4sO2IkLp6HQKDX0psSt_8aFI

Output, with printing and breakpoint in providers/dnsimple.py in _request():

Namespace(action='create', auth_otp_token=None, auth_password=None, auth_token='[REDACTED]', auth_username='beni.cherniavsky@gmail.com', content='kDA2FinGwvNPkcn6QzbrGS-q1q6fzSmiQL2EkpZPRrc', domain='www.mathdown.net', identifier=None, name='_acme-challenge.www.mathdown.net.', priority=None, provider_name='dnsimple', ttl=None, type='TXT')

> /home/beni/.local/lib/python2.7/site-packages/lexicon/providers/dnsimple.py(120)_request()
-> r = requests.request(action, self.api_endpoint + url, params=query_params,
(Pdb) pp locals()
{'action': 'GET',
 'data': {},
 'default_auth': None,
 'default_headers': {'Accept': 'application/json',
                     'Content-Type': 'application/json',
                     'X-DNSimple-Token': 'beni.cherniavsky@gmail.com:[REDACTED]'},
 'pprint': <module 'pprint' from '/usr/lib/python2.7/pprint.pyc'>,
 'query_params': {},
 'self': <lexicon.providers.dnsimple.Provider object at 0x7f201d837310>,
 'url': '/domains/mathdown.net'}
(Pdb) c
> /home/beni/.local/lib/python2.7/site-packages/lexicon/providers/dnsimple.py(120)_request()
-> r = requests.request(action, self.api_endpoint + url, params=query_params,
(Pdb) pp locals()
{'action': 'POST',
 'data': {'record': {'content': 'IquLz5DkyqvV1f37rpP4sO2IkLp6HQKDX0psSt_8aFI',
                     'name': '_acme-challenge.www.mathdown.net',
                     'record_type': 'TXT'}},
 'default_auth': None,
 'default_headers': {'Accept': 'application/json',
                     'Content-Type': 'application/json',
                     'X-DNSimple-Token': 'beni.cherniavsky@gmail.com:[REDACTED]'},
 'pdb': <module 'pdb' from '/usr/lib/python2.7/pdb.pyc'>,
 'pprint': <module 'pprint' from '/usr/lib/python2.7/pprint.pyc'>,
 'query_params': {},
 'self': <lexicon.providers.dnsimple.Provider object at 0x7f201d837310>,
 'url': '/domains/mathdown.net/records'}
(Pdb) self.options.domain
'mathdown.net'

and for mathdown.net:

+ lexicon dnsimple create mathdown.net TXT --name _acme-challenge.mathdown.net. --content NonxWWUM3KwgrW3rOTQyRnrzP-IHqEJRPedPpia1HbE
...
{'action': 'GET',
...
{'action': 'POST',
 'data': {'record': {'content': 'NonxWWUM3KwgrW3rOTQyRnrzP-IHqEJRPedPpia1HbE',
                     'name': '_acme-challenge.mathdown.net',
                     'record_type': 'TXT'}},
 'default_auth': None,
 'default_headers': {'Accept': 'application/json',
                     'Content-Type': 'application/json',
                     'X-DNSimple-Token': 'beni.cherniavsky@gmail.com:[REDACTED]'},
 'name': '_acme-challenge',
 'pprint': <module 'pprint' from '/usr/lib/python2.7/pprint.pyc'>,
 'query_params': {},
 'self': <lexicon.providers.dnsimple.Provider object at 0x7fb466b51310>,
 'url': '/domains/mathdown.net/records'}
(Pdb) p self.options.domain
'mathdown.net'

So what's going on? data['record']['name'] is taken by DNSimple as-is, but its meaning is relative to the zone. I needed to truncate it to _acme-challenge.www for www.mathdown.net and _acme-challenge for mathdown.net.

Why Cloudflare worked in your blog post? It seems its API takes absolute name (https://api.cloudflare.com/#dns-records-for-a-zone-create-dns-record — note --data '{"type":"A","name":"example.com","content":"127.0.0.1","ttl":120}' in their example), while DNSimple takes relative name (https://developer.dnsimple.com/v1/domains/records/#create — note "name": "" in their example).

=> It seems like providers/dnsimple.py is the one that should truncate names in most methods? (And list.records should append zone back to names?)

cben commented 8 years ago

BTW, what if my zone if not of "foo.TLD" form? dnsimple.py authenticate() checks payload['domain'] exists but then ignores its value and uses self.options.domain. I think it's better to verify it's equal. For refernce here is my authenticate() GET result:

{u'domain': {u'account_id': 46951,
             u'auto_renew': False,
             u'created_at': u'2015-08-12T18:32:14.350Z',
             u'expires_on': None,
             u'id': 206384,
             u'lockable': True,
             u'name': u'mathdown.net',
             u'record_count': 8,
             u'registrant_id': None,
             u'service_count': 0,
             u'state': u'hosted',
             u'token': u'[REDACTED]',
             u'unicode_name': u'mathdown.net',
             u'updated_at': u'2015-08-12T18:32:14.350Z',
             u'user_id': None,
             u'whois_protected': False}}

and GET results for list CNAME:

[{u'record': {u'content': u'prod-mathdown.rhcloud.com',
              u'created_at': u'2015-08-12T19:23:20.466Z',
              u'domain_id': 206384,
              u'id': 4833310,
              u'name': u'www',
              u'parent_id': None,
              u'prio': None,
              u'record_type': u'CNAME',
              u'system_record': False,
              u'ttl': 60,
              u'updated_at': u'2015-09-20T15:03:24.491Z'}}]
list_records: [{'content': u'prod-mathdown.rhcloud.com', 'id': 4833310, 'type': u'CNAME', 'name': u'www', 'ttl': 60}]
AnalogJ commented 8 years ago

Hmm, I'm not sure whats going wrong. I don't have a DNSimple account, I based that provider on the DNSimple sandbox, but it did work correctly. I'll take another look this weekend.

cben commented 8 years ago

So first question about my assumptions: when I run lexicon with --name foo.bar, is that supposed to mean absolute foo.bar. domain or relative foo.bar.my.zone.?

AnalogJ commented 8 years ago

it should be the absolute domain, foo.bar.example.com.

AnalogJ commented 8 years ago

Hey @cben can you try using version v1.0.11 now? I made a bunch of fixes and wrote a full test suite to verify that all the providers work in the same way. DNSimple should be working correctly now. All providers should also support relative and absolute domain entries.

cben commented 8 years ago

Cool, will test. 21 марта 2016 г. 6:49 AM пользователь "Jason Kulatunga" < notifications@github.com> написал:

Hey @cben https://github.com/cben can you try using version v1.0.11 now? I made a bunch of fixes and wrote a full test suite to verify that all the providers work in the same way. DNSimple should be working correctly now. All providers should also support relative and absolute domain entries.

— You are receiving this because you were mentioned. Reply to this email directly or view it on GitHub https://github.com/AnalogJ/lexicon/issues/3#issuecomment-199121323

AnalogJ commented 8 years ago

This looks fixed. Feel free to reopen if you still have this issue.

cben commented 8 years ago

Thanks, worked perfectly now.