KINTO Tech Blog
AWS

CloudFront FunctionsのDeployのプロセスと運用カイゼン

Cover Image for CloudFront FunctionsのDeployのプロセスと運用カイゼン

はじめに

初めまして、KINTOテクノロジーズ株式会社(以降、KTC)でプラットフォームグループのCloud Infrastructure Teamでクラウドインフラエンジニアをしている白井です。
普段はAWSで構築されているシステムのインフラ構築、および設計を行っています。趣味は、卓球とゲームです。最近だとスーパーマリオRPGがリメイクされたのを購入し、思い出に浸りながらプレイしています。
今回は、KTCで構築しているCloudFront FunctionsのDeployのプロセスと運用カイゼンをしたお話について、背景も含めてご紹介します!

KTCのCloud Infrastructure Teamについて

本題に入る前に、私たちのチームについて補足させていただきます。
KTC ではインフラの構築を Terraform を使用した IaC で管理しています。
歴史的背景など詳しくは同じチームの島川さんTerraform を抽象化し環境構築の工数を削減する取り組みについて という資料を公開していますのでぜひそちらをご確認ください。

現状の課題

KTCでは現在、一部のシステムにおけるリダイレクト処理などでCloudFront Fucntions(以降、CF2)を利用しています。
CloudFrontで利用できるエッジ関数というタイトルでCF2について、同じチームメンバの井木さんが紹介しているので、ぜひご覧になってください。

さて、KTCではCF2を利用する中で、以下3点が課題として上がってきました。

  1. Application TeamとCloud Infrastructure Teamのコミュニケーションコストが大きい
  2. Application TeamにCloudWatch Logsに出力されるログの閲覧権限を付与できていない
  3. CloudWatch Logsに出力されるログが失効されない状態で残る

この三つの課題を解決します。

課題の深掘り

1. コミュニケーションコストが大きくなっている課題

今までのCF2が適用までのプロセスは以下になります。

今までのDeployまでのプロセス

DeployがCloud Infrastructure Teamに依存している影響で、CF2のソースコードに問題があった際に、再度上の図の(2)~(4)をCloud Infrastructure Teamにて実施する必要があります。
このフローの問題点としては、

  • CF2の更新がCloud Infrastructure Teamに依存していること
  • CF2の更新時に、Cloud Infrastructure Teamも影響範囲を確認し、Application Teamとの調整が必要になること

上記二点により、コミュニケーションコストが大きくなっていました。

2. Application Teamがログを閲覧できない課題

KTCでは、Application Teamに引き渡す権限を強く絞っています。その結果、CF2のログの閲覧権限がなく、見えなくなっていました。この状況では、CF2における問題発生時にApplication Teamは調査することができません。

3. CF2のログが恒久的に残る課題

現状、CloudWatchのロググループを設定せず、CF2を構築していました。
CF2の仕様上、CF2のログが出力された際に自動的にus-east-1リージョンのCloudWatchLogsに/aws/cloudfront/function/${FunctionName}というロググループが作成されます。この状況では、ロググループは失効期間が設定されていないため、残り続けコストが嵩んでしまいます。

解決策

問題と解決策を以下にまとめました。

課題 課題 解決策
1 コミュニケーションコストが大きい Application Teamに追加権限を付与し、任意のタイミングでDeployできるようにする
2 Application Teamがログを閲覧できない Application Teamにログ閲覧権限を追加する
3 CF2のログが恒久的に残る 失効期間付きのロググループを先に作成しておく

では、それぞれの解決策について深掘りしていこうと思います。

課題1: コミュニケーションコストが大きい

解決策でも述べたように、方針としてはApplication Teamが任意のタイミングでDeployできるようにすることです。
そこで、Deployするまでのプロセスを一新しようと思いました。

まずは、CF2構築前の構成例とプロセスを一新後の構成例をお見せします。


CF2構築前構成例


最終構成例

CF2のDevelopment StageとLIVE Stageについて、補足します。LIVE Stageは実際にCloudFrontに紐づけられて動作しているCF2となります。それとは別にDevelopment Stageでは主に開発用途として使われ、LIVE Stageで流入してくるリクエストの検証が実施できます。

