Install instruction for the Enterprise Edition of the Psono server

Preamble

At this point we assume that you already have a postgres database running, ready for connections. If not follow this guide to setup postgres.

Installation with Docker

  1. Create a settings.yaml in e.g. /opt/docker/psono/ with the following content

    # generate the following six parameters with the following command
    # docker run --rm -ti psono/psono-server-enterprise:latest python3 ./psono/manage.py generateserverkeys
    SECRET_KEY: 'SOME SUPER SECRET KEY THAT SHOULD BE RANDOM AND 32 OR MORE DIGITS LONG'
    ACTIVATION_LINK_SECRET: 'SOME SUPER SECRET ACTIVATION LINK SECRET THAT SHOULD BE RANDOM AND 32 OR MORE DIGITS LONG'
    DB_SECRET: 'SOME SUPER SECRET DB SECRET THAT SHOULD BE RANDOM AND 32 OR MORE DIGITS LONG'
    EMAIL_SECRET_SALT: '$2b$12$XUG.sKxC2jmkUvWQjg53.e'
    PRIVATE_KEY: '302650c3c82f7111c2e8ceb660d32173cdc8c3d7717f1d4f982aad5234648fcb'
    PUBLIC_KEY: '02da2ad857321d701d754a7e60d0a147cdbc400ff4465e1f57bc2d9fbfeddf0b'
    
    # The URL of the web client (path to e.g activate.html without the trailing slash)
    # WEB_CLIENT_URL: 'https://www.psono.pw'
    
    # Switch DEBUG to false if you go into production
    DEBUG: False
    
    # Adjust this according to Django Documentation https://docs.djangoproject.com/en/1.10/ref/settings/
    ALLOWED_HOSTS: ['*']
    
    # Should be your domain without "www.". Will be the last part of the username
    ALLOWED_DOMAINS: ['psono.pw']
    
    # If you want to disable registration, you can comment in the following line
    # ALLOW_REGISTRATION: False
    
    # If you want to restrict registration to some email addresses you can specify here a list of domains to filter
    # REGISTRATION_EMAIL_FILTER: ['company1.com', 'company2.com']
    
    # Should be the URL of the host under which the host is reachable
    # If you open the url you should have a text similar to {"detail":"Authentication credentials were not provided."}
    HOST_URL: 'https://www.psono.pw/server'
    
    # The email used to send emails, e.g. for activation
    EMAIL_FROM: '[email protected]'
    EMAIL_HOST: 'localhost'
    EMAIL_HOST_USER: ''
    EMAIL_HOST_PASSWORD : ''
    EMAIL_PORT: 25
    EMAIL_SUBJECT_PREFIX: ''
    EMAIL_USE_TLS: False
    EMAIL_USE_SSL: False
    EMAIL_SSL_CERTFILE:
    EMAIL_SSL_KEYFILE:
    EMAIL_TIMEOUT:
    
    # In case one wants to use mailgun, comment in below lines and provide the mailgun access key and server name
    # EMAIL_BACKEND: 'django_mailgun.MailgunBackend'
    # MAILGUN_ACCESS_KEY: ''
    # MAILGUN_SERVER_NAME: ''
    
    # In case you want to offer Yubikey support, create a pair of credentials here https://upgrade.yubico.com/getapikey/
    # and update the following two lines before commenting them in
    # YUBIKEY_CLIENT_ID: '123456'
    # YUBIKEY_SECRET_KEY: '8I65IA6ASDFIUHGIH5021FKJA='
    
    # If you have own Yubico servers, you can specify here the urls as a list
    # YUBICO_API_URLS: ['https://api.yubico.com/wsapi/2.0/verify']
    
    # Cache enabled without belows Redis may lead to unexpected behaviour
    
    # Cache with Redis
    # By default you should use something different than database 0 or 1, e.g. 13 (default max is 16, can be configured in
    # redis.conf) possible URLS are:
    #    redis://[:password]@localhost:6379/0
    #    rediss://[:password]@localhost:6379/0
    #    unix://[:password]@/path/to/socket.sock?db=0
    # CACHE_ENABLE: False
    # CACHE_REDIS: False
    # CACHE_REDIS_LOCATION: 'redis://127.0.0.1:6379/13'
    
    # Disables Throttling (necessary for unittests to pass) by overriding the cache with a dummy cache
    # https://docs.djangoproject.com/en/1.11/topics/cache/#dummy-caching-for-development
    # THROTTLING: False
    
    # The server will automatically connect to the license server to get a license for 10 users.
    # For paying customers we offer the opportunity to get an offline license code.
    #
    # LICENSE_CODE: |
    #   0abcdefg...
    #   1abcdefg...
    #   2abcdefg...
    #   3abcdefg...
    #   4abcdefg...
    #   5abcdefg...
    #   6abcdefg...
    #   7abcdefg...
    #   8abcdefg...
    
    # Enables the management API, required for the psono-admin-client / admin portal
    # MANAGEMENT_ENABLED: False
    
    # Allows that users can search for partial usernames
    # ALLOW_USER_SEARCH_BY_USERNAME_PARTIAL: True
    
    # Allows that users can search for email addresses too
    # ALLOW_USER_SEARCH_BY_EMAIL: True
    
    # Allows admins to limit the offered second factors in the client
    # ALLOWED_SECOND_FACTORS: ['yubikey_otp', 'google_authenticator', 'duo']
    
    # Enforce the user to setup a second factor
    # COMPLIANCE_ENFORCE_2FA: True
    
    # Only necessary if the psono-client runs on a sub path (no trailing slash) e.g. "https://wwww.psono.pw"
    # WEB_CLIENT_URL: ''
    
    # Prevents the use of the last X passwords. 0 disables it.
    # DISABLE_LAST_PASSWORDS: 0
    
    # If you want to use LDAP, then you can configure it like this
    #
    # 		LDAP_URL: Any valid LDAP string, preferable with ldaps. usual urls are 'ldaps://example.com:636' or 'ldap://192.168.0.1:389'
    #		LDAP_DOMAIN: Your LDAP domain, is added at the end of the username to form the full username
    #		LDAP_BIND_DN: One User that can be used to search your LDAP
    #		LDAP_BIND_PASS: The password of the user specified in LDAP_BIND_DN
    #		LDAP_ATTR_GUID: The uuid attribute. e.g. on Windows 'objectGUID', but common are 'GUID' or 'entryUUID', default 'objectGUID'
    #		LDAP_OBJECT_CLASS_USER: The objectClass value to filter user objects e.g. on Windows 'user', default 'user'
    #		LDAP_OBJECT_CLASS_GROUP: The objectClass value to filter group objects e.g. on Windows 'group', default 'group'
    #		LDAP_SEARCH_USER_DN: The "root" from which downwards we search for the users
    #		LDAP_SEARCH_GROUP_DN: The "root" from which downwards we search for the groups
    #		LDAP_ATTR_USERNAME: The username attribute to try to match against. e.g. on Windows 'sAMAccountName', default 'sAMAccountName'
    #		LDAP_ATTR_EMAIL: The attribute of the user objects that holds the mail address e.g. on Windows 'mail', default 'mail'
    #		LDAP_ATTR_GROUPS: The attribute of the user objects that holds the groups e.g. on Windows 'memberOf', default 'memberOf'
    #		LDAP_CA_CERT_FILE: If you want to use ldaps and don't have a publicly trusted and signed certificate you can specify here the path to your ca certificate
    #
    # On Windows it could look like this:
    #
    # LDAP : [
    #     {
    #         'LDAP_URL': 'ldaps://192.168.0.1:636',
    #         'LDAP_DOMAIN': 'example.com',
    #         'LDAP_BIND_DN': 'CN=LDAPPsono,OU=UsersTech,OU=example.com,DC=example,DC=com',
    #         'LDAP_BIND_PASS': 'hopefully_not_123456',
    #         'LDAP_SEARCH_USER_DN': 'OU=Users,OU=example.com,DC=example,DC=com',
    #         'LDAP_SEARCH_GROUP_DN': 'OU=Groups,OU=example.com,DC=example,DC=com',
    #     },
    # ]
    # 
    # To help you setup LDAP, we have created a small "testldap" command that should make things alot easier. You can execute it like:
    # python3 psono/manage.py testldap [email protected] thePassWord
    
    # You also have to comment in the line below if you want to use LDAP (default: ['AUTHKEY'])
    # AUTHENTICATION_METHODS: ['AUTHKEY', 'LDAP']
    
    # Enable Audit logging
    # LOGGING_AUDIT: True
    
    # To log to another destination you can specify this here, default '/var/log/psono'
    # Never really necessary, as we will run the psono server in a docker container and can mount /var/log/psono to any
    # location on the underlying docker host.
    # LOGGING_AUDIT_FOLDER: '/var/log/psono'
    
    # If you prefer server time over utc, you can do that like below (default 'time_utc')
    # LOGGING_AUDIT_TIME: 'time_server'
    
    # If the server logs too much for you can either whitelist or blacklist events by their event code. (default: [])
    # LOGGING_AUDIT_WHITELIST: []
    # LOGGING_AUDIT_BLACKLIST: []
    
    # Your Postgres Database credentials
    DATABASES:
        default:
            'ENGINE': 'django.db.backends.postgresql_psycopg2'
            'NAME': 'psono'
            'USER': 'psono'
            'PASSWORD': 'password'
            'HOST': 'localhost'
            'PORT': '5432'
    # for master / slave replication setup comment in the following (all reads will be redirected to the slave
    #    slave:
    #        'ENGINE': 'django.db.backends.postgresql_psycopg2'
    #        'NAME': 'YourPostgresDatabase'
    #        'USER': 'YourPostgresUser'
    #        'PASSWORD': 'YourPostgresPassword'
    #        'HOST': 'YourPostgresHost'
    #        'PORT': 'YourPostgresPort'
    
    # The path to the template folder can be "shadowed" if required later
    TEMPLATES: [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': ['/root/psono/templates'],
            'APP_DIRS': True,
            'OPTIONS': {
                'context_processors': [
                    'django.template.context_processors.debug',
                    'django.template.context_processors.request',
                    'django.contrib.auth.context_processors.auth',
                    'django.contrib.messages.context_processors.messages',
                ],
            },
        },
    ]
    
  2. Create the local logging directory for the audit logs

    sudo mkdir -p /var/log/psono
    
  3. Test E-Mail

    The most tedious step is usually for me to get e-mail working. To make this step easier, we offer a small test script which will send a test e-mail.

    To send a test e-mail to [email protected] execute:

    docker run --rm \
      -v /path/to/modified/settings.yaml:/root/.psono_server/settings.yaml \
      -ti psono/psono-server-enterprise:latest python3 ./psono/manage.py sendtestmail [email protected]
    

    If you receive this test e-mail, e-mail should be configured proper.

  4. Prepare the database

    docker run --rm \
      -v /path/to/modified/settings.yaml:/root/.psono_server/settings.yaml \
      -ti psono/psono-server-enterprise:latest python3 ./psono/manage.py migrate
    
  5. Run the dockered psono server image and expose the server port

    docker run --name psono-server-enterprise \
        --sysctl net.core.somaxconn=65535 \
        -v /path/to/modified/settings.yaml:/root/.psono_server/settings.yaml \
        -v /path/to/log/folder:/var/log/psono \
        -d --restart=unless-stopped -p 10100:80 psono/psono-server-enterprise:latest
    

    This will start the Psono server on port 10100. If you open now http://your-ip:10100 you should see something like this:

    {"detail":"Authentication credentials were not provided."}
    

    If not, please make sure you have no firewall on the server blocking you.

  6. Setup cleanup job

    Execute the following command:

    crontab -e
    

    and add the following line:

    30 2 * * * docker run --rm -v /path/to/modified/settings.yaml:/root/.psono_server/settings.yaml -ti psono/psono-server-enterprise:latest python3 ./psono/manage.py cleartoken >> /var/log/cron.log 2>&1
    
  7. Setup Reverse Proxy

    To run the Psono password manager in production, a reverse proxy is needed, to handle the ssl offloading and glue the psono server and webclient together. Follow the guide to setup reverse proxy as a next step.

Note: Installation behind Firewall

If you have put your installation behind a firewall, you have to whitelist some ports / adjust some settings, that all features work:

  • Outgoing TCP / UDP 123 connection to time.google.com: Psono requires a synced time for various reasons (Google Authenticator, YubiKey, Throttling, Replay protection, …) Therefore it has a healthcheck, to compare the local time to a time server (by default time.google.com). You can specify your own timeserver in the settings.yaml with the “TIME_SERVER” parameter.
  • Outgoing TCP 443 connection to api*.yubico.com: Psono validates YubiKey OTP tokens against the official Yubikey Servers. You can use an own YubiKey server with the “YUBICO_API_URLS” parameter in the settings.yaml
  • Outgoing TCP 443 connection to api*.duosecurity.com: Psono initiates connection a to the Duo api server, whenever someone uses Duo’s 2 Factor authentication.
Edit me