LoginSignup
1
0

こんにちは。
株式会社クラスアクト インフラストラクチャ事業部の大塚です。

この記事ではタイトルの通り、Let's Encryptで証明書を取得して、その取得した証明書を使ってDjangoをSSL化して、セキュアな通信環境を実現したいと思います。

OSはAmazon Linux 2023を使っております。
このOSにLet's Encrypy環境を作る方法は以下となります。

構築

Django環境構築

何度目かわかりませんが、Djangoをインストールしていきます。
Amazon Linux 2023ではPython3がデフォルトでインストールされていますが、pipがインストールされていないようなので、インストールしていきます。
その後、DjangoとSSL化するためのDjango-SSLServerをインストールします。

[ec2-user@ip-192-168-3-38 ~]$ sudo su -
Last login: Sat Jun 29 12:19:06 UTC 2024 on pts/1
[root@ip-192-168-3-38 ~]# dnf update && dnf upgrade -y
[root@ip-192-168-3-38 ~]# python3 -V
Python 3.9.16
[root@ip-192-168-3-38 ~]# pip -V
-bash: pip: command not found
[root@ip-192-168-3-38 ~]# pip3 -V
-bash: pip3: command not found
[root@ip-192-168-3-38 ~]# dnf install -y python3-pip
[root@ip-192-168-3-38 ~]# pip3 --version
pip 21.3.1 from /usr/lib/python3.9/site-packages/pip (python 3.9)
[root@ip-192-168-3-38 ~]# pip3 install django django-sslserver

適当にプロジェクトを作成します。settings.pyを編集してSSL化出来るようにします。

[root@ip-192-168-3-38 ~]# pwd
/root
[root@ip-192-168-3-38 ~]# django-admin startproject testPJ
[root@ip-192-168-3-38 ~]# ls -ltr
total 0
drwxr-xr-x. 3 root root 37 Jun 29 12:31 testPJ
[root@ip-192-168-3-38 ~]# cd testPJ/
[root@ip-192-168-3-38 testPJ]# ls -ltr
total 4
drwxr-xr-x. 2 root root  89 Jun 29 12:31 testPJ
-rwxr-xr-x. 1 root root 662 Jun 29 12:31 manage.py
[root@ip-192-168-3-38 testPJ]# cd testPJ/
[root@ip-192-168-3-38 testPJ]# ls -ltr
total 16
-rw-r--r--. 1 root root  389 Jun 29 12:31 wsgi.py
-rw-r--r--. 1 root root  762 Jun 29 12:31 urls.py
-rw-r--r--. 1 root root 3222 Jun 29 12:31 settings.py
-rw-r--r--. 1 root root  389 Jun 29 12:31 asgi.py
-rw-r--r--. 1 root root    0 Jun 29 12:31 __init__.py

以下がsettings.pyの内容となります。
★部分が修正したものになりますので、適宜ご確認ください。
特にこのコンフィグの最終行に追加したものがSSLの具体的な内容になるのですが、もっとセキュアにする方法があるようですので、今後勉強していきます。
今回は一旦SSL化することを目的に、いったん先に進みます。

[root@ip-192-168-3-38 testPJ]# vi settings.py
[root@ip-192-168-3-38 testPJ]# cat settings.py
from pathlib import Path

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-+!_r_y8za^1w$$@6b6azsmtwezxxnw)04opdb&0q#1f^5^7ouz'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = ["*"] ★


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'sslserver', ★
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'testPJ.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'testPJ.wsgi.application'


# Database
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}


# Password validation
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/4.2/topics/i18n/

LANGUAGE_CODE = 'ja' ★

TIME_ZONE = 'Asia/Tokyo' ★

USE_I18N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.2/howto/static-files/

STATIC_URL = 'static/'

# Default primary key field type
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

# 2024/6/29 add SSL Server ★
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SECURE_SSL_REDIRECT = False
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True

Djangoを稼働させて、いつものロケットの画面が表示されることを確認していきます。Djangoへのアクセスは一旦非セキュアなHTTPを使います。
ここで問題ないことを確認したらSSL化していきたいと思います。

[root@ip-192-168-3-38 testPJ]# python3 manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying sessions.0001_initial... OK
  
[root@ip-192-168-3-38 testPJ]# python3 manage.py runserver 0.0.0.0:80
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).
June 29, 2024 - 21:38:50
Django version 4.2.13, using settings 'testPJ.settings'
Starting development server at http://0.0.0.0:80/
Quit the server with CONTROL-C.

EC2のパブリックIPを指定してアクセスします。問題なさそうですね。
Untitled.png

DjangoのSSL化

改めてLet's Encrypで入手した証明書等を確認します。
これの証明書ファイル(fullchain.pem)と秘密鍵ファイル(privkey.pem)を使っていきます。

[root@ip-192-168-3-38 ~]# cd /etc/letsencrypt/live/ohtsuka-aws.xyz/
[root@ip-192-168-3-38 ohtsuka-aws.xyz]# ls -ltr
total 4
lrwxrwxrwx. 1 root root  42 Jun 28 07:17 privkey.pem -> ../../archive/ohtsuka-aws.xyz/privkey1.pem
lrwxrwxrwx. 1 root root  44 Jun 28 07:17 fullchain.pem -> ../../archive/ohtsuka-aws.xyz/fullchain1.pem
lrwxrwxrwx. 1 root root  40 Jun 28 07:17 chain.pem -> ../../archive/ohtsuka-aws.xyz/chain1.pem
lrwxrwxrwx. 1 root root  39 Jun 28 07:17 cert.pem -> ../../archive/ohtsuka-aws.xyz/cert1.pem
-rw-r--r--. 1 root root 692 Jun 28 07:17 README

以下のコマンドを実行してSSL化した上でDjangoを稼働させます。

[root@ip-192-168-3-38 testPJ]# python3 manage.py runsslserver 0.0.0.0:443 --certificate /etc/letsencrypt/live/ohtsuka-aws.xyz/fullchain.pem --key /etc/letsen
crypt/live/ohtsuka-aws.xyz/privkey.pem
Watching for file changes with StatReloader
Validating models...

System check identified no issues (0 silenced).
June 29, 2024 - 21:50:37
Django version 4.2.13, using settings 'testPJ.settings'
Starting development server at https://0.0.0.0:443/
Using SSL certificate: /etc/letsencrypt/live/ohtsuka-aws.xyz/fullchain.pem
Using SSL key: /etc/letsencrypt/live/ohtsuka-aws.xyz/privkey.pem
Quit the server with CONTROL-C.

HTTPSでEC2のパブリックIPを指定してブラウジングのテストをしてみます。証明書でエラーが出ていますね。
最初は少し焦ったのですが、よくよく考えるとドメイン名でサーバにアクセスしていないから「証明書違うっぽいけど大丈夫?」的な感じで警告を出してきているのかなと・・・
Untitled (1).png
Untitled (2).png
Untitled (3).png
これを修正するために、Route 53で管理しているAレコードを修正してドメイン名でDjangoのサーバにアクセスできるようにしていきます。
Untitled (4).png
ドメイン名でサーバに接続してみます。今度は警告など特に出ずにセキュアな通信が出来ていることがわかりますね。
Untitled (5).png

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0