Amazon ConnectのGUI開発体験を維持しつつ、Terraformで安全にリリースするハイブリッドIaC戦略

はじめに

こんにちは、SREチームの森原(@daichi_morihara)です。

今回はAmazon ConnectのIaC化および開発体験向上に関する取り組みを共有していきたいと思います。Amazon ConnectはGUIのドラッグ&ドロップによる手作業で簡単にリソースを作成・変更できる利便性が特徴的です。その一方で本番環境でのリソース変更を手作業で行うのはオペミスのリスクが伴うため避けたいものです。

しかし通常リソースのようにAmazon Connectを完全にIaCで管理するのも、必ずしも適切ではありません。なぜならAmazon Connectの長所である直感的なGUIでのリソース作成・変更ができなくなってしまうからです。

そこでAmazon ConnectのGUIベースの開発を維持しつつ、Terraformでリソースを管理し安全にリリースできる仕組みを整えた事例を紹介したいと思います。

Amazon Connectとは

最初にAmazon Connectについて簡単にご紹介します。 Amazon Connectは、AWSが提供するクラウドベースのコンタクトセンターサービスです。コンタクトセンターを構築するのに必要な機能が全て搭載されたフルマネージドサービスであるため、迅速かつ低コストでコンタクトセンターを立ち上げることが可能です。 主な特徴は以下の通りです。

  • コンタクトセンターの主要機能を標準搭載: 電話の自動応答(IVR)や、問い合わせ内容に応じて適切なオペレーターに電話を振り分ける機能(ACD)など、コンタクトセンターに必要な機能が備わっている。
  • ノーコードでのフロー開発: 「コンタクトフロー」と呼ばれる顧客対応のシナリオを、GUIのドラッグ&ドロップ操作で直感的に構築できる。
  • 高い拡張性: AWS Lambdaをはじめとする他のAWSサービスと容易に連携でき、AIチャットボットの導入や、通話内容の文字起こし・分析など、機能を柔軟に拡張できる。

Amazon Connectのコンタクトフロー開発時のGUI

GUI開発とIaCの両立

Amazon Connectの直感的で簡単なGUIベースの開発とIaCによる安定した運用の両方の恩恵を受けるために、以下の開発者体験を実現する、最大限自動化されたシステムを構築することにしました。

  1. dev環境のコンタクトフローをGUIベースで開発する。
  2. 変更をトリガーに、対応する本番環境のコンタクトフローを作成/修正するPRが自動で作成される
  3. 開発者・レビュー者がコードベースで差分を確認しながら、マージを行う。
  4. 本番環境のコンタクトフローが自動で作成・公開される

全体構成は下の図の通りです。

システム構成図

このシステムによりGUIベースでの開発を維持しつつ、本番環境への変更反映はTerraformを用いて標準的なGitベースのワークフローに落とし込むことができるため安定したリリースが可能になりました。

次にシステムの各コンポーネントの役割を順に解説していきます。

1. トリガー (CloudTrail & EventBridge)

開発者がAmazon ConnectのGUIでコンタクトフローを編集し、「公開」ボタンをクリックすると、AWS内部でUpdateContactFlowContentというAPIが呼び出されます。このAPIコールはCloudTrailによって記録されています 。このCloudTrailのイベントをEventBridgeで検知しStep Functionsを発火させます。

ここで注意が必要なのが、「保存」ボタンを押したときも同じAPIが呼ばれる点です。しかしその際はコンタクトフローIDの末尾に SAVED という文字列が付与される仕様になっています。そこで、EventBridgeのイベントパターンで「contactFlowIdの末尾がSAVED以外であること」という条件を指定することで、「公開」操作のみをトリガーとして捉えることができます。

{
  "detail": {
    "eventName": ["UpdateContactFlowContent"],
    "eventSource": ["connect.amazonaws.com"],
    "requestParameters": {
      "ContactFlowId": [{
        "anything-but": {
          "suffix": "SAVED"
        }
      }]
    }
  },
  "detail-type": ["AWS API Call via CloudTrail"],
  "source": ["aws.connect"]
}
EventBridgeのイベントパターン

2. Amazon Connectのデータ取得+GitHub Actionsのワークフロー発火(Step Functions & S3)

EventBridgeにより発火されたStep Functionsで以下の処理を行います。

  1. フィルタリング: まずChoiceステートで、対象のコンタクトフローにManagedBy: terraformというタグが付与されているかをチェックします*1。これにより、Terraform管理外の検証用フローなどが誤って処理されるのを防ぎます。
  2. 情報収集と保存: 次に、トリガーとなったコンタクトフローのJSON定義と関連するコンポーネント(キュー、プロンプト、営業時間、コンタクトフロー)の一覧をAWS API経由で取得し、すべてS3バケットに保存します。
  3. GitHub Actionsワークフローの発火: 最後に、GitHub APIを呼び出し、repository_dispatchというイベントを送信します。このイベントが、変更を反映したPRを作成するGitHub Actionsワークフローを発火させます。

