CFNカスタムリソースを使用して、OpenSearch Serverlessのインデックス作成を自動化する
以下のページでOpenSearch Serverlessについて取り上げました。
上記のページでは、手動でLambda関数を実行することで、インデックスを作成しました。
本ページでは、自動的にインデックスを作成する方法を考えます。
具体的には、CloudFormationカスタムリソースを使用する方法です。
構築する環境
CloudFormationを使用して、主に2つのリソースを作成します。
1つ目はOpenSearch Serverlessコレクションです。
2つ目はLambda関数です。
関数のランタイム環境はPython3.8です。
この関数をCloudFormationカスタムリソースに関連付けて、スタック作成時に本関数が実行されるように設定します。
この関数の働きは、OpenSearch Serverlessにインデックスを作成することです。
CloudFormationテンプレートファイル
上記の構成をCloudFormationで構築します。
以下のURLにCloudFormationテンプレートを配置しています。
https://github.com/awstut-an-r/awstut-fa/tree/main/148
テンプレートファイルのポイント解説
Lambda関数
Resources:
CustomResource2:
Type: Custom::CustomResource
DependsOn:
- Function2
Properties:
ServiceToken: !GetAtt Function2.Arn
Code language: YAML (yaml)
CloudFormationカスタムリソースの本体です。
後述のLambda関数を指定し、CloudFormationスタック操作時に、同関数を実行できるようになります。
CloudFormationカスタムリソースに関しては、以下のページをご確認ください。
Resources:
Function2:
Type: AWS::Lambda::Function
Properties:
Architectures:
- !Ref Architecture
Environment:
Variables:
COLLECTION_ENDPOINT: !Sub "${Collection}.${AWS::Region}.aoss.amazonaws.com"
OPENSEARCH_INDEX_NAME: !Ref OpenSearchIndexName
REGION: !Ref AWS::Region
Code:
ZipFile: |
from opensearchpy import OpenSearch, RequestsHttpConnection, AWSV4SignerAuth
import boto3
import cfnresponse
import os
host = os.environ['COLLECTION_ENDPOINT']
opensearch_index_name = os.environ['OPENSEARCH_INDEX_NAME']
region = os.environ['REGION']
service = 'aoss'
credentials = boto3.Session().get_credentials()
auth = AWSV4SignerAuth(credentials, region, service)
CREATE = 'Create'
response_data = {}
client = OpenSearch(
hosts=[{'host': host, 'port': 443}],
http_auth=auth,
use_ssl=True,
verify_certs=True,
connection_class=RequestsHttpConnection,
pool_maxsize=20,
)
def lambda_handler(event, context):
try:
if event['RequestType'] == CREATE:
create_response = client.indices.create(
opensearch_index_name
)
print(create_response)
cfnresponse.send(event, context, cfnresponse.SUCCESS, response_data)
except Exception as e:
print(e)
cfnresponse.send(event, context, cfnresponse.FAILED, response_data)
FunctionName: !Sub "${Prefix}-function-02"
Handler: !Ref Handler
Layers:
- !Ref LambdaLayer
Runtime: !Ref Runtime
Role: !Ref FunctionRoleArn2
Timeout: 60
Code language: YAML (yaml)
CloudFormationカスタムリソースに関連づけるLambda関数です。
if文を使用して、CloudFormationスタック作成時に、以降のコードが実行されるように設定します。
OpenSearch用のクライアントオブジェクトを作成し、同オブジェクトのindices.createメソッドを実行して、インデックスを作成します。
作成するインデックスの名前は「python-test-index」です。
この名前の文字列はに環境変数として関数に渡します。
PythonからOpenSearch Serverlessにアクセスするために、AWS公式が提供しているパッケージ(opensearch-py)を使用します。
このパッケージはデフォルトのLambda関数のランタイム環境には含まれていません。
今回はLambdaレイヤーを作成し、これを含めることによって、同パッケージを使用できるようにします。
詳細につきましては、冒頭でご紹介したページをご確認ください。
CloudFormationカスタムリソースを使用して、自動的にこのLambdaレイヤーを作成します。
詳細につきましては、以下のページをご確認ください。
Resources:
FunctionRole2:
Type: AWS::IAM::Role
DeletionPolicy: Delete
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action: sts:AssumeRole
Principal:
Service:
- lambda.amazonaws.com
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Policies:
- PolicyName: FunctionRole2Policy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- aoss:APIAccessAll
Resource:
- !Sub "arn:aws:aoss:${AWS::Region}:${AWS::AccountId}:collection/*"
RoleName: !Sub "${Prefix}-FunctionRole2"
Code language: YAML (yaml)
Lambda関数用のIAMロールです。
OpenSearch Serverlessへの全APIアクセスを許可する内容です。
(参考)IAMユーザ
Resources:
User:
Type: AWS::IAM::User
Properties:
LoginProfile:
Password: !Ref Password
Policies:
- PolicyName: AllAllowPolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- aoss:*
Resource: "*"
UserName: !Sub "${Prefix}-user"
Code language: YAML (yaml)
OpenSearch Serverlessダッシュボードを操作するための専用ユーザです。
インラインポリシーでOpenSearch Serverless系の全アクションを許可します。
(参考)OpenSearch Serverless
Resources:
Collection:
Type: AWS::OpenSearchServerless::Collection
DependsOn:
- EncryptionSecurityPolicy
Properties:
Name: !Ref CollectionName
StandbyReplicas: DISABLED
Type: TIMESERIES
DataAccessPolicy1:
Type: AWS::OpenSearchServerless::AccessPolicy
Properties:
Name: !Sub "${Prefix}-data-policy-01"
Policy: !Sub >-
[{"Description":"Access for cfn user","Rules":[{"ResourceType":"index","Resource":["index/*/*"],"Permission":["aoss:*"]},
{"ResourceType":"collection","Resource":["collection/${CollectionName}"],"Permission":["aoss:*"]}],
"Principal":["${UserArn}"]}]
Type: data
DataAccessPolicy2:
Type: AWS::OpenSearchServerless::AccessPolicy
Properties:
Name: !Sub "${Prefix}-data-policy-02"
Policy: !Sub >-
[{"Description":"Access for Function2","Rules":[{"ResourceType":"index","Resource":["index/${CollectionName}/${OpenSearchIndexName}"],"Permission":["aoss:CreateIndex"]}],
"Principal":["${FunctionRoleArn2}"]}]
Type: data
NetworkSecurityPolicy:
Type: AWS::OpenSearchServerless::SecurityPolicy
Properties:
Name: !Sub "${Prefix}-network-policy"
Policy: !Sub >-
[{"Rules":[{"ResourceType":"collection","Resource":["collection/${CollectionName}"]},
{"ResourceType":"dashboard","Resource":["collection/${CollectionName}"]}],"AllowFromPublic":true}]
Type: network
EncryptionSecurityPolicy:
Type: AWS::OpenSearchServerless::SecurityPolicy
Properties:
Name: !Sub "${Prefix}-encryption-policy"
Policy: !Sub >-
{"Rules":[{"ResourceType":"collection","Resource":["collection/${CollectionName}"]}],"AWSOwnedKey":true}
Type: encryption
Code language: YAML (yaml)
OpenSearch Serverlessおよび各種ポリシーを作成します。
OpenSearch Serverlessに関する基本的な事項については、冒頭でご紹介したページをご確認ください。
ポイントはデータアクセスポリシーです。
2つ作成します。
1つ目は専用IAMユーザ用のポリシーです。
ユーザに全アクションを許可する内容です。
2つ目はLambda関数用のポリシーです。
インデックス作成に必要なアクション(aoss:CreateIndex)を許可する内容です。
環境構築
CloudFormationを使用して、本環境を構築し、実際の挙動を確認します。
CloudFormationスタックを作成し、スタック内のリソースを確認する
CloudFormationスタックを作成します。
スタックの作成および各スタックの確認方法については、以下のページをご確認ください。
今回は名前をつけるIAMリソース(IAMユーザ等)を作成しますから、以下の通りにオプションを設定します。
$ aws cloudformation create-stack \
--stack-name [stack-name] \
--template-url https://[bucket-name].s3.ap-northeast-1.amazonaws.com/[folder-name]/fa-148.yaml \
--capabilities CAPABILITY_NAMED_IAM
Code language: Bash (bash)
AWS Management ConsoleからOpenSearch Serverlessコレクションを確認します。
OpenSearch Serverlessコレクションが正常に作成されています。
データアクセスポリシーを確認します。
前者はIAMユーザ用で、2つ目はLambda関数用です。
それぞれの用途に応じたアクションが許可されています。
Lambda関数を確認します。
Lambda関数が正常に作成されています。
Lambdaレイヤーを見ると、レイヤーが作成されており、この関数に関連づいていることがわかります。
CloudFormationカスタムリソースによって、自動的にLambdaレイヤーが作成されたということです。
動作確認
準備が整いましたので、CloudWatch Logsにアクセスして、Lambda関数の動作状況を確認します。
関数が自動的に実行されていることがわかります。
つまりCloudFormationカスタムリソースによって、自動的に本関数が実行されたということです。
専用IAMユーザでOpenSearch Serverlessダッシュボードにログインします。
ダッシュボードからインデックスを確認します。
確かに「python-test-index」が作成されていることがわかります。
このことから、確かにCloudFormationカスタムリソースによってLambda関数が実行されて、OpenSearch Serverlessにインデックスが作成されたことがわかります。
まとめ
CloudFormationカスタムリソースを使用して、OpenSearch Serverlessに自動的にインデックスを作成する方法をご紹介しました。