ElastiCache for Memcached を使用し、Web サービスでログイン機能を構築してみた

ElastiCache for Memcached を使用し、Web サービスでログイン機能を構築してみた

Clock Icon2025.01.21

こんにちは!よしななです。
今回は、ElastiCache for Memcached を使用し、Web サービスでよくあるログイン機能を構築したいと思います。

目次

  • やりたいこと
  • 構成図と使用サービスについて
  • AWS 上の準備
    • VPC 作成
    • Security Group 作成
    • EC2 起動
    • RDS 起動とデータ投入
    • ElastiCache for Memcached 起動
  • Python・HTML の実装
  • 実行してみる
  • 最後に
  • 参考

やりたいこと

今回やりたいことは、ElastiCache for Memcached を使用し、ログイン機能を構築してみたいと思います。

構成図と使用サービスについて

今回構築するログイン機能の構成図は以下の通りです。
EC2 をパブリックサブネットに配置し、RDS と ElastiCache for Memcached はプライベートサブネットに配置します。

login

以下のサービスを使用します。

  • Amazon EC2
    • Flask アプリケーションをデプロイする環境
  • ElastiCache for Memcached
    • ログインしたセッション状態をキャッシュ(一時保存)しておく場所
    • 一度目のログインは RDS からパスワードとユーザーIDを取得しログインし、2回目以降のログインは ElastiCache for Memcached のセッション情報を利用する
  • Amazon RDS
    • Postgre を使用
    • ログインパスワードを保管しておくための場所
  • VPC
  • Security Group
    • EC2、RDS、ElastiCacheにアタッチ

AWS 上の準備

それでは、ログイン機能を構築するために AWS 上での準備を行います。

VPC 作成

Monosnap CreateVpc | VPC Console 2025-01-17 16-31-05

まずは、リソースを作成する VPC 空間を作成します。
以下の通り設定します。

  • 名前タグ:任意の名前
  • IPv4 CIDR:10.0.0.0/16
  • IPv6 CIDR ブロックはなし
  • タグ
    • キー:Name
    • 値:任意の名前

Security Group 作成

次に、EC2、RDS、ElastiCache に付与するための Security Group を作成します。

EC2 Security Group

インターネット(HTTP) / ローカル環境(SSH)から EC2 インスタンスに接続できるように22、80番ポートを開放しインバウンドルールを作成します。
EC2 インスタンス側から ElastiCache / インターネット(HTTP)に接続できるように11211番ポートとすべてのトラフィックを開放しアウトバウンドルールを作成します。

Monosnap CreateSecurityGroup | EC2 | ap-northeast-1 2025-01-21 11-56-59

  • セキュリティグループ名:任意の名前
  • 説明:任意の名前
  • VPC:上記で作成した VPC を入力
  • インバウンドルール
    • インバウンドルール1
      • タイプ:TCP
      • ポート範囲:22
      • ソース:マイIP(ローカルPCのIPアドレス)
    • インバウンドルール2
      • タイプ:HTTP
      • ポート範囲:80
      • ソース:0.0.0.0/0
  • アウトバウンドルール
    • アウトバウンドルール1
      • タイプ:カスタムTCP
      • ポート範囲:11211
      • ソース:作成した ElastiCache のセキュリティグループ任意の名前
    • アウトバウンドルール2
      • タイプ:すべてのトラフィック
      • ポート範囲:すべて
      • ソース:0.0.0.0/0
  • タグ
    • キー:Name
    • 値:任意の名前

RDS Security Group

EC2 インスタンスからのアクセスを許可するようにインバウンドルールを作成します。
RDS インスタンスから外側へのアクセスを許可するようにアウトバウンドルールを作成します。

  • セキュリティグループ名:任意の名前
  • 説明:任意の名前
  • VPC:上記で作成した VPC を入力
  • インバウンドルール
    • インバウンドルール1
      • タイプ:PostgreSQL
      • ポート範囲:5432
      • ソース:作成した EC2 のセキュリティグループ任意の名前
  • アウトバウンドルール
    • アウトバウンドルール1
      • タイプ:すべてのトラフィック
      • ポート範囲:すべて
      • ソース:0.0.0.0/0
  • タグ
    • キー:Name
    • 値:任意の名前

