How to configure dynamic DNS (dyndns) using restricted tokens and custom domain?

Hello

NOTE: In the below post, I will use “;” instead of “;” in domain names. This is due to the fact that when I tried to submit this post, I got this error: Sorry, new users can only put 2 links in a post. For some reason, this forum software thinks that anything that is of the format is a link which is quite unfortunate on a forum that is concerned about DNS.

I have a few hosts that are on dynamic IP addresses.
I want to set up a dyndns record for each of these devices on my own custom domain using the pattern:
;dyn;example;com

For example for the two hosts dev1 and dev2, I want these records:

dev1;dyn;example;com --> 12.34.45.67
dev2;dyn;example;com -->  76.54.32.21

So, as I understand, I should be able to run something like this via cron:

curl https://update.dedyn.io/?hostname=dev1.dyn.example.com --header "Authorization: Token <your authorization token>"

Where should be replaced by some authorization token that I need to generate through the desec.io web interface.
Am I correct so far?

If I am, then that leads me to the next question: In the event that dev1 gets compromised, I dont want dev1 to be able to change all my DNS records. So I need a token for ‘dev1’ that will only be allowed to update the record on dev1;dyn;example;com. And not e.g. dev2;dyn;example;com or (even worse) *;example;com.

So to sum up:

  1. Am I correct that in order to configure the dynamic DNS, I just need to run a cron job that runs curl as described above, e.g. every hour?
  2. How do I create a token that is limited to only change certain records on a certain domain?

Hi LydolfSleipner,

Thank you for your message, and welcome to deSEC! :slight_smile:

You’re right, that’s not very smooth. I changed the limit to 20.

You can do it this way, yes. However, there is also tooling available, like ddclient. Our docs have some details.

This is possible using Token Scoping via Domain Policies. Unfortnuately, there currenlty is no graphical interface for this, so it can only be done through the API (see examples in the link I shared).

Does this help?

Stay secure,
Peter

Hi Peter,

Thanks a lot for your quick response.
I have been looking into your link on Token Scoping via Domain Policies. I am not sure I understand exactly how to do this.
Can you provide me with an example of how to create a token that would only be allowed to edit, say dev1.dyn.example.com ?

Hi LydolfSleipner,

  1. You will have to create the target domain name as a separate domain using the “Domain Management” facilities (either in the GUI or via the API). (Configuring a parent domain is not sufficient.)*

  2. You will need to create the token. Besides writing down the token value, you will also need its ID. You can narrow down permissions for this token (e.g. disallow “manage tokens”).

  3. You will need a management token (with the “manage tokens” permission).

  4. Then, run the following commands (this is suitable for a Linux terminal):

    curl -X POST https://desec.io/api/v1/auth/tokens/{id}/policies/domain/ \
        --header "Authorization: Token {management-token}" \
        --header "Content-Type: application/json" --data @- <<< \
        '{"domain": null}'
    
    curl -X POST https://desec.io/api/v1/auth/tokens/{id}/policies/domain/ \
        --header "Authorization: Token {management-token}" \
        --header "Content-Type: application/json" --data @- <<< \
        '{"domain": "dev1.dyn.example.com", "perm_dyndns": true}'
    

    … where {id} is your dynDNS token’s ID (from step 2), and {management-token} is the value of your management token (from step 3).

* Note: If you use dedyn.io domains, I would strongly advise to create direct child domains (such as example1.dedyn.io and example2.dedyn.io, instead of dev1.example.dedyn.io). The reason is that if you create lower-level domains, you will have to take extra steps for DNSSEC to work properly. If you use domains directly under dedyn.io, this is done automatically.
If you use a custom domain, you will have to set up DNSSEC in any case (by putting DS records in the parent domain).

Does that help?

Stay secure,
Peter

Thank you for super fast response!

I do not use dedyn.io domains. I use my own domains.

This all seems a bit complex for me.
Are you saying that I need to create a subdomain apart from my primary domain as a separate domain?

So for example, lets say I have example.dk and I want to have several hosts with dynamic addresses on dyn.example.dk. Would I then have to create a separate domain as dyn.example.dk and then create tokens for this new domain “dyn.example.com”? And by separate, do you mean a completely separate account? Ie. when I login do desec.io in a browser, I have multiple domains (13 currently) listed in Domain Management tab.

So I have just created dyn.mydomain.tld right now. That seemed to work. But this is not a real domain. It is just a subdomain of mydomain.tld.

Then I would go to Token Management in a browser and create two tokens:

1: The “token management” token which will have “manage tokens” permissions set.

