ElastiCache for Memcached を使用し、Web サービスでログイン機能を構築してみた
こんにちは!よしななです。
今回は、ElastiCache for Memcached を使用し、Web サービスでよくあるログイン機能を構築したいと思います。
目次
- やりたいこと
- 構成図と使用サービスについて
- AWS 上の準備
- VPC 作成
- Security Group 作成
- EC2 起動
- RDS 起動とデータ投入
- ElastiCache for Memcached 起動
 
- Python・HTML の実装
- 実行してみる
- 最後に
- 参考
やりたいこと
今回やりたいことは、ElastiCache for Memcached を使用し、ログイン機能を構築してみたいと思います。
構成図と使用サービスについて
今回構築するログイン機能の構成図は以下の通りです。
EC2 をパブリックサブネットに配置し、RDS と ElastiCache for Memcached はプライベートサブネットに配置します。

以下のサービスを使用します。
- Amazon EC2
- Flask アプリケーションをデプロイする環境
 
- ElastiCache for Memcached
- ログインしたセッション状態をキャッシュ(一時保存)しておく場所
- 一度目のログインは RDS からパスワードとユーザーIDを取得しログインし、2回目以降のログインは ElastiCache for Memcached のセッション情報を利用する
 
- Amazon RDS
- Postgre を使用
- ログインパスワードを保管しておくための場所
 
- VPC
- Security Group
- EC2、RDS、ElastiCacheにアタッチ
 
AWS 上の準備
それでは、ログイン機能を構築するために AWS 上での準備を行います。
VPC 作成

まずは、リソースを作成する 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番ポートとすべてのトラフィックを開放しアウトバウンドルールを作成します。

- セキュリティグループ名:任意の名前
- 説明:任意の名前
- VPC:上記で作成した VPC を入力
- インバウンドルール
- インバウンドルール1
- タイプ:TCP
- ポート範囲:22
- ソース:マイIP(ローカルPCのIPアドレス)
 
- タイプ:
- インバウンドルール2
- タイプ:HTTP
- ポート範囲:80
- ソース:0.0.0.0/0
 
- タイプ:
 
- インバウンドルール1
- アウトバウンドルール
- アウトバウンドルール1
- タイプ:カスタムTCP
- ポート範囲:11211
- ソース:作成した ElastiCache のセキュリティグループ任意の名前
 
- タイプ:
- アウトバウンドルール2
- タイプ:すべてのトラフィック
- ポート範囲:すべて
- ソース:0.0.0.0/0
 
- タイプ:
 
- アウトバウンドルール1
- タグ
- キー:Name
- 値:任意の名前
 
- キー:
RDS Security Group
EC2 インスタンスからのアクセスを許可するようにインバウンドルールを作成します。
RDS インスタンスから外側へのアクセスを許可するようにアウトバウンドルールを作成します。
- セキュリティグループ名:任意の名前
- 説明:任意の名前
- VPC:上記で作成した VPC を入力
- インバウンドルール
- インバウンドルール1
- タイプ:PostgreSQL
- ポート範囲:5432
- ソース:作成した EC2 のセキュリティグループ任意の名前
 
- タイプ:
 
- インバウンドルール1
- アウトバウンドルール
- アウトバウンドルール1
- タイプ:すべてのトラフィック
- ポート範囲:すべて
- ソース:0.0.0.0/0
 
- タイプ:
 
- アウトバウンドルール1
- タグ
- キー:Name
- 値:任意の名前
 
- キー:
ElastiCache Security Group
- セキュリティグループ名:任意の名前
- 説明:任意の名前
- VPC:上記で作成した VPC を入力
- インバウンドルール
- インバウンドルール1
- タイプ:カスタムTCP
- ポート範囲:11211
- ソース:作成した EC2 のセキュリティグループ任意の名前
 
- タイプ:
 
- インバウンドルール1
- アウトバウンドルール
- アウトバウンドルール1
- タイプ:すべてのトラフィック
- ポート範囲:すべて
- ソース:0.0.0.0/0
 
- タイプ:
 
- アウトバウンドルール1
- タグ
- キー:Name
- 値:任意の名前
 
- キー:
EC2 起動
次に、作成したセキュリティグループを使用して EC2 インスタンスを起動します。

- 名前:任意の名前
- アプリケーションおよび 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"を実行
 
- 以下の画面が出力されれば接続成功

RDS 起動とデータ投入
次に、RDS を起動します。
サブネットグループの作成
RDS にアタッチするサブネットグループを作成します。

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

- パラメータグループ名:任意の名前
- 説明:任意の名前
- エンジンのタイプ:PostgreSQL
- パラメータグループファミリー:Postgres16
- タグ
- キー:Name
- 値:任意の名前
 
- キー:
RDS の起動
作成したパラメータグループ、サブネットグループを使用して RDS を起動します。
- データベース作成方法を選択:標準作成
- エンジンのオプション:PostgreSQL
- エンジンバージョン:PostgreSQL 16.3-R3
- テンプレート:無料利用枠
- 設定
- DB クラスター識別子:yoshida-test-db
- 認証情報の設定
- 認証情報管理:セルフマネージド
- パスワードを自動生成チェックボックスを ON
 
 
- DB クラスター識別子:
- インスタンスの設定
- DB インスタンスクラス:db.t4g.micro
 
- DB インスタンスクラス:
- 接続
- コンピューティングリソース: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に成功すると以下の通りになります。

ElastiCache for Memcached 起動
次に、ElastCache for Memcached を作成します。
サブネットグループの作成

- 名前:任意の名前
- 説明:任意の名前
- VPC ID:作成した VPC を入力
- タグ
- キー:Name
- 値:任意の名前
 
- キー:
パラメータグループの作成

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

- クラスターの作成方法を選択
- デプロイオプション
- 独自のキャッシュを設計
- 標準作成
 
 
- デプロイオプション
- ロケーション: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アドレスに接続します。
設定に問題なければ以下の画面が表示されます。

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

以上で、ElastiCache for Memcached を使用し、Web サービスでログイン機能を構築してみたは以上となります!
最後に
今回試してみて、セキュリティグループの設定が一番混乱しました。EC2 から ElastiCache のポートは開けられたのですが、
その逆ができていなくてエラーになったりしました。これから気をつけたいです。
今回はテスト環境なのでセキュリティなどは最低限のことしかやっていないのですが、次回以降の記事で運用を考えた構成で同じことをやってみたいと思いました。
ここまで読んでいただき、ありがとうございました!
参考
アノテーション株式会社について
アノテーション株式会社はクラスメソッドグループのオペレーション専門特化企業です。サポート・運用・開発保守・情シス・バックオフィスの専門チームが、最新 IT テクノロジー、高い技術力、蓄積されたノウハウをフル活用し、お客様の課題解決を行っています。当社は様々な職種でメンバーを募集しています。「オペレーション・エクセレンス」と「らしく働く、らしく生きる」を共に実現するカルチャー・しくみ・働き方にご興味がある方は、アノテーション株式会社 採用サイトをぜひご覧ください。