ElastiCache Security Group

  • セキュリティグループ名:任意の名前
  • 説明:任意の名前
  • VPC:上記で作成した VPC を入力
  • インバウンドルール
    • インバウンドルール1
      • タイプ:カスタムTCP
      • ポート範囲:11211
      • ソース:作成した EC2 のセキュリティグループ任意の名前
  • アウトバウンドルール
    • アウトバウンドルール1
      • タイプ:すべてのトラフィック
      • ポート範囲:すべて
      • ソース:0.0.0.0/0
  • タグ
    • キー:Name
    • 値:任意の名前

EC2 起動

次に、作成したセキュリティグループを使用して EC2 インスタンスを起動します。

Monosnap インスタンスを起動 | EC2 | ap-northeast-1 2025-01-21 15-46-25

  • 名前:任意の名前
  • アプリケーションおよび OS イメージ (Amazon マシンイメージ)
    • アーキテクチャ:64ビット(Arm)
  • インスタンスタイプ:t4g.nano
  • キーペア(ログイン)
    • 新しいキーペアの作成をクリックし、キーペア作成
    • キーペア名:任意の名前
    • キーペアのタイプ:RSA
    • プライベートキーペアファイル形式:.pem
  • ネットワーク設定
    • ネットワーク:作成した VPC 名を選択
    • サブネット:パブリックサブネットを選択
    • パブリックIPの自動割り当て:有効化
    • ファイアウォール(セキュリティグループ):既存のセキュリティグループを選択、先ほど作成した任意の名前をアタッチ
  • タグ
    • キー:Name
    • 値:任意の名前

その他はデフォルトで作成

ローカル環境から作成した EC2 に接続

以下の手順でローカル環境から作成した EC2 インスタンスに接続します。

  • 作成したキーペアをダウンロードし、作業ディレクトリに移動させる
  • chmod 400 "任意の名前.pem"を実行し、キーが公開されていないことを確認
  • 作成したキーペアのキーを~/.ssh/ファイルの配下に格納
    • scpコマンドを使用するのが楽
  • ssh コマンドをターミナルから実行
    • ssh -i "任意の名前.pem" ec2-user@"パブリック IPv4 DNS"を実行
  • 以下の画面が出力されれば接続成功

20230715223507

RDS 起動とデータ投入

次に、RDS を起動します。

サブネットグループの作成

RDS にアタッチするサブネットグループを作成します。

Monosnap RDS | ap-northeast-1 2025-01-21 16-32-33

  • 名前:任意の名前
  • 説明:任意の名前
  • VPC:上記で作成した VPC 名を入力する
  • サブネットを追加
    • アベイラビリティゾーン:選択した VPC に紐づいているアベイラビリティゾーンを選択
    • サブネット:プライベートサブネットを選択
  • タグ
    • キー:Name
    • 値:任意の名前

パラメータグループの指定

RDS にアタッチするパラメーターグループを作成します。

Monosnap RDS | ap-northeast-1 2025-01-21 17-02-02

  • パラメータグループ名:任意の名前
  • 説明:任意の名前
  • エンジンのタイプ:PostgreSQL
  • パラメータグループファミリー:Postgres16
  • タグ
    • キー:Name
    • 値:任意の名前

RDS の起動

作成したパラメータグループ、サブネットグループを使用して RDS を起動します。

  • データベース作成方法を選択:標準作成
  • エンジンのオプション:PostgreSQL
  • エンジンバージョン:PostgreSQL 16.3-R3
  • テンプレート:無料利用枠
  • 設定
    • DB クラスター識別子:yoshida-test-db
    • 認証情報の設定
      • 認証情報管理:セルフマネージド
      • パスワードを自動生成チェックボックスを ON
  • インスタンスの設定
    • DB インスタンスクラス:db.t4g.micro
  • 接続
    • コンピューティングリソース:EC2 コンピューティングリソースに接続
    • EC2 インスタンス:作成したインスタンスを選択
  • DB サブネットグループ:既存の選択 → 作成したサブネットグループを選択
  • VPC セキュリティグループ (ファイアウォール):既存の選択 → 作成した RDS セキュリティグループを選択
  • タグ
    • キー:Name
    • 値:yoshida-test-db

