K8S应用安全检测(调用分析 容器健康 审计日志)
应用安全检测
1 应用安全检测
1.1 调用分析
1.1.1 sysdig基础
学习目标
这一节,我们从 基础知识、简单实践、小结 三个方面来学习。
基础知识
简介
Sysdig 是一个开源系统(System)发掘(dig)工具,它汇聚了 strace、tcpdump、htop、iftop、lsof等工具的能力。常用于系统级别的监控、分析和故障排查等场景,可以把它看作一系列Linux系统工具的组合。
strace:追踪某个进程产生和接收的系统调用。
tcpdump:分析网络数据,监控原始网络通信。
lsof: list opened files, 列出打开的文件。
top:监控系统性能工具。
htop :交互式的进程浏览器,可以用来替换 top 命令。
iftop :主要用来显示本机网络流量情况及各相互通信的流量集合。
lua:一种嵌入式的脚本语言,从而为应用程序提供灵活的扩展和定制功能。
功能
Sysdig除了能够获取系统资源利用率、进程、网络连接、系统调用等信息,还具备了非常强的分析能力。Sysdig 不仅能分析Linux 系统的“现场”状态,也能将该状态保存为转储文件以供离线分析检查。同时还可以自定义 Sysdig 的行为,通过内建的名为chisel的小脚本增强其功能。
通过 Sysdig 可以挖掘非常多的系统信息:用户能够很方便地查看到主机上所有应用程序的cpu、文件 i/o、网络访问状况;Sysdig可以快速进行系统数据的收集和分析;提供了容器级别的信息采集命令,支持查看指定容器之间的网络流量、查看特定容器的 CPU使用情况。
项目代码: https://github.com/draios/sysdig
项目介绍: https://github.com/draios/sysdig/wiki
伴随着容器技术的大力普及和实践落地,针对容器场景的检测工具也应运而生,Sysdig就属于这里面比较典型的一套开源工具。它不仅仅能够针对传统主机进行检测,更能根据Docker软件在宿主机上落地的方式,自动发现容器内的进程,从而实现容器环境信息的采集和分析,这让我们能够即时了解客户在生产中运行云原生服务的解决方案,这也直接促使sysdig成为适用于服务器和容器的“故障定位和排除工具”。
原理解析
sysdig通过在内核的驱动模块注册系统调用的hook,这样当系统调用发生和完成的时候,它会把系统调用信息拷贝到特定的buffer,然后通过用户态组件对数据信息处理(解压、解析、过滤等),并最终通过sysdig命令行和用户进行交互。
简单实践
Centos环境部署
导入软件源
rpm --import https://download.sysdig.com/DRAIOS-GPG-KEY.public
curl -s -o /etc/yum.repos.d/draios.repo https://download.sysdig.com/stable/rpm/draios.repo
安装软件
yum -y install sysdig
加载驱动模块
scap-driver-loader
Ubuntu环境部署
curl -s https://s3.amazonaws.com/download.draios.com/DRAIOS-GPG-KEY.public | apt-key add -
curl -s -o /etc/apt/sources.list.d/draios.list http://download.draios.com/stable/deb/draios.list
apt-get update
apt-get -y install linux-headers-$(uname -r)
apt-get -y install sysdig
容器方式部署
安装依赖
yum -y install kernel-devel-$(uname -r)
获取容器
docker pull sysdig/sysdig
运行容器
docker run -i -t --name sysdig --privileged -v /var/run/docker.sock:/host/var/run/docker.sock -v /dev:/host/dev -v /proc:/host/proc:ro -v /boot:/host/boot:ro -v /lib/modules:/host/lib/modules:ro -v /usr:/host/usr:ro sysdig/sysdig
命令执行
执行命令
# sysdig
...
5121660[事件号] 13:29:48.626497991[时间] 1[cpu号] kubelet[进程名] (1755.1796[进程id]) >[进入事件] switch[事件名称] next=0 pgft_maj=0 pgft_min=18233 vm_size=1470308 vm_rss=84660 vm_swap=0[调用参数]
5121662 13:29:48.626983479 1 kubelet (1755.1756) <[退出事件] futex res=-110(ETIMEDOUT)
...
信息显示格式:
%evt.num %evt.outputtime %evt.cpu %proc.name (%thread.tid) %evt.dir %evt.type %evt.info
evt.num: 递增的事件号
evt.time: 事件发生的时间
evt.cpu: 事件被捕获时所在的 CPU,也就是系统调用是在哪个 CPU 执行的
proc.name: 生成事件的进程名字
thread.tid: 线程的 id,如果是单线程的程序,这也是进程的 pid
evt.dir: 事件的方向,> 代表进入事件,< 代表退出事件
evt.type: 事件的名称,比如 open、stat等,一般是系统调用
evt.args: 事件的参数。如果是系统调用,这些对应着系统调用的参数
自定义格式输出:sysdig -p "user:%user.name time:%evt.time proc_name:%proc.name
1.1.2 命令实践
学习目标
这一节,我们从 简单实践、扩展实践、小结 三个方面来学习。
基础知识
信息检测
使用sysdig的主要目的主要有两个:
1 自己进入到容器内部调试一些具体信息
2 检测基于开源镜像仓库镜像运行的容器是否被嵌入了木马进程
命令语法
]# sysdig --help
sysdig version 0.30.0
Usage: sysdig [options] [-p <output_format>] [filter]
...
-l, --list:列出可用于过滤和输出的字段
-M <num_seconds> :信息收集持续时长
-p <output_format>, --print=<output_format> :指定打印事件时使用的格式
-pc 是容器日志格式;-pk 是kubernetes日志格式;-pm 是mesos日志格式
-c <chiselname> <chiselargs>:指定内置工具,可直接完成具体的数据聚合、分析工作
-w <filename>:保存到文件中
-r <filename>:从文件中读取
注意:
sysdig相关的文件信息只能通过专用命令查看
信息的导出导入
导出信息
[root@kubernetes-node1 ~]# sysdig -M 5 -w sysdig_test.txt
[root@kubernetes-node1 ~]# file sysdig_test.txt
sysdig_test.txt: pcap-ng capture file - version 1.2
查看信息
[root@kubernetes-node1 ~]# sysdig -r sysdig_test.txt | head -n 5
369 17:25:00.989023587 0 <NA> (0) > switch next=5308(containerd-shim) pgft_maj=0 pgft_min=0 vm_size=0 vm_rss=0 vm_swap=0
...
指定信息输出
[root@kubernetes-node1 ~]# sysdig -p "user:%user.name time:%evt.time proc_name:%proc.name" | head -n 2
user:root time:17:28:27.818719900 proc_name:sysdig
user:root time:17:28:27.819033893 proc_name:sysdig
采用普通容器方式查看信息
[root@kubernetes-node1 ~]# sysdig -pc | head -n 2
15 17:30:33.546129321 1 <NA> (<NA>) <NA> (0:<NA>) > switch next=9 pgft_maj=0 pgft_min=0 vm_size=0 vm_rss=0 vm_swap=0
...
采用kubernetes方式查看信息
[root@kubernetes-node1 ~]# sysdig -pk | head -n 2
23 17:30:37.073045020 0 <NA> (<NA>) <NA> (0:<NA>) > switch next=9 pgft_maj=0 pgft_min=0 vm_size=0 vm_rss=0 vm_swap=0
...
采用mesos方式查看信息
[root@kubernetes-node1 ~]# sysdig -pm | head -n 2
17 17:30:40.695954481 0 <NA> (host) sysdig (126131:126131) > switch next=0 pgft_maj=0 pgft_min=5086 vm_size=107468 vm_rss=12004 vm_swap=0
...
信息过滤
[root@kubernetes-node1 ~]# sysdig -l | grep "Field Class"
Field Class: evt (All event types)
Field Class: process
Field Class: user
Field Class: group
Field Class: container
Field Class: fd
Field Class: syslog
Field Class: fdlist
Field Class: k8s
Field Class: mesos
Field Class: span
Field Class: evtin
结果显示:
sysdig 可以支持12类信息的过滤显示
语法格式
sysdig 属性字段[操作符号]值
示例:
sysdig proc.name=kubelet
操作符号:
这里的操作符号支持 =、!=、>=、<=、>、<、contains、in、exists、and、or、not等
信息过滤实践
查看进程的系统调用
[root@kubernetes-node1 ~]# sysdig proc.name=kubelet | head -n 2
255 17:42:58.846155860 0 kubelet (1794) > futex addr=C000105148 op=129(FUTEX_PRIVATE_FLAG) val=1
256 17:42:58.846174388 0 kubelet (1794) < futex res=1
查看tcp连接系统调用
[root@kubernetes-node1 ~]# sysdig evt.type=accept | head -n 2
10593 17:44:00.830242006 1 dockerd (1408) > accept flags=0
10595 17:44:00.830248505 1 dockerd (1408) < accept fd=80(<u>ffff908149c41100->ffff908149c46e80 /var/run/docker.sock) tuple=ffff908149c41100->ffff908149c46e80 /var/run/docker.sock queuepct=0 queuelen=0 queuemax=128
查看指定文件查看的系统调用
[root@kubernetes-node1 ~]# sysdig fd.name contains /opt | head -n 2
28727 17:44:50.118569699 1 calico (10424) < openat fd=3(<f>/opt/cni/bin/calico) dirfd=-100(AT_FDCWD) name=/opt/cni/bin/calico flags=4097(O_RDONLY|O_CLOEXEC) mode=0 dev=802 ino=50410640
28736 17:44:50.118595902 1 calico (10424) > fstat fd=3(<f>/opt/cni/bin/calico)
查看容器的系统调用
[root@kubernetes-node1 ~]# sysdig -M 10 container.name startswith 'k8s' | head -n 2
4 18:03:06.314990614 0 calico-node (7681) < nanosleep res=0
5 18:03:06.314995749 0 calico-node (7681) > futex addr=49670D8 op=128 val=0
工具集实践
简介
在sysdig中,存在一系列的实用工具集 -- chisels,它们是一组预定义好的功能集合,我们用来分析特定场景。我们可以通过sysdig -cl 的方式罗列所有可用的工具集信息。
使用命令格式
sysdig -c 工具集
查看能够使用的工具集场景
[root@kubernetes-node1 ~]# sysdig -cl | grep Category
Category: Application # http web应用统计信息
Category: CPU Usage # CPU统计信息
Category: Errors # 错误统计信息
Category: I/O # 输入输出统计信息
Category: Logs # 日志信息
Category: Misc # 其他信息
Category: Net # 网络信息
Category: Performance # 性能信息
Category: Security # 安全信息
Category: System State # 系统状态
Category: Tracers # 跟踪信息
查看信息
查看进程的网络信息
[root@kubernetes-node1 ~]# sysdig -c topprocs_net
Bytes Process PID
--------------------------------------------------------------------------------
8.42KB manager 8636
64B sshd 39374
Bytes Process PID
查看网络连接信息
[root@kubernetes-node1 ~]# sysdig -c netstat
Proto Server Address Client Address State TID/PID/Program Name
tcp 10.0.0.15:22 10.0.0.1:55501 ESTABLISHED 39422/39422/sshd
tcp 10.96.0.1:443 10.0.0.15:36708 ESTABLISHED 7735/7680/calico-node
tcp 10.96.0.1:443 10.0.0.15:36708 ESTABLISHED 7719/7680/calico-node
...
查看容器的cpu使用率信息
[root@kubernetes-node1 ~]# sysdig -pc -c topprocs_cpu container.name contains 'k8s'
CPU% Process Host_pid Container_pid container.name
--------------------------------------------------------------------------------
0.00% runsv 7672 69 k8s_calico-node_calico-...
0.00% nginx 7296 1 k8s_backend_app-svc-app-...
运行一个容器
docker run -d --name nginx_web -p 888:80 kubernetes-register.superopsmsb.com/superopsmsb/nginx_web:v0.1
开启监控
[root@kubernetes-node1 ~]# sysdig -s 2000 -A -c echo_fds fd.port=80 and evt.buffer contains GET
------ Read 77B from 10.0.0.16:51818->172.17.0.2:80 (nginx)
GET / HTTP/1.1
User-Agent: curl/7.29.0
Host: 10.0.0.15:888
Accept: */*
注意:
需要另开一个终端访问 10.0.0.15:888,然后才会有返回信息。
查看文件打开的相关信息
[root@kubernetes-node1 ~]# sysdig -c fdcount_by proc.name "fd.type=file"
kubelet 1632
dockerd 1127
containerd-shim 504
注意:
通过 Ctrl + C 的方式才可以在最终查看效果,否则不会有信息显示
[root@kubernetes-node1 ~]# sysdig -c topfiles_time
Time Filename
--------------------------------------------------------------------------------
91us /var/lib/docker/image/overlay2/imagedb/content/sha256/221177c6...5
查看进程收到错误信息
[root@kubernetes-node1 ~]# sysdig -c topprocs_errors
#Errors Process PID
--------------------------------------------------------------------------------
31 kubelet 1755
30 dockerd 1225
...
查看和/etc 目录相关的打开事件信息
[root@kubernetes-node1 ~]# sysdig evt.type=open and fd.name contains /etc
33987 19:03:06.310083229 0 iptables (92297.92297) < open fd=3(<f>/etc/ld.so.cache) name=/etc/ld.so.cache flags=4097(O_RDONLY|O_CLOEXEC) mode=0 dev=802 ino=17212445
...
小结
1.2 容器监控
1.2.1 CAdvisor
学习目标
这一节,我们从 软件简介、简单实践、小结 三个方面来学习。
软件简介
专属状态命令
查看容器的专属状态信息
[root@kubernetes-node1 ~]# docker stats --no-stream
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % ...
5a3c015d6cca nginx_web 0.00% 2.27MiB / 3.682GiB 0.06% ...
b105095db79e k8s_m...6 0.42% 39.4MiB / 512MiB 7.70% ...
14d961970119 k8s_c...7 1.71% 139.6MiB / 3.682GiB 3.70% ...
...
软件简介
cadvisor(Container Advisor) 是 Google 开源的一个容器监控工具,它以守护进程方式运行,用于收集、聚合、处理和导出正在运行容器的有关信息。具体来说,该组件对每个容器都会记录其资源隔离参数、历史资源使用情况、完整历史资源使用情况的直方图和网络统计信息。它不仅可以搜集一台机器上所有运行的容器信息,还提供基础查询界面和http接口,方便其他组件如Prometheus进行数据抓取
cAdvisor使用Go语言开发,对Node机器上的资源及容器进行实时监控和性能数据采集,包括CPU使用情况、内存使用情况、网络吞吐量及文件系统使用情况,利用Linux的cgroups获取容器的资源使用信息,可用于对容器资源的使用情况和性能进行监控。。
注意:
一个cAdvisor仅对一台主机进行监控。
项目主页:http://github.com/google/cadvisor。
最新版本:0.45.0
下载地址:
https://github.com/google/cadvisor/releases/latest
https://github.com/google/cadvisor/archive/refs/tags/v0.45.0.tar.gz
监控原理
CAdvisor运行时挂载了宿主机根目录,docker根目录等多个目录,由此可以从中读取容器的运行时信息。docker基础技术有Linux namespace,Control Group(CGroup),AUFS等,其中CGroup用于系统资源限制和优先级控制的。
宿主机的/sys/fs/cgroup/目录下面存储的就是CGroup的内容了,CGroup包括多个子系统,如对块设备的blkio,cpu,内存,网络IO等限制。Docker在CGroup里面的各个子系统中创建了docker目录,而CAdvisor运行时挂载了宿主机根目录和 /sys目录,从而CAdvisor可以读取到容器的资源使用记录。
简单实践
源代码安装cAdvisor
获取软件
cd /data/softs
wget https://github.com/google/cadvisor/archive/refs/tags/v0.45.0.tar.gz
tar xf v0.45.0.tar.gz -C /data/server
ln -s /data/server/cadvisor-0.45.0 /data/server/cadvisor
cd /data/server/cadvisor
chmod +x ./build/assets.sh
注意:
源码方式部署可以查看 /data/server/cadvisor/docs/runtime_options.md 文件
安装go环境,必须在 1.14+ 版本
mkdir /data/softs && cd /data/softs
wget https://studygolang.com/dl/golang/go1.17.6.linux-amd64.tar.gz
rm -rf /data/server/go && tar -C /data/server -xf go1.17.6.linux-amd64.tar.gz
echo 'export GOROOT=/data/server/go' > /etc/profile.d/go.sh
echo 'export PATH=$PATH:$GOROOT/bin' >> /etc/profile.d/go.sh
source /etc/profile.d/go.sh
go version
获取软件
go get -d github.com/google/cadvisor
go env -w GOPROXY=https://goproxy.cn
apt-get install libpfm4 libpfm4-dev jq
编译安装cadvisor
make build
确认效果
ls
启动cadvisor
./cadvisor -port=8080 &>>/var/log/cadvisor.log
浏览器访问 10.0.0.15:8080,可以查看cadvisor的默认ui页面的浏览器效果
浏览器访问 10.0.0.15:8080/metrics,可以查看cadvisor的默认采集的容器指标效果
注意:
url是 /metrics 不是 /metrics/
docker方式安装cadvisor环境
容器属性来源
https://github.com/google/cadvisor/releases
获取cadvisor的docker镜像
docker pull gcr.io/cadvisor/cadvisor:v0.45.0
启动容器
docker run \
--volume=/:/rootfs:ro --volume=/var/run:/var/run:ro --volume=/sys:/sys:ro \
--volume=/var/lib/docker/:/var/lib/docker:ro --volume=/dev/disk/:/dev/disk:ro \
--publish=8080:8080 --detach=true --name=cadvisor --privileged \
--device=/dev/kmsg gcr.io/cadvisor/cadvisor:v0.45.0
查看专属的监控指标格式
[root@kubernetes-node1 ~]# curl -s 10.0.0.15:8080/metrics | head -n 3
# HELP cadvisor_version_info A metric with a constant '1' value labeled by kernel version, OS version, docker version, cadvisor version & cadvisor revision.
# TYPE cadvisor_version_info gauge
cadvisor_version_info{cadvisorRevision="86b11c65",cadvisorVersion="v0.45.0",dockerVersion="",kernelVersion="3.10.0-1160.el7.x86_64",osVersion="Alpine Linux v3.16"} 1
小结
1.2.2 Falco基础
学习目标
这一节,我们从 软件简介、功能解读、小结 三个方面来学习。
软件简介
需求
随着容器化应用的普及,由于容器应用的变动频率过于大,据相关统计数据显示,容器寿命普遍较短,导致它非常不利于故障响应、故障定位和故障解决,可能给容器底层的主机造成安全的隐患。
由于容器的工作模式是共享宿主机内核,所以它面临着各种安全的问题,比如 耗尽主机的进程资源、容器逃逸等带来的安全隐患。虽然我们有 gVisor 和 Kata Container 等更加安全的容器技术演进,但是使用场景还是有所局限。
简介
Falco是Sysdig开源的一款为云原生平台设计的进程异常行为检测工具,它通过灵活的规则引擎来描述任何类型的主机或者容器的行为和活动,在触发策略规则后可以实时发出警报告警,从而检测传统主机上的应用程序,同时支持将告警集成到各种工作流或者告警通道,同时 Falco 可利用最新的检测规则针对恶意活动和 CVE 漏洞发出警报,而且规则可以实现动态更新和开箱即用。同时它还支持接入系统调用事件和Kubernetes审计日志,也能够检测容器环境和云平台。
Falco能够检测所有涉及系统调用的进程行为。
某容器中启动了一个shell
某服务进程创建了一个非预期类型的子进程
/etc/shadow文件被读写
/dev目录下创建了一个非设备文件
ls之类的常规系统工具向外进行了对外网络通信
Falco还可以检测云环境下的特有行为。例如:
创建了带有特权容器、挂载敏感路径或使用了宿主机网络的Pod
向用户授予大范围权限(例如cluster-admin)
创建了带有敏感信息的configmap
官方网站:https://falco.org/docs/getting-started/installation/
github地址: https://github.com/falcosecurity/falco
最新版本:0.33.0
特点
Falco主要依赖于底层Sysdig内核模块提供的系统调用事件流,提供的是一种连续式实时监控功能;
Falco自身运行在用户空间,仅仅借助内核模块来获得数据,Falco的规则变更和程序起止要更为灵活;
Falco具有非常易学的规则语法和对云环境的支持。
Falco采用C++语言编写,但它提供了丰富的告警输出方式,因此能够非常方便地与其他工具协同工作。
功能解读
程序结构
Falco是一个基于规则的进程异常行为检测工具,它支持常见的基于Sysdig内核模块 和 Kubernetes审计日志的信息采集。而且它支持多种数据输出机制,比如 标准输出、文件、Syslog、HTTP服务、其他程序(管道方式)等。
匹配流程
Falco采用规则匹配方式来检测异常,默认情况下,它自带了一份规则文件/etc/falco/falco_rules.yaml 供使用,当然我们也可以自己定义的规则文件。
以系统调用为例:
1 加载Sysdig内核模块,Falco程序读取并解析配置文件和规则文件、初始化规则引擎
2 Sysdig检测进程的系统调用,然后捕获系统调用,并把详细信息传给Falco,Falco对这些信息作规则匹配,如果满足规则就通过约定好的方式输出告警。上述工作流程可以表示如下:
规则解析
Falco的规则文件使用 YAML 格式,它决定了一个事件是否应该被视作异常行为。一个规则文件包含三类元素:
规则:一条规则是描述“在什么条件下生成什么样的告警”的规定
宏:这里宏的意义与C语言中的基本相同,它是一些“判定条件片段”,能够在不同的规则甚至宏中复用
列表:即元素集合,能够被规则、宏或者其他列表使用
示例:
- rule: <rule_name> # 规则名:必须是独一无二的名称
desc: <xxx> # 描述文字:对规则的详细说明
condition: > # 条件:用来筛选事件的过滤表达式(Falco采用Sysdig的过滤语法)
spawned_process and container
and shell_procs and proc.tty != 0
and container_entrypoint
output: > # 输出信息:与规则匹配的事件发生时,输出的告警信息
xxx
priority: NOTICE # 优先级:表示事件严重程度,包括 'emergency', 'alert'
# 'critical', 'error', 'warning', 'notice'
# 'informational', 'debug'
tags: [key1, key2 ] # 方便管理的标签
小结
1.2.3 Falco实践
学习目标
这一节,我们从 环境部署、简单实践、小结 三个方面来学习。
环境部署
Ubuntu环境
软件源配置
curl -s https://falco.org/repo/falcosecurity-3672BA8F.asc | apt-key add -
echo "deb https://download.falco.org/packages/deb stable main" | tee -a /etc/apt/sources.list.d/falcosecurity.list
apt-get update -y
安装软件
apt-get -y install linux-headers-$(uname -r)
apt-get install -y falco
Centos环境
软件源配置
rpm --import https://falco.org/repo/falcosecurity-3672BA8F.asc
curl -s -o /etc/yum.repos.d/falcosecurity.repo https://falco.org/repo/falcosecurity-rpm.repo
安装软件
yum -y install kernel-devel-$(uname -r)
yum -y install falco
注意:
这个软件安装完毕后,falco.service 服务是开机自启动样式。
配置文件
falco 配置文件目录:/etc/falco
[root@kubernetes-node1 ~]# ll /etc/falco/
aws_cloudtrail_rules.yaml
falco_rules.local.yaml # 自定义扩展规则文件
falco_rules.yaml # 默认的规则文件
falco.yaml # falco配置和告警通知方式
k8s_audit_rules.yaml # k8s相关的日志审计规则
rules.available
rules.d # 扩展的规则目录
告警示例
]# cat falco_rules.yaml
...
- rule: Read environment variable from /proc files
desc: An attempt to read process environment variables from /proc files
condition: >
open_read and container and (fd.name glob /proc/*/environ)
and not proc.name in (known_binaries_to_read_environment_variables_from_proc_files)
output: >
Environment variables were retrieved from /proc files (user=%user.name user_loginuid=%user.loginuid program=%proc.name
command=%proc.cmdline pid=%proc.pid file=%fd.name parent=%proc.pname gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4] container_id=%container.id image=%container.image.repository)
priority: WARNING
tags: [filesystem, mitre_credential_access, mitre_discovery]
简单实践
实践1 - 敏感规则
查看默认规则
- macro: bin_dir_mkdir
condition: >
(evt.arg.path startswith /bin/ or
evt.arg.path startswith /sbin/ or
evt.arg.path startswith /usr/bin/ or
evt.arg.path startswith /usr/sbin/)
在敏感目录创建文件
[root@kubernetes-node1 ~]# mkdir /usr/bin/nihao
查看日志信息
[root@kubernetes-node1 ~]# grep nihao /var/log/messages
Oct 25 22:47:41 kubernetes-node1 falco: 22:47:41.734005457: Error Directory below known binary directory created (user=root user_loginuid=0 command=mkdir /usr/bin/nihao pid=5542 directory=/usr/bin/nihao container_id=host image=<NA>)
实践2 - 监控根目录,禁止写
查看规则文件
- macro: root_dir
condition: (fd.directory=/ or fd.name startswith /root/)
在敏感目录创建文件
[root@kubernetes-node1 ~]# echo 'test_file' > /root/root_test.txt
查看日志信息
[root@kubernetes-node1 ~]# grep 'root_test.txt' /var/log/messages
Oct 25 22:52:32 kubernetes-node1 falco: 22:52:32.314707668: Error File below / or /root opened for writing (user=root user_loginuid=0 command=bash pid=5474 parent=sshd file=/root/root_test.txt program=bash container_id=host image=<NA>)
实践3 - 容器操作
查看规则文件
- rule: Terminal shell in container
desc: A shell was used as the entrypoint/exec point into a container with an attached terminal.
condition: >
spawned_process and container
and shell_procs and proc.tty != 0
and container_entrypoint
and not user_expected_terminal_shell_in_container_conditions
# spawned_process、container和shell_procs及container_entrypoint是四个宏
output: >
A shell was spawned in a container with an attached terminal (user=%user.name user_loginuid=%user.loginuid %container.info
shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline pid=%proc.pid terminal=%proc.tty container_id=%container.id image=%container.image.repository)
priority: NOTICE
tags: [container, shell, mitre_execution]
在A终端进入到容器内部
[root@kubernetes-node1 ~]# docker exec -it nginx_web /bin/bash
在B终端查看日志信息
[root@kubernetes-node1 ~]# grep 'nginx_web' /var/log/messages
Oct 25 22:57:10 kubernetes-node1 falco: 22:57:10.414572554: Notice A shell was spawned in a container with an attached terminal (user=root user_loginuid=-1 nginx_web (id=5a3c015d6cca) shell=bash parent=runc cmdline=bash pid=8698 terminal=34816 container_id=5a3c015d6cca image=kubernetes-register.superopsmsb.com/superopsmsb/nginx_web)
小结
1.2.4 进阶实践
学习目标
这一节,我们从 自定义规则、输出实践、小结 三个方面来学习。
自定义规则
规则条件
关于规则条件的写法主要涉及到两个方面:语法和样式
语法
condition: sysdig属性 操作符号 值
样式
单行示例:
condition: container.id != host and proc.name = bash
多行示例:
condition: >
container.id != host
and proc.name = bash
规则优先级
每个 Falco 规则都有一个优先级,表明违反规则的严重程度,常见的优先级有:EMERGENCY、ALERT、CRITICAL、ERROR、WARNING、NOTICE、INFORMATIONAL、DEBUG。
分配准则:
如果规则与写入状态有关,则其优先级为 ERROR。
如果规则与未经授权的读取状态有关,则其优先级为 WARNING。
如果规则与意外行为有关,则其优先级为 NOTICE。
如果规则与违反最佳实践的行为有关,则其优先级为 INFO。
如果规则仅仅是详情信息的展示,则其优先级为DEBUG。
规则标签
默认规则集有一组可选的标签,用于将规则集分类为相关规则组,常见的标签如下:
filesystem(与读/写文件有关)、software_mgmt(与软件/包管理工具有关)、process(与进程的状态有关)、database(与数据库相关)、host(与宿主机有关)、shell(与启动 shell有关)、container(与容器有关)、cis(与CIS基准相关)、users(与用户身份有关)、network(与网络活动有关)
需求
监控容器镜像来源规则,在falco_rules.local.yaml文件添加:
- rule: django镜像未来自私有仓库
# 成功的规则
# condition: spawned_process and container and container.image contains django and container.image not startswith kuber
# 异常的规则
condition: >
spawned_process and container
and container.image contains django
and container.image startswith kuber
desc: 保证镜像的来源是正常的
output: "django镜像来源不正常 (user=%user.name container_name=%container.name container_id=%container.id image=%container.image.repository shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline terminal=%proc.tty)"
priority: WARNING
tags: [process, container]
重启falco应用新配置文件:
systemctl restart falco
检测效果
在A终端创建容器
[root@kubernetes-node1 ~]# docker run -d --name django_web -p 888:8000 kubernetes-register.superopsmsb.com/superopsmsb/django_web:v0.1
在B终端查看日志信息
[root@kubernetes-node1 ~]# grep 'django_web' /var/log/messages
Oct 26 00:08:28 kubernetes-node1 falco: 00:08:28.886341055: Warning django镜像来源不正常 (user=root container_name=django_web container_id=74370161c95a image=kubernetes-register.superopsmsb.com/superopsmsb/django_web shell=python parent=python cmdline=python /data/code/blog/manage.py runserver 0.0.0.0:8000 terminal=0)
输出实践
需求
falco支持多种信息输出,因为没有其他环境,我们这里来演示一种文本输入。
修改配置
]# vim falco.yaml
...
syslog_output:
enabled: false # 关闭默认输出
...
file_output: # 定制指定输出
enabled: true
keep_alive: false
filename: /var/log/falco.log
stdout_output: # 关闭默认输出
enabled: false
...
重启falco应用新配置文件:
systemctl restart falco
重新创建异常镜像,然后查看日志
[root@kubernetes-node1 /etc/falco]# tail /var/log/falco.log
00:17:41.473060750: Warning django镜像来源不正常 (user=root container_name=django_web container_id=73b4037db442 image=kubernetes-register.superopsmsb.com/superopsmsb/django_web shell=bash parent=<NA> cmdline=bash /data/scripts/startup.sh terminal=0)
修改日志格式
]# vim falco.yaml
...
json_output: true # 开启json日志格式
...
重启falco应用新配置文件:
systemctl restart falco
重新创建异常镜像,然后查看日志
[root@kubernetes-node1 /etc/falco]# tail /var/log/falco.log
{"hostname":"kubernetes-node1","output":"00:19:36.249135765: Warning django镜像来源不正常 (user=root container_name=django_web container_id=25d4537446cb image=kubernetes-register.superopsmsb.com/superopsmsb/django_web shell=ldconfig.real parent=python cmdline=ldconfig.real -p terminal=0)","priority":"Warning","rule":"django镜像未来自私有仓库","source":"syscall","tags":["container","process"],...}
小结
1.2.5 可视化实践
学习目标
这一节,我们从 可视化环境、简单实践、小结 三个方面来学习。
可视化环境
需求
我们可以借助于falco的专属可视化界面,让所有falco的信息全部传输给可视化界面,然后通过图形的方式进行统一的效果分析。
FalcoSideKick
FalcoSideKick是基于go语言研发出来的一个集中式数据采集、传输平台,我们可以借助于配套的FalcoSideKick-UI将其作为Falco专属的集中式信息展示平台,该软件还内置了大量的可视化图形页面信息。
github地址:
https://github.com/falcosecurity/falcosidekick
https://github.com/falcosecurity/falcosidekick-ui
最新版本:2.26.0
部署环境
获取镜像
docker pull falcosecurity/falcosidekick
docker pull falcosecurity/falcosidekick-ui
redis/redis-stack-server:latest
部署falcosidekick软件
docker run -d -p 2801:2801 --name falcosidekick -e WEBUI_URL=http://10.0.0.15:2802 falcosecurity/falcosidekick
部署ui软件
docker run -d --name redis -p 6379:6379 redis/redis-stack-server:latest
docker run -d -p 2802:2802 --name falcosidekick-ui -e FALCOSIDEKICK_UI_REDIS_URL='10.0.0.15:6379' falcosecurity/falcosidekick-ui
简单实践
falco集成可视化平台
修改配置文件 falco.yaml
...
json_output: true
...
http_output:
enabled: true
url: http://10.0.0.15:2801/
user_agent: "falcosecurity/falco"
...
重启falco应用新配置文件:
systemctl restart falco
测试效果
在A终端频繁的执行
docker run -d --name django_web -p 888:8000 kubernetes-register.superopsmsb.com/superopsmsb/django_web:v0.1
docker rm -f django_web
访问10.0.0.15:2802,浏览器效果如下
环境收尾
docker rm -f falcosidekick falcosidekick-ui redis
小结
1.3 审计日志
1.3.1 日志解读
学习目标
这一节,我们从 普通日志、审计日志、小结 三个方面来学习。
普通日志
日志作用
系统组件的日志记录集群中发生的事件,这对于调试和后续信息梳理是非常有用的。 但是由于kubernetes集群的特点,业务在运行的时候,pod和数据存储有各自的生命周期,所以默认情况下,虽然kubernetes有其自身的日志结构,但是通常不足以支撑完整的日志记录解决方案,往往需要借助于第三方的平台来实现日志方案的实现。
日志架构
对于kubernetes来说,我们常见的有以下三类日志架构:
Pod级别日志:
- 我们可以借助于logs方式来查看pod内部的业务应用日志信息。
- pod消亡后,业务应用日志自动消除。
Node级别日志:
- 借助于重定向的机制,将容器化应用的信息存储到kubernetes工作节点上
- 日志位于 /var/log/pods/namespace_podname_containerid/podname/x.log
- 虽然实现了日志的延续性,但是pod一旦迁移,日志数据自然消亡。
Cluster级别日志
- 借助于第三方机制,实现集群级别的日志统一管理。
日志格式
对于kubernetes来说,它的日志表现样式,主要有四种:
原生日志格式:
kubernetes默认情况下使用的日志格式。
结构化日志:
在日志消息中引入统一结构,以便以编程方式提取信息,最终以文本方式来呈现。
上下文日志:
建立在结构化日志之上。 帮助开发人员使用日志记录依赖环境相关的调用。
JSON 日志格式:
业务场景中使用频率较高的一种日志格式,可以非常轻松的获取特定字段信息。
审计日志
审计日志
kubernetes 在1.7版本开始支持审计(Audit)日志功能,Kubernetes 审计功能通过记录所有对 apiserver 接口的调用,让我们能够非常清晰的知道与安全相关的按时间顺序排列的记录集,记录单个用户、管理员或系统其他组件影响系统的活动顺序。
它能帮助集群管理员了解 发生了什么?什么时候发生的?谁触发的?为什么发生?在哪观察到的?它从哪触发的?它将产生什么后果?等等。
api-server的完整流程
K8S中的审计日志是标准的JSON格式,APIServer会根据具体的日志策略将对应的审计日志保存本地,并可以设置最大保存周期、时间、轮转策略等。
记录阶段
kube-apiserver 是负责接收及相应用户请求的一个组件,每一个请求都会有几个阶段,每个阶段都有对应的日志,审计日志根据日志策略可以选择在事件执行的某个阶段记录,目前支持的事件阶段有:
RequestReceived
- 一旦接收到资源操作请求立刻记录审计事件。
ResponseStarted
- 开始响应数据的Header,但在响应数据Body发送前记录审计事件,比如watch操作。
ResponseComplete
- 事件响应完毕后记录审计事件。
Panic
- 内部出现panic时记录审计事件。
简单来说,apiserver 的每一个请求理论上会有三个阶段的审计日志生成。
Kubernetes 审计功能由 kube-apiserver 服务提供。每个请求在不同执行阶段都会生成审计事件;这些审计事件会根据特定策略被预处理并写入后端。策略确定要记录的内容,当前的后端支持日志文件和 webhook。审计能力主要是由kube-apiserver 的WithFailedAuthenticationAudit和WithAudit过滤器来实现的。
日志等级
审计日志根据日志策略可以选择事件保存的等级,根据等级不同,APIServer记录日志的详细程度也不同。目前支持的事件等级有:
None
- 不记录日志.
Metadata
- 只记录Request的一些metadata,但不记录Request或Response的body。
Request
- 记录Request的metadata和body。
RequestResponse
- 最全记录方式,会记录所有的metadata、Request和Response的Body。
日志记录策略
APIServer支持对每类不同的资源设置不同的审计日志策略,包括日志记录阶段以及日志记录等级,常见的日志策略,一般都遵循以下原则:
只记录所需要的信息
- 一个请求不要重复记录,每个请求有三个阶段,只记录其中需要的阶段
- 在收到请求后不立即记录日志,当返回体header发送后才开始记录
- 对于认证信息(secrets,configmaps,token等)日志仅记录metadata,不包含请求体和返回体。
不需要的日志尽可能不记录
- 不要记录所有的资源,不要记录一个资源的所有子资源
- 对于/healthz,/version, /swagger*等只读url不作审计
- 对于大量冗余的请求等不做审计,比如kube-proxy watch操作,组件间的所有get请求。
官方配置示例解读
apiVersion: audit.k8s.io/v1 # 这是必填项。
kind: Policy
# 不要在 RequestReceived 阶段为任何请求生成审计事件。
omitStages:
- "RequestReceived"
rules:
# 在日志中用 RequestResponse 级别记录 Pod 变化。
- level: RequestResponse
# verbs 代表限制的动作
# verbs: ["update","patch"]
resources:
- group: "" # core API 组
resources: ["pods"]
# 在日志中记录 kube-system 命名空间中 configmap 变更的请求消息体。
- level: Request
resources:
- group: ""
resources: ["configmaps"]
namespaces: ["kube-system"]
# 在日志中以 Request 级别记录所有其他 core 和 extensions 组中的资源操作。
- level: Request
resources:
- group: ""
- group: "extensions" # 不应包括在内的组版本。
# 在日志中按 Metadata 级别记录 "pods/log"、"pods/status" 请求
- level: Metadata
resources:
- group: ""
resources: ["pods/log", "pods/status"]
# 在日志中用 Metadata 级别记录所有其他名字空间中的 configmap 和 secret 变更。
- level: Metadata
resources:
- group: ""
resources: ["secrets", "configmaps"]
# 一个抓取所有的规则,将在日志中以 Metadata 级别记录所有其他请求。
- level: Metadata
# 审计事件不在 RequestReceived阶段生成审计事件
omitStages:
- "RequestReceived"
# 不要在日志中记录对名为 "controller-leader" 的 configmap 的请求。
- level: None
resources:
- group: ""
resources: ["configmaps"]
resourceNames: ["controller-leader"]
# 不要在日志中记录由 "system:kube-proxy" 发出的对端点或服务的监测请求。
- level: None
users: ["system:kube-proxy"]
verbs: ["watch"]
resources:
- group: "" # core API 组
resources: ["endpoints", "services"]
# 不要在日志中记录对某些非资源 URL 路径的已认证请求。
- level: None
userGroups: ["system:authenticated"]
nonResourceURLs:
- "/api*" # 通配符匹配。
- "/version"
---
# 在 Metadata 级别为所有请求生成日志
apiVersion: audit.k8s.io/v1beta1
kind: Policy
rules:
# 每个level就是一个规则,如果不写规则,那么所有日志都会记录。
- level: Metadata
日志示例
{
---- 审计日志属性信息
"kind": "Event",
"apiVersion": "audit.k8s.io/v1beta1",
"metadata": {
"creationTimestamp": "xxx"
},
"level": "Metadata",
"timestamp": "xxx",
"auditID": "xxx",
"stage": "ResponseComplete",
"requestURI": "/apis/authentication.k8s.io/v1beta1?timeout=32s",
"verb": "get",
---- 用户信息
"user": {
"username": "xxx",
"uid": "xxx",
"groups": [
"system:serviceaccounts",
"system:serviceaccounts:kube-system",
"system:authenticated"
]
},
---- 客户端IP信息
"sourceIPs": [
"10.244.0.249"
],
---- 用户标识信息
"UserAgent": "kube-scheduler/v1.12.2 (linux/amd64) kubernetes/73f3294/scheduler",
"ObjectRef": {
"Resource": "pods",
"Namespace": "default",
"Name": "xxx",
"UID": "",
"APIGroup": "",
"APIVersion": "v1",
"ResourceVersion": "",
"Subresource": ""
},
---- 响应状态信息
"responseStatus": {
"metadata": {},
"code": 200
},
---- 时间注释信息
"requestReceivedTimestamp": "xxx",
"stageTimestamp": "xxx",
"annotations": {
"authorization.k8s.io/decision": "allow",
"authorization.k8s.io/reason": "RBAC: ..."
}
}
1.3.2 审计日志
学习目标
这一节,我们从 环境准备、简单实践、小结 三个方面来学习。
环境准备
简介
对于kuberntes的审计日志功能来说,它主要支持两种收集方式:
Log 后端,将事件写入到文件系统
--audit-policy-file=/etc/kubernetes/audit-policy.yaml
--audit-log-path=/var/log/kube-audit
--audit-log-format=json
Webhook 后端,将事件发送到外部 HTTP API
--audit-policy-file=/etc/kubernetes/audit-policy.yaml
--audit-webhook-config-file=/etc/kubernetes/audit-webhook-kubeconfig
其他属性参数
--audit-log-maxage 定义保留旧审计日志文件的最大天数
--audit-log-maxbackup 定义要保留的审计日志文件的最大数量
--audit-log-maxsize 定义审计日志文件的最大大小(兆字节)
简单实践
创建策略文件
定制资源清单文件 audit-policy.yaml
apiVersion: audit.k8s.io/v1
kind: Policy
# 列表内阶段不记录审计日志
omitStages:
- "ResponseStarted"
- "RequestReceived"
rules:
# 记录用户对config、pod 和 deployment 的操作
- level: RequestResponse
resources:
- group: ""
resources: ["pods", "configmaps"]
- group: "apps"
resources: ["deployments"]
# kube-controller-manager、kube-scheduler 等已经认证过身份的请求不需要记录
- level: None
userGroups: ["system:authenticated"]
nonResourceURLs:
- "/api*"
- "/version"
# 对 secret、token 等认证信息不记录请求体和返回体
- level: Metadata
resources:
- group: "" # core API group
resources: [ "secrets"]
集群启用审计日志
定制apiserver资源清单文件 kube-apiserver.yaml
...
spec:
containers:
- command:
- kube-apiserver
...
- --audit-policy-file=/etc/kubernetes/audit-policy.yaml
- --audit-log-path=/var/log/kubernetes/audit
- --audit-log-format=json
- --audit-log-maxage 30
- --audit-log-maxbackup 10
- --audit-log-maxsize 100
...
volumeMounts:
...
- mountPath: /etc/kubernetes/audit-policy.yaml
name: audit
readOnly: true
- mountPath: /var/log/kubernetes/audit/
name: audit-log
readOnly: false
volumes:
...
- name: audit
hostPath:
path: /etc/kubernetes/audit-policy.yaml
type: File
- name: audit-log
hostPath:
path: /var/log/kubernetes/audit/
type: DirectoryOrCreate
同步效果
同步基础配置
for i in {12..14}; do scp audit-policy.yaml root@10.0.0.$i:/etc/kubernetes/audit-policy.yaml ; done
同步kube-apiserver
for i in 12 13 14; do ssh root@10.0.0.$i "rm -f /etc/kubernetes/manifests/kube-apiserver.yaml" ; scp kube-apiserver.yaml root@10.0.0.$i:/etc/kubernetes/manifests/kube-apiserver.yaml; done
检查效果
等待所有master节点上的api-server启动后,可以看到,在/var/logs/auth 目录下,出现了审计日志。