0
0

【AWS×Webアプリ】CloudFront+Cognito認証(Terraform)

Posted at

目的

・AWS上の静的Webサイトホスティングを有効にしたS3をCloudFrontで公開。
・Cognito認証を実装。

前提条件

・Terraformを使用してAWS上にリソースを作成する。
・Lambda@Edgeを使用して実装する。
・作成する内容は以下と同様

TFファイル

aws_cloudfront.tf(前回からの追加箇所のみ抜粋)
resource "aws_cloudfront_distribution" "WebBucketDistribution" {
  enabled = true
  default_root_object = "index.html"
  price_class = "PriceClass_200"

  origin {
    origin_id                = "WebBucketOrigin"
    domain_name              = aws_s3_bucket.WebBucket.bucket_regional_domain_name
    origin_access_control_id = aws_cloudfront_origin_access_control.WebBucketOriginAccessControl.id
  }

  viewer_certificate {
    cloudfront_default_certificate = true
  }

  default_cache_behavior {
    target_origin_id       = "WebBucketOrigin"
    viewer_protocol_policy = "redirect-to-https"
    compress = true
    cached_methods         = ["GET", "HEAD"]
    allowed_methods        = ["GET", "HEAD"]

    lambda_function_association {
      event_type   = "viewer-request"
      lambda_arn   = "${aws_lambda_function.AuthCognito.arn}:${aws_lambda_function.AuthCognito.version}"
    }

    cache_policy_id = aws_cloudfront_cache_policy.WebBucketCachePolicy.id
    origin_request_policy_id = aws_cloudfront_origin_request_policy.WebBucketOriginRequestPolicy.id
  }

  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }
}
aws_iam.tf(前回からの追加箇所のみ抜粋)
resource "aws_iam_role" "auth_cognito_lambda_role" {
  name = "AuthCognitoLambdaRole"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = ["lambda.amazonaws.com","edgelambda.amazonaws.com"]
        }
      },
    ]
  })
}

resource "aws_iam_role_policy" "auth_cognito_lambda_policy" {
  role = aws_iam_role.auth_cognito_lambda_role.id

  policy = jsonencode({
    Statement = [
      {
        Action = ["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"]
        Effect = "Allow"
        Resource = ["arn:aws:logs:*:*:*"]
      },
      {
        Action = ["lambda:GetFunction","lambda:EnableReplication*","iam:CreateServiceLinkedRole"]
        Effect = "Allow"
        Resource = "*"
      },
    ]
  })
}
aws_lambda.tf(前回からの追加箇所のみ抜粋)
data "archive_file" "lambda_auth_cognito" {
  type        = "zip"
  source_file = "${path.module}/lambda/AuthCognito"
  output_path = "${path.module}/lambda_zip/auth_cognito.zip"
}

resource "aws_lambda_function" "AuthCognito" {
  filename         = "${path.module}/lambda_zip/auth_cognito.zip"
  function_name    = "auth_cognito"
  role             = aws_iam_role.auth_cognito_lambda_role.arn
  handler          = "auth_cognito.handler"
  runtime          = "nodejs18.x"
  source_code_hash = filebase64sha256("${path.module}/lambda/AuthCognito/auth_cognito.js")

  timeout = 5
  
  tracing_config {
    mode = "Active"
  }

  publish = true
}
aws_cognito.tf
resource "aws_cognito_user_pool" "WebBucketUserPool" {
  name = "terraform-user-pool"

  admin_create_user_config {
    allow_admin_create_user_only = false
  }

  alias_attributes = ["email","preferred_username"]
  auto_verified_attributes = ["email"]

  software_token_mfa_configuration {
    enabled = true
  }

  mfa_configuration = "ON"

  password_policy {
    minimum_length = 8
    require_uppercase = true
    require_lowercase = true
    require_numbers = true
    require_symbols = true
    temporary_password_validity_days = 7
  }

  schema {
    name = "email"
    attribute_data_type = "String"
    mutable = true
    required = true
  }

  schema {
    name = "preferred_username"
    attribute_data_type = "String"
    mutable = true
    required = false
  }

  schema {
    name = "name"
    attribute_data_type = "String"
    mutable = true
    required = true
    string_attribute_constraints {
      min_length = 1
      max_length = 100
    }
  }

  verification_message_template {
    default_email_option = "CONFIRM_WITH_LINK"
    email_subject = "メールアドレスの確認"
    email_message = "あなたのメールアドレスを確認するには、以下のリンクをクリックしてください: {####}"
  }
}

resource "aws_cognito_user_pool_domain" "WebBucketUserPoolDomain" {
  domain = "terraform-${data.aws_caller_identity.self.account_id}"
  user_pool_id = aws_cognito_user_pool.WebBucketUserPool.id
}

resource "aws_cognito_user_pool_client" "WebBucketUserPoolClient" {
  name = "terraform-client"
  user_pool_id = aws_cognito_user_pool.WebBucketUserPool.id

  callback_urls = ["https://${aws_cloudfront_distribution.WebBucketDistribution.domain_name}"]
  supported_identity_providers = ["COGNITO"]

  allowed_oauth_flows = ["code"]
  allowed_oauth_flows_user_pool_client = true
  allowed_oauth_scopes = ["openid"]
}

◆aws_cloudfront.tf
・WebBucketDistribution(lambda_function_association):Lambda@Edgeの関連付けを追加

◆aws_iam.tf
・auth_cognito_lambda_role:Cognito認証Lambda用IAMロール
・auth_cognito_lambda_policy:「auth_cognito_lambda_role」に付与するポリシー

◆aws_lambda.tf
・lambda_auth_cognito:Lambda関数用のファイルをZip圧縮
・AuthCognito:Lambda関数定義

◆aws_cognito.tf
・WebBucketUserPool:Cognitoユーザプール
・WebBucketUserPoolDomain:Cognitoユーザプールドメイン
・WebBucketUserPoolClient:Cognitoユーザプールクライアント

Lambda

auth_cognito.js
const { Authenticator } = require('cognito-at-edge');

const authenticator = new Authenticator({
  region: 'user pool regionを指定',
  userPoolId: 'user pool IDを指定',
  userPoolAppId: 'user pool app client IDを指定',
  userPoolDomain: 'user pool domainを指定',
});

exports.handler = async (request) => authenticator.handle(request);

動作確認

①Webサイトへアクセス
・サインイン画面が表示されることを確認
image.png

②サインアップ
image.png
image.png

③メールアドレスの検証
image.png
image.png

④サインイン
image.png

⑤MFAの登録
image.png

⑥Webサイトへアクセス(完了)
image.png

⑦MFA(次回サインイン後から)
image.png

参考(前回記事)

0
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
0
0