arachnys / cabot

Self-hosted, easily-deployable monitoring and alerts service - like a lightweight PagerDuty
MIT License
5.58k stars 590 forks source link

How to create first user at setup time? #697

Closed jakubgs closed 3 years ago

jakubgs commented 3 years ago

When you setup the service the first time you try to access it you get taken to the setup screen to create the first user. What would be the canonical way of creating such a user in an automatic way at setup time?

I want to do this because I also want to use the REST API to create my services and checks at setup time using Ansible.

I noticed that there is an auth_user table in the PostgreSQL database:

cabot=# select id,last_login,is_active,is_superuser,is_staff,username,email from auth_user;
 id |          last_login           | is_active | is_superuser | is_staff | username |      email      
----+-------------------------------+-----------+--------------+----------+----------+-----------------
  1 | 2020-10-15 18:59:14.462219+00 | t         | t            | t        | admin    | admin@example.org

Would just INSERTing a user into that table at setup time be enough to get an admin user going, or would I have to do something extra? Or is there a better way of achieving the same result?

jakubgs commented 3 years ago

I see the password is hashed using pbkdf2_sha256 with 36000 iterations and using a salt. How can I find out the salt so I can inject the password correctly?

jakubgs commented 3 years ago

I think I found the correct way. The cabotapp/cabot Docker image exposes the django-admin command:

/ # django-admin --help

Type 'django-admin help <subcommand>' for help on a specific subcommand.

Available subcommands:

[auth]
    changepassword
    createsuperuser

...

I think using createsuperuser and changepassword via django-admin is the correct answer.

dbuxton commented 3 years ago

Yes that's correct

jakubgs commented 3 years ago

I tried running:

export DJANGO_SUPERUSER_PASSWORD=my-secret-password
django-admin createsuperuser --noinput --username admin --email admin@example.org

On my Cabot installation, but the password that ends up in the database doesn't look correct, and I can't login using it.

When I look in the database the password has a different format. Normally it looks like this:

pbkdf2_sha256$36000$aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=

But now I'm seeing something like this:

!aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

In the password column. Doesn't seem right.

jakubgs commented 3 years ago

@dbuxton can you reopen this?

I cannot get this to work using django-admin createsuperuser. Either it doesn't respect DJANGO_SUPERUSER_PASSWORD or the format of the password it puts into auth_user table is incorrect.

jakubgs commented 3 years ago

I have tried running the same command twice with the same value of DJANGO_SUPERUSER_PASSWORD but the resulting value in password column is different every time. I think its ignoring DJANGO_SUPERUSER_PASSWORD.

jakubgs commented 3 years ago

Oh, it appears Cabot is still using a quite old 1.11.11 version of Django from March 6, 2018:

/ # django-admin version
1.11.11

https://docs.djangoproject.com/en/3.1/releases/1.11.11/

And according to this comment the support for DJANGO_SUPERUSER_PASSWORD was added in 3.0:

As of Django 3.0 (per the docs) you can use the createsuperuser --no-input option and set the password with the DJANGO_SUPERUSER_PASSWORD environment variable, e.g. https://stackoverflow.com/a/59467275

jakubgs commented 3 years ago

Yep, the 1.11 documentation makes no reference to DJANGO_SUPERUSER_PASSWORD: https://docs.djangoproject.com/en/1.11/ref/django-admin/#createsuperuser

dbuxton commented 3 years ago

Right you are; it looks like you have to inject in some code like this:

echo "from django.contrib.auth.models import User; User.objects.create_superuser('admin', 'admin@example.com', 'pass')" | python manage.py shell
jakubgs commented 3 years ago

Yes, but where do I find manage.py? I can't find it in the Docker image:

/ # find / -iname 'manage.py'
find: /proc/tty/driver: Permission denied
/ # 
jakubgs commented 3 years ago

When I look in the module folder I see only the contents of the cabot subfolder of this repo:

/ # ls -l /usr/local/lib/python2.7/site-packages/cabot
total 144
-rw-r--r--    1 root     root           217 Jan 30  2019 __init__.py
-rw-r--r--    1 root     root           307 Jan 30  2019 __init__.pyc
-rw-r--r--    1 root     root          1361 Jan 30  2019 cabot_config.py
-rw-r--r--    1 root     root          1016 Jan 30  2019 cabot_config.pyc
drwxr-xr-x    6 root     root          4096 Jan 30  2019 cabotapp
-rw-r--r--    1 root     root           716 Jan 30  2019 celery.py
-rw-r--r--    1 root     root           974 Jan 30  2019 celery.pyc
-rw-r--r--    1 root     root           446 Jan 30  2019 celeryconfig.py
-rw-r--r--    1 root     root           616 Jan 30  2019 celeryconfig.pyc
-rw-r--r--    1 root     root           200 Jan 30  2019 context_processors.py
-rw-r--r--    1 root     root           461 Jan 30  2019 context_processors.pyc
-rw-r--r--    1 root     root           212 Jan 30  2019 entrypoint.py
-rw-r--r--    1 root     root           545 Jan 30  2019 entrypoint.pyc
-rw-r--r--    1 root     root          3868 Jan 30  2019 rest_urls.py
-rw-r--r--    1 root     root          3986 Jan 30  2019 rest_urls.pyc
-rw-r--r--    1 root     root         11436 Jan 30  2019 settings.py
-rw-r--r--    1 root     root          9903 Jan 30  2019 settings.pyc
-rw-r--r--    1 root     root           759 Jan 30  2019 settings_ldap.py
-rw-r--r--    1 root     root           858 Jan 30  2019 settings_ldap.pyc
-rw-r--r--    1 root     root           255 Jan 30  2019 settings_utils.py
-rw-r--r--    1 root     root           677 Jan 30  2019 settings_utils.pyc
drwxr-xr-x    4 root     root          4096 Jan 30  2019 templates
-rw-r--r--    1 root     root          8652 Jan 30  2019 urls.py
-rw-r--r--    1 root     root          8575 Jan 30  2019 urls.pyc
-rw-r--r--    1 root     root           141 Jan 30  2019 version.py
-rw-r--r--    1 root     root           311 Jan 30  2019 version.pyc
-rw-r--r--    1 root     root           165 Jan 30  2019 wsgi.py
-rw-r--r--    1 root     root           349 Jan 30  2019 wsgi.pyc

So it looks to me like manage.py is just not included in the image.

jakubgs commented 3 years ago

It appears that cabotapp/cabot image is not created from the Dockerfile in this repo but rather this one: https://github.com/cabotapp/docker-cabot/blob/master/Dockerfile

jakubgs commented 3 years ago

I've opened an issue with them about missing manage.py: https://github.com/cabotapp/docker-cabot/issues/43

They have had that mentioned before in https://github.com/cabotapp/docker-cabot/issues/1 but they got around by doing migrations using cabot migrate.

jakubgs commented 3 years ago

Actually, the contents of /usr/local/bin/django-admin are quite similar to manage.py:

/ # cat /usr/local/bin/django-admin
#!/usr/local/bin/python

# -*- coding: utf-8 -*-
import re
import sys

from django.core.management import execute_from_command_line

if __name__ == '__main__':
    sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
    sys.exit(execute_from_command_line())
jakubgs commented 3 years ago

It works!

/ # django-admin shell
Python 2.7.15 (default, Dec 21 2018, 03:51:20) 
[GCC 6.4.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from django.contrib.auth.models import User
>>> User.objects.create_superuser('admin', 'admin@example.com', 'pass')
<User: admin>

And I was able to log in.

Thanks for help @dbuxton !