3. 変更を反映したPRを作成(GitHub Actions)

コンタクトフローJSON定義の中には、呼び出し先のLambda関数やキュー、プロンプトなどのARN(Amazon Resource Name)がハードコードされています。ARNにはリソース固有のIDが含まれるため、dev環境で作成したコンタクトフローのJSONを、そのまま本番環境に適用することはできません。そのため以下の手順で変更を反映したPRを作成します。

  1. S3に保存されたデータを取得し、dev環境と本番環境のコンポーネントを突き合わせた上でJSONファイルとして保存
  2. 1のJSONファイルを元に各環境でARNマッピングファイルを作成・保存
  3. 該当のコンタクトフローで参照されているARNを変数化した後で、コンタクトフロー定義をTerraformテンプレート(.tfpl)ファイルとして保存
  4. これらを反映させたPRを作成
{
    "SummaryList": [
        {
            "Name": "test.wav",
            "Items": [
                {
                    "Id": “xyz123”,
                    "Arn": "arn:aws:connect:ap-northeast-1…”, # dev環境のプロンプトのARN
                    "InstanceId": “abc123” # dev環境のInstance ID
                },
                {
                    "Id": “xyz987”,
                    "Arn": "arn:aws:connect:ap-northeast-1…”, # 本番環境のプロンプトのARN
                    "InstanceId": “abc987” # 本番環境のInstance ID

                }
            ],
            "placeholder": "uuid_xyz987”
        }
   ]
}
1のコンポーネントを突き合わせたJSONの例
locals {
  arn_map = {
    "uuid_xyz987” = "arn:aws:connect:ap-northeast-1:….”,
     …..
           }
}
2のARNマッピングファイルの例
各環境に1のplaceholderとARNを使用してマッピング
    {
      "Identifier": "ramdom_id",
      "Parameters": {
        "InputTimeLimitSeconds": "10",
        "PromptId": "${uuid_xyz987}",
        "StoreInput": "False"
      },
3のARNを変数化したコンタクトフロー定義の.tfplファイルの一部
${uuid_ xyz987}の部分が環境毎にマッピングされたARNに置き換わる

安全性を確保するブランチ戦略

自動でPR作成する場合は運用方法に注意する必要があります。複数の開発者が同時にコンタクトフローを更新する可能性があり、意図せず他の人の変更を上書きするリスクがあるためです。 このリスクを回避するために次のような中間ブランチを利用する運用を採用しました。

ブランチ運用図

ステージ1:自動PR (変更の隔離)

  • 自動化ワークフローは、生成したTerraformコードをmainブランチに直接PRするのではなく、まずamazon-connect/contact-flow-id_<コンタクトフローID>のような動的な名前のブランチから、amazon-connect/pre-main-reviewという固定の中間ブランチに対してPRを作成します。
  • ブランチ名を動的にすることで、複数のコンタクトフローが同時に更新されても、それぞれの変更が独立したPRとして隔離され、互いに干渉することがありません。

ステージ2:手動PR (変更の集約と最終確認)

  • 開発者は、ステージ1のPRをレビューし、問題がなければ中間ブランチにマージします。
  • その後、一定のタイミングで、開発者はこの中間ブランチ (pre-main-review) から main ブランチへの手動PRを作成します。
  • このPRの差分(Terraform Planの結果)には、中間ブランチにマージされたすべてのコンタクトフローの変更が集約されて表示されます。これにより、開発者と承認者は、本番環境に適用される最終的な変更の全体像を把握した上でレビューすることができます。この仕組みによって、個別の変更が他の部分に与えるといった意図しない影響を防ぎ、安全にデプロイできるようになっています。

開発者体験を支える運用フロー

これらの仕組みを導入したことで、開発者体験を大きく向上させることができました。最終的なコンタクトフローの開発運用方法は以下の通りになりました。

  • 既存コンタクトフローの変更: 開発者はGUIでフローを編集して「公開」ボタンを押すだけ。あとは自動生成された2段階のPRをレビューしてマージすれば、安全に本番環境へリリースされます。
  • コンタクトフローの新規作成: 新しいTerraformのmoduleブロックを一度だけ手動で追加する必要がありますが、その他のプロセスは上記と全く同じです。
  • コンタクトフローの削除: Terraformのmoduleブロックを削除してPRを作成するという、標準的なGitベースのワークフローで完結します。

最後に

Amazon ConnectのGUI開発の利便性とIaCによる安定した運用の両方の恩恵を受けるために行った取り組みを紹介しました。 Amazon ConnectのIaC化を検討している方や、運用方法を模索している方に本記事を参考にしていただければ幸いです。

*1:Terraformのdefault_tagsの設定でTerraform管理下のリソースにはManagedBy: terraformというタグが付与されています。