次に、赤文字で記載されているメンテナンスロールとCICDユーザについて少しだけ触れさせていただきます。

メンテナンスロールとCICDユーザ

それぞれ以下の役割です。

  • メンテナンスロールの役割
    • AWSマネージメントコンソール上での各種AWSサービスの閲覧・更新をすることです。
    • KTCにおいて、AWSマネージメントコンソールにログインする際には、環境ごとに用意されているアカウントにSSOログインをします。SSOログインをした先で適切に権限を絞られているメンテナンスロールにスイッチロールすることで必要なAWSサービスの閲覧や更新を手動で行うことができます。
      • 同じアカウント内にはさまざまなプロダクトが存在しているため、誤操作防止のため、閲覧・更新権限についても強めの制限をしています。
  • CICDユーザロールの役割
    • Github ActionsなどのCICDツールを使用した各種AWSサービスの更新をすることです。
      • Applicationのデプロイで使用する権限を設定しています。各プロダクトが使用するAWSリソースによって付与する権限を決めています。例えばLambdaとECSをデプロイするプロダクトにはそれをデプロイできる権限を与え、ECSのみをデプロイするプロダクトにはECSのみをデプロイできる権限を与えています。

既存のメンテナンスロールとCICDユーザはCF2の権限が付与されていなかったので、下記権限を追加しました。

追加権限
        {
            "Action": [
                "cloudfront:UpdateFunction",
                "cloudfront:TestFunction",
                "cloudfront:PublishFunction",
                "cloudfront:ListFunctionTestEvent",
                "cloudfront:GetFunction",
                "cloudfront:DescribeFunction",
                "cloudfront:DeleteFunctionTestEvent",
                "cloudfront:CreateFunctionTestEvent"
            ],
            "Effect": "Allow",
            "Resource": "arn:aws:cloudfront::{AccountID}:function/${aws:PrincipalTag/environment}-${aws:PrincipalTag/sid}-*",
            "Sid": ""
        },
        {
            "Action": [
                "cloudfront:ListFunctions"
            ],
            "Effect": "Allow",
            "Resource": "*",
            "Sid": ""
        }

余談ですが、CF2にはDevelopment StageでLambdaのようにテストリクエストを投げることができます。その中で*TestEventの権限が必要だったのですが、公式ドキュメントにはそのアクションの記載がされておらず、CloudTrailを頼りに必要な権限を追加していきました。公式ドキュメントが全てではないことに気づくよい例だなと思いました。

次にCloud Infrastructure TeamとApplication Teamの分担について述べていきます。

Cloud Infrastructure TeamとApplicaiton Teamの役割分担

実施作業 Cloud Infrastructure Team Applicaiton Team
CF2の権限付与 -
サンプルアプリのCF2の作成とCloudFrontへの紐付け -
CF2の開発、LIVE Stageへのpublish -
CF2の運用・監視 -

では、実際にLIVE StageへのDeploy(Publish)までのプロセスを見ていきましょう。

Deployプロセス

1. Application TeamがCloud Infrastructure Teamへ構築を依頼

以下のテンプレートを元に、Jiraベースでチケットを発行していただきます。


CF2の命名:hogehoge
e.g.) redirect-cf2
構築する環境一覧: xxx
関連づけるCloudfFrontのARN: arn:aws:cloudfront::{AccoutID}:distribution/{DistributionID}
e.g.) arn:aws:cloudfront::111111111111:distribution/EXXXXXXXXXXXXX

関連づけるcache behavior ビューワーリクエスト ビューワーレスポンス
hogehoge -

2. Cloud Infrastructure Teamが構築

  • Cloud Infrastructure Teamで作成したサンプルアプリ(リクエストスルー)のCF2をCloudFrontのビヘイビアに紐付け
  • Application Teamに開発とDeployのための権限をメンテナンスロールとCICDユーザに付与
サンプルアプリのCF2
function handler(event) {
    var request = event.request;
    return request;
}


Cloud Infrastructure Teamが必要なリソースを更新・作成。赤枠が対象。

3. Application TeamがCF2のコードをDevelopment Stageにpublishする。

