Skip to content

Commit 1de6f30

Browse files
committed
Sign requests using AWS4Auth
While using OpenSearch deployed on AWS infrastructure, the requests needs to be signed with AWS4Auth signature, in order to get the data. This commit adds this possibility. To enable it make sure that following dependencies are installed withing your python env: * requests-aws4auth * botocore
1 parent f656788 commit 1de6f30

File tree

1 file changed

+46
-14
lines changed

1 file changed

+46
-14
lines changed

prometheus_es_exporter/__init__.py

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import sched
1010
import time
1111

12-
from elasticsearch import Elasticsearch
12+
from elasticsearch import Elasticsearch, RequestsHttpConnection
1313
from elasticsearch.exceptions import ConnectionTimeout
1414
from jog import JogFormatter
1515
from prometheus_client import start_http_server
@@ -26,6 +26,12 @@
2626
from .scheduler import schedule_job
2727
from .utils import log_exceptions, nice_shutdown
2828

29+
try:
30+
from requests_aws4auth import AWS4Auth
31+
from botocore.session import Session
32+
except ImportError, ModuleNotFoundError:
33+
pass
34+
2935
log = logging.getLogger(__name__)
3036

3137
CONTEXT_SETTINGS = {
@@ -209,10 +215,20 @@ def run_query(es_client, query_name, indices, query,
209215
metrics = parse_response(response, [query_name])
210216
metric_dict = group_metrics(metrics)
211217

212-
except Exception:
218+
except Exception as e:
213219
log.exception('Error while querying indices %(indices)s, query %(query)s.',
214220
{'indices': indices, 'query': query})
215221

222+
# NOTE(mjozefcz): If there is an 401 exception, and the AWS signing was
223+
# set, re-raise it and exit the exporter. It might be wrongly-configured
224+
# credentials or old session.
225+
try:
226+
if e.status_code == 401 and type(es_client.transport.kwargs.get("http_auth")) is AWS4Auth:
227+
# TODO (mjozefcz): Consider re-initialization of AWS4AUTH if possible.
228+
raise e
229+
except NameError:
230+
pass
231+
216232
# If this query has successfully run before, we need to handle any
217233
# metrics produced by that previous run.
218234
if query_name in METRICS_BY_QUERY:
@@ -404,6 +420,9 @@ def conv(value):
404420

405421

406422
@click.command(context_settings=CONTEXT_SETTINGS)
423+
@click.option('--aws-sign-request', default=False, is_flag=True,
424+
help='This should be set if you want your requests to be signed with AWS credentials retrieved from your environment.')
425+
@click.option('--aws-region', help='Region name to be used while signing request with AWS credentials')
407426
@click.option('--es-cluster', '-e', default='localhost',
408427
help='Addresses of nodes in a Elasticsearch cluster to run queries on. '
409428
'Nodes should be separated by commas e.g. es1,es2. '
@@ -516,6 +535,8 @@ def cli(**options):
516535
raise click.BadOptionUsage('basic_password', 'Password provided with no username.')
517536
elif options['basic_user']:
518537
http_auth = (options['basic_user'], options['basic_password'])
538+
elif options['aws_sign_request'] and not options['aws_region']:
539+
raise click.BadOptionUsage('aws_sign_requst', 'AWS requests signing enabled but region not provided.')
519540
else:
520541
http_auth = None
521542

@@ -562,19 +583,30 @@ def cli(**options):
562583
port = options['port']
563584
es_cluster = options['es_cluster'].split(',')
564585

586+
kwargs = {
587+
"https_auth": http_auth,
588+
"headers": options['header'],
589+
"verify_certs": False
590+
}
591+
592+
if options['aws_sign_request'] and options['aws_region']:
593+
service = 'es'
594+
credentials = Session().get_credentials()
595+
http_auth = AWS4Auth(credentials.access_key, credentials.secret_key, options['aws_region'], service, session_token=credentials.token)
596+
kwargs.update({
597+
"http_auth": http_auth,
598+
"connection_class": RequestsHttpConnection
599+
})
600+
565601
if options['ca_certs']:
566-
es_client = Elasticsearch(es_cluster,
567-
verify_certs=True,
568-
ca_certs=options['ca_certs'],
569-
client_cert=options['client_cert'],
570-
client_key=options['client_key'],
571-
headers=options['header'],
572-
http_auth=http_auth)
573-
else:
574-
es_client = Elasticsearch(es_cluster,
575-
verify_certs=False,
576-
headers=options['header'],
577-
http_auth=http_auth)
602+
kwargs.update({
603+
"verify_certs": True,
604+
"ca_certs": options['ca_certs'],
605+
"client_cert": options['client_cert'],
606+
"client_key": options['client_key']
607+
})
608+
609+
es_client = Elasticsearch(es_cluster, **kwargs)
578610

579611
scheduler = None
580612

0 commit comments

Comments
 (0)