Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Docs: Adds details to on how to set up a secure development environment #3111

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cookiecutter.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"cloud_provider": [
"AWS",
"GCP",
"nginx",
"None"
],
"mail_service": [
Expand Down
92 changes: 71 additions & 21 deletions docs/developing-locally-docker.rst
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,8 @@ The most important thing for us here now is ``env_file`` section enlisting ``./.

.envs
├── .local
│   ├── .django
│   └── .postgres
├── .django
└── .postgres
└── .production
├── .django
└── .postgres
Expand Down Expand Up @@ -200,12 +200,14 @@ By default, it's enabled both in local and production environments (``local.yml`

.. _`Flower`: https://github.com/mher/flower

Developing locally with HTTPS
-----------------------------
**Developing locally with HTTPS**
---------------------------------

Increasingly it is becoming necessary to develop software in a secure environment in order that there are very few changes when deploying to production. Recently Facebook changed their policies for apps/sites that use Facebook login which requires the use of an HTTPS URL for the OAuth redirect URL. So if you want to use the ``users`` application with a OAuth provider such as Facebook, securing your communication to the local development environment will be necessary.
It is becoming increasingly necessary to develop software in a secure environment so that there are very few changes when deploying to production. Many social media sites changed their policies for apps/sites that use their OAuth login features. They are now required the use of an HTTPS URL for the redirect URL even for ``localhost`` devloping and testing purposes.

On order to create a secure environment, we need to have a trusted SSL certficate installed in our Docker application.
So if you want to use the ``users`` application with a OAuth provider such as Facebook, securing your communication to the local development environment will be necessary.

On order to create a secure environment, we need to have a trusted SSL certficate installed in our development environment.

#. **Let's Encrypt**

Expand All @@ -219,20 +221,61 @@ On order to create a secure environment, we need to have a trusted SSL certficat

#. **mkcert: Valid Https Certificates For Localhost**

`mkcert`_ is a simple by design tool that hides all the arcane knowledge required to generate valid TLS certificates. It works for any hostname or IP, including localhost. It supports macOS, Linux, and Windows, and Firefox, Chrome and Java. It even works on mobile devices with a couple manual steps.
`mkcert`_ is a simple by design tool that hides all the arcane knowledge required to generate valid TLS certificates. It works for any hostname or IP, including ``localhost``. It supports macOS, Linux, and Windows, and Firefox, Chrome and Java. It even works on mobile devices with a couple manual steps.

See https://blog.filippo.io/mkcert-valid-https-certificates-for-localhost/

.. _`mkcert`: https://github.com/FiloSottile/mkcert/blob/master/README.md#supported-root-stores

After installing a trusted TLS certificate, configure your docker installation. We are going to configure an ``nginx`` reverse-proxy server. This makes sure that it does not interfere with our ``traefik`` configuration that is reserved for production environements.

These are the places that you should configure to secure your local environment.

certs
~~~~~

Take the certificates that you generated and place them in a folder called ``certs`` on the projects root folder. Assuming that you registered your local hostname as ``my-dev-env.local``, the certificates you will put in the folder should have the names ``my-dev-env.local.crt`` and ``my-dev-env.local.key``.
#. Generate TLS certificates with ``mkcert`` and place the certificates them in a folder in the django project root. We will call our folder ``certs``.

Assuming that you registered your local hostname as ``my-dev-env``, the certificates you will put in the folder should have the names ``my-dev-env.pem`` and ``my-dev-env-key.pem`` for the certificate and key respectively.

2. **NOTE:** Modify your ``/etc/hosts`` file to have ``my-dev-env`` as the domain you are serving traffic over HTTPS for. The entry should look something like this: ::

...
# Local HTTPS domain testing
127.0.0.1 my-dev-env
...

HTTPS on the local Python install
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

**Django SSL Server**

`django-sslserver`_ is a small library which adds the ability to run a secure debug server with the certificates we just created with ``mkcert``.

``pip install django-sslserver``

Update your ``config/settings/local.py``. ::

INSTALLED_APPS = (
...
'sslserver',
...
)
...
ALLOWED_HOSTS = ["localhost", "0.0.0.0", "127.0.0.1", "my-dev-env"]

For a particular port choice (ours is ``:8800``), in your terminal, run::

python manage.py runsslserver 0.0.0.0:8800 --certificate certs/my-dev-env.pem --key certs/my-dev-env-key.pem

You should see the secure connection *padlock* on the url ``https://my-dev-env:8800``.

For more information on this, visit `https://github.com/teddziuba/django-sslserver <https://github.com/teddziuba/django-sslserver>`_.

.. _`django-sslserver`: https://github.com/teddziuba/django-sslserver

HTTPS on the local Docker installation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Start by placing the ``certs`` folder in the project root. We will then configure an ``nginx`` container so as not to interfere with our ``traefik`` configuration that is reserved for the production environment. The plan is to copy the certificates into the ``nginx`` container that will then be the *reverse-proxy* to our django application.

These are the places that you should configure to secure your local environment.

local.yml
~~~~~~~~~
Expand All @@ -255,32 +298,39 @@ local.yml
- django

...
#. On the django service, confirm that you are connected to the ``envs`` files and remove/comment out the ``ports``. ::

...
env_file:
- ./.envs/.local/.django
...
# ports:
# - 8000:8000

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I followed these instructions and needed to keep this configuration in order to get local SSL to work.

...

#. Link the ``nginx-proxy`` to ``django`` through environmental variables.

``django`` already has an ``.env`` file connected to it. Add the following variables. You should do this especially if you are working with a team and you want to keep your local environment details to yourself.

::
``django`` already has an ``.envs/.local`` file connected to it. Add the following variables. You should do this especially if you are working with a team and you want to keep your local environment details to yourself. ::

# HTTPS
# ------------------------------------------------------------------------------
VIRTUAL_HOST=my-dev-env.local
# ----------------------
VIRTUAL_HOST=my-dev-env
VIRTUAL_PORT=8000

The services run behind the reverse proxy.
The django application and other services will now run behind the reverse proxy.

config/settings/local.py
~~~~~~~~~~~~~~~~~~~~~~~~

You should allow the new hostname. ::
You should *allow* the new hostname . ::

ALLOWED_HOSTS = ["localhost", "0.0.0.0", "127.0.0.1", "my-dev-env.local"]
ALLOWED_HOSTS = ["localhost", "0.0.0.0", "127.0.0.1", "my-dev-env"]

Rebuild your ``docker`` application. ::

$ docker-compose -f local.yml up -d --build

Go to your browser and type in your URL bar ``https://my-dev-env.local``
Go to your browser and type in your URL bar ``https://my-dev-env:8800``.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does the 8800 port apply to the Docker container approach?

I think this is a typo and meant for the Django SSL Server approach.


See `https with nginx`_ for more information on this configuration.

Expand Down
8 changes: 8 additions & 0 deletions docs/developing-locally.rst
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,14 @@ Sass Compilation & Live Reloading
If you’d like to take advantage of live reloading and Sass compilation you can do so with a little
bit of preparation, see :ref:`sass-compilation-live-reload`.

Use HTTPS on the local development environment
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If you are interested in securing your development evnvironment using TLS certificates, click `here`_ for the instructions.

.. _`here`: ../developing-locally-docker.rst#HTTPS on the local Docker installation


Summary
-------

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
FROM nginx:1.17.8-alpine
COPY ./compose/production/nginx/default.conf /etc/nginx/conf.d/default.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
server {
listen 80;
server_name localhost;
location /media/ {
alias /usr/share/nginx/media/;
}
}
2 changes: 2 additions & 0 deletions {{cookiecutter.project_slug}}/config/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,8 @@
# Django Admin URL.
ADMIN_URL = "admin/"
# https://docs.djangoproject.com/en/dev/ref/settings/#admins
# When more than one admin address is inserted, we need to create two tuples with
# the addresses looking like they should.
ADMINS = [("""{{cookiecutter.author_name}}""", "{{cookiecutter.email}}")]
# https://docs.djangoproject.com/en/dev/ref/settings/#managers
MANAGERS = ADMINS
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
"DJANGO_SECURE_CONTENT_TYPE_NOSNIFF", default=True
)