Development Stageへのソースコード更新方法は下記の通りです。

  1. メンテナンスロールを用いた、AWS マネージドコンソール上からの手動実行
  2. CICDユーザのクレデンシャルを用いた、Github ActionsなどのCI/CDツールを使用した適用

AWSマネージドコンソール上またはCI/CDツールでテストの実施が可能です。


開発とテスト

4. Application TeamがCF2のコードをLIVE Stageにpublishする。

LIVE StageへのpublishもDevelopment Stage への適用と同様にAWS マネージドコンソール、もしくはGithub ActionsなどのCI/CDツールから実行できます。


最終構成

課題2: Application Teamがログを閲覧できない。

ロググループへの閲覧権限を付与します。

ログのインサイトとロググループ閲覧用権限
        {
            "Action": [
                "logs:StartQuery",
                "logs:GetLogGroupFields",
                "logs:GetLogEvents"
            ],
            "Effect": "Allow",
            "Resource": "arn:aws:logs:us-east-1:{AccountID}:log-group:/aws/cloudfront/function/${aws:PrincipalTag/environment}-${aws:PrincipalTag/sid}-*-cloudfront-function:log-stream:*",
            "Sid": ""
        }

メンテナンスロールにおいて、上記のようにロググループの閲覧権限とログのインサイトの閲覧権限を付与しているため、ログが見えるようになりました。
その結果として、問題発生時にApplication Teamが主導で問題発生に取り組めるようになれたと思います。

課題3: CF2のログが失効されない状態で残る。

CF2構築時に併せてCloudWatchLogグループを作成するようにしました。
これは、CF2が作られる過程で参照するモジュールの中に記載することで実現しました。

resource "aws_cloudwatch_log_group" "this" {
  name              = "/aws/cloudfront/function/${local.function_name}"
  retention_in_days = var.cwlogs_retention_in_days == null ? var.env.log_retention_in_days : var.cwlogs_retention_in_days
}

まとめと最後に

今回、CF2に対して3つの改善の取り組みを行いました。箇条書きでまとめさせていただきます。

  • 課題1: コミュニケーションコストが大きい
    • 解決策: Application Teamが自分たちでDeploy可能にできる様に権限とプロセスを整理
    • 効果: Application Team が任意のタイミングで実行可能となり必要なコミュニケーションを適切にできる様になった
  • 課題2: Application Teamがログを閲覧できない
    • 解決策: Application Teamにログの閲覧権限を付与
    • 効果: 問題発生時でも自分たちでログを確認し、対応することが可能になった
  • 課題3: CF2のログが恒久的に残る
    • 解決策: 失効期間付き転送先のロググループを先に作成
    • 効果: ログの有効期限を決めたことで、コストの適正化に寄与できた

以上です。ここまで読んでいただき、ありがとうございました!

Facebook

関連記事 | Related Posts

Cover Image for CloudFrontで利用できるエッジ関数とは

CloudFrontで利用できるエッジ関数とは

Y.Suzuki
Y.Suzuki
Cover Image for 11月入社メンバー紹介

11月入社メンバー紹介

Jumpei Shimamura
Jumpei Shimamura
Cover Image for ECS環境のAuto Provisioningを実現する仕組み

ECS環境のAuto Provisioningを実現する仕組み

Cover Image for Deployment Process in CloudFront Functions and Operational Kaizen

Deployment Process in CloudFront Functions and Operational Kaizen

JL
JL
Cover Image for KINTOテクノロジーズでのアプリケーションエンジニアとしての経験

KINTOテクノロジーズでのアプリケーションエンジニアとしての経験

Taka
Taka
Cover Image for プラットフォームグループのご紹介

プラットフォームグループのご紹介

We are hiring!

【プラットフォームエンジニア】プラットフォームG/東京・大阪

プラットフォームグループについてAWS を中心とするインフラ上で稼働するアプリケーション運用改善のサポートを担当しています。

【プロダクト開発バックエンドエンジニア】共通サービス開発G/東京・大阪

共通サービス開発グループについてWebサービスやモバイルアプリの開発において、必要となる共通機能=会員プラットフォームや決済プラットフォームの開発を手がけるグループです。KINTOの名前が付くサービスやTFS関連のサービスをひとつのアカウントで利用できるよう、様々な共通機能を構築することを目的としています。