Skip to content

Commit 8e5a172

Browse files
authored
Force the admin password from CM_INITIAL_ADMIN_PASS on every boot (#24)
Upstream scripts/docker/create_superuser.py only acts when no superuser exists. Every VFB instance boots by restoring a *.pgsql dump that already contains superusers, so that check always fails and CM_INITIAL_ADMIN_PASS is silently ignored - the admin password is whatever the dump happened to carry. It has therefore never been applied to any seeded instance, and the passwords have drifted apart (l1em no longer matches the others). Postgres data lives inside the container and only /backup persists, so a manual correction is wiped on the next recreate. Reapplying on boot is the only durable fix. modify_superuser.py now reads CM_INITIAL_ADMIN_USER/CM_INITIAL_ADMIN_PASS instead of carrying a hardcoded password hash, and is idempotent: it writes only when the password or the staff/active flags actually differ, and is a no-op when the variable is unset or the user does not exist. init.sh invokes it in the background, since catmaid-entry.sh never returns, polling for up to 10 minutes while the fixture loads and the database comes up. Loaders are unaffected - they start from an empty /backup, so upstream create_superuser.py already applies the variable correctly there.
1 parent 0e9edfa commit 8e5a172

2 files changed

Lines changed: 65 additions & 3 deletions

File tree

‎init.sh‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,30 @@ tail -F /var/log/postgresql/postgresql-11-main.log &
1212
# is set. No-op when empty. Idempotent across container restarts.
1313
python3 /opt/VFB/inject_gtm.py || echo "inject_ga: non-fatal failure, continuing"
1414

15+
# Force the admin password to match CM_INITIAL_ADMIN_PASS.
16+
#
17+
# Upstream create_superuser.py only creates a superuser when none exists, so on
18+
# an instance restored from a /backup dump it does nothing and the environment
19+
# variable is silently ignored - the admin password stays whatever the dump
20+
# carried. Postgres data lives inside the container, so a manual fix is lost on
21+
# the next recreate; this reapplies it on every boot.
22+
#
23+
# catmaid-entry.sh below never returns, so wait for the database in the
24+
# background. modify_superuser.py is idempotent and a no-op when the password
25+
# already matches or CM_INITIAL_ADMIN_PASS is unset.
26+
(
27+
cd /home/django/projects || exit 0
28+
for _ in $(seq 1 120); do
29+
if printf '\n\n' | cat /opt/VFB/modify_superuser.py - \
30+
| /home/env/bin/python manage.py shell 2>/dev/null \
31+
| grep '^modify_superuser:'; then
32+
exit 0
33+
fi
34+
sleep 5
35+
done
36+
echo "modify_superuser: database not ready after 10 minutes, giving up" >&2
37+
) &
38+
1539
if [ -e /backup/*.pgsql ]
1640
then
1741
export DB_FIXTURE=true

‎modify_superuser.py‎

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,42 @@
1+
# -*- coding: utf-8 -*-
2+
# Force CATMAID's admin account to the password given in the environment.
3+
#
4+
# Upstream scripts/docker/create_superuser.py only acts when NO superuser
5+
# exists:
6+
#
7+
# if User.objects.filter(is_superuser=True).count() == 0:
8+
# User.objects.create_superuser(...)
9+
#
10+
# Every VFB instance boots by restoring a *.pgsql dump that already contains
11+
# superusers, so that check always fails and CM_INITIAL_ADMIN_PASS is silently
12+
# ignored. The admin password is then whatever the dump happened to carry,
13+
# which drifts per instance and cannot be corrected durably by setting the
14+
# environment variable.
15+
#
16+
# This script closes that gap. It is idempotent: it only writes when the
17+
# password (or the staff/active flags) actually differ, so a boot that is
18+
# already correct touches nothing.
19+
#
20+
# Piped into `manage.py shell` by init.sh; the file needs a trailing blank
21+
# line so the input stream ends cleanly.
22+
import os
23+
124
from django.contrib.auth.models import User
2-
user = User.objects.get(username='admin')
3-
user.password=u'pbkdf2_sha256$24000$OlTY7BRHr07a$Pw2rmvcwaFAx0o/ogfagwptO9/R4PtmoA407MNFYUSU='
4-
user.save()
25+
26+
admin_user = os.environ.get('CM_INITIAL_ADMIN_USER', 'admin')
27+
admin_pass = os.environ.get('CM_INITIAL_ADMIN_PASS')
28+
29+
if not admin_pass:
30+
print('modify_superuser: CM_INITIAL_ADMIN_PASS is not set, leaving the password unchanged')
31+
else:
32+
user = User.objects.filter(username=admin_user).first()
33+
if user is None:
34+
print('modify_superuser: no user %r on this instance, nothing to do' % admin_user)
35+
elif user.check_password(admin_pass) and user.is_staff and user.is_active:
36+
print('modify_superuser: %r already matches the environment, no change' % admin_user)
37+
else:
38+
user.set_password(admin_pass)
39+
user.is_staff = True
40+
user.is_active = True
41+
user.save()
42+
print('modify_superuser: reset the password for %r from the environment' % admin_user)

0 commit comments

Comments
 (0)