Managing Configuration Settings v8

There are multiple configuration files that are read at startup by Postgres Enterprise Manager. These are as follows:

  • config.py: This is the main configuration file, and should not be modified. It can be used as a reference for configuration settings, that may be overridden in one of the following files.
  • config_distro.py: This file is read after config.py and is intended for packagers to change any settings that are required for their Postgres Enterprise Manager distribution. This may typically include certain paths and file locations. This file is optional, and may be created by packagers in the same directory as config.py if needed.
  • config_setup.py: This file is read after config_distro.py and is intended for configuration script to change any settings that are required for their database connection information. This file is optional, and may be created by configuration script in the same directory as config.py if needed.
  • config_local.py: This file is read after config_distro.py and is intended for end users to change any default or packaging specific settings that they may wish to adjust to meet local preferences or standards.This file is optional, and may be created by users in the same directory as config.py if needed.

The default config.py file is shown below for reference:

    # -*- coding: utf-8 -*-

    ##########################################################################
    #
    # Postgres Enterprise Manager
    #
    # Copyright (C) 2013 - 2021, EnterpriseDB Corporation. All rights reserved.
    #
    # Portions of Postgres Enteprise Manager are derived from pgAdmin 4, which is
    # released under the PostgreSQL License.
    # Copyright (C) 2013 - 2020 The pgAdmin Development Team
    #
    # config.py - Core application configuration settings
    #
    ##########################################################################

    # WARNING: config.py file will be overwritten during upgrade.

    # If you want to override the value of any parameter in conf.py file,
    # you must update those entries in the config_local.py file.

    import builtins
    import logging
    import os
    import sys

    # We need to include the root directory in sys.path to ensure that we can
    # find everything we need when running in the standalone runtime.
    root = os.path.dirname(os.path.realpath(__file__))
    if sys.path[0] != root:
        sys.path.insert(0, root)

    from pgadmin.utils import env, IS_WIN, fs_short_path

    ##########################################################################
    # Misc stuff
    ##########################################################################

    # Path to the online help.
    HELP_PATH = '../../../docs/en_US/_build/html/'

    # Languages we support in the UI
    LANGUAGES = {
        'en': 'English',
        # 'zh': 'Chinese (Simplified)',
        # 'de': 'German',
        # 'fr': 'French',
        # 'ko': 'Korean',
        # 'ja': 'Japanese',
        # 'pl': 'Polish',
        # 'ru': 'Russian',
        # 'es': 'Spanish',
    }

    # DO NOT CHANGE UNLESS YOU KNOW WHAT YOU ARE DOING!
    # List of modules to skip when dynamically loading
    MODULE_BLACKLIST = ['test']

    # DO NOT CHANGE UNLESS YOU KNOW WHAT YOU ARE DOING!
    # List of treeview browser nodes to skip when dynamically loading
    NODE_BLACKLIST = []

    # Data directory for storage of config settings etc. This shouldn't normally
    # need to be changed - it's here as various other settings depend on it.
    if IS_WIN:
        # Use the short path on windows
        DATA_DIR = os.path.realpath(
            os.path.join(fs_short_path(env('APPDATA')), "pem")
        )
    else:
        DATA_DIR = os.path.realpath(os.path.expanduser('~/.pem/'))

    # An optional login banner to show security warnings/disclaimers etc. at
    # login and password recovery etc. HTML may be included for basic formatting,
    # For example:
    # LOGIN_BANNER = "<h4>Authorised Users Only!</h4>" \
    #                "Unauthorised use is strictly forbidden."
    LOGIN_BANNER = ""

    ##########################################################################
    # Log settings
    ##########################################################################

    # Debug mode?
    DEBUG = False

    # Application log level - one of:
    #   CRITICAL 50
    #   ERROR    40
    #   WARNING  30
    #   SQL      25
    #   INFO     20
    #   DEBUG    10
    #   NOTSET    0
    CONSOLE_LOG_LEVEL = logging.WARNING
    FILE_LOG_LEVEL = logging.WARNING

    # Log format.
    CONSOLE_LOG_FORMAT = '%(asctime)s: %(levelname)s\t%(name)s:\t%(message)s'
    FILE_LOG_FORMAT = '%(asctime)s: %(levelname)s\t%(name)s:\t%(message)s'

    # Log file name
    LOG_FILE = os.path.join(DATA_DIR, 'pem.log')

    # Log rotation setting
    # Log file will be rotated considering values for LOG_ROTATION_SIZE
    # & LOG_ROTATION_AGE. Rotated file will be named in format
    # - LOG_FILE.Y-m-d_H-M-S
    LOG_ROTATION_SIZE = 10  # In MBs
    LOG_ROTATION_AGE = 1440  # In minutes
    LOG_ROTATION_MAX_LOG_FILES = 90  # Maximum number of backups to retain

    ##########################################################################
    # Server settings
    ##########################################################################

    # This option allows the user to host the application on a LAN
    # Default hosting is on localhost (DEFAULT_SERVER='localhost').
    # To host PEM GUI application over LAN set DEFAULT_SERVER='0.0.0.0'
    # (or a specific adaptor address.
    #
    # NOTE: This is NOT recommended for production use, only for debugging
    # or testing. Production installations should be run as a WSGI application
    # behind Apache HTTPD.
    DEFAULT_SERVER = '127.0.0.1'

    # The default port on which the app server will listen if not set in the
    # environment by the runtime
    DEFAULT_SERVER_PORT = 5050

    # This param is used to validate ALLOWED_HOSTS for the application
    # This will be used to avoid Host Header Injection attack
    # For how to set ALLOWED_HOSTS see netaddr library
    # For more details https://netaddr.readthedocs.io/en/latest/tutorial_03.html
    # e.g. ALLOWED_HOSTS = ['192.0.2.0/28', '::192.0.2.0/124']
    # ALLOWED_HOSTS = ['225.0.0.0/8', '226.0.0.0/7', '228.0.0.0/6']
    # ALLOWED_HOSTS = ['127.0.0.1', '192.168.0.1']
    # if ALLOWED_HOSTS= [] then it will accept all ips (and application will be
    # vulnerable to Host Header Injection attack)
    ALLOWED_HOSTS = []

    # Enable X-Frame-Option protection.
    # Set to one of "SAMEORIGIN", "ALLOW-FROM origin" or "" to disable.
    # Note that "DENY" is NOT supported (and will be silently ignored).
    # See https://tools.ietf.org/html/rfc7034 for more info.
    X_FRAME_OPTIONS = "SAMEORIGIN"

    # The Content-Security-Policy header allows you to restrict how resources
    # such as JavaScript, CSS, or pretty much anything that the browser loads.
    # see https://content-security-policy.com/#source_list for more info
    # e.g. "default-src https: data: 'unsafe-inline' 'unsafe-eval';"
    CONTENT_SECURITY_POLICY = "default-src ws: https: data: blob: " \
                              "'unsafe-inline' 'unsafe-eval';"

    # The Strict-Transport-Security header tells the browser to convert all HTTP
    # requests to HTTPS, preventing man-in-the-middle (MITM) attacks.
    # e.g. 'max-age=31536000; includeSubDomains'
    STRICT_TRANSPORT_SECURITY = "max-age=31536000; includeSubDomains"

    # The X-Content-Type-Options header forces the browser to honor the response
    # content type instead of trying to detect it, which can be abused to
    # generate a cross-site scripting (XSS) attack.
    # e.g. nosniff
    X_CONTENT_TYPE_OPTIONS = "nosniff"

    # The browser will try to prevent reflected XSS attacks by not loading the
    # page if the request contains something that looks like JavaScript and the
    # response contains the same data. e.g. '1; mode=block'
    X_XSS_PROTECTION = "1; mode=block"


    # Hashing algorithm used for password storage
    SECURITY_PASSWORD_HASH = 'pbkdf2_sha512'

    # Reverse Proxy parameters
    # You must tell the middleware how many proxies set each header
    # so it knows what values to trust.
    # See https://tinyurl.com/yyg7r9av
    # for more information.

    # Number of values to trust for X-Forwarded-For
    PROXY_X_FOR_COUNT = 1

    # Number of values to trust for X-Forwarded-Proto.
    PROXY_X_PROTO_COUNT = 1

    # Number of values to trust for X-Forwarded-Host.
    PROXY_X_HOST_COUNT = 0

    # Number of values to trust for X-Forwarded-Port.
    PROXY_X_PORT_COUNT = 1

    # Number of values to trust for X-Forwarded-Prefix.
    PROXY_X_PREFIX_COUNT = 0

    # NOTE: CSRF_SESSION_KEY, SECRET_KEY and SECURITY_PASSWORD_SALT are no
    #       longer part of the main configuration, but are stored in the
    #       configuration databases 'keys' table and are auto-generated.
    WTF_CSRF_HEADERS = ['X-EdbPEM-CSRFToken']

    # Set the cache control max age for static files in flask to 1 year
    SEND_FILE_MAX_AGE_DEFAULT = 31556952

    # This will be added to static urls as url parameter with value as
    # APP_VERSION_INT for cache busting on version upgrade. If the value is set as
    # None or empty string then it will not be added.
    # eg - http:localhost:5050/pgadmin.css?intver=3.13
    APP_VERSION_PARAM = 'ver'

    # Add the internal version param to below extensions only
    APP_VERSION_EXTN = ('.css', '.js', '.html', '.svg', '.png', '.gif', '.ico')

    ##########################################################################
    # Server Connection Driver Settings
    ##########################################################################

    # The default driver used for making connection with PostgreSQL
    PG_DEFAULT_DRIVER = 'psycopg2'

    # Maximum allowed idle time in minutes before which releasing the connection
    # for the particular session. (in minutes)
    MAX_SESSION_IDLE_TIME = 60

    ##########################################################################
    # User account and settings storage
    ##########################################################################

    # The default path to the SQLite database used to store user accounts and
    # settings. This default places the file in the same directory as this
    # config file, but generates an absolute path for use througout the app.
    SQLITE_PATH = env('SQLITE_PATH') or os.path.join(DATA_DIR, 'pem.db')

    # SQLITE_TIMEOUT will define how long to wait before throwing the error -
    # OperationError due to database lock. On slower system, you may need to change
    # this to some higher value.
    # (Default: 500 milliseconds)
    SQLITE_TIMEOUT = 500

    # Allow database connection passwords to be saved if the user chooses.
    # Set to False to disable password saving.
    ALLOW_SAVE_PASSWORD = True

    # Maximum number of history queries stored per user/server/database
    MAX_QUERY_HIST_STORED = 20

    ##########################################################################
    # Server-side session storage path
    #
    # SESSION_DB_PATH (Default: $HOME/.pem7/sessions)
    ##########################################################################
    #
    # We use SQLite for server-side session storage. There will be one
    # SQLite database object per session created.
    #
    # Specify the path used to store your session objects.
    #
    # If the specified directory does not exist, the setup script will create
    # it with permission mode 700 to keep the session database secure.
    #
    # On certain systems, you can use shared memory (tmpfs) for maximum
    # scalability, for example, on Ubuntu:
    #
    # SESSION_DB_PATH = '/run/shm/pem7_session'
    #
    ##########################################################################
    SESSION_DB_PATH = os.path.join(DATA_DIR, 'sessions')

    SESSION_COOKIE_NAME = 'pem7_session'

    ##########################################################################
    # Mail content settings
    ##########################################################################
    UPGRADE_CHECK_ENABLED = False

    # Check if the detected browser is supported
    CHECK_SUPPORTED_BROWSER = True

    ##########################################################################
    # Storage Manager storage url config settings
    # If user sets STORAGE_DIR to empty it will show all volumes if platform
    # is Windows, '/' if it is Linux, Mac or any other unix type system.
    #
    # For example:
    # 1. STORAGE_DIR = get_drive("C") or get_drive() # return C:/ by default
    # where C can be any drive character such as "D", "E", "G" etc
    # 2. Set path manually like
    # STORAGE_DIR = "/path/to/directory/"
    ##########################################################################
    STORAGE_DIR = os.path.join(DATA_DIR, 'storage')

    ##########################################################################
    # Test settings - used primarily by the regression suite, not for users
    ##########################################################################
    # Set default testing mode
    TESTING_MODE = False

    # The default path for SQLite database for testing
    TEST_SQLITE_PATH = os.path.join(DATA_DIR, 'test_pem.db')

    ##########################################################################
    # Allows flask application to response to the each request asynchronously
    ##########################################################################
    THREADED_MODE = True

    ##########################################################################
    # Default locations for binary utilities (pg_dump, pg_restore etc)
    #
    # These are intentionally left empty in the main config file, but are
    # expected to be overridden by packagers in config_distro.py.
    #
    # A default location can be specified for each database driver ID, in
    # a dictionary. Either an absolute or relative path can be specified.
    #
    # Version-specific defaults can also be specified, which will take priority
    # over un-versioned paths.
    #
    # In cases where it may be difficult to know what the working directory
    # is, "$DIR" can be specified. This will be replaced with the path to the
    # top-level pgAdmin4.py file. For example, on macOS we might use:
    #
    # $DIR/../../SharedSupport
    #
    ##########################################################################
    DEFAULT_BINARY_PATHS = {
        "pg": "",
        "pg-9.6": "",
        "pg-10": "",
        "pg-11": "",
        "pg-12": "",
        "pg-13": "",
        "ppas": "",
        "ppas-9.6": "",
        "ppas-10": "",
        "ppas-11": "",
        "ppas-12": "",
        "ppas-13": ""
    }

    ##########################################################################
    # Database config settings
    ##########################################################################

    # Database Host
    # default: '127.0.0.1'
    #
    # PEM_DB_HOST = 'localhost'

    # Database Name
    # default: 'pem'
    #
    # PEM_DB_NAME = 'pem'

    # Database Port
    # default: 5432
    # PEM_DB_PORT = 5432

    # Do not allow SQLALCHEMY to track modification as it is going to be
    # deprecated in future
    ##########################################################################
    SQLALCHEMY_TRACK_MODIFICATIONS = False

    ##########################################################################

    ##########################################################################
    # Number of records to fetch in one batch in query tool when query result
    # set is large.
    ##########################################################################
    ON_DEMAND_RECORD_COUNT = 1000

    ##########################################################################
    # Allow users to display Gravatar image for their username in Server mode
    ##########################################################################
    SHOW_GRAVATAR_IMAGE = False

    ##########################################################################
    # Set cookie path and options
    ##########################################################################
    COOKIE_DEFAULT_PATH = '/'
    COOKIE_DEFAULT_DOMAIN = None
    SESSION_COOKIE_DOMAIN = None
    SESSION_COOKIE_SAMESITE = 'Lax'
    SESSION_COOKIE_SECURE = True,
    SESSION_COOKIE_HTTPONLY = True,

    ##########################################################################
    # Session expiration support
    ##########################################################################
    # SESSION_EXPIRATION_TIME is the interval in Days. Session will be
    # expire after the specified number of *days*.
    SESSION_EXPIRATION_TIME = 1

    # CHECK_SESSION_FILES_INTERVAL is interval in Hours. Application will check
    # the session files for cleanup after specified number of *hours*.
    CHECK_SESSION_FILES_INTERVAL = 24

    # USER_INACTIVITY_TIMEOUT is interval in Seconds. If the PEM GUI screen is
    # left unattended for <USER_INACTIVITY_TIMEOUT> seconds then the user will
    # be logged out. When set to 0, the timeout will be disabled.
    # If PEM GUI doesn't detect any activity in the time specified (in seconds),
    # the user will be forcibly logged out from PEM GUI application.
    # Set to zero to disable the timeout.
    USER_INACTIVITY_TIMEOUT = 0

    # OVERRIDE_USER_INACTIVITY_TIMEOUT when set to True will override
    # USER_INACTIVITY_TIMEOUT when long running queries in the Query tool
    # or Debugger are running. When the queries complete, the inactivity timer
    # will restart in this case. If set to False, user inactivity may cause
    # transactions or in-process debugging sessions to be aborted.
    OVERRIDE_USER_INACTIVITY_TIMEOUT = True

    ##########################################################################
    # SSH Tunneling supports only for Python 2.7 and 3.4+
    ##########################################################################
    # Enable the ssh tunnel support in the application.
    SUPPORT_SSH_TUNNEL = True
    # Allow SSH Tunnel passwords to be saved if the user chooses.
    # Set to False to disable password saving.
    ALLOW_SAVE_TUNNEL_PASSWORD = False


    ##########################################################################
    # PERFORMANCE DIAGNOSTIC
    ##########################################################################
    # PD_CONNECTION_POOL_USER_MIN_CONNECTION is number of minimum connections
    # allowed in the connection pool for performance diagnostic module.
    PD_CONNECTION_POOL_USER_MIN_CONNECTION = 1

    # PD_CONNECTION_POOL_USER_MAX_CONNECTION is number of maximum connections
    # allowed in the connection pool for performance diagnostic module.
    PD_CONNECTION_POOL_USER_MAX_CONNECTION = 3

    ##########################################################################
    # Allows PEM GUI application to create session cookies based on
    # IP address, so even if a cookie is stolen, the attacker will not be able
    # to connect to the server using that stolen cookie.
    # Note: This can cause problems when the server is deployed in dynamic IP
    # address hosting environments, such as Kubernetes or behind load
    # balancers. In such cases, this option should be set to False.
    ##########################################################################
    ENHANCED_COOKIE_PROTECTION = True


    ##########################################################################
    # Authentication Method
    ##########################################################################

    # Default setting is internal
    # If anything other than allowed values is set, it will reset the
    # authentication to 'internal'.
    #
    # Allowed authentication methods supported are: 'internal', 'kerberos'

    PEM_AUTH_METHOD = 'internal'

    ##########################################################################
    # Kerberos Authentication Configuration
    ##########################################################################

    KRB_APP_HOST_NAME = DEFAULT_SERVER

    # If the default_keytab_name is not set in krb5.conf or
    # the KRB_KTNAME environment variable is not set then, explicitly set
    # the Keytab file

    KRB_KTNAME = '<KRB5_KEYTAB_FILE>'

    # After kerberos authentication, user will be added into the SQLite database
    # automatically, if set to True.
    # Set it to False, if user should not be added automatically,
    # in this case Admin has to add the user manually in the SQLite database.

    KERBEROS_CCACHE_DIR = os.path.join(DATA_DIR, 'krbccache')

    # If set to False, the realm name from the authenticated user principal is
    # stripped off before being passed as database user name.
    PEM_USER_KRB_INCLUDE_REALM = True

    # This paratemeter is applicable only when determine, 'PEM_AUTH_METHOD' is
    # 'kerberos'.
    #
    # It determines to allow a user to connect any database server using
    # using authentication other than Kerberos.
    #
    # e.g. If 'ALLOW_DATABASE_CONNECTION_WITHOUT_KERBEROS' is True, it will allow
    # users to connect any database server using the username & password.
    ALLOW_DATABASE_CONNECTION_WITHOUT_KERBEROS = False

    ##########################################################################
    # Two-factor Authentication Configuration
    ##########################################################################

    # Set it to True, to enable the two-factor authentication
    MFA_ENABLED = False

    # Set it to True, to ask the users to register forcefully for the
    # two-authentication methods on logged-in.
    MFA_FORCE_REGISTRATION = False

    # pgAdmin supports Two-factor authentication by either sending an one-time code
    # to an email, or using the TOTP based application like Google Authenticator.
    MFA_SUPPORTED_METHODS = ["email", "authenticator"]

    # NOTE: Please set the 'Mail server Configuration' to use 'email' as two-factor
    #       authentication method.

    # Subject for the email verification code
    # Default: <APP_NAME> - Verification Code
    # e.g.  Postgres Enterprise Manager - Verification Code
    MFA_EMAIL_SUBJECT = None

    ##########################################################################
    # Mail Server Configuration
    ##########################################################################
    # PEM Server can send an email using two mechanisms
    # 1. Using the SMTP configurations saved in the PEM configuration.
    #    e.g. smtp_enabled, smtp_username, smtp_password, smtp_server, smtp_port,
    #         smtp_encrypted, etc.
    # 2. Use Flask-Mail to send an email using following configurations.

    # NOTE: These configurations are only used by Two-Factor Authentication to send
    #       an email to the user for the OTP at the moment.

    # Use SMTP configuration from the PEM configuration to send an email
    # (Default: True)
    MAIL_USE_PEM_INTERNAL = True

    # Use TSL for sending mail, when used the internal settings
    MAIL_INTERNAL_USE_TLS = False

    # If set it to 'False', following mail configuration will be used by MFA to
    # send the code on user specified email address.

    MAIL_SERVER = 'localhost'   # (Default: localhost)
    MAIL_PORT = 25              # (Default: 25)
    MAIL_USE_TLS = False        # (Defaut: False)
    MAIL_USE_SSL = False        # (Default: False)
    MAIL_USERNAME = None        # (Default: None)
    MAIL_PASSWORD = None        # (Default: None)
    # Flask-Security overrides Flask-Mail's MAIL_DEFAULT_SENDER setting, so
    # that should be set as such:
    SECURITY_EMAIL_SENDER = 'no-reply@localhost'  # (Default:'no-reply@localhost')

    # Please refer the Flask-Mail documentation for details about these
    # configurations.
    # Reference: https://pythonhosted.org/Flask-Mail/

    ##########################################################################
    # COMPRESSION
    ##########################################################################
    COMPRESS_MIMETYPES = [
        'text/css', 'text/xml', 'application/javascript', 'text/javascript',
        'application/json', 'text/json'
    ]
    COMPRESS_LEVEL = 9
    COMPRESS_MIN_SIZE = 50

    ##########################################################################
    # PSQL tool settings
    ##########################################################################
    # This will enable PSQL tool in PEM. So user can execute the commands
    # using PSQL terminal in pgAdmin.
    ENABLE_PSQL = False

    ##########################################################################
    # Email address validation
    ##########################################################################

    # flask-security-too will validate email addresses and check deliverability
    # by default. Disable the deliverability check by default, which was the old
    # behaviour in <= v5.3
    CHECK_EMAIL_DELIVERABILITY = False
    SECURITY_EMAIL_VALIDATOR_ARGS = \
        {"check_deliverability": CHECK_EMAIL_DELIVERABILITY}

    ##########################################################################
    # ENABLE_BINARY_PATH_BROWSING setting is used to enable the browse button
    # while selecting binary path for the database server in server mode.
    # In Desktop mode it is always enabled and setting is of no use.
    ##########################################################################
    ENABLE_BINARY_PATH_BROWSING = False

    ##########################################################################
    # ENABLE_LOGIN_ERROR_MASKING setting is used to hide to specific
    # login error which can limit the attacker's scope while check for
    # valid username & password.
    # When set to True PEM will display generic error like
    # 'Invalid username or password' instead of error like
    # 'FATAL: password authentication failed for user "XYZ"'
    ##########################################################################
    ENABLE_LOGIN_ERROR_MASKING = False


    ##########################################################################
    # ENABLE_DATA_ACCESS_TOOLS option allows PEM users to access certain
    # tools so that PEM users can access their data from PEM interface.
    # When set to False, PEM will disable following tools,
    # 1. Query tool & View Data option
    # 2. Import/Export utility
    # 3. Backup Utility
    # 4. Generate SQL option in Schema diff & ERD diagram tools
    ##########################################################################
    ENABLE_DATA_ACCESS_TOOLS = True


    ##########################################################################
    # ENABLE_DEBUGGER option allows PEM users to access the Debugger tool.
    # When set to False, PEM will disable Debugger tool
    ##########################################################################
    ENABLE_DEBUGGER = True
    ##########################################################################
    # Local config settings
    ##########################################################################

    # Load distribution-specific config overrides
    if os.path.exists(os.path.join(root, 'config_distro.py')):
        try:
            from config_distro import *
        except ImportError:
            pass

    if os.path.exists(os.path.join(root, 'config_setup.py')):
        # Configuration created by the configure-pem-server.sh
        try:
            from config_setup import *
        except ImportError:
            pass

    if os.path.exists(os.path.join(root, 'config_local.py')):
        #
        # Load local config overrides
        try:
            from config_local import *
        except ImportError:
            pass

    #########################################################################
    # Skip storing session in files and cache for specific paths
    #########################################################################
    SESSION_SKIP_PATHS = [
        '/misc/ping'
    ]