*****************************
Advanced Installation Options
*****************************

.. raw:: html

    <div class="section" id="enable-https">
    <h2>Enable HTTPS<a class="headerlink" href="#enable-https" title="Permalink to this headline">¶</a></h2>
    <p>Before you start:</p>
    <p>Purchase an SSL certificate and download the ssl <code class="docutils literal"><span class="pre">*.cert</span></code> file and ssl <code class="docutils literal"><span class="pre">*.key</span></code> file.</p>
    <p>NOTE: If security is not an issue, for testing you may set up a self-signed SSL certificate. See <a class="reference external" href="http://www.selfsignedcertificate.com/">http://www.selfsignedcertificate.com/</a> .</p>
    <p>Save the ssl <code class="docutils literal"><span class="pre">*.cert</span></code> file and an ssl <code class="docutils literal"><span class="pre">*.key</span></code> file in your home directory.</p>
    <p>Configure the server to use those keys and the correct ports:</p>
    <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">anaconda</span><span class="o">-</span><span class="n">server</span><span class="o">-</span><span class="n">config</span> <span class="o">--</span><span class="nb">set</span> <span class="n">ssl_options</span><span class="o">.</span><span class="n">keyfile</span> <span class="o">~/</span><span class="n">localhost</span><span class="o">.</span><span class="n">key</span>
    <span class="n">anaconda</span><span class="o">-</span><span class="n">server</span><span class="o">-</span><span class="n">config</span> <span class="o">--</span><span class="nb">set</span> <span class="n">ssl_options</span><span class="o">.</span><span class="n">certfile</span> <span class="o">~/</span><span class="n">localhost</span><span class="o">.</span><span class="n">cert</span>
    <span class="n">anaconda</span><span class="o">-</span><span class="n">server</span><span class="o">-</span><span class="n">config</span> <span class="o">--</span><span class="nb">set</span> <span class="n">port</span> <span class="mi">8443</span>
    </pre></div>
    </div>
    <p>Restart your server for the changes to take effect:</p>
    <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">supervisorctl</span> <span class="n">restart</span> <span class="nb">all</span>
    </pre></div>
    </div>
    <p>To test, navigate to the site using https in the address bar.</p>
    <p>NOTE: If you use a self-signed SSL certificate, your web browser will issue a warning that the website certificate cannot be verified.</p>
    </div>
    <div class="section" id="using-standard-ports">
    <h2>Using Standard Ports<a class="headerlink" href="#using-standard-ports" title="Permalink to this headline">¶</a></h2>
    <div class="section" id="http">
    <h3>HTTP<a class="headerlink" href="#http" title="Permalink to this headline">¶</a></h3>
    <p>The easiest way to enable clients to access an Anaconda Repository server on standard ports is to configure the server to redirect traffic received on standard HTTP port 80 to the standard Anaconda Repository HTTP port 8080:</p>
    <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">sudo</span> <span class="n">iptables</span> <span class="o">-</span><span class="n">t</span> <span class="n">nat</span> <span class="o">-</span><span class="n">F</span>
    <span class="n">sudo</span> <span class="n">iptables</span> <span class="o">-</span><span class="n">t</span> <span class="n">nat</span> <span class="o">-</span><span class="n">A</span> <span class="n">OUTPUT</span> <span class="o">-</span><span class="n">d</span> <span class="n">localhost</span> <span class="o">-</span><span class="n">p</span> <span class="n">tcp</span> <span class="o">--</span><span class="n">dport</span> <span class="mi">80</span> <span class="o">-</span><span class="n">j</span> <span class="n">REDIRECT</span> <span class="o">--</span><span class="n">to</span><span class="o">-</span><span class="n">ports</span> <span class="mi">8080</span>
    <span class="n">sudo</span> <span class="n">iptables</span> <span class="o">-</span><span class="n">t</span> <span class="n">nat</span> <span class="o">-</span><span class="n">I</span> <span class="n">PREROUTING</span> <span class="o">-</span><span class="n">p</span> <span class="n">tcp</span> <span class="o">--</span><span class="n">dport</span> <span class="mi">80</span> <span class="o">-</span><span class="n">j</span> <span class="n">REDIRECT</span> <span class="o">--</span><span class="n">to</span><span class="o">-</span><span class="n">port</span> <span class="mi">8080</span>
    </pre></div>
    </div>
    </div>
    <div class="section" id="https">
    <h3>HTTPS<a class="headerlink" href="#https" title="Permalink to this headline">¶</a></h3>
    <p>To use HTTPS, redirect traffic from standard HTTPS port 443 to standard Anaconda Repository HTTPS port 8443:</p>
    <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">sudo</span> <span class="n">iptables</span> <span class="o">-</span><span class="n">t</span> <span class="n">nat</span> <span class="o">-</span><span class="n">A</span> <span class="n">OUTPUT</span> <span class="o">-</span><span class="n">d</span> <span class="n">localhost</span> <span class="o">-</span><span class="n">p</span> <span class="n">tcp</span> <span class="o">--</span><span class="n">dport</span> <span class="mi">443</span> <span class="o">-</span><span class="n">j</span> <span class="n">REDIRECT</span> <span class="o">--</span><span class="n">to</span><span class="o">-</span><span class="n">ports</span> <span class="mi">8443</span>
    <span class="n">sudo</span> <span class="n">iptables</span> <span class="o">-</span><span class="n">t</span> <span class="n">nat</span> <span class="o">-</span><span class="n">I</span> <span class="n">PREROUTING</span> <span class="o">-</span><span class="n">p</span> <span class="n">tcp</span> <span class="o">--</span><span class="n">dport</span> <span class="mi">443</span> <span class="o">-</span><span class="n">j</span> <span class="n">REDIRECT</span> <span class="o">--</span><span class="n">to</span><span class="o">-</span><span class="n">port</span> <span class="mi">8443</span>
    </pre></div>
    </div>
    <p>NOTE: See also &#8220;Enable HTTPS&#8221; above.</p>
    </div>
    </div>
    <div class="section" id="connect-to-an-existing-mongodb-database">
    <span id="connect-to-existing-mongodb-db"></span><h2>Connect to an Existing MongoDB Database<a class="headerlink" href="#connect-to-an-existing-mongodb-database" title="Permalink to this headline">¶</a></h2>
    <p>If you already have a mongodb server running, you can connect to it by setting the MONGO_URL config variable:</p>
    <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">anaconda</span><span class="o">-</span><span class="n">server</span><span class="o">-</span><span class="n">config</span> <span class="o">--</span><span class="nb">set</span> <span class="n">MONGO_URL</span> <span class="s1">&#39;mongodb://&lt;hostname&gt;&#39;</span>
    </pre></div>
    </div>
    <p>NOTE: For more information, see the <a class="reference external" href="http://docs.mongodb.org/manual/reference/connection-string/">MongoDB Connection String URI Format</a>
    manual.</p>
    </div>
    <div class="section" id="whitelist-or-blacklist-certain-packages">
    <h2>Whitelist or Blacklist certain packages<a class="headerlink" href="#whitelist-or-blacklist-certain-packages" title="Permalink to this headline">¶</a></h2>
    <p>Sometimes you do not want to replicate all the packages from the Anaconda Repository into your mirror. The anaconda-server-sync-conda tool includes whitelist/blacklist functionality to manipulate your list of mirrored packages in a variety of ways.</p>
    <p>A mirror config file can be specified when you run anaconda-server-sync-conda with the flag <code class="docutils literal"><span class="pre">--mirror-config=FILEPATH</span></code> and replace FILEPATH with the path to your config file.</p>
    <p>To customize your distribution, you have the following options:</p>
    <ul class="simple">
    <li><strong>remote_url</strong>: Anaconda Enterprise Repository mirrors packages from this source URL.</li>
    <li><strong>mirror_dir</strong>: AE Repository stores packages in this directory on the machine where the script is executed.</li>
    <li><strong>platforms</strong>: AE Repository mirrors packages for these platforms.</li>
    <li><strong>license_blacklist</strong>: AE Repository omits packages with these licenses.</li>
    <li><strong>blacklist</strong>: AE Repository omits these packages.</li>
    <li><strong>whitelist</strong>: AE Repository always mirrors these packages.</li>
    </ul>
    <p>NOTE: Configuration files are yaml files.</p>
    <p>A fully working example can look like this:</p>
    <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">mirror_dir</span><span class="p">:</span> <span class="o">/</span><span class="n">opt</span><span class="o">/</span><span class="n">anaconda</span><span class="o">-</span><span class="n">server</span><span class="o">/</span><span class="n">package</span><span class="o">-</span><span class="n">storage</span>
    <span class="n">platforms</span><span class="p">:</span>
      <span class="o">-</span> <span class="n">linux</span><span class="o">-</span><span class="mi">32</span>
      <span class="o">-</span> <span class="n">linux</span><span class="o">-</span><span class="mi">64</span>
    <span class="n">license_blacklist</span><span class="p">:</span> <span class="n">GPL</span>
    <span class="n">whitelist</span><span class="p">:</span>
      <span class="o">-</span> <span class="n">distribute</span>
      <span class="o">-</span> <span class="n">conda</span>
    <span class="n">blacklist</span><span class="p">:</span>
      <span class="o">-</span> <span class="n">flask</span>
      <span class="o">-</span> <span class="n">readline</span>
    </pre></div>
    </div>
    <p>It only selects packages that are available for linux-32 and linux-64 platforms (for example, win-32 or win-64 packages will not be mirrored at all).</p>
    <p>From the ultimate list of packages that are mirrored, the tool:</p>
    <ul class="simple">
    <li>Removes all packages that are under the GPL license so that every license except GPL is allowed</li>
    <li>Removes any packages that are explicitly mentioned in the &#8216;blacklist&#8217; option, regardless of the platform or license-type</li>
    <li>Adds packages explicitly mentioned in the &#8216;whitelist&#8217; option to the list of packages that are mirrored</li>
    </ul>
    <p>NOTE: Currently GPL licenses are the only license type that can be license_blacklisted.</p>
    <p>NOTE: The whitelist option overrides license_blacklist and blacklist, so that a package listed here is mirrored even when under a GPL license or if it appears in the &#8216;blacklist&#8217; option.</p>
    <p>REMEMBER: You do not <em>need</em> to set up each option manually. If you only want to adjust one or two options, that is allowed. Untouched options remain defined by the default setting.</p>
    <p>The step-by-step algorithm that is used by the cas-mirror to create the ultimate list of packages to mirror follows this procedure:</p>
    <ol class="arabic simple">
    <li>Get a full list of packages from default_url.</li>
    <li>If the platforms option is present, only those packages available to the platforms listed here are left on the list.</li>
    <li>If license_blacklist is present, then all the packages subject to any of the licenses mentioned here are removed from the list.</li>
    <li>If blacklist is present then all member packages explicitly mentioned here are removed from the list.</li>
    <li>If whitelist is present then those assigned member packages are added to the list.</li>
    </ol>
    <p>After performing all of the above actions sequentially, the script produces the ultimate list of packages that are mirrored in the next step.</p>
    </div>
    <div class="section" id="securing-user-created-content">
    <span id="id1"></span><h2>Securing User-created Content<a class="headerlink" href="#securing-user-created-content" title="Permalink to this headline">¶</a></h2>
    <p>To prevent cross-site scripting attacks (XSS), user content (such as Jupyter notebooks) can be
    served from a separate domain.</p>
    <p>To enable this, configure the project to use a separate content domain:</p>
    <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">anaconda</span><span class="o">-</span><span class="n">server</span><span class="o">-</span><span class="n">config</span> <span class="o">--</span><span class="nb">set</span> <span class="n">SERVER_NAME</span> <span class="n">your</span><span class="o">.</span><span class="n">anaconda</span><span class="o">.</span><span class="n">server</span>
    <span class="n">anaconda</span><span class="o">-</span><span class="n">server</span><span class="o">-</span><span class="n">config</span> <span class="o">--</span><span class="nb">set</span> <span class="n">USER_CONTENT_DOMAIN</span> <span class="n">your</span><span class="o">.</span><span class="n">usercontent</span><span class="o">.</span><span class="n">server</span>
    </pre></div>
    </div>
    <p>If your user content domain is a subdomain of your Anaconda Repository domain,
    you must also configure the session cookie to only send to the root domain:</p>
    <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">anaconda</span><span class="o">-</span><span class="n">server</span><span class="o">-</span><span class="n">config</span> <span class="o">--</span><span class="nb">set</span> <span class="n">SERVER_NAME</span> <span class="n">your</span><span class="o">.</span><span class="n">anaconda</span><span class="o">.</span><span class="n">server</span>
    <span class="n">anaconda</span><span class="o">-</span><span class="n">server</span><span class="o">-</span><span class="n">config</span> <span class="o">--</span><span class="nb">set</span> <span class="n">USER_CONTENT_DOMAIN</span> <span class="n">usercontent</span><span class="o">.</span><span class="n">your</span><span class="o">.</span><span class="n">anaconda</span><span class="o">.</span><span class="n">server</span>
    <span class="n">anaconda</span><span class="o">-</span><span class="n">server</span><span class="o">-</span><span class="n">config</span> <span class="o">--</span><span class="nb">set</span> <span class="n">SESSION_COOKIE_DOMAIN</span> <span class="n">your</span><span class="o">.</span><span class="n">anaconda</span><span class="o">.</span><span class="n">server</span>
    </pre></div>
    </div>
    </div>
    <div class="section" id="configure-anaconda-repository-to-use-ldap">
    <h2>Configure Anaconda Repository to use LDAP<a class="headerlink" href="#configure-anaconda-repository-to-use-ldap" title="Permalink to this headline">¶</a></h2>
    <p>Open the Anaconda Repository configuration file <cite>/etc/binstar/config.yaml</cite> and add the following configuration to enable Lightweight Directory Access Protocol (LDAP) support:</p>
    <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">LDAP</span><span class="p">:</span> <span class="p">{</span>
      <span class="c1"># Replace with company LDAP server</span>
      <span class="s1">&#39;URI&#39;</span><span class="p">:</span> <span class="s1">&#39;ldap://&lt;ldap.company.com&gt;&#39;</span><span class="p">,</span>

      <span class="c1"># Replace &lt;uid=%(username)s,ou=People,dc=company,dc=com&gt; with your company specific LDAP Bind/Base DN</span>
      <span class="c1"># Bind directly to this Base DN.</span>
      <span class="s1">&#39;BIND_DN&#39;</span><span class="p">:</span> <span class="s1">&#39;&lt;uid=</span><span class="si">%(username)s</span><span class="s1">,ou=People,dc=company,dc=com&gt;&#39;</span><span class="p">,</span>

      <span class="c1"># Map ldap keys into application specific keys</span>
      <span class="s1">&#39;KEY_MAP&#39;</span><span class="p">:</span> <span class="p">{</span>
          <span class="s1">&#39;name&#39;</span><span class="p">:</span><span class="s1">&#39;cn&#39;</span><span class="p">,</span>
          <span class="s1">&#39;company&#39;</span><span class="p">:</span> <span class="s1">&#39;o&#39;</span><span class="p">,</span>
          <span class="s1">&#39;location&#39;</span><span class="p">:</span><span class="s1">&#39;l&#39;</span><span class="p">,</span>
          <span class="s1">&#39;email&#39;</span><span class="p">:</span> <span class="s1">&#39;mail&#39;</span><span class="p">,</span>
        <span class="p">},</span>
    <span class="p">}</span>
    </pre></div>
    </div>
    <p>Update the <strong>URI</strong> with the location of your LDAP server and <strong>BIND_DN</strong> with the values specific to your LDAP server.
    Change the <strong>KEY_MAP</strong> keys with the associated values for your LDAP server.</p>
    <p>When switching authentication to LDAP the admin account is lost, so you need to add your admin account again:</p>
    <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">anaconda</span><span class="o">-</span><span class="n">server</span><span class="o">-</span><span class="n">admin</span> <span class="nb">set</span><span class="o">-</span><span class="n">superuser</span> <span class="s2">&quot;jsmith&quot;</span>
    </pre></div>
    </div>
    <p>Run the flask-ldap-login-check command to verify LDAP connectivity:</p>
    <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">flask</span><span class="o">-</span><span class="n">ldap</span><span class="o">-</span><span class="n">login</span><span class="o">-</span><span class="n">check</span> <span class="n">binstar</span><span class="o">.</span><span class="n">wsgi</span><span class="p">:</span><span class="n">app</span> <span class="o">--</span><span class="n">username</span> <span class="s1">&#39;jsmith&#39;</span> <span class="o">--</span><span class="n">password</span> <span class="s1">&#39;abc123DEF&#39;</span>
    </pre></div>
    </div>
    <p>NOTE: Replace jsmith and abc123DEF with your actual LDAP username and password.</p>
    <p>To apply the changes, restart the Anaconda Repository server:</p>
    <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">supervisorctl</span> <span class="n">restart</span> <span class="nb">all</span>
    </pre></div>
    </div>
    <p>Open a new browser window and navigate to your local Anaconda Repository installation:</p>
    <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">your</span><span class="o">.</span><span class="n">anaconda</span><span class="o">.</span><span class="n">server</span>
    </pre></div>
    </div>
    <p>NOTE: Replace &#8220;your.anaconda.server&#8221; with your actual Anaconda Repository server IP address or domain name.</p>
    <p>You can now log in using your LDAP credentials.</p>
    </div>
    <div class="section" id="configure-anaconda-repository-to-use-active-directory">
    <h2>Configure Anaconda Repository to use Active Directory<a class="headerlink" href="#configure-anaconda-repository-to-use-active-directory" title="Permalink to this headline">¶</a></h2>
    <p>Microsoft Active Directory is a server program that provides directory services and uses the open industry standard Lightweight Directory Access Protocol (LDAP).</p>
    <p>Open the Anaconda Repository configuration file <cite>/etc/binstar/config.yaml</cite> and add the following configuration to enable Active Directory support:</p>
    <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">LDAP</span> <span class="p">:</span> <span class="p">{</span>
        <span class="s1">&#39;URI&#39;</span><span class="p">:</span> <span class="s1">&#39;ldap://&lt;ldap.server.url&gt;&#39;</span><span class="p">,</span>

        <span class="c1"># This BIND_DN/BIND_PASSWORD default to &#39;&#39;, this is shown here for</span>
        <span class="c1"># demonstrative purposes. To enable Authorized Bind, insert the AD</span>
        <span class="c1"># BIND_DN and BIND_AUTH password for and authorized AD user.</span>
        <span class="c1">#</span>
        <span class="c1">#e.g. &#39;BIND_DN&#39;: &#39;&lt;cn=Authorized User,cn=users,dc=company,dc=local&gt;&#39;,</span>
        <span class="c1">#e.g. &#39;BIND_AUTH&#39;: &#39;&lt;AuthUsrPassword&gt;&#39;,</span>

        <span class="c1"># The values &#39;&#39; perform an anonymous bind so we may use search/bind method</span>
        <span class="s1">&#39;BIND_DN&#39;</span><span class="p">:</span> <span class="s1">&#39;&#39;</span><span class="p">,</span>
        <span class="s1">&#39;BIND_AUTH&#39;</span><span class="p">:</span> <span class="s1">&#39;&#39;</span><span class="p">,</span>

        <span class="c1"># Adding the USER_SEARCH field tells the flask-ldap-login that we</span>
        <span class="c1"># are using the search/bind method</span>
        <span class="s1">&#39;USER_SEARCH&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;base&#39;</span><span class="p">:</span> <span class="s1">&#39;&lt;cn=users,dc=company,dc=local&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;filter&#39;</span><span class="p">:</span> <span class="s1">&#39;sAMAccountName=</span><span class="si">%(username)s</span><span class="s1">&#39;</span><span class="p">},</span>

        <span class="c1"># Map ldap keys into application specific keys</span>
        <span class="s1">&#39;KEY_MAP&#39;</span><span class="p">:</span> <span class="p">{</span>
            <span class="s1">&#39;name&#39;</span><span class="p">:</span><span class="s1">&#39;cn&#39;</span><span class="p">,</span>
            <span class="s1">&#39;company&#39;</span><span class="p">:</span> <span class="s1">&#39;o&#39;</span><span class="p">,</span>
            <span class="s1">&#39;location&#39;</span><span class="p">:</span><span class="s1">&#39;l&#39;</span><span class="p">,</span>
            <span class="s1">&#39;email&#39;</span><span class="p">:</span> <span class="s1">&#39;userPrincipalName&#39;</span><span class="p">,</span>
            <span class="p">},</span>
    <span class="p">}</span>
    </pre></div>
    </div>
    <p>Update the <em>URI</em> &lt;ldap.server.url&gt; with the location of your Active Directory server, <em>BIND_DN</em> with the values specific to your Active Directory server and the <em>BIND_AUTH</em> with the password of the user specified in the <em>BIND_DN</em>. Change the <strong>KEY_MAP</strong> keys with the associated values from your Active Directory server.</p>
    <p>To apply the changes, restart the Anaconda Repository server:</p>
    <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">supervisorctl</span> <span class="n">restart</span> <span class="nb">all</span>
    </pre></div>
    </div>
    <p>Run the flask-ldap-login-check command to verify Active Directory connectivity:</p>
    <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">flask</span><span class="o">-</span><span class="n">ldap</span><span class="o">-</span><span class="n">login</span><span class="o">-</span><span class="n">check</span> <span class="n">binstar</span><span class="o">.</span><span class="n">wsgi</span><span class="p">:</span><span class="n">app</span> <span class="o">--</span><span class="n">username</span> <span class="s1">&#39;jsmith&#39;</span> <span class="o">--</span><span class="n">password</span> <span class="s1">&#39;abc123DEF&#39;</span>
    </pre></div>
    </div>
    <p>NOTE: Replace jsmith and abc123DEF with your actual Active Directory username and password.</p>
    <p>You will see a response similar to the following:</p>
    <div class="highlight-default"><div class="highlight"><pre><span></span><span class="p">[</span><span class="n">anaconda</span><span class="o">.</span><span class="n">server</span><span class="p">]</span> <span class="n">Started</span> <span class="n">Site</span>
    <span class="n">Got</span> <span class="n">userdata</span> <span class="k">for</span> <span class="n">jsmith</span>
    <span class="p">{</span><span class="s1">&#39;company&#39;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span> <span class="s1">&#39;email&#39;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span> <span class="s1">&#39;location&#39;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span> <span class="s1">&#39;name&#39;</span><span class="p">:</span> <span class="s1">&#39;Jane Smith&#39;</span><span class="p">}</span>
    </pre></div>
    </div>
    <p>Open your browser and navigate to your local Anaconda Repository installation:</p>
    <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">your</span><span class="o">.</span><span class="n">anaconda</span><span class="o">.</span><span class="n">server</span>
    </pre></div>
    </div>
    <p>NOTE: Replace &#8220;your.anaconda.server&#8221; with your actual Anaconda Repository IP address or domain name.</p>
    <p>You can now log in with Active Directory.</p>
    </div>
    <div class="section" id="configuring-anaconda-repository-to-use-ldap-groups">
    <h2>Configuring Anaconda Repository to use LDAP groups<a class="headerlink" href="#configuring-anaconda-repository-to-use-ldap-groups" title="Permalink to this headline">¶</a></h2>
    <p>Anaconda Repository can be configured to allow synchronizing the membership of
    organization groups with groups in an LDAP directory. Owners of an organization
    can select a specific LDAP group as the source of group members. Once this is enabled,
    users who sign in to Anaconda Repository who are members of the LDAP group will
    automatically be granted the permissions of the organization group.</p>
    <p>In order to enable this, the following configuration is required:</p>
    <ul class="simple">
    <li>authenticated bind to LDAP (Anaconda Repository needs to perform searches against
    the directory to determine the available groups, and the membership of those groups)</li>
    <li>a query for Anaconda Repository to identify the groups in your LDAP directory
    (see <a class="reference internal" href="#group-search">GROUP_SEARCH</a>)</li>
    </ul>
    <p>If LDAP synchronization is disabled or the LDAP server is unreachable, the member list
    at the time is used for the group.</p>
    <p>In order to administer and debug LDAP synchronization, a superuser can
    visit:</p>
    <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">your</span><span class="o">.</span><span class="n">anaconda</span><span class="o">.</span><span class="n">server</span><span class="o">/</span><span class="n">admin</span><span class="o">/</span><span class="n">ldap</span>
    </pre></div>
    </div>
    </div>
    <div class="section" id="enable-tls-on-ldap-active-directory">
    <h2>Enable TLS on LDAP/Active Directory<a class="headerlink" href="#enable-tls-on-ldap-active-directory" title="Permalink to this headline">¶</a></h2>
    <p>Microsoft Active Directory is a server program that provides directory services and uses the open industry standard Lightweight Directory Access Protocol (LDAP).</p>
    <p>To enable a secure Transport Layer Security (TLS) connection, add the following to the LDAP configuration section of the file <cite>/etc/binstar/config.yaml</cite>:</p>
    <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">LDAP</span><span class="o">=</span><span class="p">{</span>  <span class="o">....</span>

      <span class="s1">&#39;START_TLS&#39;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
      <span class="s1">&#39;OPTIONS&#39;</span><span class="p">:</span> <span class="p">{</span> <span class="s1">&#39;OPT_PROTOCOL_VERSION&#39;</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span>
                   <span class="s1">&#39;OPT_X_TLS_DEMAND&#39;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
                   <span class="s1">&#39;OPT_X_TLS_REQUIRE_CERT&#39;</span><span class="p">:</span> <span class="s1">&#39;OPT_X_TLS_NEVER&#39;</span><span class="p">,</span>
                   <span class="s1">&#39;OPT_X_TLS_CACERTFILE&#39;</span><span class="p">:</span> <span class="s1">&#39;/path/to/certfile&#39;</span><span class="p">)</span>
                  <span class="p">}</span>
        <span class="o">....</span>
    <span class="p">}</span>
    </pre></div>
    </div>
    </div>
    <div class="section" id="ldap-and-tls-configuration-options">
    <span id="ldap-configuration-options"></span><h2>LDAP and TLS Configuration Options<a class="headerlink" href="#ldap-and-tls-configuration-options" title="Permalink to this headline">¶</a></h2>
    <div class="section" id="uri">
    <h3>URI<a class="headerlink" href="#uri" title="Permalink to this headline">¶</a></h3>
    <p>Start by setting URI to point to your server. The value of this setting can be
    anything that your LDAP library supports. For instance, openldap may allow you
    to give a comma- or space-separated list of URIs to try in sequence.</p>
    </div>
    <div class="section" id="bind-dn">
    <h3>BIND_DN<a class="headerlink" href="#bind-dn" title="Permalink to this headline">¶</a></h3>
    <p>The distinguished name to use when binding to the LDAP server (with <code class="docutils literal"><span class="pre">BIND_AUTH</span></code>).
    Use the empty string (the default) for an anonymous bind.</p>
    </div>
    <div class="section" id="bind-auth">
    <h3>BIND_AUTH<a class="headerlink" href="#bind-auth" title="Permalink to this headline">¶</a></h3>
    <p>The password to use with <code class="docutils literal"><span class="pre">BIND_DN</span></code>.</p>
    </div>
    <div class="section" id="user-search">
    <h3>USER_SEARCH<a class="headerlink" href="#user-search" title="Permalink to this headline">¶</a></h3>
    <p>A dict that will locate a user in the directory. The dict object must contain
    the required entries <code class="docutils literal"><span class="pre">base</span></code> and <code class="docutils literal"><span class="pre">filter</span></code> and may contain the optional entry
    <code class="docutils literal"><span class="pre">scope</span></code>.</p>
    <ul class="simple">
    <li>base: The base DN to search.</li>
    <li>filter: Should contain the placeholder <code class="docutils literal"><span class="pre">%(username)s</span></code> for the username.</li>
    <li>scope: One of <code class="docutils literal"><span class="pre">LDAP_SCOPE_BASE</span></code>, <code class="docutils literal"><span class="pre">LDAP_SCOPE_ONELEVEL</span></code>, or <code class="docutils literal"><span class="pre">LDAP_SCOPE_SUBTREE</span></code>.</li>
    </ul>
    <p>For example:</p>
    <div class="highlight-yaml"><div class="highlight"><pre><span></span><span class="p p-Indicator">{</span><span class="s">&#39;base&#39;</span><span class="p p-Indicator">:</span> <span class="s">&#39;dc=example,dc=com&#39;</span><span class="p p-Indicator">,</span> <span class="s">&#39;filter&#39;</span><span class="p p-Indicator">:</span> <span class="s">&#39;uid=%(username)s&#39;</span><span class="p p-Indicator">}</span>
    </pre></div>
    </div>
    </div>
    <div class="section" id="enable-groups">
    <h3>ENABLE_GROUPS<a class="headerlink" href="#enable-groups" title="Permalink to this headline">¶</a></h3>
    <p>Whether to enable LDAP group synchronization, allowing users to synchronize
    group membership with an LDAP directory. Defaults to <code class="docutils literal"><span class="pre">false</span></code>.</p>
    <p>For example:</p>
    <div class="highlight-yaml"><div class="highlight"><pre><span></span><span class="l l-Scalar l-Scalar-Plain">ENABLE_GROUPS</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">true</span>
    </pre></div>
    </div>
    </div>
    <div class="section" id="group-search">
    <h3>GROUP_SEARCH<a class="headerlink" href="#group-search" title="Permalink to this headline">¶</a></h3>
    <p>A dictionary that will locate a group in the directory. An LDAP search is performed
    using the <code class="docutils literal"><span class="pre">base</span></code> distinguished name and <code class="docutils literal"><span class="pre">filter</span></code>.</p>
    <p>For example:</p>
    <div class="highlight-yaml"><div class="highlight"><pre><span></span><span class="l l-Scalar l-Scalar-Plain">GROUP_SEARCH</span><span class="p p-Indicator">:</span>
        <span class="l l-Scalar l-Scalar-Plain">base</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">dc=example,dc=com</span>
        <span class="l l-Scalar l-Scalar-Plain">filter</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">(objectClass=group)</span>
    </pre></div>
    </div>
    </div>
    <div class="section" id="group-members-attr">
    <h3>GROUP_MEMBERS_ATTR<a class="headerlink" href="#group-members-attr" title="Permalink to this headline">¶</a></h3>
    <p>The LDAP attribute on a group object that indicates the users that are
    members of the group. Defaults to <code class="docutils literal"><span class="pre">member</span></code>.</p>
    <p>For example:</p>
    <div class="highlight-yaml"><div class="highlight"><pre><span></span><span class="l l-Scalar l-Scalar-Plain">GROUP_MEMBERS_ATTR</span><span class="p p-Indicator">:</span> <span class="s">&#39;member&#39;</span>
    </pre></div>
    </div>
    </div>
    <div class="section" id="refresh-interval">
    <h3>REFRESH_INTERVAL<a class="headerlink" href="#refresh-interval" title="Permalink to this headline">¶</a></h3>
    <p>The number of seconds that group membership information from LDAP is used
    before being fetched from the directory server again. Defaults to <code class="docutils literal"><span class="pre">3600</span></code> (1 hour).</p>
    <p>For example:</p>
    <div class="highlight-yaml"><div class="highlight"><pre><span></span><span class="l l-Scalar l-Scalar-Plain">REFRESH_INTERVAL</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">600</span>
    </pre></div>
    </div>
    </div>
    <div class="section" id="key-map">
    <h3>KEY_MAP<a class="headerlink" href="#key-map" title="Permalink to this headline">¶</a></h3>
    <p>This is a dict mapping application context to ldap. An application may expect
    user data to be consistent and not all ldap setups use the same configuration:</p>
    <div class="highlight-yaml"><div class="highlight"><pre><span></span><span class="s">&#39;application_key&#39;</span><span class="p p-Indicator">:</span> <span class="s">&#39;ldap_key&#39;</span>
    </pre></div>
    </div>
    <p>For example:</p>
    <div class="highlight-none"><div class="highlight"><pre><span></span>KEY_MAP={&#39;name&#39;: &#39;cn&#39;, &#39;company&#39;: &#39;o&#39;, &#39;email&#39;: &#39;mail&#39;}
    </pre></div>
    </div>
    </div>
    <div class="section" id="start-tls">
    <h3>START_TLS<a class="headerlink" href="#start-tls" title="Permalink to this headline">¶</a></h3>
    <p>If <code class="docutils literal"><span class="pre">True</span></code>, each connection to the LDAP server will call <code class="docutils literal"><span class="pre">start_tls_s()</span></code>
    to enable TLS encryption over the standard LDAP port. There are a number of
    configuration options that can be given to <code class="docutils literal"><span class="pre">OPTIONS</span></code> that affect the TLS
    connection. For example, <code class="docutils literal"><span class="pre">OPT_X_TLS_REQUIRE_CERT</span></code> can be set to
    <code class="docutils literal"><span class="pre">OPT_X_TLS_NEVER</span></code> to disable certificate verification, perhaps to allow
    self-signed certificates.</p>
    </div>
    <div class="section" id="options">
    <h3>OPTIONS<a class="headerlink" href="#options" title="Permalink to this headline">¶</a></h3>
    <p>This stores LDAP specific options. For example:</p>
    <div class="highlight-yaml"><div class="highlight"><pre><span></span><span class="l l-Scalar l-Scalar-Plain">LDAP</span><span class="p p-Indicator">:</span>
        <span class="l l-Scalar l-Scalar-Plain">OPTIONS</span><span class="p p-Indicator">:</span>
            <span class="l l-Scalar l-Scalar-Plain">OPT_PROTOCOL_VERSION</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">3</span>
            <span class="l l-Scalar l-Scalar-Plain">OPT_X_TLS_REQUIRE_CERT</span><span class="p p-Indicator">:</span> <span class="s">&#39;OPT_X_TLS_NEVER&#39;</span>
    </pre></div>
    </div>
    </div>
    <div class="section" id="tls-secure-ldap">
    <h3>TLS (secure LDAP)<a class="headerlink" href="#tls-secure-ldap" title="Permalink to this headline">¶</a></h3>
    <p>To enable a secure TLS connection you must set <code class="docutils literal"><span class="pre">START_TLS</span></code> to True. There are
    a number of configuration options that can be given to <code class="docutils literal"><span class="pre">OPTIONS</span></code> that affect
    the TLS connection. For example, <code class="docutils literal"><span class="pre">OPT_X_TLS_REQUIRE_CERT</span></code> <code class="docutils literal"><span class="pre">OPT_X_TLS_NEVER</span></code>
    disables certificate verification, perhaps to allow self-signed certificates.</p>
    <div class="highlight-yaml"><div class="highlight"><pre><span></span><span class="l l-Scalar l-Scalar-Plain">LDAP</span><span class="p p-Indicator">:</span>
        <span class="l l-Scalar l-Scalar-Plain">START_TLS</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">true</span>
        <span class="l l-Scalar l-Scalar-Plain">OPTIONS</span><span class="p p-Indicator">:</span>
            <span class="l l-Scalar l-Scalar-Plain">OPT_PROTOCOL_VERSION</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">3</span>
            <span class="l l-Scalar l-Scalar-Plain">OPT_X_TLS_DEMAND</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">true</span>
            <span class="l l-Scalar l-Scalar-Plain">OPT_X_TLS_REQUIRE_CERT</span><span class="p p-Indicator">:</span> <span class="s">&#39;OPT_X_TLS_NEVER&#39;</span>
            <span class="l l-Scalar l-Scalar-Plain">OPT_X_TLS_CACERTFILE</span><span class="p p-Indicator">:</span> <span class="s">&#39;/path/to/certfile&#39;</span>
    </pre></div>
    </div>
    </div>
    </div>
    <div class="section" id="configure-anaconda-repository-to-use-kerberos">
    <span id="using-kerberos"></span><h2>Configure Anaconda Repository to use Kerberos<a class="headerlink" href="#configure-anaconda-repository-to-use-kerberos" title="Permalink to this headline">¶</a></h2>
    <p>Kerberos is an authentication protocol designed to allow nodes communicating
    over an insecure network to verify identity.  Anaconda Repository can use
    Kerberos to authenticate users.</p>
    <p>The Kerberos protocol uses timestamps to prevent replay attacks on expired
    credentials, so the Network Time Protocol (NTP) service must be set up and
    working correctly.</p>
    <p>Several aspects of Kerberos rely on name service. Your
    Domain Name System (DNS) entries and your hosts must have the correct information.
    The <code class="docutils literal"><span class="pre">hostname</span></code> command and the configuration file <code class="docutils literal"><span class="pre">/etc/hostname</span></code> must
    reflect the fully-qualified domain name (FQDN) of the machine.
    The configuration file <code class="docutils literal"><span class="pre">/etc/hosts</span></code> must include an entry with the FQDN, to
    allow reverse-DNS lookups to be performed.</p>
    <p>To allow clients to authenticate against Anaconda Repository, create a
    principal for the service with a private key that identifies the service.
    Create a service principal <code class="docutils literal"><span class="pre">HTTP/your.anaconda.server</span></code>, and create the keytab
    containing this principal to <code class="docutils literal"><span class="pre">/etc/binstar/http.keytab</span></code>:</p>
    <div class="highlight-bash"><div class="highlight"><pre><span></span><span class="nv">SERVER_NAME</span><span class="o">=</span>your.anaconda.server
    </pre></div>
    </div>
    <p>If you are using MIT Kerberos:</p>
    <div class="highlight-bash"><div class="highlight"><pre><span></span>kadmin -q <span class="s2">&quot;addprinc HTTP/</span><span class="si">${</span><span class="nv">SERVER_NAME</span><span class="si">}</span><span class="s2">&quot;</span>
    kadmin -q <span class="s2">&quot;ktadd -k /etc/binstar/http.keytab HTTP/</span><span class="si">${</span><span class="nv">SERVER_NAME</span><span class="si">}</span><span class="s2">&quot;</span>
    chown binstar:binstar /etc/binstar/http.keytab
    chmod <span class="m">600</span> /etc/binstar/http.keytab
    </pre></div>
    </div>
    <p>If you are using Active Directory:</p>
    <ul class="simple">
    <li>Open <strong>Active Directory Users and Computers</strong></li>
    <li>Select the <strong>Users</strong> container</li>
    <li>Select the menu item <strong>Action</strong> &gt; <strong>New</strong> &gt; <strong>User</strong></li>
    <li>In the <strong>New Object - User</strong> dialog, fill in the user information. In this
    example, we use <code class="docutils literal"><span class="pre">your-anaconda-server</span></code> as the login.</li>
    <li>In the next dialog, select the options <strong>Password never expires</strong> and
    <strong>User cannot change password</strong></li>
    <li>Right-click on the newly created user, and select <strong>Properties</strong></li>
    <li>In the <strong>Properties</strong> dialog, select the <strong>Account</strong> tab, and ensure the
    <strong>Do not require Kerberos preauthentication</strong> option is selected</li>
    <li>Open an <em>Administrative</em> prompt and run:</li>
    </ul>
    <div class="highlight-bash"><div class="highlight"><pre><span></span>ktpass -princ HTTP/your.anaconda.server@YOUR.DOMAIN -out http.keytab -pass <span class="s2">&quot;*&quot;</span> -mapUser your-anaconda-server -ptype KRB5_NT_PRINCIPAL
    </pre></div>
    </div>
    <ul class="simple">
    <li>Copy the newly created file <code class="docutils literal"><span class="pre">http.keytab</span></code> to <code class="docutils literal"><span class="pre">/etc/binstar/http.keytab</span></code> on
    your Anaconda Repository server.</li>
    </ul>
    <p>To enable Kerberos authentication on Anaconda Repository, add the configuration
    options to <code class="docutils literal"><span class="pre">/etc/binstar/config.yaml</span></code>:</p>
    <div class="highlight-yaml"><div class="highlight"><pre><span></span><span class="l l-Scalar l-Scalar-Plain">AUTH_TYPE</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">KERBEROS</span>
    <span class="l l-Scalar l-Scalar-Plain">KRB5_KTNAME</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">/etc/binstar/http.keytab</span>
    </pre></div>
    </div>
    <p>To diagnose possible issues, enable logging for
    the Kerberos authentication component. To enable logging, modify the <code class="docutils literal"><span class="pre">LOGGING</span></code> stanza
    in <code class="docutils literal"><span class="pre">/etc/binstar/config.yaml</span></code> to include:</p>
    <div class="highlight-yaml"><div class="highlight"><pre><span></span><span class="l l-Scalar l-Scalar-Plain">LOGGING</span><span class="p p-Indicator">:</span>
      <span class="c1"># ...</span>
      <span class="l l-Scalar l-Scalar-Plain">loggers</span><span class="p p-Indicator">:</span>
        <span class="c1"># ...</span>
        <span class="l l-Scalar l-Scalar-Plain">flask_kerberos_login</span><span class="p p-Indicator">:</span>
          <span class="l l-Scalar l-Scalar-Plain">handlers</span><span class="p p-Indicator">:</span>
          <span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">console</span>
          <span class="l l-Scalar l-Scalar-Plain">level</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">INFO</span>
          <span class="l l-Scalar l-Scalar-Plain">propagate</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">true</span>
    </pre></div>
    </div>
    <div class="section" id="kerberos-configuration-options">
    <span id="id2"></span><h3>Kerberos Configuration Options<a class="headerlink" href="#kerberos-configuration-options" title="Permalink to this headline">¶</a></h3>
    <dl class="docutils">
    <dt><code class="docutils literal"><span class="pre">AUTH_TYPE</span></code></dt>
     <span class="classifier-delimiter">:</span> <span class="classifier">string</span><dd>Configures the authentication scheme used for Anaconda Repository.
    Set to <code class="docutils literal"><span class="pre">KERBEROS</span></code> to enable Kerberos authentication. Default: <code class="docutils literal"><span class="pre">NATIVE</span></code>.</dd>
    <dt><code class="docutils literal"><span class="pre">KRB5_KTNAME</span></code></dt>
     <span class="classifier-delimiter">:</span> <span class="classifier">string</span><dd>The file path of the keytab containing the service principal for Anaconda
    Repository. Default: <code class="docutils literal"><span class="pre">/etc/krb5.keytab</span></code>.</dd>
    <dt><code class="docutils literal"><span class="pre">KRB5_SERVICE_NAME</span></code></dt>
     <span class="classifier-delimiter">:</span> <span class="classifier">string</span><dd>The service type used to identify the service principal for Anaconda
    Repository. <em>HTTP</em> in <code class="docutils literal"><span class="pre">HTTP/your.anaconda.server&#64;YOUR.REALM</span></code>.
    Default: <code class="docutils literal"><span class="pre">HTTP</span></code>.</dd>
    <dt><code class="docutils literal"><span class="pre">KRB5_HOSTNAME</span></code></dt>
     <span class="classifier-delimiter">:</span> <span class="classifier">string</span><dd>The hostname used to identify the service principal for Anaconda
    Repository. <em>your.anaconda.server</em> in <code class="docutils literal"><span class="pre">HTTP/your.anaconda.server&#64;YOUR.REALM</span></code>.
    Default: the hostname of the machine on which Anaconda Repository is running.</dd>
    </dl>
    </div>
    </div>
