Advanced Installation Options (AER 2.31)

Enable HTTPS

Before you start:

Purchase an SSL certificate and download the ssl *.cert file and ssl *.key file.

NOTE: If security is not an issue, for testing you may set up a self-signed SSL certificate. See http://www.selfsignedcertificate.com/ .

Save the ssl *.cert file and an ssl *.key file in your home directory.

Configure the server to use those keys and the correct ports:

anaconda-server-config --set ssl_options.keyfile ~/localhost.key
anaconda-server-config --set ssl_options.certfile ~/localhost.cert
anaconda-server-config --set port 8443

Restart your server for the changes to take effect:

supervisorctl restart all

To test, navigate to the site using https in the address bar.

NOTE: If you use a self-signed SSL certificate, your web browser will issue a warning that the website certificate cannot be verified.

Email and SMTP

To send emails such as password reset emails, Anaconda Repository must have the email settings configured.

Using Standard Ports

HTTP

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:

sudo iptables -t nat -F
sudo iptables -t nat -A OUTPUT -d localhost -p tcp --dport 80 -j REDIRECT --to-ports 8080
sudo iptables -t nat -I PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080

HTTPS

To use HTTPS, redirect traffic from standard HTTPS port 443 to standard Anaconda Repository HTTPS port 8443:

sudo iptables -t nat -A OUTPUT -d localhost -p tcp --dport 443 -j REDIRECT --to-ports 8443
sudo iptables -t nat -I PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 8443

NOTE: See also “Enable HTTPS” above.

Adjust IPTables to accept requests on port 80

Enable clients to access an Anaconda Repository on standard ports by configuring the server to redirect traffic received on standard HTTP port 80 to the standard Anaconda Repository HTTP port 8080.

NOTE: These commands assume the default state of IPTables which is “on” and allowing inbound SSH access on port 22. This is the factory default state for CentOS 6.7. If this default has been changed you can reset it as follows:

sudo iptables -L

CAUTION: Mistakes with IPTables rules can render a remote machine inaccessible.

  1. Allow inbound access to tcp port 80:

    sudo iptables -I INPUT -i eth0 -p tcp --dport 80 -m comment --comment "# Anaconda Repo #" -j ACCEPT
    
  2. Allow inbound access to tcp port 8080:

    sudo iptables -I INPUT -i eth0 -p tcp --dport 8080 -m comment --comment "# Anaconda Repo #" -j ACCEPT
    
  3. Redirect inbound requests to port 80 to port 8080:

    sudo iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -m comment --comment "# Anaconda Repo #" -j REDIRECT --to-port 8080
    
  4. Display the current iptables rules:

    iptables -L -n
    Chain INPUT (policy ACCEPT)
    target     prot opt source               destination
    ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:8080 /* # Anaconda Repo # */
    ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:80 /* # Anaconda Repo # */
    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           state RELATED,ESTABLISHED
    ACCEPT     icmp --  0.0.0.0/0            0.0.0.0/0
    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0
    ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:22
    REJECT     all  --  0.0.0.0/0            0.0.0.0/0           reject-with icmp-host-prohibited
    
    Chain FORWARD (policy ACCEPT)
    target     prot opt source               destination
    REJECT     all  --  0.0.0.0/0            0.0.0.0/0           reject-with icmp-host-prohibited
    
    Chain OUTPUT (policy ACCEPT)
    target     prot opt source               destination
    

NOTE: the PREROUTING (nat) IPTables chain is not displayed by default. To show it, use:

iptables -L -n -t nat
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
REDIRECT   tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:80 /* # Anaconda Repo # */ redir ports 8080

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
  1. Save the running iptables configuration to /etc/sysconfig/iptables:

    sudo service iptables save
    

Connect to an Existing MongoDB Database

If you already have a mongodb server running, you can connect to it by setting the MONGO_URL config variable:

anaconda-server-config --set MONGO_URL 'mongodb://<hostname>'

