there are some gists floating around to adapt, most look like this block of JSON for the cloudformation custom resources file. You likely want to lock down the permission a bit more.
{"ConfigureESCustom":{"Type":"Custom::ConfigureES","Properties":{"ServiceToken":{"Fn::GetAtt":["ConfigureES","Arn"]}}},"ConfigureES":{"Type":"AWS::Lambda::Function","Properties":{"Environment":{"Variables":{"ES_ENDPOINT":{"Fn::ImportValue":{"Fn::Join":[":",[{"Ref":"AppSyncApiId"},"GetAtt","Elasticsearch","DomainEndpoint"]]}},"ES_REGION":{"Ref":"AWS::Region"}}},"Code":{"ZipFile":"import base64
import json
import logging
import string
import boto3
import os
import time
import datetime
import traceback
from urllib.parse import urlparse, quote
from botocore.vendored import requests
from botocore.auth import SigV4Auth
from botocore.awsrequest import AWSRequest
from botocore.credentials import get_credentials
from botocore.endpoint import BotocoreHTTPSession
from botocore.session import Session
import cfnresponse
logger = logging.getLogger()
logger.setLevel(logging.INFO)
# The following parameters are required to configure the ES cluster
ES_ENDPOINT = os.environ['ES_ENDPOINT']
ES_REGION = os.environ['ES_REGION']
DEBUG = True if os.environ['DEBUG'] is not None else False
def es_put(payload, region, creds, host, path, method='PUT', proto='https://'):
'''Put index data to ES endpoint with SigV4 signed http headers'''
req = AWSRequest(method=method, url=proto + host +
quote(path), data=payload, headers={'Host': host, 'Content-Type': 'application/json'})
SigV4Auth(creds, 'es', region).add_auth(req)
http_session = BotocoreHTTPSession()
res = http_session.send(req.prepare())
return res._content
def lambda_handler(event, context):
logger.info('got event {}'.format(event))
if event['RequestType'] == 'Create':
# Get aws_region and credentials to post signed URL to ES
es_region = ES_REGION or os.environ['AWS_REGION']
session = Session({'region': es_region})
creds = get_credentials(session)
es_url = urlparse(ES_ENDPOINT)
# Extract the domain name in ES_ENDPOINT
es_endpoint = es_url.netloc or es_url.path
es_put('', es_region, creds,
es_endpoint, '/s12doctor')
es_actions = []
es_actions.append('') # Add one empty line to force final \
es_payload = '\
'.join(es_actions)
action = {\"properties\": {\"location\": {\"type\": \"geo_point\"}, \"coordinates\": {\"type\": \"geo_point\"}}}
es_actions.append(json.dumps(action))
es_actions.append('') # Add one empty line to force final \
es_payload = '\
'.join(es_actions)
es_put(es_payload, es_region, creds,
es_endpoint, '/INDEX_NAME_HERE/_mapping/doc')
cfnresponse.send(event, context, cfnresponse.SUCCESS, {})
"},"FunctionName":{"Fn::Join":["-",["ConfigureES",{"Ref":"env"}]]},"Handler":"index.lambda_handler","Timeout":30,"Role":{"Fn::GetAtt":["LambdaRole","Arn"]},"Runtime":"python3.6","Layers":["arn:aws:lambda:eu-west-2:142628438157:layer:AWSLambda-Python-AWS-SDK:1"]}},"LambdaRole":{"Type":"AWS::IAM::Role","Properties":{"AssumeRolePolicyDocument":{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":["lambda.amazonaws.com"]},"Action":["sts:AssumeRole"]}]},"Path":"/","Policies":[{"PolicyName":"lambda-logs","PolicyDocument":{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"],"Resource":["arn:aws:logs:*:*:*"]}]}},{"PolicyName":"ES","PolicyDocument":{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["es:*"],"Resource":{"Fn::Join":["",[{"Fn::ImportValue":{"Fn::Join":[":",[{"Ref":"AppSyncApiId"},"GetAtt","Elasticsearch","DomainArn"]]}},"/*"]]}}]}}]}}}
Ok nice, I was not aware of that. Do you have some more info / referencence documentation about this?
there are some gists floating around to adapt, most look like this block of JSON for the cloudformation custom resources file. You likely want to lock down the permission a bit more.
Thx, will look into it and update this post accordingly