1

我最近發佈了一個關於How to allow invoking an AWS Lambda function only from EC2 instances inside a VPC的問題。 我設法通過將具有「AWS lambda role」策略的IAM角色附加到EC2實例來實現它,現在我可以使用boto3調用lambda函數。如何使用python asyncio從EC2實例調用AWS Lambda函數

現在,我想使用asyncio await語法異步調用lambda函數。我通過設置InvokeType='Event'來讀取lambda函數提供的異步版本,但實際上使得調用立即返回而沒有得到函數的結果。

由於該函數需要一些時間,我想並行啓動很多,我希望避免在等待函數返回時阻止執行。

我試過使用aiobotocore,但那只是支持基本的's3'服務功能。

解決這個問題的最好方法就是使用AWS API網關服務通過GET/POST請求調用lambda函數,該請求可以使用aiohttp輕鬆處理。

儘管如此,我並沒有設法使它工作。

我加入到EC2 IAM角色的政策「AmazonAPIGatewayInvokeFullAccess」但每次我嘗試時間:

import requests 
r = requests.get('https://url_to_api_gateway_for_function') 

我得到禁止迴應<Response [403]>

我直接使用lambda函數中的觸發器創建了API網關。

我還嘗試編輯API網關設置,方法是在函數路徑中添加post方法,並設置「AWS_IAM」身份驗證,然後將其部署爲「prod」部署...沒有運氣。同樣禁止的迴應。當我通過「API網關上的測試屏幕」進行測試時,它可以正常工作。

任何想法如何解決這個問題?我錯過了一些步驟?

+0

http://docs.aws.amazon.com/apigateway/latest/developerguide/getting-started.html#getting-started-prerequisites'你可以使用或自定義所管理的策略AWSLambdaFullAccess(arn:aws:iam :: aws:policy/AWSLambdaFullAccess)並將其附加到IAM用戶 – mootmoot

+0

我試過這個教程,我設法使它工作,只要我沒有設置** AWS_IAM **作爲授權API ...只要我打開它,從EC2即使我使用策略AWSLambdaFullAccess作爲EC2實例,我也可以獲得403響應... – Bertone

+0

什麼是AWS_IAM授權? – mootmoot

回答

2

經過一番努力,我設法解決了我的問題。

問題是curl和python模塊(如python的請求)不會使用它們運行的​​EC2計算機的IAM憑證對http請求進行簽名。對AWS GATEWAY API的http請求必須使用AWS v4登錄協議進行簽名。

一個例子是在這裏: http://docs.aws.amazon.com/general/latest/gr/sigv4-signed-request-examples.html

幸運的是,讓事情變得簡單,有喜歡的請求 - AWS-SIGN一些輔助模塊: https://github.com/jmenga/requests-aws-sign

在結束時,代碼可能看起來是這樣的:

import aiohttp 
import asyncio 
from requests_aws_sign import AWSV4Sign 
from boto3 import session 

session = session.Session() 
credentials = session.get_credentials() 
region = session.region_name or 'ap-southeast-2' 
service = 'execute-api' 
url = "get_it_from_api->stages->your_deployment->invoke_url" 
auth=AWSV4Sign(credentials, region, service) 

async def invoke_func(loop): 
    async with aiohttp.request('GET', url, auth=auth, loop=loop) as resp: 
     html = await resp.text() 
     print(html) 

loop = asyncio.get_event_loop() 
loop.run_until_complete(main(loop)) 

希望這會節省時間給其他人!

編輯:

的完整性和幫助別人我不得不說,上面的代碼不工作的緣故,由於這樣的事實,requests_aws_sign不與aiohttp兼容。我得到一些「驗證字段錯誤」。

我manged通過使用來解決它:

async with session.get(url, headers=update_headers()) as resp: 

其中update_headers()是一個模擬什麼requests_aws_sign在做到標題(使我可以然後直接將它們設置於上述使用請求一個簡單的函數標題參數)。 它看起來像這樣:

def update_headers(sim_id): 
    url = urlparse("get_it_from_api->stages->your_deployment->invoke_url") 
    path = url.path or '/' 
    querystring = '' 
    if url.query: 
     querystring = '?' + urlencode(parse_qs(url.query), doseq=True) 
    safe_url = url.scheme + '://' + url.netloc.split(':')[0] + path + querystring 
    request = AWSRequest(method='GET', url=safe_url) 
    SigV4Auth(credentials, service, region).add_auth(request) 
    return dict(request.headers.items()) 
相關問題