Skip to content

Conversation

@inoue22
Copy link
Contributor

@inoue22 inoue22 commented Jan 3, 2026

Description of Changes

Please explain the changes in detail.
If there is any impact on existing users (compatibility, degradation, breaking changes, etc.), be sure to include it in the explanation.

CognitoユーザープールへMFA有効化を追加し、ログイン時にメールを用いたMFAを可能としました。

変更内容

  • MFA機能の実装
    • cdk.jsonに以下の設定パラメータを追加しました
      • mfaEnabled: MFA機能の有効/無効を制御(デフォルト: false)
      • mfaFromEmail: MFA認証コード送信元メールアドレス(例: no-reply@example.com
      • mfaReplyToEmail: 返信先メールアドレス(オプション)
    • パラメータを受け取るようCDKのauth.tsを改修しました

デプロイ済み環境への影響

  • mfaEnabledのデフォルト値はfalseのため、デプロイ済み環境への影響はありません
  • MFA機能を有効にする場合は、cdk.jsonmfaEnabled: true, mfaFromEmailに送信元メールアドレスをに設定し、SESの事前設定を完了させてからCDKスタックの更新が必要です

注意事項

  • MFA有効化時はパスワードリセットが制限されます

  • AWS公式ドキュメントに記載の通り、CognitoユーザープールではMFAとパスワードリセットコードを同じメールアドレス(または電話番号)で受け取ることができません

    ユーザーは、MFA とパスワードのリセットコードを、同じ E メールアドレスや電話番号で受け取ることはできません。E メールメッセージのワンタイムパスワード (OTP) を MFA に使用する場合、アカウントの復旧には SMS メッセージを使用する必要があります。

  • メールベースのMFAを有効化した場合、セルフサービスでパスワードリセットを行うにはSMS(電話番号)が必要ですが、電話番号を必須属性として追加することは既存のCognitoユーザープールへの破壊的変更となるため、本PRでは以下の対応としました

    • MFA有効化時はパスワードリセット画面(パスワードを忘れましたか?)を無効化
    • パスワードリセットが必要な場合は、管理者によるマネジメントコンソールまたはAWS CLIによる操作を想定

補足事項

SESドメイン認証

  • mfaFromEmailで指定するメールアドレスのドメインは、Amazon SESで認証済みである必要があります
    • 厳密には認証なしでもMFAの送信は可能ですが、GmailやOutlookではSPF認証が必須のためメールサービス側でMFAを受信できない問題が発生します
  • 以下のスクリプトを実行することでRoute 53に登録済みの独自ドメインに対して設定を適用できることを確認しました
Amazon SESの独自ドメイン認証設定スクリプト(注意: Route 53のDNS設定を書き換えます)
#!/bin/bash

set -e

DOMAIN="example.com"
HOSTED_ZONE_ID="XXXXXXXXXXXXXXXXXXXXX"
REGION="us-east-1"
# ---- 以下の値は変更不要 -----
MAIL_FROM_SUBDOMAIN="ses"
MAIL_FROM_DOMAIN="${MAIL_FROM_SUBDOMAIN}.${DOMAIN}"

#######################################
# 色付きの出力用
#######################################
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

#######################################
# ログ出力関数
#######################################
log_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

# Route 53にレコードを追加する関数
add_route53_record() {
    local zone_id=$1
    local name=$2
    local type=$3
    local ttl=$4
    local value=$5
    local comment=$6

    log_info "Route 53にレコードを追加: $name ($type)"

    # TXTレコードの場合は値を引用符で囲む
    if [ "$type" = "TXT" ]; then
        value="\\\"${value}\\\""
    fi

    # JSONファイルを作成
    cat > /tmp/route53-change.json < /dev/null

    if [ $? -ne 0 ]; then
        log_error "✗ レコード追加失敗: $name"
        return 1
    fi
}

# MXレコードを追加する関数
add_route53_mx_record() {
    local zone_id=$1
    local name=$2
    local ttl=$3
    local priority=$4
    local value=$5

    log_info "Route 53にMXレコードを追加: $name"

    cat > /tmp/route53-change-mx.json < /dev/null

    if [ $? -ne 0 ]; then
        log_error "✗ MXレコード追加失敗: $name"
        return 1
    fi
}

# パラメータ解析
while getopts "r:h" opt; do
    case $opt in
        r) REGION="$OPTARG" ;;
        h) usage ;;
        *) usage ;;
    esac
done

log_info "=========================================="
log_info "SES Domain Authentication Setup"
log_info "=========================================="
log_info "ドメイン: $DOMAIN"
log_info "Hosted Zone ID: $HOSTED_ZONE_ID"
log_info "SESリージョン: $REGION"
log_info "カスタムMAIL FROMドメイン: $MAIL_FROM_DOMAIN"
log_info "=========================================="
echo ""

# AWS CLIの設定確認
if ! command -v aws &> /dev/null; then
    log_error "AWS CLI v2がインストールされていません"
    exit 1
fi

log_info "AWS CLI バージョン: $(aws --version)"
echo ""

#######################################
# 1. ドメイン検証用のTXTレコード
#######################################
log_info "Step 1: ドメイン検証の開始"