NOTE: For more information, see the MongoDB Connection String URI Format manual.

Configure MongoDB authentication

By default, MongoDB does not require a username or password to access or modify the database. We recommend enabling and configuring mandatory authentication.

To do so, open a MongoDB shell:

mongo

Anaconda Repository requires read/write access to the database binstar. Enter the following commands into the MongoDB shell to create an administrative user and a service user:

use admin

Create an administrative user to manage database users:

db.createUser({user:'siteUserAdmin', pwd: '<secure password #1>', roles:['userAdminAnyDatabase']})

Authorize as that user to verify the password:

db.auth('siteUserAdmin', '<secure password #1>')

Create a service user for Anaconda Repository:

db.createUser({user:'anaconda', pwd: '<secure password #2>', roles:[{db:'binstar', role:'readWrite'}]})

Enable mandatory authentication in MongoDB and restart for the configuration to take effect. If you are using the legacy MongoDB configuration format, add the auth key to /etc/mongod.conf:

auth=true

Otherwise, if you are using the current MongoDB configuration format, add the security.authorization key to /etc/mongod.conf:

security:
    authorization: enabled

Finally, restart MongoDB to reload the configuration:

sudo service mongod restart

For additional information about MongoDB authentication and authorization see https://docs.mongodb.com/v2.6/core/authentication/ and https://docs.mongodb.com/v2.6/core/authorization/

Whitelist or Blacklist certain packages

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.

A mirror config file can be specified when you run anaconda-server-sync-conda with the flag --mirror-config=FILEPATH and replace FILEPATH with the path to your config file.

To customize your distribution, you have the following options:

  • remote_url: Anaconda Enterprise Repository mirrors packages from this source URL.
  • mirror_dir: AE Repository stores packages in this directory on the machine where the script is executed.
  • platforms: AE Repository mirrors packages for these platforms.
  • license_blacklist: AE Repository omits packages with these licenses.
  • blacklist: AE Repository omits these packages.
  • whitelist: AE Repository always mirrors these packages.

NOTE: Configuration files are yaml files.

A fully working example can look like this:

mirror_dir: /opt/anaconda-server/package-storage
platforms:
  - linux-32
  - linux-64
license_blacklist: GPL
whitelist:
  - distribute
  - conda
blacklist:
  - flask
  - readline

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).

From the ultimate list of packages that are mirrored, the tool:

  • Removes all packages that are under the GPL license so that every license except GPL is allowed
  • Removes any packages that are explicitly mentioned in the ‘blacklist’ option, regardless of the platform or license-type
  • Adds packages explicitly mentioned in the ‘whitelist’ option to the list of packages that are mirrored

NOTE: Currently GPL licenses are the only license type that can be license_blacklisted.

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 ‘blacklist’ option.

REMEMBER: You do not need 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.

The step-by-step algorithm that is used by the cas-mirror to create the ultimate list of packages to mirror follows this procedure:

  1. Get a full list of packages from default_url.
  2. If the platforms option is present, only those packages available to the platforms listed here are left on the list.
  3. If license_blacklist is present, then all the packages subject to any of the licenses mentioned here are removed from the list.
  4. If blacklist is present then all member packages explicitly mentioned here are removed from the list.
  5. If whitelist is present then those assigned member packages are added to the list.

After performing all of the above actions sequentially, the script produces the ultimate list of packages that are mirrored in the next step.

Securing User-created Content

To prevent cross-site scripting attacks (XSS), user content (such as Jupyter notebooks) can be served from a separate domain.

To enable this, configure the project to use a separate content domain:

anaconda-server-config --set SERVER_NAME your.anaconda.server
anaconda-server-config --set USER_CONTENT_DOMAIN your.usercontent.server

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:

anaconda-server-config --set SERVER_NAME your.anaconda.server
anaconda-server-config --set USER_CONTENT_DOMAIN usercontent.your.anaconda.server
anaconda-server-config --set SESSION_COOKIE_DOMAIN your.anaconda.server

Configure Anaconda Repository to use LDAP

Open the Anaconda Repository configuration file $PREFIX/etc/anaconda-server/config.yaml and add the following configuration to enable Lightweight Directory Access Protocol (LDAP) support:

LDAP: {
  # Replace with company LDAP server
  'URI': 'ldap://<ldap.company.com>',

  # Replace <uid=%(username)s,ou=People,dc=company,dc=com> with your company specific LDAP Bind/Base DN
  # Bind directly to this Base DN.
  'BIND_DN': '<uid=%(username)s,ou=People,dc=company,dc=com>',

  # Map ldap keys into application specific keys
  'KEY_MAP': {
      'name':'cn',
      'company': 'o',
      'location':'l',
      'email': 'mail',
    },
}

Update the URI with the location of your LDAP server and BIND_DN with the values specific to your LDAP server. Change the KEY_MAP keys with the associated values for your LDAP server.

When switching authentication to LDAP the admin account is lost, so you need to add your admin account again:

anaconda-server-admin set-superuser "jsmith"

Run the flask-ldap-login-check command to verify LDAP connectivity:

flask-ldap-login-check binstar.wsgi:app --username 'jsmith' --password 'abc123DEF'

NOTE: Replace jsmith and abc123DEF with your actual LDAP username and password.

To apply the changes, restart the Anaconda Repository server:

supervisorctl restart all

Open a new browser window and navigate to your local Anaconda Repository installation:

http://your.anaconda.server

NOTE: Replace “your.anaconda.server” with your actual Anaconda Repository server IP address or domain name.

You can now log in using your LDAP credentials.

You may set an LDAP network timeout in seconds with the options OPT_NETWORK_TIMEOUT and OPT_TIMEOUT. The default value is 0, meaning no timeout. For example, to set the timeout to 60 seconds, add this block to the LDAP settings in your configuration file:

OPTIONS:
    OPT_NETWORK_TIMEOUT: 60
    OPT_TIMEOUT: 60

Configure Anaconda Repository to use Active Directory

Microsoft Active Directory is a server program that provides directory services and uses the open industry standard Lightweight Directory Access Protocol (LDAP).

Open the Anaconda Repository configuration file $PREFIX/etc/anaconda-server/config.yaml and add the following configuration to enable Active Directory support:

LDAP : {
    'URI': 'ldap://<ldap.server.url>',

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

    # The values '' perform an anonymous bind so we may use search/bind method
    'BIND_DN': '',
    'BIND_AUTH': '',

    # Adding the USER_SEARCH field tells the flask-ldap-login that we
    # are using the search/bind method
    'USER_SEARCH': {'base': '<cn=users,dc=company,dc=local>', 'filter': 'sAMAccountName=%(username)s'},

    # Map ldap keys into application specific keys
    'KEY_MAP': {
        'name':'cn',
        'company': 'o',
        'location':'l',
        'email': 'userPrincipalName',
        },
}

Update the URI <ldap.server.url> with the location of your Active Directory server, BIND_DN with the values specific to your Active Directory server and the BIND_AUTH with the password of the user specified in the BIND_DN. Change the KEY_MAP keys with the associated values from your Active Directory server.

To apply the changes, restart the Anaconda Repository server:

supervisorctl restart all

Run the flask-ldap-login-check command to verify Active Directory connectivity:

flask-ldap-login-check binstar.wsgi:app --username 'jsmith' --password 'abc123DEF'

NOTE: Replace jsmith and abc123DEF with your actual Active Directory username and password.

You will see a response similar to the following:

[anaconda.server] Started Site
Got userdata for jsmith
{'company': None, 'email': None, 'location': None, 'name': 'Jane Smith'}

Open your browser and navigate to your local Anaconda Repository installation:

http://your.anaconda.server

NOTE: Replace “your.anaconda.server” with your actual Anaconda Repository IP address or domain name.

