collectstatic files chown'ed by root

909 views
Skip to first unread message

Tim

unread,
Feb 14, 2022, 9:05:33 AM2/14/22
to Django users
Hi all,
I'm deploying Django 4 via docker-compose. For security reasons, the Dockerfile creates a non-root user before running the entrypoint.sh script (which does migrations, collectstatic and starts the server with gunicorn). All app files are "chown"ed by this non-root user.

Everything works fine except for the collectstatic command (in entrypoint.sh), which creates the "staticfiles" directory but it's owned by root. This leads to permission denied errors when the collectstatic command tries to delete a static file.

My question: Why does collectstatic assign the folder to "root" despite the non-root user calling the collectstatic command? How to prevent this?

I tried doing the collectstatic command before switching to the non-root user (in the Dockerfile) which works. But it stops working when I put the Django SECRET_KEY in a .env file (as we should in production) since this env var is not available during docker build time.

Now I could find a hackier way by making the secret key available during build time or switching back to a root user in entrypoint.sh, but all of this is a bad workaround in my opinion.

I'm sure everyone deploying Django with docker and being mindful of security has come across this - Any hints about why collectstatic is owned by root? Is this a bug?

Should I add additional details?

Thanks for any tips!
Tim

Mike Dewhirst

unread,
Feb 14, 2022, 5:44:56 PM2/14/22
to django...@googlegroups.com
On 14/02/2022 10:14 pm, 'Tim' via Django users wrote:
> Hi all,
> I'm deploying Django 4 via docker-compose. For security reasons, the
> Dockerfile creates a non-root user before running the entrypoint.sh
> script (which does migrations, collectstatic and starts the server
> with gunicorn). All app files are "chown"ed by this non-root user.

I seem to remember from a long ago release note or other documentation
that making dirs was changed to replicate what Linux does. Which is that
parent dirs take the system defaults while the created dir takes
ownership/mode from the user

You might need to create directories one at a time with the appropriate
mode to suit your purposes.

>
> Everything works fine except for the collectstatic command (in
> entrypoint.sh), which creates the "staticfiles" directory but it's
> owned by root. This leads to permission denied errors when the
> collectstatic command tries to delete a static file.
>
> My question: Why does collectstatic assign the folder to "root"
> despite the non-root user calling the collectstatic command? How to
> prevent this?
>
> I tried doing the collectstatic command before switching to the
> non-root user (in the Dockerfile) which works. But it stops working
> when I put the Django SECRET_KEY in a .env file (as we should in
> production) since this env var is not available during docker build time.
>
> Now I could find a hackier way by making the secret key available
> during build time or switching back to a root user in entrypoint.sh,
> but all of this is a bad workaround in my opinion.
>
> I'm sure everyone deploying Django with docker and being mindful of
> security has come across this - Any hints about why collectstatic is
> owned by root? Is this a bug?
>
> Should I add additional details?
>
> Thanks for any tips!
> Tim
> --
> You received this message because you are subscribed to the Google
> Groups "Django users" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to django-users...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/django-users/c3381f62-4bf1-4142-b27f-189ef45a75fan%40googlegroups.com
> <https://groups.google.com/d/msgid/django-users/c3381f62-4bf1-4142-b27f-189ef45a75fan%40googlegroups.com?utm_medium=email&utm_source=footer>.


--
Signed email is an absolute defence against phishing. This email has
been signed with my private key. If you import my public key you can
automatically decrypt my signature and be sure it came from me. Just
ask and I'll send it to you. Your email software can handle signing.

OpenPGP_signature

Antonis Christofides

unread,
Feb 15, 2022, 1:51:42 AM2/15/22
to django...@googlegroups.com

Everything works fine except for the collectstatic command (in entrypoint.sh), which creates the "staticfiles" directory but it's owned by root.

This is not possible. If "manage.py" is running as a non-root user, it wouldn't be possible for it to create a directory owned by root. Something else is going on. Could you share your entrypoint.sh script?

Antonis Christofides
+30-6979924665 (mobile)
--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.

Derek

unread,
Feb 15, 2022, 12:48:41 PM2/15/22
to Django users
I literally spent the last few days trying to fix this same issue (apart from your "Django SECRET_KEY in a .env file" problem, which I don't understand as it does not seem related).

There are numerous suggestions on Stack Overflow and various blogs; which either don't work or are too complex to understand and implement.

What worked for me was:

1. Using the default, non-root user (in my case called "django")  to create and set permissions on a 'staticfiles' directory as part of the Django container build
2. NOT setting a default, non-root user at the end of the Dockerfile used for the Django container build
3. Adding these lines to the end of the 'entrypoint' script:
chown -R django:django /app/staticfiles
exec runuser -u django "$@"
4. Adding the "python /app/manage.py collectstatic --noinput" command into the "start" script

In my case (you did not state yours) the staticfiles directory is mounted outside the container, and the same outside mount point is also accessed by the nGinx container to serve the static files.

Many folks have also commented about "hackiness" in this process, but it comes down to file permissions in Docker not being independent of those in the host; and there is a LOT of reading around that if you want to dig into it. IMO, its not a "workaround" if you just actually do need to work with multiple permissions at different points in a process.

HTH
Derek




Tim

unread,
Feb 16, 2022, 3:42:51 AM2/16/22
to Django users
Thanks a lot for your input, it helped me figure it out!

Antonis, you're right, it's basically not possible that those files are owned by root when manage.py is run as "user". This gave me the clue that those directories (and many of the staticfiles) were created at a time before I switched to a non-root user in the Dockerfile. With a fresh staticfiles directory (nginx accesses it too), everything worked perfectly and everything's owned by the non-root user.

In the production environment, I'll have to change the permissions of that folder manually once (I think) and it should work there too.
Reply all
Reply to author
Forward
0 new messages