その他はデフォルトで作成

RDS の作成に成功すると、DB に接続するためのパスワードが表示されます。
画面遷移をするとパスワードが消えるので、メモとして残しておきます。

RDS に接続

作成したデータベースにログインに使用する Password と ID をINSERTします。
テーブルに接続するためには ローカル環境から EC2 へ接続後、EC2 から RDS に接続する必要があります。
以下の手順で EC2 から RDS に接続します。

  • ローカルPC から EC2 に接続
  • sudo dnf update -yを実行し、EC2 インスタンスのソフトウェアを更新して、最新のバグ修正とセキュリティ更新を入手
  • sudo dnf install postgresql16を実行し、PostgreSQL の psql コマンドラインクライアントを Amazon Linux 2023 にインストール
  • 上記が成功したら、psql --host="作成した RDS のエンドポイント" --port=5432 --dbname=postgres --username=postgresを実行します。
  • パスワードの入力を求められるので、パスワードを入力

成功するとターミナルに以下が表示されます。

psql (14.3, server 14.6)
SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off)
Type "help" for help.

postgres=> 

RDS にパスワードと ID を INSERT

RDS に接続できたら、ログインに使用するパスワードと ID をINSERTします。
以下の手順でログインに使用するパスワードと ID をINSERTします。

  • test_loginデータベースを作成する
CREATE DATABASE test_login;
  • usersテーブルを作成する
CREATE TABLE users (
    user_id VARCHAR(255) PRIMARY KEY,
    pass VARCHAR(255)
);
  • 作成したusersテーブルにデータをINSERTする
INSERT INTO users (user_id,pass) VALUES (test,password123nm);

データがINSERTに成功すると以下の通りになります。

