1. イントロダクション
1.1 ソリューション概要と利点
Amazon Connect の階層グループ(ユーザー階層グループ)の変更を自動的に検知し、その情報を S3 に保存する機構です
まるで「階層グループの変化を嗅ぎ分ける優秀な番犬」のような存在🐶
よくあるアーキテクチャですがCloudFormation の記述含めご説明します
主な利点
利点 | 説明 |
---|---|
リアルタイム同期 | 階層グループの変更を即座に検知し、S3に反映 |
データの永続化 | 重要な階層情報を安全にS3に保存 |
自動化 | 人手を介さずに自動的に同期処理を実行 |
監査性 | 変更履歴をS3に保存することで、監査証跡として活用可能 |
コスト効率 | サーバーレスアーキテクチャにより、運用コストを最小化 |
2. アーキテクチャ解説
2.1 全体フロー
[Amazon Connect] → [CloudTrail] → [EventBridge] → [Lambda] → [S3]
2.2 各コンポーネントの役割
コンポーネント | 役割 | 特徴 |
---|---|---|
Amazon Connect | 階層グループの管理 | コールセンターの組織構造を管理 |
CloudTrail | API呼び出しの記録 | すべてのAPIアクションをログとして記録 |
EventBridge | イベントルーティング | 特定のイベントを検知してLambdaをトリガー |
Lambda | 処理実行 | 階層情報を取得しS3に保存 |
S3 | データ保存 | 階層情報をJSON形式で保存 |
実際の使用イメージとしてはバックエンドAPIが適宜S3の階層グループを参照しに行き、最新の情報を取得できるといったものです
2.3 データフローの詳細
-
イベント発生
- Amazon Connectで階層グループの変更が発生
- 変更操作(作成/更新/削除)が実行される
-
イベント検知
- CloudTrailがAPI呼び出しを記録
- EventBridgeが特定のイベントパターンを検知
-
処理実行
- Lambda関数がトリガーされる
- 最新の階層グループ情報を取得
-
データ保存
- 取得した情報をJSON形式でS3に保存
3. 実装手順
connect-hierarchy-sync.yml
AWSTemplateFormatVersion: 2010-09-09
Description: "Lambda Function Stack For Amazon Connect Hierarchy Sync Stack"
# -------------------------------------
# Metadata
# -------------------------------------
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: "Project Configuration"
Parameters:
- ProjectName
- Environment
- Label:
default: "Lambda Configuration"
Parameters:
- LambdaArchiveBucketName
- LambdaArchiveBucketObjectKey
- LambdaHandler
- LambdaMemorySize
- LambdaTimeout
- LambdaRuntime
- Label:
default: "EventBridge Configuration"
Parameters:
- EventBridgeRuleName
- ConnectInstanceId
- Label:
default: "S3 Configuration"
Parameters:
- ConnectHierarchyBucketName
- ECSTaskRoleArn
# -------------------------------------
# Input parameters
# -------------------------------------
Parameters:
ProjectName:
Description: "Enter the project name. (ex: your-project-name)"
Type: String
MinLength: 1
ConstraintDescription: "ProjectName must be enter."
Default: your-project-name
Environment:
Description: "Select the environment."
Type: String
AllowedValues:
- dev
- stg
- prd
ConstraintDescription: "Environment must be select."
LambdaArchiveBucketName:
Description: "Enter the S3 bucket name for storing Lambda function deployment package. (ex: your-project-name-<environment>-lambda-function-archive)"
Type: String
LambdaArchiveBucketObjectKey:
Description: "Enter the Lambda function package file (zip) object key of the Lambda archive bucket. (ex: connect-hierarchy-sync/lambda_function.zip)"
Type: String
LambdaHandler:
Description: "Enter the Lambda function name for Connect hierarchy sync. (ex: lambda_function.lambda_handler)"
Type: String
Default: lambda_function.lambda_handler
LambdaMemorySize:
Description: "Enter the Lambda function memory size (MiB). (default: 128)"
Type: Number
Default: 128
MinValue: 128
MaxValue: 512
LambdaTimeout:
Description: "Enter the Lambda function timeout second. (default: 60)"
Type: Number
Default: 60
LambdaRuntime:
Description: "Select the Lambda function runtime. (default: python3.13)"
Type: String
AllowedValues:
- python3.13
Default: python3.13
ConstraintDescription: "Runtime must be select."
EventBridgeRuleName:
Description: "Enter the EventBridge rule name for Connect hierarchy sync. (ex: notice-connect-hierarchy-sync-your-project-name-<environment>)"
Type: String
ConnectInstanceId:
Description: "Enter the Amazon Connect Instance ID."
Type: String
ConnectHierarchyBucketName:
Description: "Enter the S3 bucket name for storing Amazon Connect hierarchy group data. (ex: your-project-name-<environment>-connect-hierarchy-sync)"
Type: String
ECSTaskRoleArn:
Description: "Specify the IAM Role ARN required to run the application. (ex: arn:aws:iam::012345678910:role/ECSTaskRole)"
Type: String
# -------------------------------------
# Resources
# -------------------------------------
Resources:
# -------------------------------------
# IAM
# -------------------------------------
LambdaFunctionRolePolicy:
DeletionPolicy: Retain
UpdateReplacePolicy: Retain
Type: AWS::IAM::ManagedPolicy
Properties:
ManagedPolicyName: !Sub LambdaToConnectAndS3Access-${Environment}
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action: logs:CreateLogGroup
Resource: !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:*
- Effect: Allow
Action:
- logs:CreateLogStream
- logs:PutLogEvents
Resource: !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${ProjectName}-${Environment}-connect-hierarchy-sync:*
- Effect: Allow
Action:
- connect:ListUserHierarchyGroups
Resource: !Sub arn:aws:connect:${AWS::Region}:${AWS::AccountId}:instance/${ConnectInstanceId}
- Effect: Allow
Action:
- s3:PutObject
Resource: !Sub arn:aws:s3:::${ConnectHierarchyBucketName}/*
LambdaFunctionRole:
DeletionPolicy: Retain
UpdateReplacePolicy: Retain
Type: AWS::IAM::Role
Properties:
RoleName: !Sub LambdaToConnectAndS3Role-${Environment}
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
Path: /
ManagedPolicyArns:
- !Ref LambdaFunctionRolePolicy
# -------------------------------------
# Lambda
# -------------------------------------
LambdaFunction:
Type: AWS::Lambda::Function
Properties:
Code:
S3Bucket: !Ref LambdaArchiveBucketName
S3Key: !Ref LambdaArchiveBucketObjectKey
Description: "This function syncs Amazon Connect hierarchy data to S3."
Environment:
Variables:
CONNECT_INSTANCE_ID: !Ref ConnectInstanceId
S3_BUCKET_NAME: !Ref ConnectHierarchyBucketName
FunctionName: !Sub ${ProjectName}-${Environment}-connect-hierarchy-sync
Handler: !Ref LambdaHandler
MemorySize: !Ref LambdaMemorySize
PackageType: Zip
Timeout: !Ref LambdaTimeout
Role: !GetAtt LambdaFunctionRole.Arn
Runtime: !Ref LambdaRuntime
LambdaFunctionPermission:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
FunctionName: !GetAtt LambdaFunction.Arn
Principal: events.amazonaws.com
SourceArn: !GetAtt ConnectHierarchyRule.Arn
# -------------------------------------
# EventBridge
# -------------------------------------
ConnectHierarchyRule:
Type: AWS::Events::Rule
Properties:
Name: !Ref EventBridgeRuleName
Description: "Amazon Connect の階層グループ変更時に指定する Lambda 関数をトリガー"
EventPattern:
source:
- aws.connect
detail-type:
- AWS API Call via CloudTrail
detail:
eventSource:
- connect.amazonaws.com
eventName:
- CreateUserHierarchyGroup
- UpdateUserHierarchyGroupName
- DeleteUserHierarchyGroup
requestParameters:
InstanceId:
- !Ref ConnectInstanceId
Targets:
- Arn: !GetAtt LambdaFunction.Arn
Id: Lambda
- Arn: !GetAtt EventBridgeLogGroup.Arn
Id: CloudWatchLogs
# -------------------------------------
# CloudWatchLogs LogGroup
# -------------------------------------
EventBridgeLogGroup:
DeletionPolicy: Retain
UpdateReplacePolicy: Retain
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub /aws/events/eventbridge/${EventBridgeRuleName}
RetentionInDays: 30
Tags:
- Key: ProjectName
Value: !Ref ProjectName
- Key: Environment
Value: !Ref Environment
EventBridgeLogGroupPolicy:
Type: AWS::Logs::ResourcePolicy
Properties:
PolicyName: !Sub EventBridgeLogGroupPolicy-${Environment}
PolicyDocument: !Sub |
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "EventBridgeToCloudWatchLogs",
"Effect": "Allow",
"Principal": {
"Service": "events.amazonaws.com"
},
"Action": [
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "${EventBridgeLogGroup.Arn}"
}
]
}
# -------------------------------------
# S3
# -------------------------------------
ConnectHierarchyBucket:
Type: AWS::S3::Bucket
DeletionPolicy: Retain
UpdateReplacePolicy: Retain
Properties:
BucketName: !Ref ConnectHierarchyBucketName
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
Tags:
- Key: ProjectName
Value: !Ref ProjectName
- Key: Environment
Value: !Ref Environment
ConnectHierarchyBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref ConnectHierarchyBucket
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Deny
Principal: "*"
Action: "s3:*"
Resource:
- !Sub ${ConnectHierarchyBucket.Arn}
- !Sub ${ConnectHierarchyBucket.Arn}/*
Condition:
Bool:
"aws:SecureTransport": false
- Effect: Allow
Principal:
AWS: !Ref ECSTaskRoleArn
Action:
- s3:GetObject
Resource: !Sub ${ConnectHierarchyBucket.Arn}/*
3.1 CloudFormation テンプレートの解説
重要なパラメータ
パラメータ名 | 説明 |
---|---|
ProjectName | プロジェクト名 |
Environment | 環境(dev/stg/prd) |
ConnectInstanceId | Amazon ConnectインスタンスID |
ConnectHierarchyBucketName | 階層情報保存用S3バケット名 |
主要なリソース定義
リソース | 説明 | 重要な設定 |
---|---|---|
LambdaFunctionRole | Lambda実行用IAMロール | ConnectとS3へのアクセス権限 |
LambdaFunction | Lambda関数定義 | メモリ128MB、タイムアウト60秒 |
ConnectHierarchyRule | EventBridgeルール | 階層グループ変更イベントの検知 |
ConnectHierarchyBucket | S3バケット | 暗号化とパブリックアクセス制限 |
3.2 Lambda 関数のコード解説
# 主要な処理ロジック
def lambda_handler(event, context):
try:
# 1. Connectから階層グループ情報を取得
response = connect.list_user_hierarchy_groups(
InstanceId=CONNECT_INSTANCE_ID
)
# 2. 階層グループ名を抽出
hierarchy_groups = []
for group in response["UserHierarchyGroupSummaryList"]:
hierarchy_groups.append(group["Name"])
# 3. S3にJSON形式で保存
s3.put_object(
Bucket=S3_BUCKET_NAME,
Key=S3_HIERARCHY_GROUPS_KEY,
Body=json.dumps({"name": hierarchy_groups}, default=str, ensure_ascii=False),
ContentType="application/json"
)
return {"statusCode": 200}
except Exception as e:
return {
"statusCode": 500,
"body": json.dumps({"error": str(e)}, default=str, ensure_ascii=False)
}
今回は階層グループ名のみを取得していますが、別の Amazon Connect API を使用すれば大体の情報は取得できると思います
5. セキュリティのベストプラクティス
セキュリティ対策 | 実装内容 | 効果 |
---|---|---|
IAMロール | 最小権限の原則 | 必要な権限のみ付与 |
S3暗号化 | サーバーサイド暗号化 | データの保護 |
パブリックアクセス制限 | バケットポリシー | 不正アクセスの防止 |
セキュアトランスポート | HTTPS強制 | 通信の暗号化 |
6. まとめ
「階層グループの番犬」として、組織の構造変化を確実に記録し、必要な時にすぐに参照できる状態を維持しますU^ェ^U
まるで優秀な番犬が、家の出入りを記録するように、階層グループの変更を確実に記録していくのです・・・U・x・U