diff options
author | Mike Crute <mike@crute.us> | 2022-12-04 22:20:03 -0800 |
---|---|---|
committer | Mike Crute <mike@crute.us> | 2022-12-04 22:20:03 -0800 |
commit | 1b297be993b39c38a29f2d4a512fe8f3a9b3cacf (patch) | |
tree | 5309589797fd0a8e75b3e8aec37ac3acd96c12bb | |
parent | d4efff4950b6105f1d62362f8944a24659af4ea7 (diff) | |
download | dockerfiles-1b297be993b39c38a29f2d4a512fe8f3a9b3cacf.tar.bz2 dockerfiles-1b297be993b39c38a29f2d4a512fe8f3a9b3cacf.tar.xz dockerfiles-1b297be993b39c38a29f2d4a512fe8f3a9b3cacf.zip |
netbox: upgrade to 3.3.9 and remove patches
This change migrates to using simplevisor which handles Vault credential
fetching and renewal. It removes quite a lot of fragile hacks at the
Django layer in favor of straightforward environment variable passing.
-rw-r--r-- | netbox/Dockerfile | 44 | ||||
-rw-r--r-- | netbox/Makefile | 2 | ||||
-rw-r--r-- | netbox/config-patch1.diff | 26 | ||||
-rw-r--r-- | netbox/config-patch2.diff | 92 | ||||
-rw-r--r-- | netbox/configuration.py | 30 | ||||
-rw-r--r-- | netbox/django-driver.py | 77 | ||||
-rw-r--r-- | netbox/django-vault-client.py | 88 | ||||
-rwxr-xr-x | netbox/entrypoint.sh | 22 | ||||
-rwxr-xr-x | netbox/etc/service/netbox-rq/log/run | 3 | ||||
-rwxr-xr-x | netbox/etc/service/netbox-rq/run | 23 | ||||
-rwxr-xr-x | netbox/etc/service/uwsgi/log/run | 3 | ||||
-rwxr-xr-x | netbox/etc/service/uwsgi/run | 23 | ||||
-rw-r--r-- | netbox/netbox.ini (renamed from netbox/etc/uwsgi/netbox.ini) | 0 | ||||
-rw-r--r-- | netbox/settings-patch.diff | 11 | ||||
-rw-r--r-- | netbox/settings.patch | 10 | ||||
-rw-r--r-- | netbox/simplevisor.json | 69 |
16 files changed, 126 insertions, 397 deletions
diff --git a/netbox/Dockerfile b/netbox/Dockerfile index 022aebf..3b63944 100644 --- a/netbox/Dockerfile +++ b/netbox/Dockerfile | |||
@@ -3,15 +3,13 @@ LABEL maintainer="Mike Crute <mike@crute.us>" | |||
3 | 3 | ||
4 | ARG netbox_version | 4 | ARG netbox_version |
5 | 5 | ||
6 | ADD config-patch1.diff /config-patch1.diff | 6 | ADD configuration.py /configuration.py |
7 | ADD config-patch2.diff /config-patch2.diff | 7 | ADD settings.patch /settings.patch |
8 | ADD settings-patch.diff /settings-patch.diff | ||
9 | 8 | ||
10 | RUN set -euxo pipefail; \ | 9 | RUN set -euxo pipefail; \ |
11 | \ | 10 | \ |
12 | apk --no-cache add \ | 11 | apk --no-cache add \ |
13 | build-base \ | 12 | build-base \ |
14 | dumb-init \ | ||
15 | jpeg-dev \ | 13 | jpeg-dev \ |
16 | libffi-dev \ | 14 | libffi-dev \ |
17 | libxml2-dev \ | 15 | libxml2-dev \ |
@@ -19,13 +17,13 @@ RUN set -euxo pipefail; \ | |||
19 | openssl-dev \ | 17 | openssl-dev \ |
20 | postgresql-dev \ | 18 | postgresql-dev \ |
21 | py3-pip \ | 19 | py3-pip \ |
20 | py3-wheel \ | ||
22 | python3-dev \ | 21 | python3-dev \ |
23 | runit \ | ||
24 | su-exec \ | ||
25 | uwsgi \ | 22 | uwsgi \ |
26 | uwsgi-python \ | 23 | uwsgi-python \ |
27 | zlib-dev \ | 24 | zlib-dev \ |
28 | ; \ | 25 | ; \ |
26 | \ | ||
29 | cd /tmp; \ | 27 | cd /tmp; \ |
30 | wget "https://github.com/netbox-community/netbox/archive/v${netbox_version}.tar.gz"; \ | 28 | wget "https://github.com/netbox-community/netbox/archive/v${netbox_version}.tar.gz"; \ |
31 | tar -xvf "v${netbox_version}.tar.gz" -C /opt; \ | 29 | tar -xvf "v${netbox_version}.tar.gz" -C /opt; \ |
@@ -33,41 +31,31 @@ RUN set -euxo pipefail; \ | |||
33 | mv /opt/netbox-${netbox_version}/ /opt/netbox/; \ | 31 | mv /opt/netbox-${netbox_version}/ /opt/netbox/; \ |
34 | \ | 32 | \ |
35 | cd /; \ | 33 | cd /; \ |
36 | cp /opt/netbox/netbox/netbox/configuration.example.py /opt/netbox/netbox/netbox/configuration.py; \ | 34 | mv /configuration.py /opt/netbox/netbox/netbox/configuration.py; \ |
37 | patch -p1 < /config-patch1.diff; \ | 35 | patch -p1 < /settings.patch; rm /settings.patch; \ |
38 | rm /config-patch1.diff; \ | ||
39 | \ | 36 | \ |
40 | addgroup -S netbox; \ | 37 | addgroup -S netbox; \ |
41 | adduser -S -G netbox netbox; \ | 38 | adduser -S -G netbox netbox; \ |
42 | chown -R netbox:netbox /opt/netbox/netbox/media; \ | 39 | chown -R netbox:netbox /opt/netbox/netbox/media; \ |
43 | \ | 40 | \ |
44 | cd /opt/netbox; \ | 41 | cd /opt/netbox; \ |
45 | pip3 install wheel; \ | ||
46 | pip3 install -r requirements.txt; \ | 42 | pip3 install -r requirements.txt; \ |
43 | pip3 install django-postgresql-setrole; \ | ||
47 | \ | 44 | \ |
48 | python3 netbox/manage.py collectstatic --no-input; \ | 45 | export NETBOX_SECRET_KEY="testing key for running the build"; \ |
49 | \ | 46 | export NETBOX_DB_PORT="0"; \ |
50 | cd /; \ | 47 | export NETBOX_REDIS_TASK_DB="0"; \ |
51 | cp /opt/netbox/netbox/netbox/configuration.example.py /opt/netbox/netbox/netbox/configuration.py; \ | 48 | export NETBOX_REDIS_CACHE_DB="0"; \ |
52 | patch -p1 < /config-patch2.diff; \ | ||
53 | rm /config-patch2.diff; \ | ||
54 | \ | ||
55 | patch -p1 < /settings-patch.diff; \ | ||
56 | rm /settings-patch.diff; \ | ||
57 | \ | 49 | \ |
58 | mkdir -p /usr/lib/python3.8/site-packages/django/db/backends/postgresqlvault; \ | 50 | python3 netbox/manage.py collectstatic --no-input; \ |
59 | touch /usr/lib/python3.8/site-packages/django/db/backends/postgresqlvault/__init__.py; \ | ||
60 | \ | 51 | \ |
61 | rm -rf /root/.cache; \ | 52 | rm -rf /root/.cache; \ |
62 | apk --no-cache del --purge \ | 53 | apk --no-cache del --purge \ |
63 | build-base \ | 54 | build-base \ |
64 | ; | 55 | ; |
65 | 56 | ||
66 | ADD django-vault-client.py /usr/lib/python3.8/site-packages/django/contrib/vault_client.py | 57 | ADD netbox.ini /etc/uwsgi/netbox.ini |
67 | ADD django-driver.py /usr/lib/python3.8/site-packages/django/db/backends/postgresqlvault/base.py | 58 | ADD simplevisor.json /simplevisor.json |
68 | ADD etc/ /etc/ | 59 | ADD simplevisor /simplevisor |
69 | ADD entrypoint.sh /entrypoint.sh | ||
70 | 60 | ||
71 | STOPSIGNAL SIGHUP | 61 | CMD [ "/simplevisor" ] |
72 | ENTRYPOINT [ "/entrypoint.sh" ] | ||
73 | CMD [ "/usr/bin/dumb-init", "/sbin/runsvdir", "/etc/service" ] | ||
diff --git a/netbox/Makefile b/netbox/Makefile index 1fb4dad..f572b39 100644 --- a/netbox/Makefile +++ b/netbox/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | VERSION=2.11.9 | 1 | VERSION=3.3.9 |
2 | IMAGE=docker.crute.me/netbox:$(VERSION) | 2 | IMAGE=docker.crute.me/netbox:$(VERSION) |
3 | LATEST=$(subst :$(VERSION),,$(IMAGE)):latest | 3 | LATEST=$(subst :$(VERSION),,$(IMAGE)):latest |
4 | 4 | ||
diff --git a/netbox/config-patch1.diff b/netbox/config-patch1.diff deleted file mode 100644 index cc5c6d2..0000000 --- a/netbox/config-patch1.diff +++ /dev/null | |||
@@ -1,26 +0,0 @@ | |||
1 | --- a/opt/netbox/netbox/netbox/configuration.py 2021-07-11 22:24:55.365668931 +0000 | ||
2 | +++ b/opt/netbox/netbox/netbox/configuration.py 2021-07-11 22:25:25.077103585 +0000 | ||
3 | @@ -4,11 +4,13 @@ | ||
4 | # # | ||
5 | ######################### | ||
6 | |||
7 | +import urllib3; urllib3.disable_warnings() | ||
8 | + | ||
9 | # This is a list of valid fully-qualified domain names (FQDNs) for the NetBox server. NetBox will not permit write | ||
10 | # access to the server via any other hostnames. The first FQDN in the list will be treated as the preferred name. | ||
11 | # | ||
12 | # Example: ALLOWED_HOSTS = ['netbox.example.com', 'netbox.internal.local'] | ||
13 | -ALLOWED_HOSTS = [] | ||
14 | +ALLOWED_HOSTS = ['*'] | ||
15 | |||
16 | # PostgreSQL database configuration. See the Django documentation for a complete list of available parameters: | ||
17 | # https://docs.djangoproject.com/en/stable/ref/settings/#databases | ||
18 | @@ -57,7 +59,7 @@ | ||
19 | # For optimal security, SECRET_KEY should be at least 50 characters in length and contain a mix of letters, numbers, and | ||
20 | # symbols. NetBox will not run without this defined. For more information, see | ||
21 | # https://docs.djangoproject.com/en/stable/ref/settings/#std:setting-SECRET_KEY | ||
22 | -SECRET_KEY = '' | ||
23 | +SECRET_KEY = 'dummy setup value will get cleared after setup run' | ||
24 | |||
25 | |||
26 | ######################### | ||
diff --git a/netbox/config-patch2.diff b/netbox/config-patch2.diff deleted file mode 100644 index 69162e4..0000000 --- a/netbox/config-patch2.diff +++ /dev/null | |||
@@ -1,92 +0,0 @@ | |||
1 | --- a/opt/netbox/netbox/netbox/configuration.py 2021-07-11 22:24:55.365668931 +0000 | ||
2 | +++ b/opt/netbox/netbox/netbox/configuration.py 2021-07-11 22:28:09.665982854 +0000 | ||
3 | @@ -4,21 +4,35 @@ | ||
4 | # # | ||
5 | ######################### | ||
6 | |||
7 | +import os | ||
8 | +from django.contrib.vault_client import SimpleVaultClient | ||
9 | + | ||
10 | + | ||
11 | +def _is_affirmative(value): | ||
12 | + value = "" if not value else value | ||
13 | + return value.lower() in ["yes", "true", "on", "1"] | ||
14 | + | ||
15 | + | ||
16 | # This is a list of valid fully-qualified domain names (FQDNs) for the NetBox server. NetBox will not permit write | ||
17 | # access to the server via any other hostnames. The first FQDN in the list will be treated as the preferred name. | ||
18 | # | ||
19 | # Example: ALLOWED_HOSTS = ['netbox.example.com', 'netbox.internal.local'] | ||
20 | -ALLOWED_HOSTS = [] | ||
21 | +ALLOWED_HOSTS = ['*'] | ||
22 | |||
23 | # PostgreSQL database configuration. See the Django documentation for a complete list of available parameters: | ||
24 | # https://docs.djangoproject.com/en/stable/ref/settings/#databases | ||
25 | +port = os.getenv("NETBOX_DB_PORT") | ||
26 | DATABASE = { | ||
27 | - 'NAME': 'netbox', # Database name | ||
28 | - 'USER': '', # PostgreSQL username | ||
29 | - 'PASSWORD': '', # PostgreSQL password | ||
30 | - 'HOST': 'localhost', # Database server | ||
31 | - 'PORT': '', # Database port (leave blank for default) | ||
32 | - 'CONN_MAX_AGE': 300, # Max database connection age | ||
33 | + 'NAME': os.getenv("NETBOX_DB_NAME"), | ||
34 | + 'HOST': os.getenv("NETBOX_DB_HOST"), | ||
35 | + 'PORT': int(port) if port else "", | ||
36 | + 'CONN_MAX_AGE': 300, | ||
37 | + "VAULT_SKIP_VERIFY": os.getenv("VAULT_SKIP_VERIFY"), | ||
38 | + "VAULT_ADDR": os.getenv("VAULT_ADDR"), | ||
39 | + "VAULT_TOKEN": os.getenv("VAULT_TOKEN"), | ||
40 | + "VAULT_DB_ROLE_NAME": os.getenv("VAULT_DB_ROLE_NAME"), | ||
41 | + "VAULT_ROLE_ID": os.getenv("VAULT_ROLE_ID"), | ||
42 | + "VAULT_SECRET_ID": os.getenv("VAULT_SECRET_ID"), | ||
43 | } | ||
44 | |||
45 | # Redis database settings. Redis is used for caching and for queuing background tasks such as webhook events. A separate | ||
46 | @@ -26,26 +40,26 @@ | ||
47 | # to use two separate database IDs. | ||
48 | REDIS = { | ||
49 | 'tasks': { | ||
50 | - 'HOST': 'localhost', | ||
51 | + 'HOST': os.getenv("NETBOX_REDIS_HOST"), | ||
52 | 'PORT': 6379, | ||
53 | # Comment out `HOST` and `PORT` lines and uncomment the following if using Redis Sentinel | ||
54 | # 'SENTINELS': [('mysentinel.redis.example.com', 6379)], | ||
55 | # 'SENTINEL_SERVICE': 'netbox', | ||
56 | 'PASSWORD': '', | ||
57 | - 'DATABASE': 0, | ||
58 | + 'DATABASE': int(os.getenv("NETBOX_REDIS_TASK_DB")), | ||
59 | 'SSL': False, | ||
60 | # Set this to True to skip TLS certificate verification | ||
61 | # This can expose the connection to attacks, be careful | ||
62 | # 'INSECURE_SKIP_TLS_VERIFY': False, | ||
63 | }, | ||
64 | 'caching': { | ||
65 | - 'HOST': 'localhost', | ||
66 | + 'HOST': os.getenv("NETBOX_REDIS_HOST"), | ||
67 | 'PORT': 6379, | ||
68 | # Comment out `HOST` and `PORT` lines and uncomment the following if using Redis Sentinel | ||
69 | # 'SENTINELS': [('mysentinel.redis.example.com', 6379)], | ||
70 | # 'SENTINEL_SERVICE': 'netbox', | ||
71 | 'PASSWORD': '', | ||
72 | - 'DATABASE': 1, | ||
73 | + 'DATABASE': int(os.getenv("NETBOX_REDIS_CACHE_DB")), | ||
74 | 'SSL': False, | ||
75 | # Set this to True to skip TLS certificate verification | ||
76 | # This can expose the connection to attacks, be careful | ||
77 | @@ -57,7 +71,14 @@ | ||
78 | # For optimal security, SECRET_KEY should be at least 50 characters in length and contain a mix of letters, numbers, and | ||
79 | # symbols. NetBox will not run without this defined. For more information, see | ||
80 | # https://docs.djangoproject.com/en/stable/ref/settings/#std:setting-SECRET_KEY | ||
81 | -SECRET_KEY = '' | ||
82 | +vc = SimpleVaultClient( | ||
83 | + os.getenv("VAULT_ADDR"), | ||
84 | + os.getenv("VAULT_ROLE_ID"), | ||
85 | + os.getenv("VAULT_SECRET_ID"), | ||
86 | + ssl_verify=not _is_affirmative(os.getenv("VAULT_SKIP_VERIFY")) | ||
87 | +) | ||
88 | +SECRET_KEY = vc.get_kv_secret(os.getenv("NETBOX_VAULT_SECRET_NAME"), "key") | ||
89 | +del vc | ||
90 | |||
91 | |||
92 | ######################### | ||
diff --git a/netbox/configuration.py b/netbox/configuration.py new file mode 100644 index 0000000..9abd2aa --- /dev/null +++ b/netbox/configuration.py | |||
@@ -0,0 +1,30 @@ | |||
1 | import os | ||
2 | |||
3 | ALLOWED_HOSTS = ["*"] | ||
4 | |||
5 | DATABASE = { | ||
6 | 'NAME': os.getenv("NETBOX_DB_NAME"), | ||
7 | 'HOST': os.getenv("NETBOX_DB_HOST"), | ||
8 | 'PORT': int(os.getenv("NETBOX_DB_PORT")), | ||
9 | 'USER': os.getenv("NETBOX_DB_USERNAME"), | ||
10 | 'PASSWORD': os.getenv("NETBOX_DB_PASSWORD"), | ||
11 | 'SET_ROLE': os.getenv("NETBOX_SET_ROLE"), | ||
12 | 'CONN_MAX_AGE': 300, | ||
13 | } | ||
14 | |||
15 | REDIS = { | ||
16 | 'tasks': { | ||
17 | 'HOST': os.getenv("NETBOX_REDIS_HOST"), | ||
18 | 'PORT': 6379, | ||
19 | 'DATABASE': int(os.getenv("NETBOX_REDIS_TASK_DB")), | ||
20 | 'SSL': False, | ||
21 | }, | ||
22 | 'caching': { | ||
23 | 'HOST': os.getenv("NETBOX_REDIS_HOST"), | ||
24 | 'PORT': 6379, | ||
25 | 'DATABASE': int(os.getenv("NETBOX_REDIS_CACHE_DB")), | ||
26 | 'SSL': False, | ||
27 | } | ||
28 | } | ||
29 | |||
30 | SECRET_KEY = os.getenv("NETBOX_SECRET_KEY") | ||
diff --git a/netbox/django-driver.py b/netbox/django-driver.py deleted file mode 100644 index 80bfa13..0000000 --- a/netbox/django-driver.py +++ /dev/null | |||
@@ -1,77 +0,0 @@ | |||
1 | import threading | ||
2 | from datetime import datetime, timedelta | ||
3 | |||
4 | from django.core.exceptions import ImproperlyConfigured | ||
5 | from django.contrib.vault_client import SimpleVaultClient, Credential | ||
6 | from django.db.backends.postgresql.base import DatabaseWrapper as OrigWrapper | ||
7 | |||
8 | |||
9 | def _is_affirmative(value): | ||
10 | value = "" if not value else value | ||
11 | return value.lower() in ["yes", "true", "on", "1"] | ||
12 | |||
13 | |||
14 | def _must_get(store, key): | ||
15 | value = store.get(key) | ||
16 | |||
17 | if not value: | ||
18 | raise ImproperlyConfigured( | ||
19 | f"Database parameter {key} is required but not set.") | ||
20 | |||
21 | return value | ||
22 | |||
23 | |||
24 | class DatabaseWrapper(OrigWrapper): | ||
25 | |||
26 | def __init__(self, *args, **kwargs): | ||
27 | super().__init__(*args, **kwargs) | ||
28 | self._vault_cache_lock = threading.Lock() | ||
29 | self._vault_cred_cache = Credential.empty() | ||
30 | |||
31 | def close(self): | ||
32 | self._vault_cred_cache = Credential.empty() | ||
33 | super().close() | ||
34 | |||
35 | def close_if_unusable_or_obsolete(self): | ||
36 | super().close_if_unusable_or_obsolete() | ||
37 | |||
38 | if self.connection is None: | ||
39 | return | ||
40 | |||
41 | if not self.is_usable(): | ||
42 | self.close() | ||
43 | return | ||
44 | |||
45 | with self._vault_cache_lock: | ||
46 | if not self._vault_cred_cache.is_valid: | ||
47 | self.close() | ||
48 | |||
49 | # All of this is done under lock | ||
50 | def _get_vault_cred(self): | ||
51 | print("Getting credentials from vault") | ||
52 | params = self.settings_dict | ||
53 | |||
54 | verify = not _is_affirmative(params.get("VAULT_SKIP_VERIFY")) | ||
55 | url = _must_get(params, "VAULT_ADDR") | ||
56 | token = params.get("VAULT_TOKEN") | ||
57 | db_role_name = _must_get(params, "VAULT_DB_ROLE_NAME") | ||
58 | role_id = _must_get(params, "VAULT_ROLE_ID") | ||
59 | role_secret = _must_get(params, "VAULT_SECRET_ID") | ||
60 | |||
61 | client = SimpleVaultClient(url, role_id, role_secret, verify) | ||
62 | |||
63 | self._vault_cred_cache = client.get_db_credential(db_role_name) | ||
64 | |||
65 | def get_connection_params(self): | ||
66 | conn_params = super().get_connection_params() | ||
67 | |||
68 | # Do the fetch under lock to prevent multiple threads from piling onto | ||
69 | # the vault server | ||
70 | with self._vault_cache_lock: | ||
71 | if not self._vault_cred_cache.is_valid: | ||
72 | self._get_vault_cred() | ||
73 | |||
74 | conn_params["user"] = self._vault_cred_cache.username | ||
75 | conn_params["password"] = self._vault_cred_cache.password | ||
76 | |||
77 | return conn_params | ||
diff --git a/netbox/django-vault-client.py b/netbox/django-vault-client.py deleted file mode 100644 index 85b5671..0000000 --- a/netbox/django-vault-client.py +++ /dev/null | |||
@@ -1,88 +0,0 @@ | |||
1 | import os | ||
2 | import ssl | ||
3 | import json | ||
4 | from urllib import request, parse | ||
5 | from datetime import datetime, timedelta | ||
6 | |||
7 | |||
8 | class Credential: | ||
9 | |||
10 | def __init__(self, data): | ||
11 | self.username = data["data"]["username"] | ||
12 | self.password = data["data"]["password"] | ||
13 | |||
14 | # Leave 2 minutes in case we encounter a failure | ||
15 | _duration = timedelta(seconds=data["lease_duration"] - 120) | ||
16 | self.expires = datetime.now() + _duration | ||
17 | |||
18 | @classmethod | ||
19 | def empty(cls): | ||
20 | return cls({ | ||
21 | "lease_duration": -1, | ||
22 | "data": { "username": "", "password": "" } | ||
23 | }) | ||
24 | |||
25 | @property | ||
26 | def is_valid(self): | ||
27 | return self.expires > datetime.now() | ||
28 | |||
29 | |||
30 | |||
31 | class SimpleVaultClient: | ||
32 | |||
33 | def __init__(self, base_url, role_id, role_secret, ssl_verify=True): | ||
34 | self.base_url = base_url | ||
35 | self.ssl_verify = ssl_verify | ||
36 | self.role_id = role_id | ||
37 | self.role_secret = role_secret | ||
38 | |||
39 | env_token = os.getenv("VAULT_TOKEN") | ||
40 | if env_token: | ||
41 | self._token = env_token | ||
42 | self._token_expires = None # Token is assumed to never expire | ||
43 | else: | ||
44 | self._token = None | ||
45 | self._token_expires = datetime.now() + timedelta(seconds=-1) | ||
46 | |||
47 | def _login_approle(self, role_id, secret): | ||
48 | res = self._make_request("auth/approle/login", auth=False, data={ | ||
49 | "role_id": role_id, | ||
50 | "secret_id": secret, | ||
51 | }) | ||
52 | |||
53 | self._token = res["auth"]["client_token"] | ||
54 | self._token_expires = datetime.now() + \ | ||
55 | timedelta(seconds=res["auth"]["lease_duration"]) | ||
56 | |||
57 | @property | ||
58 | def _token_is_expired(self): | ||
59 | return self._token_expires and \ | ||
60 | self._token_expires < (datetime.now() + timedelta(seconds=120)) | ||
61 | |||
62 | def _auth_as_needed(self): | ||
63 | if self._token_is_expired: | ||
64 | self._login_approle(self.role_id, self.role_secret) | ||
65 | |||
66 | def _make_request(self, url, data=None, auth=True): | ||
67 | context = ssl._create_unverified_context() \ | ||
68 | if not self.ssl_verify else None | ||
69 | |||
70 | data = json.dumps(data).encode("utf-8") if data else None | ||
71 | headers = { "X-Vault-Token": self._token } if auth else {} | ||
72 | |||
73 | url = parse.urljoin(self.base_url, parse.urljoin("/v1/", url)) | ||
74 | req = request.Request(url, headers=headers, data=data) | ||
75 | res = request.urlopen(req, context=context) | ||
76 | |||
77 | if res.status != 200: | ||
78 | raise Exception("Failed to fetch credential from vault") | ||
79 | |||
80 | return json.load(res) | ||
81 | |||
82 | def get_kv_secret(self, path, key): | ||
83 | self._auth_as_needed() | ||
84 | return self._make_request(f"kv/data/{path}")["data"]["data"][key] | ||
85 | |||
86 | def get_db_credential(self, role): | ||
87 | self._auth_as_needed() | ||
88 | return Credential(self._make_request(f"database/creds/{role}")) | ||
diff --git a/netbox/entrypoint.sh b/netbox/entrypoint.sh deleted file mode 100755 index a4f844c..0000000 --- a/netbox/entrypoint.sh +++ /dev/null | |||
@@ -1,22 +0,0 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | set -e | ||
4 | |||
5 | cd "/opt/netbox" | ||
6 | |||
7 | # Apply any database migrations | ||
8 | /sbin/su-exec netbox python3 netbox/manage.py migrate | ||
9 | |||
10 | # Trace any missing cable paths (not typically needed) | ||
11 | /sbin/su-exec netbox python3 netbox/manage.py trace_paths --no-input | ||
12 | |||
13 | # Delete any stale content types | ||
14 | /sbin/su-exec netbox python3 netbox/manage.py remove_stale_contenttypes --no-input | ||
15 | |||
16 | # Delete any expired user sessions | ||
17 | /sbin/su-exec netbox python3 netbox/manage.py clearsessions | ||
18 | |||
19 | # Clear all cached data | ||
20 | /sbin/su-exec netbox python3 netbox/manage.py invalidate all | ||
21 | |||
22 | exec "$@" | ||
diff --git a/netbox/etc/service/netbox-rq/log/run b/netbox/etc/service/netbox-rq/log/run deleted file mode 100755 index 6193824..0000000 --- a/netbox/etc/service/netbox-rq/log/run +++ /dev/null | |||
@@ -1,3 +0,0 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | cat - | ||
diff --git a/netbox/etc/service/netbox-rq/run b/netbox/etc/service/netbox-rq/run deleted file mode 100755 index aa4b675..0000000 --- a/netbox/etc/service/netbox-rq/run +++ /dev/null | |||
@@ -1,23 +0,0 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | # runsv sends us a TERM but uwsgi will only shutdown cleanly | ||
4 | # if it receives an INT so we need to translate the signal | ||
5 | # properly for uwsgi | ||
6 | trap 'kill -INT $PID' TERM | ||
7 | |||
8 | /sbin/su-exec netbox /usr/bin/python3 /opt/netbox/netbox/manage.py rqworker & | ||
9 | |||
10 | PID=$! | ||
11 | |||
12 | # wait for uwsgi, will get cancelled when runsv TERMs us and | ||
13 | # the trap will get executed next, unless something goes wrong | ||
14 | # and uwsgi fails then this wait will run | ||
15 | wait $PID | ||
16 | |||
17 | # if something went wrong then unregister the trap because it | ||
18 | # won't have a target | ||
19 | trap - TERM | ||
20 | |||
21 | # waiting on a dead process will return the return code of the | ||
22 | # processes original exit | ||
23 | wait $PID | ||
diff --git a/netbox/etc/service/uwsgi/log/run b/netbox/etc/service/uwsgi/log/run deleted file mode 100755 index 6193824..0000000 --- a/netbox/etc/service/uwsgi/log/run +++ /dev/null | |||
@@ -1,3 +0,0 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | cat - | ||
diff --git a/netbox/etc/service/uwsgi/run b/netbox/etc/service/uwsgi/run deleted file mode 100755 index e24ede7..0000000 --- a/netbox/etc/service/uwsgi/run +++ /dev/null | |||
@@ -1,23 +0,0 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | # runsv sends us a TERM but uwsgi will only shutdown cleanly | ||
4 | # if it receives an INT so we need to translate the signal | ||
5 | # properly for uwsgi | ||
6 | trap 'kill -INT $PID' TERM | ||
7 | |||
8 | /usr/sbin/uwsgi --ini /etc/uwsgi/netbox.ini & | ||
9 | |||
10 | PID=$! | ||
11 | |||
12 | # wait for uwsgi, will get cancelled when runsv TERMs us and | ||
13 | # the trap will get executed next, unless something goes wrong | ||
14 | # and uwsgi fails then this wait will run | ||
15 | wait $PID | ||
16 | |||
17 | # if something went wrong then unregister the trap because it | ||
18 | # won't have a target | ||
19 | trap - TERM | ||
20 | |||
21 | # waiting on a dead process will return the return code of the | ||
22 | # processes original exit | ||
23 | wait $PID | ||
diff --git a/netbox/etc/uwsgi/netbox.ini b/netbox/netbox.ini index 8431c6f..8431c6f 100644 --- a/netbox/etc/uwsgi/netbox.ini +++ b/netbox/netbox.ini | |||
diff --git a/netbox/settings-patch.diff b/netbox/settings-patch.diff deleted file mode 100644 index 78510ad..0000000 --- a/netbox/settings-patch.diff +++ /dev/null | |||
@@ -1,11 +0,0 @@ | |||
1 | --- /opt/netbox/netbox/netbox/settings.py | ||
2 | +++ /opt/netbox/netbox/netbox/settings.py | ||
3 | @@ -147,7 +147,7 @@ | ||
4 | }) | ||
5 | else: | ||
6 | DATABASE.update({ | ||
7 | - 'ENGINE': 'django.db.backends.postgresql' | ||
8 | + 'ENGINE': 'django.db.backends.postgresqlvault' | ||
9 | }) | ||
10 | |||
11 | DATABASES = { | ||
diff --git a/netbox/settings.patch b/netbox/settings.patch new file mode 100644 index 0000000..1141d64 --- /dev/null +++ b/netbox/settings.patch | |||
@@ -0,0 +1,10 @@ | |||
1 | --- a/opt/netbox/netbox/netbox/settings.py 2022-11-30 13:14:00.000000000 -0800 | ||
2 | +++ b/opt/netbox/netbox/netbox/settings.py 2022-12-04 21:35:52.779482819 -0800 | ||
3 | @@ -302,6 +302,7 @@ | ||
4 | # | ||
5 | |||
6 | INSTALLED_APPS = [ | ||
7 | + 'postgresql_setrole', | ||
8 | 'django.contrib.admin', | ||
9 | 'django.contrib.auth', | ||
10 | 'django.contrib.contenttypes', | ||
diff --git a/netbox/simplevisor.json b/netbox/simplevisor.json new file mode 100644 index 0000000..666a765 --- /dev/null +++ b/netbox/simplevisor.json | |||
@@ -0,0 +1,69 @@ | |||
1 | { | ||
2 | "env": { | ||
3 | "pass": [ | ||
4 | "PATH", | ||
5 | "HOSTNAME", | ||
6 | "SHLVL", | ||
7 | "HOME", | ||
8 | "PWD", | ||
9 | |||
10 | "NETBOX_REDIS_TASK_DB", | ||
11 | "NETBOX_DB_HOST", | ||
12 | "NETBOX_DB_PORT", | ||
13 | "NETBOX_REDIS_HOST", | ||
14 | "NETBOX_DB_NAME", | ||
15 | "NETBOX_REDIS_CACHE_DB", | ||
16 | "NETBOX_DB_USERNAME", | ||
17 | "NETBOX_DB_PASSWORD", | ||
18 | "NETBOX_DELETE_LEGACY_DATA", | ||
19 | "NETBOX_SET_ROLE", | ||
20 | "NETBOX_SECRET_KEY" | ||
21 | ], | ||
22 | "vault-replace": [ | ||
23 | "NETBOX_DB_USERNAME", | ||
24 | "NETBOX_DB_PASSWORD", | ||
25 | "NETBOX_SECRET_KEY" | ||
26 | ] | ||
27 | }, | ||
28 | "jobs": { | ||
29 | "init": [ | ||
30 | { | ||
31 | "name": "migrate", | ||
32 | "cmd": ["/usr/bin/python3", "/opt/netbox/netbox/manage.py", "migrate"], | ||
33 | "run-as": "netbox" | ||
34 | }, | ||
35 | { | ||
36 | "name": "trace_paths", | ||
37 | "cmd": ["/usr/bin/python3", "/opt/netbox/netbox/manage.py", "trace_paths", "--no-input"], | ||
38 | "run-as": "netbox" | ||
39 | }, | ||
40 | { | ||
41 | "name": "remove_stale_contenttypes", | ||
42 | "cmd": ["/usr/bin/python3", "/opt/netbox/netbox/manage.py", "remove_stale_contenttypes", "--no-input"], | ||
43 | "run-as": "netbox" | ||
44 | }, | ||
45 | { | ||
46 | "name": "clearsessions", | ||
47 | "cmd": ["/usr/bin/python3", "/opt/netbox/netbox/manage.py", "clearsessions"], | ||
48 | "run-as": "netbox" | ||
49 | }, | ||
50 | { | ||
51 | "name": "clearcache", | ||
52 | "cmd": ["/usr/bin/python3", "/opt/netbox/netbox/manage.py", "clearcache"], | ||
53 | "run-as": "netbox" | ||
54 | } | ||
55 | ], | ||
56 | "main": [ | ||
57 | { | ||
58 | "name": "queue-worker", | ||
59 | "cmd": ["/usr/bin/python3", "/opt/netbox/netbox/manage.py", "rqworker"], | ||
60 | "run-as": "netbox" | ||
61 | }, | ||
62 | { | ||
63 | "cmd": ["/usr/sbin/uwsgi", "--ini", "/etc/uwsgi/netbox.ini"], | ||
64 | "kill-signal": "INT", | ||
65 | "run-as": "root" | ||
66 | } | ||
67 | ] | ||
68 | } | ||
69 | } | ||