Monosnap CREATE TABLE users ( • Untitled-2 — work 2025-01-16 00-31-32

ElastiCache for Memcached 起動

次に、ElastCache for Memcached を作成します。

サブネットグループの作成

Monosnap ElastiCache Management Console - subnet groups create 2025-01-21 21-38-17

  • 名前:任意の名前
  • 説明:任意の名前
  • VPC ID:作成した VPC を入力
  • タグ
    • キー:Name
    • 値:任意の名前

パラメータグループの作成

Monosnap ElastiCache Management Console - parameter groups create 2025-01-21 21-42-10

  • 名前:任意の名前
  • 説明:任意の名前
  • ファミリー:Memcached1.6
    • 今回作成する ElastiCache のエンジンを選択
  • タグ
    • キー:Name
    • 値:任意の名前

ElastiCache for Memcached 起動

Monosnap ElastiCache Management Console - memcached create 2025-01-21 21-43-37

  • クラスターの作成方法を選択
    • デプロイオプション
      • 独自のキャッシュを設計
      • 標準作成
  • ロケーション:AWS クラウド
  • 設定:デモ
  • クラスター情報
    • 名前:任意の名前
    • 説明:任意の名前
  • クラスター設定
    • エンジンバージョン:1.6.22
    • ポート:11211
    • パラメータグループ:先ほど作成したパラメータグループを選択
    • ノードのタイプ:cache.t4g.micro
    • ノードの数:1
  • 接続性
    • ネットワークタイプ:IPv4
    • サブネットグループ:先ほど作成したサブネットグループを選択
  • セキュリティ
    • 選択済みのセキュリティグループ:先ほど作成したセキュリティグループを選択
  • タグ
    • キー:Name
    • 値:任意の名前

Python,HTML の準備

フォルダ構成

/home
└─ ec2-user
   └─ test_login
      ├─ app.py
      └─ templates
         └─ login.html

ローカル環境から EC2 インスタンスに接続し、ec2-user配下にtest_loginディレクトリ、
test_loginディレクトリ配下にtemplatesディレクトリを作成します。
mkdirコマンドを使用します。

scpコマンドを使用して、EC2 インスタンスに Python ファイルと HTML ファイルをデプロイします。
以下、コマンド例です。

scp -i ~/.ssh/"作成したキーペア".pem \                    
  ~/.ssh/"作成したキーペア".pem \
  ec2-user@1.1.1.1:/home/ec2-user/test_login/app.py

app.py(ログイン処理・状態維持を行うスクリプト)

from flask import Flask, request, render_template, session, redirect, url_for
from pymemcache.client.base import Client
import psycopg2
import json

# Memcachedの設定
memcached_client = Client('{作成した ElastiCache のエンドポイント}', 11211)

# PostgreSQL RDSの設定
db_config = {
    'host': '{作成した RDS のエンドポイント}',
    'user': 'postgres',
    'password': '{RDS 作成時に表示されるパスワード}',
    'dbname': 'test_login',  # PostgreSQLでは'dbname'を使用
    'port': '5432'            # PostgreSQLのデフォルトポート
}

# アプリ部分の実装
app = Flask(__name__)
app.secret_key = 'your-secret-key'  # セッション用のシークレットキー

@app.route('/')
def index():
    if 'user_id' in session:
        return f'Welcome {session["user_id"]}'
    return redirect(url_for('login'))

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        user_id = request.form['user_id']
        password = request.form['password']
        conn = None

        try:
            conn = psycopg2.connect(**db_config)
            cursor = conn.cursor()

            sql = "SELECT * FROM users WHERE user_id = %s AND password = %s"
            cursor.execute(sql, (user_id, password))
            result = cursor.fetchone()

            if result:
                # セッション情報をMemcachedに保存
                session['user_id'] = user_id
                # データを文字列に変換してからJSONに変換
                session_data = {
                    'user_id': str(user_id),  # 文字列に変換
                    'logged_in': True
                }
                memcached_client.set(f'session_{user_id}', json.dumps(session_data))
                return redirect(url_for('index'))

            cursor.close()
            return 'Login failed'

        except Exception as e:
            print(f"Database error: {e}")
            return f"Login error: {str(e)}"
        finally:
            if conn:
                conn.close()

    return render_template('login.html')

@app.route('/logout')
def logout():
    if 'user_id' in session:
        memcached_client.delete(f'session_{session["user_id"]}')
        session.pop('user_id', None)
    return redirect(url_for('login'))

if __name__ == '__main__':
    app.debug = True
    app.run(host='0.0.0.0', port=80)

HTML コード

<!DOCTYPE html>
<html>
<head>
    <title>Login</title>
</head>
<body>
    <h1>Login</h1>
    <form method="POST">
        <p>User ID: <input type="text" name="user_id" ></p>
        <p>Password: <input type="password" name="password"></p>
        <p><input type="submit" value="Login"></p>
    </form>
</body>
</html>

実行してみる

上記が完了したら、EC2 からapp.pyを実行します。

sudo python3 app.py

ブラウザから EC2 インスタンスのパブリックIPアドレスに接続します。
設定に問題なければ以下の画面が表示されます。

Monosnap Login 2025-01-16 11-05-52

パスワードとIDを入力し、ログインできるか確認します。

Monosnap 18.181.170.35 2025-01-16 16-30-43

以上で、ElastiCache for Memcached を使用し、Web サービスでログイン機能を構築してみたは以上となります!

最後に

今回試してみて、セキュリティグループの設定が一番混乱しました。EC2 から ElastiCache のポートは開けられたのですが、
その逆ができていなくてエラーになったりしました。これから気をつけたいです。

今回はテスト環境なのでセキュリティなどは最低限のことしかやっていないのですが、次回以降の記事で運用を考えた構成で同じことをやってみたいと思いました。
ここまで読んでいただき、ありがとうございました!

参考

https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/CHAP_GettingStarted.CreatingConnecting.PostgreSQL.html
https://docs.aws.amazon.com/general/latest/gr/Welcome.html
https://msiz07-flask-docs-ja.readthedocs.io/ja/latest/

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.