pleins de questions sur le déploiement d’une application django

Amaury a marqué ce sujet comme résolu.

Bonjour,

Mon moteur de blog django étant à peu près terminé, j’aimerai profiter des vacances pour le mettre en ligne. Première fois pour moi.

J’ouvre un topic unique pour toutes mes questions sur le sujet. Je déterrerai au fur et à mesure que de nouvelles questions arrivent.

J’ai fait mes premiers tests dans une debian virtuelle cet après-midi, en suivant le tuto de zds. Ça à l’air de fonctionner. Je crois. J’ai pas réussi à accéder à mon site depuis mon navigateur, mais je ne suis pas sûr que le localhost soit le même sur mon ordi et sur la vm. Ça vient peut-être de là. Avec curl dans la machine virtuelle j’ai eu une erreur 400. Mais en même temps j’ai dû modifier un peu l’app pour faire le premier migrate, donc c’est peut-être pour ça. Je referai des tests demain.

Pour le moment j’ai quatre questions principales.

En regardant plusieurs tutos, j’ai vu que le répertoire d’installation n’est pas toujours le même. Sur ZdS, c’est /home/[username]/public_html/[appname]. Déjà à ce stade: lorsque je travaille dans le répertoire toto (pour l’exemple). Le virtual env est donc créer dans toto. Je demande ensuite à django de me créer une nouvelle application website, django crée un sous-répertoire website. puis ce site utilisera une application blog.

J’ai donc :

./
|->toto/
    |->env/
    |->website/
        |->settings.py
        |->wsgi.py
        |…
    |->blog/
        |->urls.py
        |->views.py
        |->admin.py
        |…
    |->manage.py
    |…

sur le tutoriel il semble que l’arborescence soit plus un truc du style :

./
|->public_html/
    |->website/
        |->env/
        |->settings.py
        |->wsgi.py
        |->manage.py
        |…
    |->blog  # Et lui je ne sais pas où il est censé se trouver
        |->urls.py
        |->views.py
        |->admin.py
        |…
    |…

ou peut-être

./
|->public_html/
    |->manage.py
    |->website/
        |->env/
        |->settings.py
        |->wsgi.py
        
        |…
    |->blog  # Et lui je ne sais pas où il est censé se trouver
        |->urls.py
        |->views.py
        |->admin.py
        |…
    |…

Du coup, je ne comprends pas trop comment est organisé le répertoire. public_html est-il le répertoire dans lequel il va mettre tout ses sites web (un dossier par site dans public_html) ? Où est-ce le projet django dans lequels il va mettre ses app ? Dans ce cas, il y a un environnement virtuel par application ?

Ensuite en regardant dans d’autres tutoriels il y en a aussi qui installent leur applications dans /django plutôt que dans `/home/[username]/

Question 1 : quelles sont les règles de bonnes pratiques, ou a défaut les avantages et inconvénients des différentes méthodes quand à l’organisation des répertoire du serveur ? Accessoirement, plusieurs tuto parles de créer un user www-data. Même question pour les utilisateurs.

Ensuite le fichier settings.prod :

Offuscation de la clé secrète : La méthode écrite dans la doc est simple à mettre en œuvre et vu que c’est la doc officielle, j’imagine qu’elle est fiable :

with open('/etc/secret_key.txt') as f:
    SECRET_KEY = f.read().strip()

Très bien.

Question 2 : est-ce une bonne pratique de faire la même chose pour le réglage de DATABASES. La doc dit « Vous devez les protéger aussi bien que SECRET_KEY » sans donner plus d’information. Je mets aussi le fichier dans /etc ?

Question 3 : une fois que ces deux opérations sont effectuées, est-ce que je peux considérer que mon fichier settings est safe ? Ça ne pose pas de problème s’il traîne sur gitlab ? Dans le cas contraire, ça signifie que je devrais le réediter à chaque git pull ou à minima mettre des information bidon lors du premier push, l’éditer sur le serveur, et ensuite l’ajouter à gitignore ?

Question 4 : mon projet en dev est sur gitlab. Y compris le fichier settings (version dev). Du coup la clé secrète n’est plus utilisable en production. Je peux mettre la clé que je veux (par exemple générée aléatoirement avec un autre logiciel) et juste éditer mon /etc/secret_key.txt, ou doit-elle correspondre à un paramètre de django pour être valide ?

J’aurai sûrement d’autres questions, mais on va déjà se concentrer sur ces quatre là.

Merci d’avance.

Question 1 : quelles sont les règles de bonnes pratiques, ou a défaut les avantages et inconvénients des différentes méthodes quand à l’organisation des répertoire du serveur ? Accessoirement, plusieurs tuto parles de créer un user www-data. Même question pour les utilisateurs.

Ça se discute, mais moi j’aime bien créer un utilisateur par site que j’héberge (membre du groupe www-data) et placer les fichiers python dans son home. Cet utilisateur n’étant pas administrateur, si malheur devait arriver, ça évite au moins qu’il aie accès au reste des projets. Le reste étant un peu de configuration côté NGINX.

Pour ce qui est du virtalenv, chez moi, c’est un part projet: si website/ et blog/ sont deux projets différents, il y aura 2 virtualenv (et … Deux utilisateurs, en vrai). Par contre, si c’est différentes partie d’un même site, ça va ensemble et le virtualenv est créé un cran plus haut.

Question 2 : est-ce une bonne pratique de faire la même chose pour le réglage de DATABASES. La doc dit « Vous devez les protéger aussi bien que SECRET_KEY » sans donner plus d’information. Je mets aussi le fichier dans /etc ?

À l’époque ou je travaillais dessus (dieu que ça a changé <3), Zeste de Savoir utilisait un fichier settings_prod.py, non versionné, qui était appellé de la manière suivante:

try:
    from settings_prod import *  # noqa
except ImportError:
    pass

Globalement, c’est ce fichier qui contenait toute la "vraie" config. Zeste de Savoir ayant changé de méthode, peut être qu’il existe une meilleure manière de faire.

Question 3 : une fois que ces deux opérations sont effectuées, est-ce que je peux considérer que mon fichier settings est safe ? Ça ne pose pas de problème s’il traîne sur gitlab ? Dans le cas contraire, ça signifie que je devrais le réediter à chaque git pull ou à minima mettre des information bidon lors du premier push, l’éditer sur le serveur, et ensuite l’ajouter à gitignore ?

Avec la manière de faire ci-dessus, il "suffit" de rajouter settings_prod.py au .gitignore.

Question 4 : mon projet en dev est sur gitlab. Y compris le fichier settings (version dev). Du coup la clé secrète n’est plus utilisable en production. Je peux mettre la clé que je veux (par exemple générée aléatoirement avec un autre logiciel) et juste éditer mon /etc/secret_key.txt, ou doit-elle correspondre à un paramètre de django pour être valide ?

Pour moi, le but du jeu est de t’arranger pour mettre assez d’infos bidons pour que quelqu’un qui veille t’aider puisse facilement installer son propre environnement de développement, quitte à suivre une procédure pour ce faire (forcer l’adresse et le port pour la base de donnée, etc).

Par exemple,

SECRET_KEY='une_clé_secrete'

path_secret = pathlib.Path('/etc/prod_secret.txt')
if path_secret.exists():
  with path_secret.open() as f:
    SECRET_KEY = f.read()

En faisant ça, tu t’assure que ça fonctionne quand même si quelqu’un n’a pas mis le fichier qui va bien pour la prod. Tu notera que ça revient un peut à la réponse à la question 2, mais que c’est une autre manière de faire.

+3 -0

Merci.

Pour la première question, c’est clair, et ça me parait propre.

Pour la deuxième question. La [doc officielle](https://docs.djangoproject.com/fr/4.1/howto/deployment/checklist/#secret-key] dit explicitement :

Au lieu d’inscrire statiquement la clé secrète dans votre module de réglages, envisagez de la charger à partir d’une variable d’environnement […] ou à partir d’un fichier

Du coup, je ne suis un peu perplexe. Si je comprends bien la manip sert uniquement à éviter que la clé traîne sur le dépôt git. Mais en soit, /etc/secret_key.txt n’est pas plus sécurisé que /home/user/website/settings.py ? Ça n’est pas une question de droits d’accès où quelque chose comme ça ?

Question 4 : je me suis peut-être mal exprimé. J’ai besoin d’une nouvelle clé secrète, celle générée lors de la création du projet n’étant actuellement plus secrète pour un sous. Est-ce que je peux mettre n’importe quoi (par exemple générer une clé avec keepass et copier coller dans le fichier de prod), ou est-ce qu’elle doit correspondre à quelque chose, par exemple une clé publique gérée par Django ?

Et question 5 : Est-ce que plusieurs projets peuvent récupérer le même /etc/secret_key.txt, ou est-ce qu’il faut à tout prix une clé par projet ?

+0 -0

Et retour à la question 1 :

j’ai créé un user avec sudo adduser -g www-data -m username. Lorsque je me connecte avec cet utilisateur, je peux créer un répertoir avec mkdir, cd et virtualenv, mais source env/bin/activate ne fonctionne pas (source not found). Alors qu’il fonctionne avec l’utilisateur admin. Why ?

Question 2 : est-ce une bonne pratique de faire la même chose pour le réglage de DATABASES. La doc dit « Vous devez les protéger aussi bien que SECRET_KEY » sans donner plus d’information. Je mets aussi le fichier dans /etc ?

À l’époque ou je travaillais dessus (dieu que ça a changé <3), Zeste de Savoir utilisait un fichier settings_prod.py, non versionné, qui était appellé de la manière suivante:

try:
    from settings_prod import *  # noqa
except ImportError:
    pass

Globalement, c’est ce fichier qui contenait toute la "vraie" config. Zeste de Savoir ayant changé de méthode, peut être qu’il existe une meilleure manière de faire.

Question 3 : une fois que ces deux opérations sont effectuées, est-ce que je peux considérer que mon fichier settings est safe ? Ça ne pose pas de problème s’il traîne sur gitlab ? Dans le cas contraire, ça signifie que je devrais le réediter à chaque git pull ou à minima mettre des information bidon lors du premier push, l’éditer sur le serveur, et ensuite l’ajouter à gitignore ?

Avec la manière de faire ci-dessus, il "suffit" de rajouter settings_prod.py au .gitignore.

pierre_24

Aujourd’hui, le système a un peu changé : on met les données sensibles dans un ficher TOML qui n’est, bien entendu, pas dans le dépôt (un modèle du fichier sans données sensibles est dispo ici). Elles sont chargées dans un fichier importé avant tous les autres réglages.

default_config_path = str(Path.cwd() / "config.toml")
config_path = os.environ.get("ZDS_CONFIG", default_config_path)

try:
    with open(config_path, "rb") as f:
        config = tomllib.load(f)
    print(f"Using the config file at {config_path!r}")
except OSError:
    config = {}

Ensuite, les autres fichiers peuvent utiliser config — c’est juste un dictionnaire classique. Dans les fichiers de dev, on l’utilise avec config.get("key", default) afin d’avoir des valeurs pour le dév même en l’absence de configuration (vu que dans un tel cas, cf. au dessus, on a un dictionnaire vide) ; dans la configuration de prod, on utilise la notation config["key"] car on veut que ça plante s’il manque une clef.

Ce n’est qu’une manière de faire, qui marche bien si on a pas mal d’options de configuration.

Une autre méthode, qui est très prisée ces temps-ci et d’autant plus avec l’avènement des hébergeurs cloud qui la rendent très pratique, est d’utiliser des variables d’environnement pour les données sensibles. On peut y accéder avec le module standard env (cf. code plus haut, ligne deux) et il est facile de les configurer dans le terminal courant avec export ou un fichier .env. De plus, tous les hébergeurs cloud permettent de configurer les variables d’environnement.


Pour la deuxième question. La [doc officielle](https://docs.djangoproject.com/fr/4.1/howto/deployment/checklist/#secret-key] dit explicitement :

Au lieu d’inscrire statiquement la clé secrète dans votre module de réglages, envisagez de la charger à partir d’une variable d’environnement […] ou à partir d’un fichier

Du coup, je ne suis un peu perplexe. Si je comprends bien la manip sert uniquement à éviter que la clé traîne sur le dépôt git. Mais en soit, /etc/secret_key.txt n’est pas plus sécurisé que /home/user/website/settings.py ? Ça n’est pas une question de droits d’accès où quelque chose comme ça ?

@1e49ba0eba

Non, en effet. Il tient à toi de sécuriser les accès à ton serveur. L’avantage de ne pas écrire la clef statiquement est d’éviter qu’elle soit dans le dépôt ; la question de sa sécurisation est séparée. Si les accès à ton serveur sont sécurisés, la mettre dans un fichier est OK (c’est ce qu’on fait sur ZdS). Avec certains hébergeurs, tu peux la mettre dans une variable d’environnement qui est stockée chiffrée et injectée uniquement sous forme de variable d’environnement, donc jamais stockée en clair. Ça dépend de ton hébergement, de sa fiabilité, de la fiabilité de ta gestion de la sécurité, et de tes contraintes.

Cette discussion sur StackOverflow peut donner des pistes de réflexion supplémentaires.

Question 4 : je me suis peut-être mal exprimé. J’ai besoin d’une nouvelle clé secrète, celle générée lors de la création du projet n’étant actuellement plus secrète pour un sous. Est-ce que je peux mettre n’importe quoi (par exemple générer une clé avec keepass et copier coller dans le fichier de prod), ou est-ce qu’elle doit correspondre à quelque chose, par exemple une clé publique gérée par Django ?

@1e49ba0eba

La clef secrète peut être n’importe quelle chaîne de caractère (ou même autre chose) ; cependant, il est conseillé de la générer comme un mot de passe, avec une source d’aléatoire fort, afin qu’elle soit difficilement devinable. Django vient avec un utilitaire pour générer une clef privée de qualité, utilisant les générateurs aléatoires cryptographiques de ton système si possible.

$ python manage.py shell

Python 3.10.9 (main, Dec 15 2022, 17:11:09) [Clang 14.0.0 (clang-1400.0.29.202)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)

>>> from django.core.management.utils import get_random_secret_key
>>> get_random_secret_key()
'3&@lll34+jzs$3fu1*@ox*u=v!kro9eh13ns=hr5(!n(&l34ek'

Si tu préfères, django-extensions, une collection d’outils pour étendre Django, permet d’exécuter cette même fonction avec une commande.

$ python manage.py generate_secret_key
^a0z7h+3ree8#n-e-yf3nv7!^6!38%#hzz_ze366t*cbkwgjb0

Et question 5 : Est-ce que plusieurs projets peuvent récupérer le même /etc/secret_key.txt, ou est-ce qu’il faut à tout prix une clé par projet ?

@1e49ba0eba

C’est possible, ça fonctionnera, mais ce n’est pas recommandé, afin que la compromission d’une clef ne compromette pas tous les projets d’un coup — de la même façon qu’il est déconseillé d’utiliser un même mot de passe sur plusieurs sites.

+1 -0

Et retour à la question 1 :

j’ai créé un user avec sudo adduser -g www-data -m username. Lorsque je me connecte avec cet utilisateur, je peux créer un répertoir avec mkdir, cd et virtualenv, mais source env/bin/activate ne fonctionne pas (source not found). Alors qu’il fonctionne avec l’utilisateur admin. Why ?

@1e49ba0eba

Est-ce que si tu exécutes la commande bash (ou zsh, ou un autre shell) en étant connecté·e avec cet utilisateur, source fonctionne ? Si oui, c’est probablement que ton utilisateur n’a pas de login shell, et donc que quand tu te connectes, tu as un terminal sans shell.

Le shell peut être configuré avec :

$ usermod -s /bin/zsh username  # ou /bin/bash, ou le shell que tu veux

…ou avec la même option -s directement passée à useradd.

+1 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte