{"id":2570,"date":"2021-06-07T08:00:47","date_gmt":"2021-06-07T06:00:47","guid":{"rendered":"https:\/\/possiblelossofprecision.net\/?p=2570"},"modified":"2021-05-15T11:46:36","modified_gmt":"2021-05-15T09:46:36","slug":"ldap-server-with-389ds-part-3-acls","status":"publish","type":"post","link":"https:\/\/possiblelossofprecision.net\/?p=2570","title":{"rendered":"LDAP server with 389ds: Part 3 \u2013 ACLs"},"content":{"rendered":"<p>Now that we&#8217;ve set up an instance of the 389 Directory Server in <a href=\"https:\/\/possiblelossofprecision.net\/?p=2519\">part 1<\/a> and configured essential plugins in <a href=\"https:\/\/possiblelossofprecision.net\/?p=2534\">part 2<\/a>, it&#8217;s time to take a closer look at <a href=\"https:\/\/en.wikipedia.org\/wiki\/Access-control_list\">access-control list<\/a> (ACLs). After all, regular users of the directory shouldn&#8217;t be able to change data that they&#8217;re not supposed to or have universal read access in most use cases.<\/p>\n<p><!--more--><\/p>\n<h2>4. ACLs<\/h2>\n<p>The directory server grants or denies access to objects in the DIT based on what&#8217;s called Access Control Instructions (ACI). These are multi-valued (operational) attributes that are added to the directory entry in question. There are <a href=\"https:\/\/access.redhat.com\/documentation\/en-us\/red_hat_directory_server\/11\/html-single\/administration_guide\/index#user_rights\">eight operations<\/a> that the server can allow or deny access for: <em>read<\/em>, <em>write<\/em>, <em>add<\/em>, <em>delete<\/em>, <em>search<\/em>, <em>compare<\/em>, <em>selfwrite<\/em> and <em>proxy<\/em>.<br \/>\nThe <a href=\"https:\/\/access.redhat.com\/documentation\/en-us\/red_hat_directory_server\/11\/html-single\/administration_guide\/index#defining_bind_rules\">syntax of an ACI attributes<\/a> looks like this:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n(target_rule) (version 3.0; acl &quot;ACL_name&quot;; permission_rule bind_rules;)\r\n<\/pre>\n<h3>4.1. 389 Directory Server sample ACIs<\/h3>\n<p>Or course, this can get rather complex really quickly and is heavily dependent on the environment and use case. But to get started, there&#8217;s a set of sample ACIs that were installed during the setup of our 389ds instance in <a href=\"https:\/\/possiblelossofprecision.net\/?p=2519#2-create-an-instance\">part 1<\/a>. Since we&#8217;ve set the <code>sample_entries<\/code> option to <code>yes<\/code> we can take advantage of those:<\/p>\n<pre class=\"brush: plain; highlight: [14]; title: instance.inf; notranslate\" title=\"instance.inf\">\r\n&#x5B;general]\r\nfull_machine_name = ldap.example.com\r\nstart = True\r\nstrict_host_checking = False\r\n\r\n&#x5B;slapd]\r\ninstance_name = localhost\r\nroot_password = mysecret\r\nport = 389\r\nsecure_port = 636\r\nself_sign_cert = False\r\n\r\n&#x5B;backend-userroot]\r\nsample_entries = yes\r\nsuffix = dc=example,dc=com\r\n<\/pre>\n<p><a href=\"https:\/\/github.com\/389ds\/389-ds-base\/blob\/master\/src\/lib389\/lib389\/configurations\/config_001004002.py\">This does a couple of things<\/a>: It sets up the organizational units (OU) <em>groups<\/em> and <em>people<\/em> where future users and groups can be stored and creates a demo user and group within these OUs. But it also creates the OU <em>permissions<\/em> that contains a bunch of groups:<\/p>\n<ul>\n<li>group_admin<\/li>\n<li>group_modify<\/li>\n<li>user_admin<\/li>\n<li>user_modify<\/li>\n<li>user_passwd_reset<\/li>\n<li>user_private_read<\/li>\n<\/ul>\n<p>These groups are then used in various ACI attributes. We can list those by running:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nldapsearch -LLL -D &quot;cn=Directory Manager&quot; -W -x -b &quot;dc=example,dc=com&quot; -s sub '(aci=*)' aci\r\n<\/pre>\n<p>The output should look like this:<\/p>\n<pre class=\"brush: plain; collapse: true; light: false; smart-tabs: true; tab-size: 4; title: ; toolbar: true; notranslate\" title=\"\">\r\ndn: dc=example,dc=com\r\naci:\r\n  (targetattr=&quot;dc || description || objectClass&quot;)\r\n  (targetfilter=&quot;(objectClass=domain)&quot;)\r\n  (version 3.0;\r\n    acl &quot;Enable anyone domain read&quot;;\r\n    allow (read, search, compare)\r\n    (userdn=&quot;ldap:\/\/\/anyone&quot;);\r\n  )\r\naci:\r\n  (targetattr=&quot;ou || objectClass&quot;)\r\n  (targetfilter=&quot;(objectClass=organizationalUnit)&quot;)\r\n  (version 3.0;\r\n    acl &quot;Enable anyone ou read&quot;;\r\n    allow (read, search, compare)\r\n    (userdn=&quot;ldap:\/\/\/anyone&quot;);\r\n  )\r\n\r\ndn: ou=groups,dc=example,dc=com\r\naci:\r\n  (targetattr=&quot;cn || member || gidNumber || nsUniqueId || description || objectClass&quot;)\r\n  (targetfilter=&quot;(objectClass=groupOfNames)&quot;)\r\n  (version 3.0;\r\n    acl &quot;Enable anyone group read&quot;;\r\n    allow (read, search, compare)\r\n    (userdn=&quot;ldap:\/\/\/anyone&quot;);\r\n  )\r\naci:\r\n  (targetattr=&quot;member&quot;)\r\n  (targetfilter=&quot;(objectClass=groupOfNames)&quot;)\r\n  (version 3.0;\r\n    acl &quot;Enable group_modify to alter members&quot;;\r\n    allow (write)\r\n    (groupdn=&quot;ldap:\/\/\/cn=group_modify,ou=permissions,dc=example,dc=com&quot;);\r\n  )\r\naci:\r\n  (targetattr=&quot;cn || member || gidNumber || description || objectClass&quot;)\r\n  (targetfilter=&quot;(objectClass=groupOfNames)&quot;)\r\n  (version 3.0;\r\n    acl &quot;Enable group_adminto manage groups&quot;;\r\n    allow (write, add, delete)\r\n    (groupdn=&quot;ldap:\/\/\/cn=group_admin,ou=permissions,dc=example,dc=com&quot;);\r\n  )\r\n\r\ndn: ou=people,dc=example,dc=com\r\naci:\r\n  (targetattr=&quot;objectClass || description || nsUniqueId || uid || displayName || loginShell || uidNumber || gidNumber || gecos || homeDirectory || cn || memberOf || mail || nsSshPublicKey || nsAccountLock || userCertificate&quot;)\r\n  (targetfilter=&quot;(objectClass=posixaccount)&quot;)\r\n  (version 3.0;\r\n    acl &quot;Enable anyone user read&quot;;\r\n    allow (read, search, compare)\r\n    (userdn=&quot;ldap:\/\/\/anyone&quot;);\r\n  )\r\naci:\r\n  (targetattr=&quot;displayName || legalName || userPassword || nsSshPublicKey&quot;)\r\n  (version 3.0;\r\n    acl &quot;Enable self partial modify&quot;;\r\n    allow (write)\r\n    (userdn=&quot;ldap:\/\/\/self&quot;);\r\n  )\r\naci:\r\n  (targetattr=&quot;legalName || telephoneNumber || mobile || sn&quot;)\r\n  (targetfilter=&quot;(|(objectClass=nsPerson)(objectClass=inetOrgPerson))&quot;)\r\n  (version 3.0;\r\n    acl &quot;Enable self legalname read&quot;;\r\n    allow (read, search, compare)\r\n    (userdn=&quot;ldap:\/\/\/self&quot;);\r\n  )\r\naci:\r\n  (targetattr=&quot;legalName || telephoneNumber&quot;)\r\n  (targetfilter=&quot;(objectClass=nsPerson)&quot;)\r\n  (version 3.0;\r\n    acl &quot;Enable user legalname read&quot;;\r\n    allow (read, search, compare)\r\n    (groupdn=&quot;ldap:\/\/\/cn=user_private_read,ou=permissions,dc=example,dc=com&quot;);\r\n  )\r\naci:\r\n  (targetattr=&quot;uid || description || displayName || loginShell || uidNumber || gidNumber || gecos || homeDirectory || cn || memberOf || mail || legalName || telephoneNumber || mobile&quot;)\r\n  (targetfilter=&quot;(&amp;(objectClass=nsPerson)(objectClass=nsAccount))&quot;)\r\n  (version 3.0;\r\n    acl &quot;Enable user admin create&quot;;\r\n    allow (write, add, delete, read)\r\n    (groupdn=&quot;ldap:\/\/\/cn=user_admin,ou=permissions,dc=example,dc=com&quot;);\r\n  )\r\naci:\r\n  (targetattr=&quot;uid || description || displayName || loginShell || uidNumber || gidNumber || gecos || homeDirectory || cn || memberOf || mail || legalName || telephoneNumber || mobile&quot;)\r\n  (targetfilter=&quot;(&amp;(objectClass=nsPerson)(objectClass=nsAccount))&quot;)\r\n  (version 3.0;\r\n    acl &quot;Enable user modify to change users&quot;;\r\n    allow (write, read)(groupdn=&quot;ldap:\/\/\/cn=user_modify,ou=permissions,dc=example,dc=com&quot;);\r\n  )\r\naci:\r\n  (targetattr=&quot;userPassword || nsAccountLock || userCertificate || nsSshPublicKey&quot;)\r\n  (targetfilter=&quot;(objectClass=nsAccount)&quot;)\r\n  (version 3.0;\r\n    acl &quot;Enable user password reset&quot;;\r\n    allow (write, read)\r\n    (groupdn=&quot;ldap:\/\/\/cn=user_passwd_reset,ou=permissions,dc=example,dc=com&quot;);\r\n  )\r\n\r\ndn: ou=services,dc=example,dc=com\r\naci:\r\n  (targetattr=&quot;objectClass || description || nsUniqueId || cn || memberOf || nsAccountLock &quot;)\r\n  (targetfilter=&quot;(objectClass=netscapeServer)&quot;)\r\n  (version 3.0;\r\n    acl &quot;Enable anyone service account read&quot;;\r\n    allow (read, search, compare)\r\n    (userdn=&quot;ldap:\/\/\/anyone&quot;);\r\n  )\r\n<\/pre>\n<p>Wow, that&#8217;s a lot to unpack. But it looks worse than it actually is. Let&#8217;s go through one ACI as an example:<\/p>\n<pre class=\"brush: plain; highlight: [7]; title: ; notranslate\" title=\"\">\r\ndn: ou=people,dc=example,dc=com\r\n...\r\naci:\r\n  (targetattr=&quot;userPassword || nsAccountLock || userCertificate || nsSshPublicKey&quot;)\r\n  (targetfilter=&quot;(objectClass=nsAccount)&quot;)\r\n  (version 3.0;\r\n    acl &quot;Enable user password reset&quot;;\r\n    allow (write, read)\r\n    (groupdn=&quot;ldap:\/\/\/cn=user_passwd_reset,ou=permissions,dc=example,dc=com&quot;);\r\n  )\r\n<\/pre>\n<p>Line 1 tells us that this access control instruction acts on the entry <code>ou=people,dc=example,dc=com<\/code> and all entries below (if it has children), i.e. all users in our directory.<br \/>\nIt only concerns the attributes <code>userPassword<\/code>, <code>nsAccountLock<\/code>, <code>userCertificate<\/code> or <code>nsSshPublicKey<\/code> (line 4) on  <code>nsAccount<\/code> class objects (line 5).<br \/>\nAnd it grants write and read rights (line 8) to every user who&#8217;s a member of our permission OU <code>cn=user_passwd_reset,ou=permissions,dc=example,dc=com<\/code> (line 9).<br \/>\nLine 7 describes what the ACI does in a human readable way.<\/p>\n<h3>4.2. Granting privileges<\/h3>\n<p>By adding a user to one or more groups of the <em>permissions<\/em> OU we can grant them the associated privileges. For example, to give the user <em>Eve<\/em> (for details on how that user was created check <a href=\"https:\/\/possiblelossofprecision.net\/?p=2534#3-2-distributed-numeric-assignment\">part 2<\/a>) privileges to modify certain attributes of other users we simply add it to the <code>user_modify<\/code> group:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\n# ldapmodify -D &quot;cn=Directory Manager&quot; -w mysecret -x &lt;&lt; EOL\r\ndn: cn=user_modify,ou=permissions,dc=example,dc=com\r\nchangetype: modify\r\nadd: member\r\nmember: uid=eve,ou=people,dc=example,dc=com\r\nEOL\r\nmodifying entry &quot;cn=user_modify,ou=permissions,dc=example,dc=com&quot;\r\n<\/pre>\n<p>Since the groups in the <em>permissions<\/em> OU are fairly self-explanatory and the names of the default ACIs also quite descriptive it should be somewhat straightforward how to use them.<\/p>\n<h3>4.3. Changing ACIs<\/h3>\n<p>Let&#8217;s assume we would like to change these sample ACIs to make access to the directory a bit more restrictive. For example it could be necessary (e.g. for <a href=\"https:\/\/en.wikipedia.org\/wiki\/General_Data_Protection_Regulation\">GDPR<\/a> reasons) to deny regular users the permission to search the directory and read the personal details of other users (i.e. attributes such as their <code>displayName<\/code> or even <code>uid<\/code>, since those are often comprised of first and last name).<br \/>\nIn this case the ACI to change would be:<\/p>\n<pre class=\"brush: plain; highlight: [8]; title: ; notranslate\" title=\"\">\r\ndn: ou=people,dc=example,dc=com\r\naci:\r\n  (targetattr=&quot;objectClass || description || nsUniqueId || uid || displayName || loginShell || uidNumber || gidNumber || gecos || homeDirectory || cn || memberOf || mail || nsSshPublicKey || nsAccountLock || userCertificate&quot;)\r\n  (targetfilter=&quot;(objectClass=posixaccount)&quot;)\r\n  (version 3.0;\r\n    acl &quot;Enable anyone user read&quot;;\r\n    allow (read, search, compare)\r\n    (userdn=&quot;ldap:\/\/\/anyone&quot;);\r\n  )\r\n<\/pre>\n<p>since this ACI allows <em>anyone<\/em> to read attributes such as <code>displayName<\/code> or <code>uid<\/code> (see the <code>targetattr<\/code> list in line 3).<br \/>\nTo change that, we delete the ACI and recreate it with the <code>userdn<\/code> altered from <em>anyone<\/em> to <em>self<\/em>:<\/p>\n<pre class=\"brush: plain; highlight: [5,10]; title: ; notranslate\" title=\"\">\r\n# ldapmodify -D &quot;cn=Directory Manager&quot; -w mysecret -x &lt;&lt; EOL\r\ndn: ou=people,dc=example,dc=com\r\nchangetype: modify\r\ndelete: aci\r\naci: (targetattr=&quot;objectClass || description || nsUniqueId || uid || displayName || loginShell || uidNumber || gidNumber || gecos || homeDirectory || cn || memberOf || mail || nsSshPublicKey || nsAccountLock || userCertificate&quot;)(targetfilter=&quot;(objectClass=posixaccount)&quot;)(version 3.0; acl &quot;Enable anyone user read&quot;; allow (read, search, compare)(userdn=&quot;ldap:\/\/\/anyone&quot;);)\r\n\r\ndn: ou=people,dc=example,dc=com\r\nchangetype: modify\r\nadd: aci\r\naci: (targetattr=&quot;objectClass || description || nsUniqueId || uid || displayName || loginShell || uidNumber || gidNumber || gecos || homeDirectory || cn || memberOf || mail || nsSshPublicKey || nsAccountLock || userCertificate&quot;)(targetfilter=&quot;(objectClass=posixaccount)&quot;)(version 3.0; acl &quot;Enable self user read&quot;; allow (read, search, compare)(userdn=&quot;ldap:\/\/\/self&quot;);)\r\nEOL\r\nmodifying entry &quot;ou=people,dc=example,dc=com&quot;\r\nmodifying entry &quot;ou=people,dc=example,dc=com&quot;\r\n<\/pre>\n<p>Now a user is only able to read their own attributes but not those of other users below the OU <em>people<\/em>.<\/p>\n<p>Since ACLs are so heavily dependent on use case and environment this will conclude part 3. You should check the <a href=\"https:\/\/access.redhat.com\/documentation\/en-us\/red_hat_directory_server\/11\/html-single\/administration_guide\/index#managing_access_control\">RHDS 11 documentation<\/a> for more details on ACLs to suit your concrete needs but the sample ACIs should get you off and running.<br \/>\nIn <a href=\"https:\/\/possiblelossofprecision.net\/?p=2586\">part 4<\/a> we&#8217;re going to take a look at password storage schemes, securing our 389ds instance with TLS and how to disable anonymous access.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Now that we&#8217;ve set up an instance of the 389 Directory Server in part 1 and configured essential plugins in part 2, it&#8217;s time to take a closer look at access-control list (ACLs). After all, regular users of the directory shouldn&#8217;t be able to change data that they&#8217;re not supposed to or have universal read access in most use cases.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[84,13,7,83],"class_list":["post-2570","post","type-post","status-publish","format-standard","hentry","category-uncategorized","tag-389ds","tag-centos","tag-fedora","tag-ldap"],"_links":{"self":[{"href":"https:\/\/possiblelossofprecision.net\/index.php?rest_route=\/wp\/v2\/posts\/2570","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/possiblelossofprecision.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/possiblelossofprecision.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/possiblelossofprecision.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/possiblelossofprecision.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2570"}],"version-history":[{"count":26,"href":"https:\/\/possiblelossofprecision.net\/index.php?rest_route=\/wp\/v2\/posts\/2570\/revisions"}],"predecessor-version":[{"id":2644,"href":"https:\/\/possiblelossofprecision.net\/index.php?rest_route=\/wp\/v2\/posts\/2570\/revisions\/2644"}],"wp:attachment":[{"href":"https:\/\/possiblelossofprecision.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2570"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/possiblelossofprecision.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2570"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/possiblelossofprecision.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2570"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}