{"id":2586,"date":"2021-06-17T08:00:41","date_gmt":"2021-06-17T06:00:41","guid":{"rendered":"https:\/\/possiblelossofprecision.net\/?p=2586"},"modified":"2021-05-15T11:46:36","modified_gmt":"2021-05-15T09:46:36","slug":"ldap-server-with-389ds-part-4-security","status":"publish","type":"post","link":"https:\/\/possiblelossofprecision.net\/?p=2586","title":{"rendered":"LDAP server with 389ds: Part 4 \u2013 Security"},"content":{"rendered":"<p>In <a href=\"https:\/\/possiblelossofprecision.net\/?p=2570\">part 3<\/a> we&#8217;ve looked at ACLs and how to use them to restrict privileges of directory users. Unfortunately it&#8217;s still possible to access the 389 Directory Server instance that we&#8217;ve created all the way back in <a href=\"https:\/\/possiblelossofprecision.net\/?p=2519#2-create-an-instance\">part 1<\/a> anonymously (i.e. without authenticating as a directory user) which renders the ACLs somewhat pointless. So it&#8217;s time to tighten up security a bit.<\/p>\n<p><!--more--><\/p>\n<h2>5. Securing an instance<\/h2>\n<h3>5.1. Disabling anonymous binds<\/h3>\n<p>Connecting to an LDAP server without a user name or password is called an <em>anonymous bind<\/em>. This is frequently used to simplify searching the DIT for common information such as group names or email addresses since it doesn&#8217;t require to authenticate with a service account first. By default the 389 Directory Server <a href=\"https:\/\/access.redhat.com\/documentation\/en-us\/red_hat_directory_server\/11\/html-single\/administration_guide\/index#disabling-anonymous-binds\">allows anonymous binds for search and read operations<\/a>.<br \/>\nThis introduces some security concerns however: Not only need the ACLs to be watertight to prevent access to sensitive information (especially if the <a href=\"https:\/\/en.wikipedia.org\/wiki\/General_Data_Protection_Regulation\">GDPR<\/a> is applicable) but anonymous binds can also be used for denial of service attacks or other attack vectors.<\/p>\n<p>To disable anonymous binds we can make use of <code>dsconf<\/code>:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\ndsconf localhost config replace nsslapd-allow-anonymous-access=off\r\n<\/pre>\n<h3>5.2. TLS encryption with Let&#8217;s Encrypt<\/h3>\n<p>Non-encrypted communication with an LDAP server is simply just a bad idea. Even in LAN environments it&#8217;s just best practise to use TLS to meet potential threats with <a href=\"https:\/\/en.wikipedia.org\/wiki\/Defense_in_depth_(computing)\">defense in depth<\/a>.<br \/>\nThe 389 Directory Server supports encrypted communication via the LDAPS protocol (TLS encryption is used right after the connection has been established) or <a href=\"https:\/\/en.wikipedia.org\/wiki\/Opportunistic_TLS\">STARTTLS<\/a> over LDAP (the connection is not encrypted until the STARTTLS command is sent by the client). For both we need a valid certificate.<\/p>\n<p>While it&#8217;s possible to use a self-signed certificate (which can be conveniently created by setting <code>self_sign_cert<\/code> to <code>True<\/code> in an inf answer file, see <a href=\"https:\/\/possiblelossofprecision.net\/?p=2519#2-create-an-instance\">part 1<\/a>) it can be quite laborious (or maybe not even possible) to ensure that the certificate authority is trusted by all applications that want to communicate with out LDAP server. And if the certificate can&#8217;t be verified, applications won&#8217;t (or at least shouldn&#8217;t) establish a connection.<br \/>\n<a href=\"https:\/\/letsencrypt.org\/\">Let&#8217;s encrypt<\/a> is a CA that&#8217;s run by the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Internet_Security_Research_Group\">Internet Security Research Group<\/a> and is trusted by almost all applications. Certificates are free, easy to create and use and can be automatically renewed with <code>certbot<\/code>, so we might as well just use that.<\/p>\n<p>To install certbot and enable automatic certificate renewal:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\n# dnf install certbot\r\n# systemctl enable certbot-renew.timer \r\nCreated symlink \/etc\/systemd\/system\/timers.target.wants\/certbot-renew.timer \u2192 \/usr\/lib\/systemd\/system\/certbot-renew.timer.\r\n<\/pre>\n<p>and assuming our 389ds instance is reachable on port 80 from the internet we can use the standalone mode to create a certificate (for other methods on how to create certificates, have a look at the <a href=\"https:\/\/certbot.eff.org\/docs\/\">certbot documentation<\/a>):<\/p>\n<pre class=\"brush: bash; highlight: [12,14]; title: ; notranslate\" title=\"\">\r\n# certbot certonly --standalone -m &lt;your_email&gt; --agree-tos -d ldap.example.com\r\nSaving debug log to \/var\/log\/letsencrypt\/letsencrypt.log\r\nPlugins selected: Authenticator standalone, Installer None\r\nRequesting a certificate for ldap.example.com\r\nPerforming the following challenges:\r\nhttp-01 challenge for ldap.example.com\r\nWaiting for verification...\r\nCleaning up challenges\r\n\r\nIMPORTANT NOTES:\r\n - Congratulations! Your certificate and chain have been saved at:\r\n   \/etc\/letsencrypt\/live\/ldap.example.com\/fullchain.pem\r\n   Your key file has been saved at:\r\n   \/etc\/letsencrypt\/live\/ldap.example.com\/privkey.pem\r\n   Your certificate will expire on 2021-08-11. To obtain a new or\r\n   tweaked version of this certificate in the future, simply run\r\n   certbot again. To non-interactively renew *all* of your\r\n   certificates, run &quot;certbot renew&quot;\r\n - If you like Certbot, please consider supporting our work by:\r\n\r\n   Donating to ISRG \/ Let's Encrypt:   https:\/\/letsencrypt.org\/donate\r\n   Donating to EFF:                    https:\/\/eff.org\/donate-le\r\n<\/pre>\n<p>The certificates and private key were installed to <code>\/etc\/letsencrypt\/live\/ldap.example.com\/<\/code> so all that&#8217;s left to do is to import them into the 389ds instance and enable TLS:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\ndsctl localhost tls import-server-key-cert \\\r\n  \/etc\/letsencrypt\/live\/ldap.example.com\/fullchain.pem \\\r\n  \/etc\/letsencrypt\/live\/ldap.example.com\/privkey.pem\r\ndsconf localhost config replace nsslapd-securePort=636 nsslapd-security=on\r\ndsctl localhost restart\r\n<\/pre>\n<p>We can now communicate with our LDAP server via LDAPS on port 636 or using STARTTLS on port 389.<\/p>\n<h3>5.3. Requiring secure binds<\/h3>\n<p>So now we <em>can<\/em> communicate securely with our LDAP server. However, it&#8217;s not required and unencrypted communication is still possible on port 389. To require secure, enctypted communication, we set <code>nsslapd-require-secure-binds<\/code> to <code>on<\/code><\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\ndsconf localhost config replace nsslapd-require-secure-binds=on\r\ndsctl instance_name restart\r\n<\/pre>\n<p>Note that <strong>this only concerns authenticated binds<\/strong>, i.e. when a user name and password is used. <a href=\"https:\/\/possiblelossofprecision.net\/?p=2586#5-1-disabling-anonymous-binds\">If we hadn&#8217;t disabled<\/a> <em>anonymous bind<\/em>, establishing an unecrypted connection <a href=\"https:\/\/access.redhat.com\/documentation\/en-us\/red_hat_directory_server\/11\/html-single\/administration_guide\/index#requiring-secure-binds\">would still be possible<\/a>.<\/p>\n<h3>5.4. Password storage schemes<\/h3>\n<p>Passwords are not stored in the directory server database in cleartext but <a href=\"https:\/\/en.wikipedia.org\/wiki\/Hash_function\">hashed<\/a>. The algorithm that&#8217;s used to hash the passwords is called the <em>password storage scheme<\/em>.<br \/>\nThere are two separate password storage schemes, one for the directory manager (<code>nsslapd-rootpwstoragescheme<\/code>) and another one for user passwords (<code>nsslapd-pwstoragescheme<\/code>). Both default to <code><a href=\"https:\/\/en.wikipedia.org\/wiki\/PBKDF2\">PBKDF2_SHA256<\/a><\/code>, which is considered to be <a href=\"https:\/\/en.wikipedia.org\/wiki\/PBKDF2#Alternatives_to_PBKDF2\">susceptible to GPU or ASIC brute force attacks<\/a>. Unfortunately, more modern hashing algorithms that would solve this problem by requiring larger amounts of RAM like <a href=\"https:\/\/en.wikipedia.org\/wiki\/Bcrypt\">bcrypt<\/a> or <a href=\"https:\/\/en.wikipedia.org\/wiki\/Scrypt\">scrypt<\/a> are currently not supported by the 389 Directory Server (see the list of <a href=\"https:\/\/access.redhat.com\/documentation\/en-us\/red_hat_directory_server\/11\/html\/configuration_command_and_file_reference\/plug_in_implemented_server_functionality_reference#password-storage-schemes\">available password storage schemes<\/a>)<\/p>\n<p>Changing the password storage schemes is rather straighforward though. Assuming we wanted to change both, the directory manager scheme as well as the user password scheme to <code>CRYPT-SHA512<\/code>, we can run<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\ndsconf localhost pwpolicy set --pwdscheme=CRYPT-SHA512\r\ndsconf localhost config replace nsslapd-rootpwstoragescheme=CRYPT-SHA512\r\n<\/pre>\n<p>Of course, since the clear text is unknown <strong>all passwords have to be rehashed<\/strong>. To rehash the directory manager password:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\ndsconf localhost config replace nsslapd-rootpw=&quot;mysecret&quot;\r\n<\/pre>\n<p><strong>Note that&#8217;s it&#8217;s questionable<\/strong> if <code>CRYPT-SHA512<\/code> offers more resilience to brute force attacks than the default <code>PBKDF2_SHA256<\/code>.<\/p>\n<p>Now that our 389ds instance is completely configured and we&#8217;ve tightened up security it&#8217;s time to look at how to back it up and &#8211; in case of a disaster &#8211; restore it in <a href=\"https:\/\/possiblelossofprecision.net\/?p=2597&#038;preview=true\">part 5<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In part 3 we&#8217;ve looked at ACLs and how to use them to restrict privileges of directory users. Unfortunately it&#8217;s still possible to access the 389 Directory Server instance that we&#8217;ve created all the way back in part 1 anonymously (i.e. without authenticating as a directory user) which renders the ACLs somewhat pointless. So it&#8217;s time to tighten up security&#8230; <a href=\"https:\/\/possiblelossofprecision.net\/?p=2586\">Read more &raquo;<\/a><\/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-2586","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\/2586","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=2586"}],"version-history":[{"count":21,"href":"https:\/\/possiblelossofprecision.net\/index.php?rest_route=\/wp\/v2\/posts\/2586\/revisions"}],"predecessor-version":[{"id":2656,"href":"https:\/\/possiblelossofprecision.net\/index.php?rest_route=\/wp\/v2\/posts\/2586\/revisions\/2656"}],"wp:attachment":[{"href":"https:\/\/possiblelossofprecision.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2586"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/possiblelossofprecision.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2586"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/possiblelossofprecision.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2586"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}