{"id":6443,"date":"2020-08-22T07:00:12","date_gmt":"2020-08-22T13:00:12","guid":{"rendered":"http:\/\/gregsowell.com\/?p=6443"},"modified":"2023-03-01T12:45:27","modified_gmt":"2023-03-01T18:45:27","slug":"authenticating-to-ansible-tower-via-windows-active-directory","status":"publish","type":"post","link":"https:\/\/gregsowell.com\/?p=6443","title":{"rendered":"Authenticating To Ansible Tower Via Windows Active Directory"},"content":{"rendered":"<p><a href=\"http:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/Untitled-1-1.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/Untitled-1-1-300x169.png\" alt=\"\" width=\"300\" height=\"169\" class=\"aligncenter size-medium wp-image-6463\" srcset=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/Untitled-1-1-300x169.png 300w, https:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/Untitled-1-1-768x432.png 768w, https:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/Untitled-1-1-1024x576.png 1024w, https:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/Untitled-1-1.png 1280w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><br \/>\nThe Ansible automation platform has many awesome features, and one in particular is its ability to authenticate off of something other than itself.  A common one I&#8217;m running into with customers is having Tower authenticate off of their Active Directory, so that&#8217;s what I&#8217;m going to tackle here.  This assumes you have a functioning AD environment(though turning up a domain controller is still a very simple process(I haven&#8217;t stood up a DC since windows 2000 LOL)).  <a href=\"https:\/\/docs.ansible.com\/ansible-tower\/latest\/html\/administration\/ldap_auth.html\">Here&#8217;s Ansible&#8217;s documentation on it<\/a>.<\/p>\n<h2>Demo Video<\/h2>\n<p><iframe loading=\"lazy\" width=\"560\" height=\"315\" src=\"https:\/\/www.youtube.com\/embed\/Q-E2I67s_Dg\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe><\/p>\n<h2>Active Directory Configuration<\/h2>\n<p>My AD server is windows server 2016 essentials and all of my screen shots are done from my laptop using <a href=\"https:\/\/docs.microsoft.com\/en-us\/sysinternals\/downloads\/adexplorer\">Active Directory Explorer<\/a>.<\/p>\n<p>My AD domain is DEMO.local:<br \/>\n<a href=\"http:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/ad1.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/ad1-244x300.png\" alt=\"\" width=\"244\" height=\"300\" class=\"aligncenter size-medium wp-image-6447\" srcset=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/ad1-244x300.png 244w, https:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/ad1.png 392w\" sizes=\"auto, (max-width: 244px) 100vw, 244px\" \/><\/a><\/p>\n<p>I stuck everything in the Users CN:<br \/>\n<a href=\"http:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/ad2.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/ad2-183x300.png\" alt=\"\" width=\"183\" height=\"300\" class=\"aligncenter size-medium wp-image-6448\" srcset=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/ad2-183x300.png 183w, https:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/ad2.png 409w\" sizes=\"auto, (max-width: 183px) 100vw, 183px\" \/><\/a><br \/>\nNotice in the above that I have two users:<br \/>\n&#8211; test1<br \/>\n&#8211; test2<br \/>\nI also have 4 groups defined:<br \/>\n&#8211; tower_admins<br \/>\n&#8211; tower_auditors<br \/>\n&#8211; tower_users<br \/>\n&#8211; tower_team_network<\/p>\n<p>The groups will be mapped to various things in tower, which I&#8217;ll cover in just a bit.<\/p>\n<h2>Tower Configuration<\/h2>\n<p>So navigating to system -> authentication will present me with my external authentication options.  From here I&#8217;m going to choose LDAP since AD is really just LDAP under the hood.<br \/>\n<a href=\"http:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/tower1-1.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/tower1-1-300x124.png\" alt=\"\" width=\"300\" height=\"124\" class=\"aligncenter size-medium wp-image-6450\" srcset=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/tower1-1-300x124.png 300w, https:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/tower1-1-768x318.png 768w, https:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/tower1-1-1024x424.png 1024w, https:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/tower1-1.png 1101w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><br \/>\nI&#8217;ve highlighted&#8230;highlit&#8230;multiple things here.<br \/>\n<strong>KEEP &#8220;LDAP USER DN TEMPLATE&#8221; and &#8220;LDAP DENY GROUP&#8221; BLANK<\/strong>.  It tends to break things if you don&#8217;t need it.<br \/>\nFor LDAP server I&#8217;m doing an unencrypted connection so I just use ldap:x.x.x.x:389; if it was to be secure I&#8217;d specify ldaps:x.x.x.x:636.<br \/>\nFor LDAP BIND DN I&#8217;ve specified a user that has access to access the various users and groups(this is the account Tower uses to authenticate with the LDAP server).<br \/>\nI use MemberDNGroupType for my LDAP group type, though there is an AD option.  If you have <strong>nested LDAP groups<\/strong>, be sure to set the option here.<br \/>\nThe LDAP Require Group is an optional field.  If this option is set, then only AD users that are members of this group are allowed to connect.  This prevents random AD users from connecting.<br \/>\n If you don&#8217;t specify anything here, then any AD user can connect to the system, but they won&#8217;t have access to do anything(other than create a credential) by default.  In my case I use the tower_users group.<\/p>\n<p>Here&#8217;s my next set of options:<br \/>\n<a href=\"http:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/tower2-1.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/tower2-1-130x300.png\" alt=\"\" width=\"130\" height=\"300\" class=\"aligncenter size-medium wp-image-6451\" srcset=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/tower2-1-130x300.png 130w, https:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/tower2-1.png 316w\" sizes=\"auto, (max-width: 130px) 100vw, 130px\" \/><\/a><br \/>\nLDAP User Search is where in LDAP the system will look for users.  I have them all in the users group as specified here, but I also use scope_subtree, which tells Tower to look here, but also look in other groups under this.  I also specify the sAMAccountName object to be the username as shown in the following screenshot:<br \/>\n<a href=\"http:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/ad3.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/ad3-300x151.png\" alt=\"\" width=\"300\" height=\"151\" class=\"aligncenter size-medium wp-image-6452\" srcset=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/ad3-300x151.png 300w, https:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/ad3-768x387.png 768w, https:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/ad3.png 888w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<pre class=\"gs-code\"><code class=\"language-plaintext\">[\r\n &quot;CN=Users,DC=DEMO,DC=local&quot;,\r\n &quot;SCOPE_SUBTREE&quot;,\r\n &quot;(sAMAccountName=%(user)s)&quot;\r\n]<\/code><\/pre>\n<p>Next will be the LDAP Group Search option, which tells tower where to look in the LDAP tree for the configured groups used for users.<\/p>\n<pre class=\"gs-code\"><code class=\"language-plaintext\">[\r\n &quot;CN=Users,DC=DEMO,DC=local&quot;,\r\n &quot;SCOPE_SUBTREE&quot;,\r\n &quot;(objectClass=group)&quot;\r\n]<\/code><\/pre>\n<p>Then we hit the LDAP User Attribute Map, which maps LDAP options to tower options.<\/p>\n<pre class=\"gs-code\"><code class=\"language-plaintext\">{\r\n &quot;first_name&quot;: &quot;givenName&quot;,\r\n &quot;last_name&quot;: &quot;sn&quot;,\r\n &quot;email&quot;: &quot;mail&quot;\r\n}<\/code><\/pre>\n<p>The LDAP Group Type Parameters do a little more mapping.<\/p>\n<pre class=\"gs-code\"><code class=\"language-plaintext\">{\r\n &quot;member_attr&quot;: &quot;member&quot;,\r\n &quot;name_attr&quot;: &quot;cn&quot;\r\n}<\/code><\/pre>\n<p><a href=\"http:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/tower3.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/tower3-288x300.png\" alt=\"\" width=\"288\" height=\"300\" class=\"aligncenter size-medium wp-image-6453\" srcset=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/tower3-288x300.png 288w, https:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/tower3.png 551w\" sizes=\"auto, (max-width: 288px) 100vw, 288px\" \/><\/a><br \/>\nLDAP User Flags By Group is where I map my singleton roles roles for admins and auditors.  The AD tower_admins group and tower_auditors group get mapped to system admins\/auditors in tower.<\/p>\n<pre class=\"gs-code\"><code class=\"language-plaintext\">{\r\n &quot;is_superuser&quot;: [\r\n  &quot;CN=tower_admins,CN=Users,DC=DEMO,DC=local&quot;\r\n ],\r\n &quot;is_system_auditor&quot;: [\r\n  &quot;CN=tower_auditors,CN=Users,DC=DEMO,DC=local&quot;\r\n ]\r\n}<\/code><\/pre>\n<p>LDAP Organization Map maps groups to various levels as shown below.  tower_admins become admins and every other group are users.<\/p>\n<pre class=\"gs-code\"><code class=\"language-plaintext\">{\r\n &quot;Default&quot;: {\r\n  &quot;remove_admins&quot;: true,\r\n  &quot;admins&quot;: &quot;CN=tower_admins,CN=Users,DC=DEMO,DC=local&quot;,\r\n  &quot;users&quot;: [\r\n   &quot;CN=_tower_auditors,CN=Users,DC=DEMO,DC=local&quot;,\r\n   &quot;CN=tower_users,CN=Users,DC=DEMO,DC=local&quot;,\r\n   &quot;CN=tower_team_network,CN=Users,DC=DEMO,DC=local&quot;\r\n  ]\r\n }\r\n}<\/code><\/pre>\n<p>Last is the LDAP Team Map.  This is where various AD groups are mapped to teams within Ansible Tower.  If the team doesn&#8217;t exist, then the first time a user authenticates, the teams will be created.  After the groups exist it&#8217;s an admin&#8217;s job to go and add permissions for the various groups.  <\/p>\n<pre class=\"gs-code\"><code class=\"language-plaintext\">{\r\n &quot;LDAP Admins&quot;: {\r\n  &quot;remove&quot;: true,\r\n  &quot;organization&quot;: &quot;Default&quot;,\r\n  &quot;users&quot;: &quot;CN=tower_admins,CN=Users,DC=DEMO,DC=local&quot;\r\n },\r\n &quot;LDAP Auditors&quot;: {\r\n  &quot;remove&quot;: true,\r\n  &quot;organization&quot;: &quot;Default&quot;,\r\n  &quot;users&quot;: &quot;CN=tower_auditors,CN=Users,DC=DEMO,DC=local&quot;\r\n },\r\n &quot;LDAP Users&quot;: {\r\n  &quot;remove&quot;: true,\r\n  &quot;organization&quot;: &quot;Default&quot;,\r\n  &quot;users&quot;: &quot;CN=tower_users,CN=Users,DC=DEMO,DC=local&quot;\r\n },\r\n &quot;LDAP Network&quot;: {\r\n  &quot;remove&quot;: true,\r\n  &quot;organization&quot;: &quot;Default&quot;,\r\n  &quot;users&quot;: &quot;CN=tower_team_network,CN=Users,DC=DEMO,DC=local&quot;\r\n }\r\n}<\/code><\/pre>\n<p>So any AD user that is a member of the tower_team_network group is put into Tower&#8217;s &#8220;LDAP Network&#8221; team.<br \/>\n<a href=\"http:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/ad4.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/ad4-300x86.png\" alt=\"\" width=\"300\" height=\"86\" class=\"aligncenter size-medium wp-image-6458\" srcset=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/ad4-300x86.png 300w, https:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/ad4-768x220.png 768w, https:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/ad4-1024x293.png 1024w, https:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/ad4.png 1322w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><br \/>\n<a href=\"http:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/tower4.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/tower4-300x137.png\" alt=\"\" width=\"300\" height=\"137\" class=\"aligncenter size-medium wp-image-6457\" srcset=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/tower4-300x137.png 300w, https:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/tower4-768x350.png 768w, https:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/tower4-1024x467.png 1024w, https:\/\/gregsowell.com\/wp-content\/uploads\/2020\/08\/tower4.png 1075w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<h2>LDAP Order Of Operation<\/h2>\n<p><a href=\"https:\/\/django-auth-ldap.readthedocs.io\/en\/latest\/multiconfig.html\">Check the link here<\/a> on how multiple LDAP servers are utilized.<br \/>\nThe TLDR is:<\/p>\n<blockquote><p>All of the usual rules apply: Django will attempt to authenticate a user with each backend in turn until one of them succeeds. When a particular backend successfully authenticates a user, that user will be linked to the backend for the duration of their session.<\/p><\/blockquote>\n<h2>LDAP Troubleshooting On Tower<\/h2>\n<p>When things inevitably go wrong, here&#8217;s some troubleshooting options.<br \/>\nIn tower, create this file(\/etc\/tower\/conf.d\/ldap.py) with the following option:<\/p>\n<pre class=\"gs-code\"><code class=\"language-plaintext\">LOGGING[&#039;handlers&#039;][&#039;tower_warnings&#039;][&#039;level&#039;] =  &#039;DEBUG&#039;<\/code><\/pre>\n<p>After that, restart the Tower services<\/p>\n<pre class=\"gs-code\"><code class=\"language-plaintext\">ansible-tower-service restart<\/code><\/pre>\n<p>You can now do a tail on the \/var\/log\/tower\/tower.log log file to see LDAP specific messages.<\/p>\n<p>You also want to use the LDAP search command(you will have to download the tool) to do some testing with the following command:<\/p>\n<pre class=\"gs-code\"><code class=\"language-plaintext\">ldapsearch -x  -H ldap:\/\/192.168.51.6 -D &quot;CN=Greg Sowell,CN=Users,DC=DEMO,DC=local&quot; -b &quot;dc=DEMO,dc=local&quot; -w MyPassword<\/code><\/pre>\n<p>Jeremy turned me on to the fact that a convenient way to see what&#8217;s going on is to do a wireshark capture on the packets; it will give you indications on what&#8217;s happening in the auth process.<\/p>\n<p>Big thanks to Jimmy for helping me suss the last bug out of my config.  Turns out if any group that Tower is searching LDAP for isn&#8217;t found, then it will just fail with a very nondescript error(so double check all of your spellings).<\/p>\n<p>Hope this helps and happy authenticating.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The Ansible automation platform has many awesome features, and one in particular is its ability to authenticate off of something other than itself. A\u2026<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[49,13,15],"tags":[],"class_list":["post-6443","post","type-post","status-publish","format-standard","hentry","category-ansible","category-server","category-windows"],"_links":{"self":[{"href":"https:\/\/gregsowell.com\/index.php?rest_route=\/wp\/v2\/posts\/6443","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/gregsowell.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/gregsowell.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/gregsowell.com\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/gregsowell.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=6443"}],"version-history":[{"count":17,"href":"https:\/\/gregsowell.com\/index.php?rest_route=\/wp\/v2\/posts\/6443\/revisions"}],"predecessor-version":[{"id":7429,"href":"https:\/\/gregsowell.com\/index.php?rest_route=\/wp\/v2\/posts\/6443\/revisions\/7429"}],"wp:attachment":[{"href":"https:\/\/gregsowell.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=6443"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/gregsowell.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=6443"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/gregsowell.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=6443"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}