{"id":2347,"date":"2024-05-31T13:02:43","date_gmt":"2024-05-31T12:02:43","guid":{"rendered":"http:\/\/blogs-new.it.ox.ac.uk\/networks\/?p=2347"},"modified":"2024-06-03T12:18:16","modified_gmt":"2024-06-03T11:18:16","slug":"hydra-token-authentication","status":"publish","type":"post","link":"https:\/\/blogs-new.it.ox.ac.uk\/networks\/2024\/05\/31\/hydra-token-authentication\/","title":{"rendered":"Hydra: Token authentication"},"content":{"rendered":"<p>Hydra is the name for the central IPAM at the University of Oxford. To those of you that did not know this, I will suggest that you may stop reading further as this blog post is not for you.<\/p>\n<p>Right, since you\u2019re still reading, I assume you know about Hydra and are interested enough to know about its changes and developments. This blog post will lay out one new development in particular: a new means of authentication named tokens.<\/p>\n<p>This post goes into a fair bit of detail, but if you want to skip to the Conclusion section at the end, there should be a fairly concise summary.<\/p>\n<div id=\"outline-container-orgce8fbd8\" class=\"outline-2\">\n<h2 id=\"orgce8fbd8\"><span class=\"section-number-2\">1.<\/span> Prerequisite knowledge: authentication vs authorization<\/h2>\n<div id=\"text-1\" class=\"outline-text-2\">\n<p><em>Skip this section if you know the difference between these two words within the context of access control.<\/em><\/p>\n<p>With a computer interface with any degree of access control, the system needs to verify who you are. This is authentication [authN]. Traditionally this has been done using a shared secret, a password. These days more modern and fancier mechanisms exist such as biometrics and multifactor authentication, but these are just different means to the same end: can you prove who you say you are?<\/p>\n<p>Post authentication the system knows you\u2019re you.\u00a0 Now, it needs to know what you are authorized to do, or what you\u2019re allowed to read or change. This unsurprisingly is authorization [authZ].<\/p>\n<p>AuthZ and authN are two distinct processes but sometimes they have been merged together, and lines have blurred. Microsoft\u2019s Active Directory springs to mind. In Hydra they are distinct subsystems.<\/p>\n<\/div>\n<\/div>\n<div id=\"outline-container-org446c0b9\" class=\"outline-2\">\n<h2 id=\"org446c0b9\"><span class=\"section-number-2\">2.<\/span> History: Hydra, stats and SPNEGO authentication<\/h2>\n<div id=\"text-2\" class=\"outline-text-2\">\n<p>Ever since Hydra went live, its API has been a very prominent part of the service. There is nothing that you can do in the user interface that is not possible using the API, and for those of you out there who have made use of the API, thank you! We appreciate that it is being used.<\/p>\n<p>To put some numbers out there, there have been 411 \u201cusers\u201d (I write \u201cusers\u201d in quotes to mean the union of human users and API users) who have updated entries in Hydra. Of those \u201cusers\u201d, 5 have been API users. Doesn\u2019t sound like much, but the number of transactions is a bit different: these 5 users account for 39% of all transactions within the system!<\/p>\n<p>Hydra\u2019s authZ database is a join of two data sources, Groupstore and Hydra\u2019s own databases. Groupstore handles the creation of Groups and the assignment of users to them. Hydra then has a mechanism to pull the data into its own database, and augment it with domains and subnet associations to said Groups. Further, ACLs are assigned to DNS zones, but I mention that only for completeness.<\/p>\n<p>On the authN side, currently, the method used depends on what kind of access is being requested. Human users use Shibboleth, and machine API calls use SPNEGO.<\/p>\n<p>Now, the authN system that underpins the API is a tried and tested one shared by other systems, including CUD and SAVANT. This SPNEGO system has some alluring advantages, particularly at the time of Hydra\u2019s introduction:<\/p>\n<ol class=\"org-ol\">\n<li>It made use of the same backend authN (not authZ) database used by users at the time.<\/li>\n<li>The \u201cusers\u201d that can authenticate are visible and assignable to Groups in Groupstore. Adding and removing \u201cusers\u201d to groups is an identical process for the two types of user.<\/li>\n<\/ol>\n<p>However, there is this feeling that SPNEGO authentication is rather heavyweight, and it favours Unix-like clients (surprising given that SPNEGO\u2019s first implementation was Microsoft\u2019s!) Whether that feeling is justified or not is not going to be discussed further, but it\u2019s not escaped our notice in the Network Support and Development team that this sentiment exists. Perhaps the 5 Hydra API users is a testament to SPNEGO\u2019s daunting reputation!<\/p>\n<p>As such, we will be hoping to introduce <a href=\"https:\/\/en.wikipedia.org\/wiki\/Basic_access_authentication\">Basic Authentication<\/a> to Hydra as an additional authN mechanism, called tokens. These tokens&#8217;\u00a0authZ are totally managed outside of Groupstore and thus do not have the same fine-grained level of control as \u201cusers\u201d do.<\/p>\n<ol class=\"org-ol\">\n<li>Each token is only associated with one group. You cannot affiliate one token with multiple groups, not by direct association nor by indirect inheritance.<\/li>\n<li>Tokens can be created, and destroyed. There are no mechanisms by which you can modify an existing token.<\/li>\n<li>Tokens cannot be used for user UI access, or said another way, tokens will only grant the holder API access.<\/li>\n<\/ol>\n<\/div>\n<\/div>\n<div id=\"outline-container-org98291a8\" class=\"outline-2\">\n<h2 id=\"org98291a8\"><span class=\"section-number-2\">3.<\/span> Token constraints: masks<\/h2>\n<div id=\"text-3\" class=\"outline-text-2\">\n<p>If Basic Authentication was all I had to say about tokens, then this blog post could probably have just been a few lines in an email. However, the self imposed limitations above allow us to do something that up until this point has been impossible: further constrain a token by use of masks.<\/p>\n<p>When you create a token, which at creation time is associated to a Group, you will have the opportunity to assign the following masks:<\/p>\n<ul class=\"org-ul\">\n<li>Hostname mask<\/li>\n<li>IP mask<\/li>\n<li>Content mask<\/li>\n<li>Target mask<\/li>\n<\/ul>\n<p>With these masks set wide open, this token will have the same permissions as any \u201cuser\u201d in the group. However, the utility comes where these values are set to either blank, in which case the creation of any record of a particular type is impossible, or to some other value, thus constraining the records that can be created.<\/p>\n<p>As an aside, you may be thinking that the word \u201cmask\u201d isn\u2019t accurate here, as these permissions are not based on binary values, and you would be correct. However, I hope some sloppy, but acknowledged, terminology doesn\u2019t get in the way of understanding the core principles of what this system gives you, which is a fairly powerful self-service permissions system. It\u2019s also a word that is close enough to a correct term, and all the other good words were taken!<\/p>\n<p>Some examples may be helpful here:<\/p>\n<\/div>\n<div id=\"outline-container-orgd345832\" class=\"outline-4\">\n<h4 id=\"orgd345832\"><span class=\"section-number-4\">3.0.1.<\/span> Example 1: Same permissions as any \u201cuser\u201d in the group.<\/h4>\n<div id=\"text-3-0-1\" class=\"outline-text-4\">\n<ul class=\"org-ul\">\n<li>hostname: <code>%<\/code><\/li>\n<li>ip: <code>0.0.0.0\/0,::\/0<\/code><\/li>\n<li>content: <code>%<\/code><\/li>\n<li>target: <code>%<\/code><\/li>\n<\/ul>\n<p>Note that there are additional checks outside these masks, and so even with these fully permissive values the token will be constrained by the permissions of the zones and of the Group in which it belongs.<\/p>\n<\/div>\n<\/div>\n<div id=\"outline-container-org124a465\" class=\"outline-4\">\n<h4 id=\"org124a465\"><span class=\"section-number-4\">3.0.2.<\/span> Example 2: An A record for any hostname within the group<\/h4>\n<div id=\"text-3-0-2\" class=\"outline-text-4\">\n<ul class=\"org-ul\">\n<li>hostname: <code>%<\/code><\/li>\n<li>ip: <code>0.0.0.0\/0<\/code><\/li>\n<li>content: <em>[blank]<\/em><\/li>\n<li>target: <em>[blank]<\/em><\/li>\n<\/ul>\n<p>Note that creation of CNAME, TXT records will not be permitted with these masks. Also no AAAA (IPv6) records are permitted.<\/p>\n<\/div>\n<\/div>\n<div id=\"outline-container-orga7471c0\" class=\"outline-4\">\n<h4 id=\"orga7471c0\"><span class=\"section-number-4\">3.0.3.<\/span> Example 3: SPF records for example.org. and example.com.<\/h4>\n<div id=\"text-3-0-3\" class=\"outline-text-4\">\n<ul class=\"org-ul\">\n<li>hostname: <code>%.example.(org|com).<\/code><\/li>\n<li>ip: <em>[blank]<\/em><\/li>\n<li>content: <code>v=spf1 %<\/code><\/li>\n<li>target: <em>[blank]<\/em><\/li>\n<\/ul>\n<p>Note that if this token is placed in a group which does not have permissions to edit either example.org or example.com, then this token is incapable of doing anything.<\/p>\n<\/div>\n<\/div>\n<div id=\"outline-container-orga109ac0\" class=\"outline-4\">\n<h4 id=\"orga109ac0\"><span class=\"section-number-4\">3.0.4.<\/span> Example 4: SRV records pointing to example.org.<\/h4>\n<div id=\"text-3-0-4\" class=\"outline-text-4\">\n<p>This example is more complicated:<\/p>\n<ul class=\"org-ul\">\n<li>hostname: <code>_%.(tls|tcp|udp).%<\/code><\/li>\n<li>ip: <em>[blank]<\/em><\/li>\n<li>content: <em>[blank]<\/em><\/li>\n<li>target: <code>example.org.<\/code><\/li>\n<\/ul>\n<p>Three main points about this example:<\/p>\n<p>This hostname mask is imperfect: the first \u201c<code>%<\/code>\u201d could include a \u2019<code>.<\/code>\u2019 thus breaking the format of an SRV record. To be truly restrictive you would need to use character classes, which I leave as an exercise for the reader, especially since this is an unrealistic example already. For full details on the mask format, please see below.<\/p>\n<p>Secondly, the target can only point to one value. You would not be able to point an SRV record to <code>foo.example.org.<\/code>, for example. If you want that then the target mask needs to be %.example.org. Finally, there is only an implication that this is limited to SRV records. A CNAME record with the same hostname, target values would be just as valid and indeed would be accepted by Hydra. An MX record would be too, except that MX<br \/>\nrecords cannot begin with \u2019_\u2019 so would be rejected for that reason.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div id=\"outline-container-orgfcd29f7\" class=\"outline-2\">\n<h2 id=\"orgfcd29f7\"><span class=\"section-number-2\">4.<\/span> Mask format<\/h2>\n<div id=\"text-4\" class=\"outline-text-2\">\n<p>Let\u2019s get the easy one out the way: the IP mask is a comma separated list of subnets. It currently only supports IPv4 and IPv6 subnets. Invalid entries (e.g. 0.0.x.0\/24, FOOOOO) will be accepted as entries but will be silently ignored by the system at validation time.<\/p>\n<p>For the remaining masks, hostname, content and target, the format uses PostgreSQL\u2019s <a href=\"https:\/\/www.w3resource.com\/PostgreSQL\/postgresql-similar-operator.php\">SIMILAR TO<\/a> syntax. This, to me, seems to sit between the ease-of-use (if you can call it that) of <a href=\"https:\/\/www.w3schools.com\/SQL\/sql_like.asp\">SQL\u2019s LIKE<\/a> syntax, and the flexibility and power of regular expressions. To those of you who don\u2019t immerse yourself in the PostgreSQL\u2019s manual pages on a daily basis (you\u2019re missing out), the syntax may be unfamiliar to you, or worse, be similar enough to SQL\u2019s LIKE syntax that you mistake it for that when in fact it\u2019s more flexible and powerful. However, it is hoped that the easy stuff is intuitive enough and that you can use this blog post and documentation as a guide, and failing that there is a whole wealth of non-Hydra-specific documentation on the syntax on the internet already.<\/p>\n<p>As with most things, there\u2019s a level of trust placed on the people creating the tokens, some of it obvious, some of it less so. This is a self service tool, where you can write your own mask. While testing of various inputs has been positive in terms of SIMILAR TO being resistent to <a href=\"https:\/\/en.wikipedia.org\/wiki\/ReDoS\">ReDoS attacks<\/a>, that is not an invitation to try! While I myself was not able to cause a timeout, that perhaps is more due to my own lack of imagination: PostgreSQL&#8217;s documentation itself warns that using SIMILAR TO is a potential vector for a DoS attack. As such, we will be monitoring the backend for malicious masks and all tokens will be forever associated with the username of the person who created it.<\/p>\n<p>On the subject of performance, masks will only be referenced on record changes, because they are slow for lookups. Said another way, masks are not consulted for retrieving records. For most use-cases this will be fine, but it should be noted a token API request will be given all records belonging to its group regardless of masks, and such a token query may well provide a record that fails mask validations upon edit.<\/p>\n<\/div>\n<\/div>\n<div id=\"outline-container-orgbf0378c\" class=\"outline-2\">\n<h2 id=\"orgbf0378c\"><span class=\"section-number-2\">5.<\/span> Who can create these masks, and what\u2019s the timescale?<\/h2>\n<div id=\"text-5\" class=\"outline-text-2\">\n<p>I said earlier that this functionality was completely detached from Groupstore, but in reality that was an oversimplification: If you are a manager of a Group in Groupstore, you will have the ability to create tokens for that group.<\/p>\n<p>Much of the functionality is written and ready for deployment, but not all of it, and as such there is no firm release schedule. The reason that this blog post is being posted in advance of the feature\u2019s (maybe) imminent release is that for those of you who are wishing to automate say ACME challenges, then a path of lower resistence and higher security is on the horizon, so please sit tight! Further firmer announcements will be made on the ict-a maillist. To start a discussion on the topic, please make use of the hydra-discuss maillist.<\/p>\n<\/div>\n<\/div>\n<div id=\"outline-container-org0dd2af9\" class=\"outline-2\">\n<h2 id=\"org0dd2af9\"><span class=\"section-number-2\">6.<\/span> Conclusion<\/h2>\n<div id=\"text-6\" class=\"outline-text-2\">\n<p>Hydra\u2019s API, which up until now has been secured using SPNEGO authentication, will be augmented with a new method, Basic Authentication, using tokens. Further, these tokens may be further constrained by masks such that they may be shared with third parties while not exposing your entire IP and domain estate to them. The assignment of masks will be self-service.<\/p>\n<\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Hydra is the name for the central IPAM at the University of Oxford. To those of you that did not know this, I will suggest that you may stop reading further as this blog post is not for you. Right, &hellip; <a href=\"https:\/\/blogs-new.it.ox.ac.uk\/networks\/2024\/05\/31\/hydra-token-authentication\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":136,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[450],"tags":[],"class_list":["post-2347","post","type-post","status-publish","format-standard","hentry","category-dns"],"_links":{"self":[{"href":"https:\/\/blogs-new.it.ox.ac.uk\/networks\/wp-json\/wp\/v2\/posts\/2347","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs-new.it.ox.ac.uk\/networks\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs-new.it.ox.ac.uk\/networks\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs-new.it.ox.ac.uk\/networks\/wp-json\/wp\/v2\/users\/136"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs-new.it.ox.ac.uk\/networks\/wp-json\/wp\/v2\/comments?post=2347"}],"version-history":[{"count":7,"href":"https:\/\/blogs-new.it.ox.ac.uk\/networks\/wp-json\/wp\/v2\/posts\/2347\/revisions"}],"predecessor-version":[{"id":2355,"href":"https:\/\/blogs-new.it.ox.ac.uk\/networks\/wp-json\/wp\/v2\/posts\/2347\/revisions\/2355"}],"wp:attachment":[{"href":"https:\/\/blogs-new.it.ox.ac.uk\/networks\/wp-json\/wp\/v2\/media?parent=2347"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs-new.it.ox.ac.uk\/networks\/wp-json\/wp\/v2\/categories?post=2347"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs-new.it.ox.ac.uk\/networks\/wp-json\/wp\/v2\/tags?post=2347"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}