2: The tokens for each of the host ‘dev1’, ‘dev2’ and so on? These will NOT have “manage tokens” enabled.

Then I will run these commands for each individual host:

curl -X POST https://desec.io/api/v1/auth/tokens/{id}/policies/domain/ \
    --header "Authorization: Token {management-token}" \
    --header "Content-Type: application/json" --data @- <<< \
    '{"domain": null}'

curl -X POST https://desec.io/api/v1/auth/tokens/{id}/policies/domain/ \
    --header "Authorization: Token {management-token}" \
    --header "Content-Type: application/json" --data @- <<< \
    '{"domain": "{hostname}.dyn.example.com", "perm_dyndns": true}'

Where:

  • {id} is the token ID for the respective host
  • {management-token} is the management token
  • {hostname} is the hostname of the respective host

Is this correctly understood?

PS. This forum could really benefit from a “Preview” function…

If you would like to use domain-based token scoping, that is correct. We do not yet support token scoping for subdmains within a domain.

If you do that, the token will be able to perform dynDNS updates for this domain name, and all of its subdomains. If you want to restrict dynDNS updates to dev1.dyn.example.com, then you need to create a separate domain with this name, and configure a token correspondingly.

No, see Step 1 in my previous post.

You will first need to create domains for these.

If you are getting close to your account’s domain limit, just shoot us an email and we can increase it.

Stay secure,
Peter

Thanks Peter. I tried following your advice.

First time, I had a typo on the domain in request two. So that failed.
I then ran the same two commands again but with the domain name fixed.
Now I get this error:

{"detail":"Conflict: duplicate key value violates unique constraint \"unique_entry_null_domain\"\nDETAIL: Key (token_id)=(***) already exists.\n"}{"domain":"dyn.example.dk","perm_dyndns":true,"perm_rrsets":false}%

I then tried running the queries again. I then got the error again for the first query as well as another error for the second query:

Query 1
{"detail":"Conflict: duplicate key value violates unique constraint \"unique_entry_null_domain\"\nDETAIL:  Key (token_id)=(****) already exists.\n"}
Query 2
{"detail":"Conflict: duplicate key value violates unique constraint \"unique_entry\"\nDETAIL:  Key (token_id, domain_id)=(****) already exists.\n"}%

I hope this means that it just works now.
However, I am a bit surprised that these queries do not seem to be idempotent. Ie. they seem to add a value to something instead of setting a value.

Now I have one concern, though:
How can I verify that my policies for these tokens are indeed correct and that this token do not accidentially provide access to other domains?
I mean, if I go to Token Management in the desec.io UI, I am not able to see any restrictions. Not even when I enable “Show advanced settings”.
Would it be possible to provide a way to at least see hidden settings such as these policies - even though it is not (yet?) possible to create or edit them in the web UI?

Is my understanding of these two queries correct?

Query 1:
Reset the token with {id} setting domain to null. Removing any permissions there might be on it. Meaning that effectively, it cannot be used.

Query 2
Reset the token with {id} setting domain to the specified domain name such that it can only be used on that single domain. Also, allow dyndns.

I hope my understanding is correct. Even though, I still do not understand why it is not idempotent…

The API works somewhat different from your understanding.
TL;DR: Think of the domain field as a “filter” that decides, if a policy is applicable to an action or not.

Query 1 creates the default policy for the token {id}. This policy applies whenever an action is attempted with this token and no more specific policy exists. Since the policy does not contain perm_dyndns or perm_rrsets, these permissions are not granted. So, this query effectively prevents the token from doing anything at all.

Query 2 creates a policy for the given domain. This policy applies whenever an action within this domain is attempted with this token. Since perm_dyndns is set to true, the token is allowed to do dyndns updates. Since perm_rrsets is not included, it is implicitly set to false. This policy does not say anything about what the token can do on other domains.

So in summary, the token can not do anything in your account, except on the domain {hostname}.dyn.example.com (and its subdomains), where it can do dyndns, but no other DNS changes.

The API docs have more detailed information:
https://desec.readthedocs.io/en/latest/auth/tokens.html#token-domain-policy-management

Side note: If you use PUT instead of POST, you can create new or change existing policies. This avoids the error message when the policy already exists and may be more to your liking.

Another note: There are a number of tools that can interface with the deSEC API: Tools implementing deSEC
I believe, the only one that supports token domain policies is this:
GitHub - s-hamann/desec-dns: A simple deSEC.io API client
It’s arguably slightly more convenient than using curl directly, but still requires a basic understanding of the API.

2 Likes