6.1 ユーザーの認証と認可
この段階では、マルチコンテナアプリケーションのセキュリティとアクセス管理をどのように確保するかについて説明するよ。これには、ユーザーの認証、データ暗号化、APIの保護、サービス間の安全な接続の設定が含まれるんだ。
目的: 登録済みの認証されたユーザーだけがアプリケーションとやり取りして操作を実行できるようにすること。
JWT (JSON Web Token) を使った認証の実装
ステップ 1. 必要なライブラリのインストール:
pip install Flask-JWT-Extended
ステップ 2. FlaskアプリでJWTの設定:
次の変更をbackend/app/__init__.py
ファイルに追加してね:
from flask_jwt_extended import JWTManager
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://taskuser:taskpassword@database:5432/taskdb'
app.config['JWT_SECRET_KEY'] = 'your_jwt_secret_key' # あなたの秘密鍵に置き換えてね
db = SQLAlchemy(app)
jwt = JWTManager(app)
from app import routes
ステップ 3. 登録と認証用のルートを作成:
次のルートをbackend/app/routes.py
ファイルに追加してね:
from flask_jwt_extended import create_access_token, jwt_required, get_jwt_identity
from werkzeug.security import generate_password_hash, check_password_hash
from app.models import User, Task
@app.route('/register', methods=['POST'])
def register():
data = request.get_json()
hashed_password = generate_password_hash(data['password'], method='sha256')
new_user = User(username=data['username'], password=hashed_password)
db.session.add(new_user)
db.session.commit()
return jsonify({'message': 'ユーザーが正常に登録されました'}), 201
@app.route('/login', methods=['POST'])
def login():
data = request.get_json()
user = User.query.filter_by(username=data['username']).first()
if not user or not check_password_hash(user.password, data['password']):
return jsonify({'message': '資格情報が無効です'}), 401
access_token = create_access_token(identity=user.id)
return jsonify({'access_token': access_token}), 200
@app.route('/tasks', methods=['GET'])
@jwt_required()
def get_tasks():
current_user_id = get_jwt_identity()
tasks = Task.query.filter_by(owner_id=current_user_id).all()
return jsonify([task.to_dict() for task in tasks])
ステップ 4. パスワードを保存するためのUserモデルの更新:
backend/app/models.py
ファイルを更新してね:
from app import db
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
password = db.Column(db.String(120), nullable=False)
tasks = db.relationship('Task', backref='owner', lazy=True)
6.2 データの暗号化
目的: クライアントとサーバー間のデータ転送を保護すること。
HTTPSの使用
ステップ1. HTTPSをサポートするリバースプロキシとしてNginxを設定:
プロジェクトのルートディレクトリにnginx.conf
ファイルを作成する:
server {
listen 80;
server_name your_domain.com;
location / {
proxy_pass http://frontend:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /api {
proxy_pass http://backend:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
ステップ2. Nginx用のDockerfileを作成:
nginx
ディレクトリにDockerfile
ファイルを作成する:
FROM nginx:latest
COPY nginx.conf /etc/nginx/nginx.conf
ステップ3. compose.yaml
にNginxを追加:
Nginxサービスを追加するためにcompose.yaml
ファイルを更新する:
version: '3'
services:
frontend:
build: ./frontend
ports:
- "3000:3000"
networks:
- task-network
backend:
build: ./backend
ports:
- "5000:5000"
depends_on:
- database
networks:
- task-network
environment:
- DATABASE_URL=postgresql://taskuser:taskpassword@database:5432/taskdb
database:
image: postgres:13
environment:
- POSTGRES_DB=taskdb
- POSTGRES_USER=taskuser
- POSTGRES_PASSWORD=taskpassword
networks:
- task-network
volumes:
- db-data:/var/lib/postgresql/data
nginx:
build: ./nginx
ports:
- "80:80"
depends_on:
- frontend
- backend
networks:
- task-network
networks:
task-network:
driver: bridge
volumes:
db-data:
6.3 Let's EncryptでSSL証明書を取得する
ステップ1. Certbotのインストール:
Certbotをインストールするには、Certbotの公式サイトの指示に従ってね。
ステップ2. 証明書を取得する:
sudo certbot certonly --standalone -d your_domain.com
ステップ3. NginxをSSL対応に設定する:
nginx.conf
を更新してSSLを使用するように設定する:
server {
listen 80;
server_name your_domain.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name your_domain.com;
ssl_certificate /etc/letsencrypt/live/your_domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your_domain.com/privkey.pem;
location / {
proxy_pass http://frontend:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /api {
proxy_pass http://backend:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
ステップ4. Nginx用のDockerfileを更新して証明書をコピーする:
FROM nginx:latest
COPY nginx.conf /etc/nginx/nginx.conf
COPY /etc/letsencrypt /etc/letsencrypt
6.4 APIの保護
目的: APIへのアクセスを制限し、不正なリクエストを防ぐこと。
JWTを使用したルートの保護
すでに、@jwt_required()
デコレーターを使用してタスクリスト用ルートの保護を追加しました。このデコレーターで、すべての機密ルートを保護していることを確認してください:
from flask_jwt_extended import jwt_required, get_jwt_identity
@app.route('/tasks', methods=['GET'])
@jwt_required()
def get_tasks():
current_user_id = get_jwt_identity()
tasks = Task.query.filter_by(owner_id=current_user_id).all()
return jsonify([task.to_dict() for task in tasks])
データベースアクセスの制限
目的: 不正なデータベースアクセスを防ぐこと。
ロールと特権の設定
ステップ 1. 制限付き権限を持つユーザーの作成:
CREATE USER limited_user WITH PASSWORD 'limited_password';
GRANT CONNECT ON DATABASE taskdb TO limited_user;
GRANT USAGE ON SCHEMA public TO limited_user;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO limited_user;
ステップ 2. 環境変数 DATABASE_URL
の更新:
compose.yaml
ファイル内の環境変数DATABASE_URL
を更新します:
environment:
- DATABASE_URL=postgresql://limited_user:limited_password@database:5432/taskdb
GO TO FULL VERSION