Traffine I/O

日本語

2023-02-16

dbtのドキュメントをホスティングするAWS環境をTerraformで構築

dbtのドキュメントをホスティングするAWS環境をTerraformで構築

この記事では、dbtのドキュメントをホスティングするAWS環境をTerraformで構築する方法を紹介します。S3にアップロードされたdbtドキュメントをCloudFrontを経由して確認できるようにします。また、CloudFrontには、Lambda@Edgeを利用してBasic認証をかけます。

Terraformコード

Terraformのコードは以下のGitHubレポジトリで確認することができます。

https://github.com/ryuseikakujo/dbt-docs-terraform/tree/main

ディレクトリ構成

以下のディレクトリ構成となっています。

.
├── backend.tf
├── cloudfront.tf
├── iam.tf
├── lambda.tf
├── lambda_edge
│   └── index.py
├── lambda_edge_archive
├── provider.tf
├── s3.tf
└── variables.tf

構築のステップ

以下の順でdbt DocsをAWSにホスティングする環境を構築します。

  1. Lambda@Edgeの関数を記述
  2. Terraformでインフラを構築

Lambda@Edgeの関数を記述

以下のようにBasic認証用のLambda@Edgeのコードをindex.pyに記述します。

lambda_edge/index.py
"""
Lambda@Edge for authentication
"""

import base64


def authenticate(user, password):
    return user == "admin" and password == "passW0rd"


def handler(event, context):
    request = event["Records"][0]["cf"]["request"]
    headers = request["headers"]

    error_response = {
        "status": "401",
        "statusDescription": "Unauthorized",
        "body": "Authentication Failed",
        "headers": {
            "www-authenticate": [
                {
                    "key": "WWW-Authenticate",
                    "value": 'Basic realm="Basic Authentication"',
                }
            ]
        },
    }

    if "authorization" not in headers:
        return error_response

    try:
        auth_values = headers["authorization"][0]["value"].split(" ")
        auth = base64.b64decode(auth_values[1]).decode().split(":")
        (user, password) = (auth[0], auth[1])
        return request if authenticate(user, password) else error_response
    except Exception:
        return error_response

Terraformでインフラを構築

Terraformを使用してインフラの構築を行います。

ソースコードの記述

Terraformのコードを記述します。ソースコードは以下のレポジトリを参照してください。

https://github.com/ryuseikakujo/dbt-docs-terraform/tree/main

ここでは、ポイントとなる点のみを解説します。

マルチリージョン

provider.tfにはAWSプロバイダーが記述されています。今回、Lambda@Edgeを使用するため、Lambda関数はバージニアリージョンにデプロイする必要があります。そのため、us-east-1リージョンのプロバイダーを定義し、Lambdaの定義時に参照しています。

provider.tf
provider "aws" {
  region = "ap-northeast-1"

  default_tags {
    tags = {
      Env       = "dev"
      App       = "my-app"
      ManagedBy = "Terraform"
    }
  }
}

provider "aws" {
  alias  = "virginia"
  region = "us-east-1"

  default_tags {
    tags = {
      Env       = "dev"
      App       = "my-app"
      ManagedBy = "Terraform"
    }
  }
}
lambda.tf
resource "aws_lambda_function" "cloudfront_auth" {
  provider         = aws.virginia
  .
  .
  .
}

https://io.traffine.com/ja/articles/terraform-aws-multi-regions

LambdaのZip化

lambda.tfarchive_fileというデータソースを使うと指定のディレクトリのZipファイルを生成することができます。

lambda.tf
data "archive_file" "function_source" {
  type        = "zip"
  source_dir  = "lambda_edge"
  output_path = "lambda_edge_archive/function.zip"
}

生成されるZipファイルをLambda定義時に参照しています。

lambda.tf
resource "aws_lambda_function" "cloudfront_auth" {
  .
  .
  .
  filename         = data.archive_file.function_source.output_path
  source_code_hash = data.archive_file.function_source.output_base64sha256
}

Lambdaのバージョニング

CloudFrontではLambdaのバージョンを指定する必要があります。Lambdaのバージョンニングについては以下の記事を参照ください。

https://io.traffine.com/ja/articles/version-and-alias-in-lambda

Lambda定義時にpublish=trueとするとバージョニングが行われます。

lambda
resource "aws_lambda_function" "cloudfront_auth" {
  .
  .
  .
  publish          = true
}

CloudFrontではバージョンを指定したLambdaが参照されています。

cloudfront.tf
resource "aws_cloudfront_distribution" "main" {
  .
  .
  .
    lambda_function_association {
      .
      .
      lambda_arn   = aws_lambda_function.cloudfront_auth.qualified_arn
    }
}

Terraform Apply

terraform applyを実行して環境構築します。

dbtドキュメントをS3に格納

dbtのプロジェクトのディレクトリにて、以下のコマンドでS3にdbtドキュメントをアップロードします。

bash
$ dbt docs generate
$ aws s3 cp target/manifest.json s3://<s3 bucket name created by terraform>/
$ aws s3 cp target/run_results.json s3://<s3 bucket name created by terraform>/
$ aws s3 cp target/index.html s3://<s3 bucket name created by terraform>/
$ aws s3 cp target/catalog.json s3://<s3 bucket name created by terraform>/

ドキュメントの確認

CloudFrontのディストリビューションドメインにアクセスしてみると、Basic認証がかかっていることが確認できます。

CloudFront

認証後、ドキュメントを見ることができるようになります。

また、S3に直接アクセスすると、拒否されることも確認できます。

S3

Ryusei Kakujo

researchgatelinkedingithub

Focusing on data science for mobility

Bench Press 100kg!