{% if cookiecutter.cloud_provider != 'None' -%}
{% if cookiecutter.cloud_provider != 'None' and cookiecutter.cloud_provider != 'nginx' -%}
# STORAGES
# ------------------------------------------------------------------------------
# https://django-storages.readthedocs.io/en/latest/#installation
Expand Down
18 changes: 18 additions & 0 deletions {{cookiecutter.project_slug}}/production.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,20 @@ volumes:
production_postgres_data: {}
production_postgres_data_backups: {}
production_traefik: {}
{%- if cookiecutter.cloud_provider == 'nginx' %}
production_django_media: {}
{%- endif %}

services:
django:{% if cookiecutter.use_celery == 'y' %} &django{% endif %}
build:
context: .
dockerfile: ./compose/production/django/Dockerfile
image: {{ cookiecutter.project_slug }}_production_django
{%- if cookiecutter.cloud_provider == 'nginx' %}
volumes:
- production_django_media:/app/{{ cookiecutter.project_slug }}/media
{%- endif %}
depends_on:
- postgres
- redis
Expand Down Expand Up @@ -77,3 +84,14 @@ services:
volumes:
- production_postgres_data_backups:/backups:z
{%- endif %}
{%- if cookiecutter.cloud_provider == 'nginx' %}
nginx:
build:
context: .
dockerfile: ./compose/production/nginx/Dockerfile
image: {{ cookiecutter.project_slug }}_local_nginx
depends_on:
- django
volumes:
- production_django_media:/usr/share/nginx/media:ro
{%- endif %}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
To understand why this file is here, please read:

http://cookiecutter-django.readthedocs.io/en/latest/faq.html#why-is-there-a-django-contrib-sites-directory-in-cookiecutter-django
https://cookiecutter-django.readthedocs.io/en/latest/faq.html#why-is-there-a-django-contrib-sites-directory-in-cookiecutter-django
"""
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
To understand why this file is here, please read:

http://cookiecutter-django.readthedocs.io/en/latest/faq.html#why-is-there-a-django-contrib-sites-directory-in-cookiecutter-django
https://cookiecutter-django.readthedocs.io/en/latest/faq.html#why-is-there-a-django-contrib-sites-directory-in-cookiecutter-django
"""