【问题标题】:Making a signed HTTP request to AWS Elasticsearch in Python在 Python 中向 AWS Elasticsearch 发出签名的 HTTP 请求
【发布时间】:2016-11-03 19:10:00
【问题描述】:

我正在尝试制作一个简单的 Python Lambda,用于制作 Elasticsearch 数据库的快照。这是通过 Elasticsearch's REST API 使用简单的 HTTP 请求完成的。

但是,对于 AWS,我必须签署这些请求。我有一种感觉,它可以通过boto3 的低级客户端可能与generate_presigned_url 来实现,但我终生无法弄清楚如何正确调用此函数。例如,有效的ClientMethods 是什么?我试过ESHttpGet,但无济于事。

谁能指出我正确的方向?

【问题讨论】:

标签: python-2.7 amazon-web-services elasticsearch boto3


【解决方案1】:

编辑:显然这个解决方法是broken by Elastic

我挣扎了一段时间来做类似的事情。目前 boto3 库不支持发出签名的 es 请求,但由于我 raised an issue 与它们一起它已成为功能请求。

在此期间,我使用上述DavidMuller's library 和 boto3 来获取我的 STS 会话凭据:

import boto3
from aws_requests_auth.aws_auth import AWSRequestsAuth
from elasticsearch import Elasticsearch, RequestsHttpConnection

session = boto3.session.Session()
credentials = session.get_credentials().get_frozen_credentials()

es_host = 'search-my-es-domain.eu-west-1.es.amazonaws.com'
awsauth = AWSRequestsAuth(
    aws_access_key=credentials.access_key,
    aws_secret_access_key=credentials.secret_key,
    aws_token=credentials.token,
    aws_host=es_host,
    aws_region=session.region_name,
    aws_service='es'
)

# use the requests connection_class and pass in our custom auth class
es = Elasticsearch(
    hosts=[{'host': es_host, 'port': 443}],
    http_auth=awsauth,
    use_ssl=True,
    verify_certs=True,
    connection_class=RequestsHttpConnection
)

print(es.info())

希望这可以节省一些时间。

【讨论】:

    【解决方案2】:

    请求库有几个 Python 扩展,可以为您执行 SigV4 签名。我用过this one,效果很好。

    【讨论】:

    • 是的,我一直希望将其保留为 boto3botocore,但我最终在 boto 中使用了 AWSAuthConnection - 似乎可以解决问题。
    【解决方案3】:

    虽然其他答案都很好,但我想消除对外部软件包的使用。显然,botocore 本身具有签署请求所需的所有功能,只需查看源代码即可。这就是我最终直接发送 AWS API 请求的结果(为了演示目的,这些东西是硬编码的):

          import boto3
          import botocore.credentials
          from botocore.awsrequest import AWSRequest
          from botocore.endpoint import URLLib3Session
          from botocore.auth import SigV4Auth
    
          params = '{"name": "hello"}'
          headers = {
            'Host': 'ram.ap-southeast-2.amazonaws.com',
          }
          request = AWSRequest(method="POST", url="https://ram.ap-southeast-2.amazonaws.com/createresourceshare", data=params, headers=headers)
          SigV4Auth(boto3.Session().get_credentials(), "ram", "ap-southeast-2").add_auth(request)    
    
    
          session = URLLib3Session()
          r = session.send(request.prepare())
    

    【讨论】:

    • BotocoreHTTPSession 在最新版本的boto3 上导致ImportError(撰写本文时为1.9.42)。将该行更改为以下内容可为我解决错误:from botocore.httpsession import URLLib3Session
    【解决方案4】:

    我最近发布了requests-aws-sign,它为 Python 请求库提供 AWS V4 请求签名。

    如果您查看this code,您将了解如何使用 Botocore 生成 V4 请求签名。

    【讨论】:

      【解决方案5】:

      为什么不只使用请求?

      import requests
      headers = {'Content-Type': 'application/json',}
      data = '{"director": "Burton, Tim", "genre": ["Comedy","Sci-Fi","R-rated"],"profit" : 98 , "year": 1996, "actor": ["Jack Nicholson","PierceBrosnan","Sarah Jessica Parker"], "title": "Mars Attacks!"}'
      response = requests.post('https://search-your-awsendpoint.us-west-2.es.amazonaws.com/yourindex/_yourdoc/', headers=headers, data=data)
      

      这对我有用

      【讨论】:

      • 这意味着您的终端节点允许公共访问或(希望)隐藏在 VPC 后面。 The docs say "如果您的域访问策略包括 IAM 用户或角色,您必须签署对 Elasticsearch API 的请求。"
      • 我使用 lambda 调用它,是的,它是面向公众的。如果你想要它在 vpc 中,你可以在 vpc 中创建 lambda 并将 iam 角色附加到 lambda。那是我的用例。
      • 所以它是面向公众的,并且您允许任何人将数据放入其中?
      • docs.aws.amazon.com/elasticsearch-service/latest/developerguide/… 请遵循该文档。即使它是面向公众的,我也可以根据 iam 权限或 IP 地址限制请求。谢谢
      • 在某些情况下,无论资源策略、vpc 安全组或 iam 权限如何,您都需要签名请求,例如手动快照。
      猜你喜欢
      • 1970-01-01
      • 2022-08-20
      • 2019-04-16
      • 2022-06-11
      • 2017-11-28
      • 2021-10-13
      • 2019-11-30
      • 1970-01-01
      • 2021-10-06
      相关资源
      最近更新 更多