VERIFICATION_TOKEN=$(aws ses verify-domain-identity \
    --domain "$DOMAIN" \
    --region "$REGION" \
    --query 'VerificationToken' \
    --output text)

if [ $? -eq 0 ]; then
    log_info "  トークン: $VERIFICATION_TOKEN"

    # TXTレコードを追加
    add_route53_record "$HOSTED_ZONE_ID" \
        "_amazonses.${DOMAIN}" \
        "TXT" \
        "3600" \
        "${VERIFICATION_TOKEN}" \
        "SES Domain Verification Token"
else
    log_error "✗ ドメイン検証トークンの取得に失敗しました"
    exit 1
fi

echo ""

#######################################
# 2. DKIM設定 (CNAME x3)
#######################################
log_info "Step 2: DKIM設定"

DKIM_TOKENS=$(aws ses verify-domain-dkim \
    --domain "$DOMAIN" \
    --region "$REGION" \
    --query 'DkimTokens' \
    --output text)

if [ $? -eq 0 ]; then
    # 各DKIMトークンに対してCNAMEレコードを作成
    TOKEN_COUNT=0
    for TOKEN in $DKIM_TOKENS; do
        TOKEN_COUNT=$((TOKEN_COUNT + 1))
        log_info "  DKIMトークン $TOKEN_COUNT: $TOKEN"

        add_route53_record "$HOSTED_ZONE_ID" \
            "${TOKEN}._domainkey.${DOMAIN}" \
            "CNAME" \
            "3600" \
            "${TOKEN}.dkim.amazonses.com." \
            "SES DKIM CNAME Record ${TOKEN_COUNT}"
    done
else
    log_error "✗ DKIMトークンの取得に失敗しました"
    exit 1
fi

echo ""

#######################################
# 3. カスタムMAIL FROMドメイン設定
#######################################
log_info "Step 3: カスタムMAIL FROMドメイン設定"

# AWS SESでカスタムMAIL FROMドメインを設定
aws ses set-identity-mail-from-domain \
    --identity "$DOMAIN" \
    --mail-from-domain "$MAIL_FROM_DOMAIN" \
    --behavior-on-mx-failure UseDefaultValue \
    --region "$REGION" \
    --output json > /dev/null

if [ $? -ne 0 ]; then
    log_error "✗ カスタムMAIL FROMドメインの設定に失敗しました"
    exit 1
fi

# MXレコードを追加
add_route53_mx_record "$HOSTED_ZONE_ID" \
    "$MAIL_FROM_DOMAIN" \
    "3600" \
    "10" \
    "feedback-smtp.${REGION}.amazonses.com."

# SPFレコード (TXT) を追加
SPF_VALUE="v=spf1 include:amazonses.com ~all"
add_route53_record "$HOSTED_ZONE_ID" \
    "$MAIL_FROM_DOMAIN" \
    "TXT" \
    "3600" \
    "${SPF_VALUE}" \
    "SPF Record for Custom MAIL FROM"

echo ""

#######################################
# 4. SPF設定(メインドメイン)
#######################################
log_info "Step 4: SPF設定(メインドメイン)"

# メインドメインのSPFレコード (TXT) を追加
SPF_VALUE="v=spf1 include:amazonses.com ~all"
add_route53_record "$HOSTED_ZONE_ID" \
    "$DOMAIN" \
    "TXT" \
    "3600" \
    "${SPF_VALUE}" \
    "SPF Record for Main Domain"

echo ""

#######################################
# 5. DMARC設定 (TXT)
#######################################
log_info "Step 5: DMARC設定"

# DMARCポリシー
DMARC_VALUE="v=DMARC1; p=none"

add_route53_record "$HOSTED_ZONE_ID" \
    "_dmarc.${DOMAIN}" \
    "TXT" \
    "3600" \
    "${DMARC_VALUE}" \
    "DMARC Policy Record"

echo ""

#######################################
# 完了メッセージ
#######################################
log_info "=========================================="
log_info "セットアップ完了!"
log_info "=========================================="

# クリーンアップ
rm -f /tmp/route53-change.json /tmp/route53-change-mx.json

メールのカスタマイズの制限

  • 本PRではメールの件名・本文のカスタマイズには対応していません
  • MFA認証コードは英文のメールで送信されます(ユーザー作成時と同様)
  • aws-cdk-lib/aws-cognitoには件名・本文をカスタマイズするためのパラメータは存在するため、将来的な拡張の余地はあります

Checklist

  • Modified relevant documentation
  • Verified operation in local environment
  • Executed npm run cdk:test and if there are snapshot differences, execute npm run cdk:test:update-snapshot to update snapshots

Related Issues

Please list related issues as much as possible.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 5, 2026

This PR is stale because it has been open for 30 days with no activity.

@github-actions github-actions bot added the stale Issues or Pull Requests with no updates label Feb 5, 2026
@inoue22
Copy link
Contributor Author

inoue22 commented Feb 5, 2026

#1433 の変更の取り込み・動作確認を実施します。

@github-actions github-actions bot removed the stale Issues or Pull Requests with no updates label Feb 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant