diff --git a/uwsgi-python/handlers/main.yml b/uwsgi-python/handlers/main.yml index 0da2ba00bc7d45cfec6f6542a420918bbaa8642a..3625c7b774bb1baaddbcc3ee8871316fccb40e75 100644 --- a/uwsgi-python/handlers/main.yml +++ b/uwsgi-python/handlers/main.yml @@ -103,3 +103,10 @@ - name: restart uwsgi instance infoscreen service: name="uwsgi@infoscreen" state=restarted + +- name: restart uwsgi instance netbox + service: name="uwsgi@netbox" state=restarted + +# - name: restart uwsgi instance netbox rqworker +# service: name="netbox-rqworker" state=restarted +# listen: "restart uwsgi instance netbox" diff --git a/uwsgi-python/tasks/app.yml b/uwsgi-python/tasks/app.yml index 7f26ce64385209fd491f2f702319faa55c60a16f..cc8f2a613e4e6009fdb310507b2a202b1f2206a7 100644 --- a/uwsgi-python/tasks/app.yml +++ b/uwsgi-python/tasks/app.yml @@ -56,6 +56,10 @@ - include: postgres.yml when: app_db_type == "postgres" when: app_db_type is defined + tags: + - uwsgi-app + - "{{ app.app }}" + - "{{ app.instance }}" - name: ensure we have a group group: diff --git a/uwsgi-python/tasks/apps/netbox.yml b/uwsgi-python/tasks/apps/netbox.yml new file mode 100644 index 0000000000000000000000000000000000000000..032e500385a0582bb44dcda51fece54882c28e3e --- /dev/null +++ b/uwsgi-python/tasks/apps/netbox.yml @@ -0,0 +1,67 @@ +--- + +- name: Install LDAP auth configuration + template: + src: apps/netbox-ldap.py.j2 + dest: "{{app_path}}/netbox/netbox/ldap_config.py" + owner: root + group: "{{app_group}}" + mode: '0640' + notify: + - "restart uwsgi instance {{ app.instance }}" + +# https://github.com/ansible/ansible/issues/42983 +- name: ensure there exists a .ansible folder + file: + path: "{{app_path}}/.ansible" + state: directory + owner: "{{app_user}}" + group: "{{app_group}}" + +- name: ensure plugins are installed # noqa 403 + pip: + name: + - napalm + - django-auth-ldap + virtualenv: "{{ app_venv }}" + virtualenv_python: "python{{ app_python_version }}" + state: latest + notify: + - "restart uwsgi instance {{ app.instance }}" + +- name: ensure data model migrations are applied # noqa 301 + command: "{{app_venv}}/bin/python manage.py migrate" + args: + chdir: "{{app_chdir}}" + become: true + become_user: "{{app_user}}" + notify: + - "restart uwsgi instance {{app.instance}}" + +- name: Collect static files # noqa 301 + command: "{{app_venv}}/bin/python manage.py collectstatic --no-input" + args: + chdir: "{{app_chdir}}" + +- name: ensure the folder from above is not present anymore + file: + path: "{{app_path}}/.ansible" + state: absent + +- name: ensure the rqworker unit file exists + template: + src: apps/netbox-rqworker.service.j2 + dest: "/etc/systemd/system/{{ app_name }}-rqworker.service" + owner: root + group: root + mode: '0644' + notify: + - reload systemd service files + - "restart uwsgi instance {{app.instance}}" + +# Not needed (and working) at the moment +# - name: ensure the rqworker service is enabled +# service: +# name: "{{app_name}}-rqworker" +# enabled: true +# state: started diff --git a/uwsgi-python/templates/apps/netbox-ldap.py.j2 b/uwsgi-python/templates/apps/netbox-ldap.py.j2 new file mode 100644 index 0000000000000000000000000000000000000000..ec891e3be69865da7b471ae8056bbb1b8bd4185f --- /dev/null +++ b/uwsgi-python/templates/apps/netbox-ldap.py.j2 @@ -0,0 +1,61 @@ +import ldap +from django_auth_ldap.config import LDAPSearch, NestedGroupOfNamesType + +# Server URI +AUTH_LDAP_SERVER_URI = "{{netbox_ldap.uri}}" + +# The following may be needed if you are binding to Active Directory. +AUTH_LDAP_CONNECTION_OPTIONS = { + ldap.OPT_REFERRALS: 0 +} + +# Set the DN and password for the NetBox service account. +AUTH_LDAP_BIND_DN = "{{netbox_ldap.binddn}}" +AUTH_LDAP_BIND_PASSWORD = "{{netbox_ldap.bindpw}}" + +# Include this setting if you want to ignore certificate errors. This might be needed to accept a self-signed cert. +# Note that this is a NetBox-specific setting which sets: +# ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) +LDAP_IGNORE_CERT_ERRORS = False + +# This search matches users with the sAMAccountName equal to the provided username. This is required if the user's +# username is not in their DN (Active Directory). +AUTH_LDAP_USER_SEARCH = LDAPSearch("{{netbox_ldap.user_base}}", + ldap.SCOPE_SUBTREE, + "(sAMAccountName=%(user)s)") + +# If a user's DN is producible from their username, we don't need to search. +AUTH_LDAP_USER_DN_TEMPLATE = "cn=%(user)s,{{netbox_ldap.user_base}}" + +# You can map user attributes to Django attributes as so. +AUTH_LDAP_USER_ATTR_MAP = { + "first_name": "givenName", + "last_name": "sn", + "email": "mail" +} + +# This search ought to return all groups to which the user belongs. django_auth_ldap uses this to determine group +# hierarchy. +AUTH_LDAP_GROUP_SEARCH = LDAPSearch("{{netbox_ldap.group_base}}", ldap.SCOPE_SUBTREE, + "(objectClass=group)") +AUTH_LDAP_GROUP_TYPE = NestedGroupOfNamesType() + +# Define a group required to login. +AUTH_LDAP_REQUIRE_GROUP = "{{netbox_ldap.login_group}}" + +# Mirror LDAP group assignments. +AUTH_LDAP_MIRROR_GROUPS = True + +# Define special user types using groups. Exercise great caution when assigning superuser status. +AUTH_LDAP_USER_FLAGS_BY_GROUP = { + "is_active": "{{netbox_ldap.group_flags.is_active}}", + "is_staff": "{{netbox_ldap.group_flags.is_staff}}", + "is_superuser": "{{netbox_ldap.group_flags.is_superuser}}" +} + +# For more granular permissions, we can map LDAP groups to Django groups. +AUTH_LDAP_FIND_GROUP_PERMS = True + +# Cache groups for one hour to reduce LDAP traffic +AUTH_LDAP_CACHE_GROUPS = True +AUTH_LDAP_GROUP_CACHE_TIMEOUT = 3600 diff --git a/uwsgi-python/templates/apps/netbox-rqworker.service.j2 b/uwsgi-python/templates/apps/netbox-rqworker.service.j2 new file mode 100644 index 0000000000000000000000000000000000000000..9cf00677ddc20f1276905b4b5c742f78e7130741 --- /dev/null +++ b/uwsgi-python/templates/apps/netbox-rqworker.service.j2 @@ -0,0 +1,15 @@ +[Unit] +Description={{ app_name }}-rqworker +After=network.target + +[Service] +User={{ app_user }} +Group={{ app_group }} +WorkingDirectory={{ app_chdir }} +Environment="VIRTUAL_ENV={{ app_venv }}" +Environment="PATH={{ app_venv }}/bin:/usr/local/bin:/usr/bin:/bin" +ExecStart={{ app_venv }}/bin/python manage.py rqworker +Restart=always + +[Install] +WantedBy=multi-user.target diff --git a/uwsgi-python/templates/apps/netbox.j2 b/uwsgi-python/templates/apps/netbox.j2 new file mode 100644 index 0000000000000000000000000000000000000000..68b23b57c0c27e5322643b96c18f012046861469 --- /dev/null +++ b/uwsgi-python/templates/apps/netbox.j2 @@ -0,0 +1,178 @@ +######################### +# # +# Required settings # +# # +######################### + +# This is a list of valid fully-qualified domain names (FQDNs) for the NetBox server. NetBox will not permit write +# access to the server via any other hostnames. The first FQDN in the list will be treated as the preferred name. +# +# Example: ALLOWED_HOSTS = ['netbox.example.com', 'netbox.internal.local'] +ALLOWED_HOSTS = ['{{ netbox_host }}'] + +# PostgreSQL database configuration. +DATABASE = { + 'NAME': 'netbox', # Database name + 'USER': '', # PostgreSQL username + 'PASSWORD': '', # PostgreSQL password + 'HOST': '', # Database server + 'PORT': '', # Database port (leave blank for default) +} + +# This key is used for secure generation of random numbers and strings. It must never be exposed outside of this file. +# For optimal security, SECRET_KEY should be at least 50 characters in length and contain a mix of letters, numbers, and +# symbols. NetBox will not run without this defined. For more information, see +# https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-SECRET_KEY +from .secret_config import secret_key as SECRET_KEY + +# Redis database settings. The Redis database is used for caching and background processing such as webhooks +REDIS = { + 'HOST': 'localhost', + 'PORT': 6379, + 'PASSWORD': '', + 'DATABASE': 0, + 'CACHE_DATABASE': 1, + 'DEFAULT_TIMEOUT': 300, + 'SSL': False, +} + + +######################### +# # +# Optional settings # +# # +######################### + +# Specify one or more name and email address tuples representing NetBox administrators. These people will be notified of +# application errors (assuming correct email settings are provided). +ADMINS = [ + {% for a in netbox_admins %} + [ "{{ a[0] }}", "{{ a[1] }}" ], + {% endfor %} +] + +# Optionally display a persistent banner at the top and/or bottom of every page. HTML is allowed. To display the same +# content in both banners, define BANNER_TOP and set BANNER_BOTTOM = BANNER_TOP. +BANNER_TOP = '' +BANNER_BOTTOM = '' + +# Text to include on the login page above the login form. HTML is allowed. +BANNER_LOGIN = '' + +# Base URL path if accessing NetBox within a directory. For example, if installed at http://example.com/netbox/, set: +# BASE_PATH = 'netbox/' +BASE_PATH = '' + +# Cache timeout in seconds. Set to 0 to dissable caching. Defaults to 900 (15 minutes) +CACHE_TIMEOUT = 900 + +# Maximum number of days to retain logged changes. Set to 0 to retain changes indefinitely. (Default: 90) +CHANGELOG_RETENTION = 90 + +# API Cross-Origin Resource Sharing (CORS) settings. If CORS_ORIGIN_ALLOW_ALL is set to True, all origins will be +# allowed. Otherwise, define a list of allowed origins using either CORS_ORIGIN_WHITELIST or +# CORS_ORIGIN_REGEX_WHITELIST. For more information, see https://github.com/ottoyiu/django-cors-headers +CORS_ORIGIN_ALLOW_ALL = False +CORS_ORIGIN_WHITELIST = [ + # 'https://hostname.example.com', +] +CORS_ORIGIN_REGEX_WHITELIST = [ + # r'^(https?://)?(\w+\.)?example\.com$', +] + +# Set to True to enable server debugging. WARNING: Debugging introduces a substantial performance penalty and may reveal +# sensitive information about your installation. Only enable debugging while performing testing. Never enable debugging +# on a production system. +DEBUG = False + +# Email settings +EMAIL = { + 'SERVER': '{{ netbox_mail.server }}', + 'PORT': 25, + 'USERNAME': '', + 'PASSWORD': '', + 'TIMEOUT': 10, # seconds + 'FROM_EMAIL': '{{ netbox_mail.from }}', +} + +# Enforcement of unique IP space can be toggled on a per-VRF basis. To enforce unique IP space within the global table +# (all prefixes and IP addresses not assigned to a VRF), set ENFORCE_GLOBAL_UNIQUE to True. +ENFORCE_GLOBAL_UNIQUE = False + +# Exempt certain models from the enforcement of view permissions. Models listed here will be viewable by all users and +# by anonymous users. List models in the form `<app>.<model>`. Add '*' to this list to exempt all models. +EXEMPT_VIEW_PERMISSIONS = [ + # 'dcim.site', + # 'dcim.region', + # 'ipam.prefix', +] + +# Enable custom logging. Please see the Django documentation for detailed guidance on configuring custom logs: +# https://docs.djangoproject.com/en/1.11/topics/logging/ +LOGGING = {} + +# Setting this to True will permit only authenticated users to access any part of NetBox. By default, anonymous users +# are permitted to access most data in NetBox (excluding secrets) but not make any changes. +LOGIN_REQUIRED = True + +# The length of time (in seconds) for which a user will remain logged into the web UI before being prompted to +# re-authenticate. (Default: 1209600 [14 days]) +LOGIN_TIMEOUT = None + +# Setting this to True will display a "maintenance mode" banner at the top of every page. +MAINTENANCE_MODE = False + +# An API consumer can request an arbitrary number of objects =by appending the "limit" parameter to the URL (e.g. +# "?limit=1000"). This setting defines the maximum limit. Setting it to 0 or None will allow an API consumer to request +# all objects by specifying "?limit=0". +MAX_PAGE_SIZE = 1000 + +# The file path where uploaded media such as image attachments are stored. A trailing slash is not needed. Note that +# the default value of this setting is derived from the installed location. +# MEDIA_ROOT = '/opt/netbox/netbox/media' + +# Expose Prometheus monitoring metrics at the HTTP endpoint '/metrics' +METRICS_ENABLED = False + +# Credentials that NetBox will uses to authenticate to devices when connecting via NAPALM. +NAPALM_USERNAME = '' +NAPALM_PASSWORD = '' + +# NAPALM timeout (in seconds). (Default: 30) +NAPALM_TIMEOUT = 30 + +# NAPALM optional arguments (see http://napalm.readthedocs.io/en/latest/support/#optional-arguments). Arguments must +# be provided as a dictionary. +NAPALM_ARGS = {} + +# Determine how many objects to display per page within a list. (Default: 50) +PAGINATE_COUNT = 50 + +# When determining the primary IP address for a device, IPv6 is preferred over IPv4 by default. Set this to True to +# prefer IPv4 instead. +PREFER_IPV4 = True + +# The file path where custom reports will be stored. A trailing slash is not needed. Note that the default value of +# this setting is derived from the installed location. +# REPORTS_ROOT = '/opt/netbox/netbox/reports' + +# By default, NetBox will store session data in the database. Alternatively, a file path can be specified here to use +# local file storage instead. (This can be useful for enabling authentication on a standby instance with read-only +# database access.) Note that the user as which NetBox runs must have read and write permissions to this path. +SESSION_FILE_PATH = None + +# Time zone (default: UTC) +TIME_ZONE = '{{ netbox_tz }}' + +# The webhooks backend is disabled by default. Set this to True to enable it. Note that this requires a Redis +# database be configured and accessible by NetBox. +WEBHOOKS_ENABLED = False + +# Date/time formatting. See the following link for supported formats: +# https://docs.djangoproject.com/en/dev/ref/templates/builtins/#date +DATE_FORMAT = 'N j, Y' +SHORT_DATE_FORMAT = 'Y-m-d' +TIME_FORMAT = 'g:i a' +SHORT_TIME_FORMAT = 'H:i:s' +DATETIME_FORMAT = 'N j, Y g:i a' +SHORT_DATETIME_FORMAT = 'Y-m-d H:i' diff --git a/uwsgi-python/templates/uwsgi.ini.j2 b/uwsgi-python/templates/uwsgi.ini.j2 index 3b8d9bcbe390ebff8a0ba12146afea40c16d39f1..7ac8a12f6ffdf4fc57b1cbc9b7070cebcb9d419b 100644 --- a/uwsgi-python/templates/uwsgi.ini.j2 +++ b/uwsgi-python/templates/uwsgi.ini.j2 @@ -32,7 +32,7 @@ env = {{ env }} mule = {% endfor %} #umask = 227 -chdir = {{app_path}} +chdir = {{app_chdir}} uid = {{app_user}} gid = {{app_group}} log-date = diff --git a/uwsgi-python/vars/default.yml b/uwsgi-python/vars/default.yml index 2e5ded0fc8fb3a451773ac3f8556e2202effbdbf..90db232e671330e7eda297ffa2b4024914c52126 100644 --- a/uwsgi-python/vars/default.yml +++ b/uwsgi-python/vars/default.yml @@ -5,6 +5,7 @@ app_user: "{{ app.app }}" app_group: "{{ app.app }}" app_home: "/var/www/{{ app.app }}" app_path: "/var/www/{{ app.app }}" +app_chdir: "{{ app_path }}" app_python_version: 3 app_venv: "/var/www/{{ app.app }}/venv/" app_program: "{{ app.app }}.py" diff --git a/uwsgi-python/vars/netbox.yml b/uwsgi-python/vars/netbox.yml new file mode 100644 index 0000000000000000000000000000000000000000..bd6ba44651fa18213f1534dd1dc2dc53a1525958 --- /dev/null +++ b/uwsgi-python/vars/netbox.yml @@ -0,0 +1,29 @@ +--- +app_db_name: netbox +app_db_type: postgres +app_git_url: 'https://github.com/netbox-community/netbox.git' +app_git_version: 'v2.6.7' +app_config_file: netbox/netbox/configuration.py +app_chdir: "{{ app_path }}/netbox" +app_module: netbox.wsgi:application +app_secret_config: true +app_deploy_key: "" + +netbox_admins: + - ['Admin', 'admin@example.com'] +netbox_mail: + server: localhost + from: netbox@example.com +netbox_host: netbox.example.com +netbox_tz: UTC +netbox_ldap: + uri: ldaps://dc.example.com + binddn: "CN=NETBOXSA, OU=Service Accounts,DC=example,DC=com" + bindpw: hunter2 + user_base: "OU=Users,DC=example,DC=com" + group_base: "OU=Groups,DC=example,DC=com" + login_group: "CN=Netbox Users,OU=Groups,DC=example,DC=com" + group_flags: + is_active: "cn=active,ou=groups,dc=example,dc=com" + is_staff: "cn=staff,ou=groups,dc=example,dc=com" + is_superuser: "cn=superuser,ou=groups,dc=example,dc=com" diff --git a/webserver/tasks/main.yml b/webserver/tasks/main.yml index 1cd54ec20d337f6a1214d23a87ccca92bc547f69..187b4ab6acb057e14152632b6ddfbe3e1ef2db01 100644 --- a/webserver/tasks/main.yml +++ b/webserver/tasks/main.yml @@ -4,6 +4,9 @@ - name: include debian version specific configuration include_vars: file: "{{debian_version|default('fallback')}}.yml" + tags: + - nginx + - webservices - name: ensure nginx is installed apt: