Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fixed all aws query runners auth #6914

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
41 changes: 22 additions & 19 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ optional = true
[tool.poetry.group.all_ds.dependencies]
atsd-client = "3.0.5"
azure-kusto-data = "0.0.35"
boto3 = "1.28.8"
botocore = "1.31.8"
boto3 = "1.34.89"
botocore = "1.34.89"
cassandra-driver = "3.21.0"
certifi = ">=2019.9.11"
cmem-cmempy = "21.2.3"
Expand Down
39 changes: 26 additions & 13 deletions redash/query_runner/amazon_elasticsearch.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from .elasticsearch2 import ElasticSearch2

try:
import boto3
from botocore import credentials, session
from requests_aws_sign import AWSV4Sign

Expand Down Expand Up @@ -32,9 +33,10 @@ def configuration_schema(cls):
"region": {"type": "string"},
"access_key": {"type": "string", "title": "Access Key"},
"secret_key": {"type": "string", "title": "Secret Key"},
"use_aws_iam_profile": {
"type": "boolean",
"title": "Use AWS IAM Profile",
"iam_role": {"type": "string", "title": "IAM role to assume"},
"external_id": {
"type": "string",
"title": "External ID to be used while STS assume role",
},
},
"secret": ["secret_key"],
Expand All @@ -43,24 +45,35 @@ def configuration_schema(cls):
"region",
"access_key",
"secret_key",
"use_aws_iam_profile",
"iam_role",
"external_id",
],
"required": ["server", "region"],
}

def __init__(self, configuration):
super(AmazonElasticsearchService, self).__init__(configuration)

region = configuration["region"]
cred = None
if configuration.get("use_aws_iam_profile", False):
cred = credentials.get_credentials(session.Session())
else:
cred = credentials.Credentials(
access_key=configuration.get("access_key", ""),
secret_key=configuration.get("secret_key", ""),
args = {
"region_name": region,
"aws_access_key_id": configuration.get("access_key", None),
"aws_secret_access_key": configuration.get("secret_key", None),
}
if configuration.get("iam_role"):
role_session_name = "redash"
sts = boto3.client("sts", **args)
creds = sts.assume_role(
RoleArn=configuration.get("iam_role"),
RoleSessionName=role_session_name,
ExternalId=configuration.get("external_id"),
)

args = {
"aws_access_key_id": creds["Credentials"]["AccessKeyId"],
"aws_secret_access_key": creds["Credentials"]["SecretAccessKey"],
"aws_session_token": creds["Credentials"]["SessionToken"],
"region_name": region,
}
cred = credentials.get_credentials(session.Session(**args))
self.auth = AWSV4Sign(cred, region, "es")

def get_auth(self):
Expand Down
70 changes: 23 additions & 47 deletions redash/query_runner/athena.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@

logger = logging.getLogger(__name__)
ANNOTATE_QUERY = parse_boolean(os.environ.get("ATHENA_ANNOTATE_QUERY", "true"))
SHOW_EXTRA_SETTINGS = parse_boolean(os.environ.get("ATHENA_SHOW_EXTRA_SETTINGS", "true"))
ASSUME_ROLE = parse_boolean(os.environ.get("ATHENA_ASSUME_ROLE", "false"))
OPTIONAL_CREDENTIALS = parse_boolean(os.environ.get("ATHENA_OPTIONAL_CREDENTIALS", "true"))

try:
import boto3
Expand Down Expand Up @@ -65,6 +62,11 @@ def configuration_schema(cls):
schema = {
"type": "object",
"properties": {
"iam_role": {"type": "string", "title": "IAM role to assume"},
"external_id": {
"type": "string",
"title": "External ID to be used while STS assume role",
},
"region": {"type": "string", "title": "AWS Region"},
"aws_access_key": {"type": "string", "title": "AWS Access Key"},
"aws_secret_key": {"type": "string", "title": "AWS Secret Key"},
Expand All @@ -88,11 +90,20 @@ def configuration_schema(cls):
"title": "Athena cost per Tb scanned (USD)",
"default": 5,
},
"encryption_option": {
"type": "string",
"title": "Encryption Option",
},
"kms_key": {"type": "string", "title": "KMS Key"},
},
"required": ["region", "s3_staging_dir"],
"extra_options": ["glue", "cost_per_tb"],
"extra_options": ["glue", "cost_per_tb", "encryption_option", "kms_key"],
"order": [
"aws_access_key",
"aws_secret_key",
"region",
"iam_role",
"external_id",
"s3_staging_dir",
"schema",
"work_group",
Expand All @@ -101,42 +112,6 @@ def configuration_schema(cls):
"secret": ["aws_secret_key"],
}

if SHOW_EXTRA_SETTINGS:
schema["properties"].update(
{
"encryption_option": {
"type": "string",
"title": "Encryption Option",
},
"kms_key": {"type": "string", "title": "KMS Key"},
}
)
schema["extra_options"].append("encryption_option")
schema["extra_options"].append("kms_key")

if ASSUME_ROLE:
del schema["properties"]["aws_access_key"]
del schema["properties"]["aws_secret_key"]
schema["secret"] = []

schema["order"].insert(1, "iam_role")
schema["order"].insert(2, "external_id")
schema["properties"].update(
{
"iam_role": {"type": "string", "title": "IAM role to assume"},
"external_id": {
"type": "string",
"title": "External ID to be used while STS assume role",
},
}
)
else:
schema["order"].insert(1, "aws_access_key")
schema["order"].insert(2, "aws_secret_key")

if not OPTIONAL_CREDENTIALS and not ASSUME_ROLE:
schema["required"] += ["aws_access_key", "aws_secret_key"]

return schema

@classmethod
Expand All @@ -153,9 +128,14 @@ def type(cls):
return "athena"

def _get_iam_credentials(self, user=None):
if ASSUME_ROLE:
args = {
"aws_access_key_id": self.configuration.get("aws_access_key", None),
"aws_secret_access_key": self.configuration.get("aws_secret_key", None),
"region_name": self.configuration["region"],
}
if self.configuration.get("iam_role"):
role_session_name = "redash" if user is None else user.email
sts = boto3.client("sts")
sts = boto3.client("sts", **args)
creds = sts.assume_role(
RoleArn=self.configuration.get("iam_role"),
RoleSessionName=role_session_name,
Expand All @@ -168,11 +148,7 @@ def _get_iam_credentials(self, user=None):
"region_name": self.configuration["region"],
}
else:
return {
"aws_access_key_id": self.configuration.get("aws_access_key", None),
"aws_secret_access_key": self.configuration.get("aws_secret_key", None),
"region_name": self.configuration["region"],
}
return args

def __get_schema_from_glue(self):
client = boto3.client("glue", **self._get_iam_credentials())
Expand Down
40 changes: 29 additions & 11 deletions redash/query_runner/cloudwatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,17 @@ def configuration_schema(cls):
return {
"type": "object",
"properties": {
"iam_role": {"type": "string", "title": "IAM role to assume"},
"external_id": {
"type": "string",
"title": "External ID to be used while STS assume role",
},
"region": {"type": "string", "title": "AWS Region"},
"aws_access_key": {"type": "string", "title": "AWS Access Key"},
"aws_secret_key": {"type": "string", "title": "AWS Secret Key"},
},
"required": ["region", "aws_access_key", "aws_secret_key"],
"order": ["region", "aws_access_key", "aws_secret_key"],
"required": ["region"],
"order": ["region", "aws_access_key", "aws_secret_key", "iam_role", "external_id"],
"secret": ["aws_secret_key"],
}

Expand All @@ -81,14 +86,27 @@ def __init__(self, configuration):
def test_connection(self):
self.get_schema()

def _get_client(self):
cloudwatch = boto3.client(
"cloudwatch",
region_name=self.configuration.get("region"),
aws_access_key_id=self.configuration.get("aws_access_key"),
aws_secret_access_key=self.configuration.get("aws_secret_key"),
)
return cloudwatch
def _get_client(self, user=None):
args = {
"aws_access_key_id": self.configuration.get("aws_access_key", None),
"aws_secret_access_key": self.configuration.get("aws_secret_key", None),
"region_name": self.configuration["region"],
}
if self.configuration.get("iam_role"):
role_session_name = "redash" if user is None else user.email
sts = boto3.client("sts", **args)
creds = sts.assume_role(
RoleArn=self.configuration.get("iam_role"),
RoleSessionName=role_session_name,
ExternalId=self.configuration.get("external_id"),
)
return {
"aws_access_key_id": creds["Credentials"]["AccessKeyId"],
"aws_secret_access_key": creds["Credentials"]["SecretAccessKey"],
"aws_session_token": creds["Credentials"]["SessionToken"],
"region_name": self.configuration["region"],
}
return boto3.client("cloudwatch", **args)

def get_schema(self, get_stats=False):
client = self._get_client()
Expand All @@ -110,7 +128,7 @@ def get_schema(self, get_stats=False):
return list(metrics.values())

def run_query(self, query, user):
cloudwatch = self._get_client()
cloudwatch = self._get_client(user)

query = parse_query(query)

Expand Down