You can now log in with Active Directory.

Configuring Anaconda Repository to use LDAP groups

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.

In order to enable this, the following configuration is required:

  • authenticated bind to LDAP (Anaconda Repository needs to perform searches against the directory to determine the available groups, and the membership of those groups)
  • a query for Anaconda Repository to identify the groups in your LDAP directory (see GROUP_SEARCH)

If LDAP synchronization is disabled or the LDAP server is unreachable, the member list at the time is used for the group.

In order to administer and debug LDAP synchronization, a superuser can visit:

http://your.anaconda.server/admin/ldap

Enable TLS on LDAP/Active Directory

Microsoft Active Directory is a server program that provides directory services and uses the open industry standard Lightweight Directory Access Protocol (LDAP).

To enable a secure Transport Layer Security (TLS) connection, add the following to the LDAP configuration section of the file $PREFIX/etc/anaconda-server/config.yaml:

LDAP={  ....

  'START_TLS': True,
  'OPTIONS': { 'OPT_PROTOCOL_VERSION': 3,
               'OPT_X_TLS_DEMAND': True,
               'OPT_X_TLS_REQUIRE_CERT': 'OPT_X_TLS_NEVER',
               'OPT_X_TLS_CACERTFILE': '/path/to/certfile')
              }
    ....
}

LDAP and TLS Configuration Options

URI

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.

BIND_DN

The distinguished name to use when binding to the LDAP server (with BIND_AUTH). Use the empty string (the default) for an anonymous bind.

BIND_AUTH

The password to use with BIND_DN.

ENABLE_GROUPS

Whether to enable LDAP group synchronization, allowing users to synchronize group membership with an LDAP directory. Defaults to false.

For example:

ENABLE_GROUPS: true

GROUP_MEMBERS_ATTR

The LDAP attribute on a group object that indicates the users that are members of the group. Defaults to member.

For example:

GROUP_MEMBERS_ATTR: 'member'

REFRESH_INTERVAL

The number of seconds that group membership information from LDAP is used before being fetched from the directory server again. Defaults to 3600 (1 hour).

For example:

REFRESH_INTERVAL: 600

KEY_MAP

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:

'application_key': 'ldap_key'

For example:

KEY_MAP={'name': 'cn', 'company': 'o', 'email': 'mail'}

START_TLS

If True, each connection to the LDAP server will call start_tls_s() to enable TLS encryption over the standard LDAP port. There are a number of configuration options that can be given to OPTIONS that affect the TLS connection. For example, OPT_X_TLS_REQUIRE_CERT can be set to OPT_X_TLS_NEVER to disable certificate verification, perhaps to allow self-signed certificates.

OPTIONS

This stores LDAP specific options. For example:

LDAP:
    OPTIONS:
        OPT_PROTOCOL_VERSION: 3
        OPT_X_TLS_REQUIRE_CERT: 'OPT_X_TLS_NEVER'

TLS (secure LDAP)

To enable a secure TLS connection you must set START_TLS to True. There are a number of configuration options that can be given to OPTIONS that affect the TLS connection. For example, OPT_X_TLS_REQUIRE_CERT OPT_X_TLS_NEVER disables certificate verification, perhaps to allow self-signed certificates.

LDAP:
    START_TLS: true
    OPTIONS:
        OPT_PROTOCOL_VERSION: 3
        OPT_X_TLS_DEMAND: true
        OPT_X_TLS_REQUIRE_CERT: 'OPT_X_TLS_NEVER'
        OPT_X_TLS_CACERTFILE: '/path/to/certfile'

Configure Anaconda Repository to use Kerberos

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.

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.

Several aspects of Kerberos rely on name service. Your Domain Name System (DNS) entries and your hosts must have the correct information. The hostname command and the configuration file /etc/hostname must reflect the fully-qualified domain name (FQDN) of the machine. The configuration file /etc/hosts must include an entry with the FQDN, to allow reverse-DNS lookups to be performed.

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 HTTP/your.anaconda.server, and create the keytab containing this principal to $PREFIX/etc/anaconda-server/http.keytab:

SERVER_NAME=your.anaconda.server

If you are using MIT Kerberos:

kadmin -q "addprinc HTTP/${SERVER_NAME}"
kadmin -q "ktadd -k $PREFIX/etc/anaconda-server/http.keytab HTTP/${SERVER_NAME}"
chown anaconda-server:anaconda-server $PREFIX/etc/anaconda-server/http.keytab
chmod 600 $PREFIX/etc/anaconda-server/http.keytab

If you are using Active Directory:

  • Open Active Directory Users and Computers
  • Select the Users container
  • Select the menu item Action > New > User
  • In the New Object - User dialog, fill in the user information. In this example, we use your-anaconda-server as the login.
  • In the next dialog, select the options Password never expires and User cannot change password
  • Right-click on the newly created user, and select Properties
  • In the Properties dialog, select the Account tab, and ensure the Do not require Kerberos preauthentication option is selected
  • Open an Administrative prompt and run:
ktpass -princ HTTP/your.anaconda.server@YOUR.DOMAIN -out http.keytab -pass "*" -mapUser your-anaconda-server -ptype KRB5_NT_PRINCIPAL
  • Copy the newly created file http.keytab to $PREFIX/etc/anaconda-server/http.keytab on your Anaconda Repository server.

To enable Kerberos authentication on Anaconda Repository, add the configuration options to $PREFIX/etc/anaconda-server/config.yaml:

AUTH_TYPE: KERBEROS
KRB5_KTNAME: /home/anaconda-server/repo/etc/anaconda-server/http.keytab

Kerberos Configuration Options

AUTH_TYPE
: string
Configures the authentication scheme used for Anaconda Repository. Set to KERBEROS to enable Kerberos authentication. Default: NATIVE.
KRB5_KTNAME
: string
The file path of the keytab containing the service principal for Anaconda Repository. Default: /etc/krb5.keytab.
KRB5_SERVICE_NAME
: string
The service type used to identify the service principal for Anaconda Repository. HTTP in HTTP/your.anaconda.server@YOUR.REALM. Default: HTTP.
KRB5_HOSTNAME
: string
The hostname used to identify the service principal for Anaconda Repository. your.anaconda.server in HTTP/your.anaconda.server@YOUR.REALM. Default: the hostname of the machine on which Anaconda Repository is running.

Checking for Orphan Files or Packages

Certain errors may push the filesystem and the database out of sync.

This can be caused by files in the filesystem that are not referenced from the database, or by packages in the database that do not have a corresponding file in the filesystem.

You can use the “orphan-check” tool to resynchronize the filesystem and the database.

By default it will print on stdout a list of files on the filesystem that aren’t referenced from the database:

anaconda-server-orphan-check --dryrun

NOTE: You can use the –json option to get a JSON representation of the output.

Running anaconda-server-orphan-check with no arguments is the same as running anaconda-server-orphan-check --dryrun.

Once you’ve viewed the list of files without references, “orphan-check” can delete them:

anaconda-server-orphan-check --clean

You can also check for packages that have missing files:

anaconda-server-orphan-check --reverse

Then you can delete those file objects from the database:

anaconda-server-orphan-check --reverse --clean

Checking the checksum of a file

To help ensure that a file was correctly uploaded or synced you can use the checksum tool. This will fetch a file from a database and check that the stored hash checksum and the calculated hash checksum of the file on disk are the same.

On a package’s page, view the file list and click the Info button next to a file to see the file’s keyname.

To check the file’s hash checksum run:

anaconda-server-checksum keyname

NOTE: Replace “keyname” with the file’s keyname.

The output will be either Hashes are the same or Hashes differ.

To overwrite the old hash checksum in the database with the new hash checksum you calculated, use the option --fix.