原文: https://www.freecodecamp.org/news/how-to-pass-the-certified-kubernetes-security-specialist-exam/

本文基于我学习并通过 Kubernetes 安全专家认证考试的经验。2021 年 9 月,我第一次参加考试就通过了。

我于 2020 年 2 月通过了认证 Kubernetes 应用程序开发人员考试,随后于 2020 年 3 月通过了认证 Kubernetes 管理员。

认证 Kubernetes 安全专家或 CKS 考试于 2020 年 11 月左右发布,但我在 2021 年 9 月之前没有机会参加该考试。

作为一些背景信息,在过去的 3 年里,我几乎每天都在使用 Kubernetes,这些经验为我通过 CKS 考试提供了额外的优势。

在本文中,我将分享一些可以帮助您学习和通过考试的资源,以及可以在准备时使用的有用备忘单。 我还将分享一些建议,这些建议应该对您有所帮助。

什么是 Kubernetes

Kubernetes 是目前最先进、功能最丰富的容器编排系统,并且它一直在变得更好。

它有一个庞大的社区提供支持,并一直在开发新功能和解决问题。Kubernetes 无疑正在以惊人的速度发展,要跟上其发展速度成为一项挑战。 这使其成为容器编排解决方案的最佳选择。

目录


备考资料

以下是通过 CKS 考试的一些很棒的资源:

  1. 认证 Kubernetes 安全专家 by Killer.sh
  2. 认证 Kubernetes 安全专家(CKS)by KodeKloud
  3. Walid Shaari 收集了一些 CKS 考试不可或缺的资料
  4. Abdennour's References 的 CKS 考试目标参考资料
  5. Ibrahim Jelliti 的准备 Kubernetes 安全专家认证(CKSS)考试的资源集

KodeKloud 和 Killer.sh 的课程提供了模拟考试模拟器,这对备考非常有帮助,而且还能让人对考试有一个大致的了解。我强烈建议注册一门或两门课程。

从 Linux Foundation 购买考试后,你可以免费尝试 2 次来自 kill.sh 的考试模拟器。 这样,如果您精通课程内容,您可以跳过课程并直接进入考试提供的考试模拟器。

考试费用为 375 美元,但也有一些优惠和折扣,如果你留意一下,可能会得到更优惠的价格。考试时间为 2 小时,有效期为 2 年,而 CKA 和 CKAD 的有效期为 3 年。

Aliases

CKS 是一项基于表现的考试,您将获得一个考试模拟器,您必须在其中解决问题。 除了考试选项卡外,您只能打开一个选项卡。

因为这个考试需要你写很多命令,所以我很早就想到我必须依靠别名来减少击键次数以节省时间。

我在考试时使用了 vi 编辑器,所以在这里我将分享一些关于这个编辑器的实用技巧。

vi defaults for ~/.vimrc:

vi ~/.vimrc
---
:set number
:set et
:set sw=2 ts=2 sts=2
---
^: Start of word in line
0: Start of line
$: End of line
w: End of word
GG: End of file

kubectl defaults for ~/.bashrc:

vi ~/.bashrc
---
alias k='kubectl'
alias kg='k get'
alias kd='k describe'
alias kl='k logs'
alias ke='k explain'
alias kr='k replace'
alias kc='k create'
alias kgp='k get po'
alias kgn='k get no'
alias kge='k get ev'
alias kex='k exec -it'
alias kgc='k config get-contexts'
alias ksn='k config set-context --current --namespace'
alias kuc='k config use-context'
alias krun='k run'
export do='--dry-run=client -oyaml'
export force='--grace-period=0 --force'

source <(kubectl completion bash)
source <(kubectl completion bash | sed 's/kubectl/k/g' )
complete -F __start_kubectl k


alias krp='k run test --image=busybox --restart=Never'
alias kuc='k config use-context'
---

一些捷径

kubectl get 命令为访问资源提供了简短易懂的名称,例如 pvc 用于 persistentstorageclaim。这些可以帮助人们在考试期间节省大量击键和宝贵的时间。

  • po for pods
  • rs for replicasets
  • deploy for deployments
  • svc for services
  • ns for namespace
  • netpol for networkpolicy
  • pv for persistentstorage
  • pvc for persistentstorageclaim
  • sa for serviceaccounts

Kubernetes 手册

kubectl run 命令

kubectl run 命令提供了一个标志 --restart,它允许您创建从 Deployment 到 CronJob 的不同类型的 Kubernetes 对象。

下面的代码片段显示了可用于 --restart 标志的不同选项。

k run:
--restart=Always                             #Creates a deployment
--restart=Never                              #Creates a Pod
--restart=OnFailure                          #Creates a Job
--restart=OnFailure --schedule="*/1 * * * *" #Creates a CronJob

如何从现有的 pod 生成 yaml 规范

有时,从现有 pod 生成规范并对其进行更改比从头开始创建新的更容易。 kubectl get pod 命令为我们提供了所需的标志,以我们想要的格式输出 pod 规范。

kgp <pod-name> -o wide

# Generating YAML Pod spec
kgp <pod-name> -o yaml
kgp <pod-name> -o yaml > <pod-name>.yaml

# Get a pod's YAML spec without cluster specific information
kgp my-pod -o yaml --export > <pod-name>.yaml

kubectl pod 命令

kubectl run 命令提供了很多选项,例如指定请求和 Pod 应该使用的限制,或者容器在创建后应该运行的命令。

# Output YAML for a nginx pod running an echo command
krun nginx --image=nginx --restart=Never --dry-run -o yaml -- /bin/sh -c 'echo Hello World!'
# Output YAML for a busybox pod running a sleep command
krun busybox --image=busybox:1.28 --restart=Never --dry-run -o yaml -- /bin/sh -c 'while true; do echo sleep; sleep 10; done'
# Run a pod with set requests and limits
krun nginx --image=nginx --restart=Never --requests='cpu=100m,memory=512Mi' --limits='cpu=300m,memory=1Gi'
# Delete pod without delay
k delete po busybox --grace-period=0 --force

如何打印日志并导出

在调试应用程序时,日志是信息的基本来源。kubectl logs 命令提供了检查给定 pod 日志的功能。 您可以使用以下命令检查给定 pod 的日志。

kubectl logs deploy/<podname>
kubectl logs deployment/<podname>
#Follow logs
kubectl logs deploy/<podname> --tail 1 --follow

除了查看日志外,我们还可以将日志导出到文件中,以便进一步调试与任何人共享相同的内容。

kubectl logs <podname> --namespace <ns> > /path/to/file.format

如何创建配置映射和机密

kubectl create 命令让我们可以从命令行创建 ConfigMap 和 Secret。 我们还可以使用 YAML 文件来创建相同的资源,并通过使用 kubectl apply -f <filename> 我们可以应用命令。

kc cm my-cm --from-literal=APP_ENV=dev
kc cm my-cm --from-file=test.txt
kc cm my-cm --from-env-file=config.env

kc secret generic my-secret --from-literal=APP_SECRET=sdcdcsdcsdcsdc
kc secret generic my-secret --from-file=secret.txt
kc secret generic my-secret --from-env-file=secret.env

有用的调试命令

当您在日常工作中以及在 CKS 考试中解决问题时遇到问题和错误时,调试是一项非常重要的技能。

除了能够从容器输出日志外,kubectl exec 命令还允许您登录到正在运行的容器并调试问题。 在容器内,您还可以使用 ncnslookup 等实用程序来诊断与网络相关的问题。

# Run busybox container
k run busybox --image=busybox:1.28 --rm --restart=Never -it sh
# Connect to a specific container in a Pod
k exec -it busybox -c busybox2 -- /bin/sh
# adding limits and requests in command
kubectl run nginx --image=nginx --restart=Never --requests='cpu=100m,memory=256Mi' --limits='cpu=200m,memory=512Mi'
# Create a Pod with a service
kubectl run nginx --image=nginx --restart=Never --port=80 --expose
# Check port
nc -z -v -w 2 <service-name> <port-name>
# NSLookup
nslookup <service-name>
nslookup 10-32-0-10.default.pod

滚动更新和推出

kubectl rollout 命令提供了检查更新状态的能力,如果需要,还可以回滚到以前的版本。

k set image deploy/nginx nginx=nginx:1.17.0 --record
k rollout status deploy/nginx
k rollout history deploy/nginx
# Rollback to previous version
k rollout undo deploy/nginx
# Rollback to revision number
k rollout undo deploy/nginx --to-revision=2
k rollout pause deploy/nginx
k rollout resume deploy/nginx
k rollout restart deploy/nginx
kubectl run nginx-deploy --image=nginx:1.16 --replias=1 --record

缩放和自动缩放命令

kubectl scale 命令提供了在给定部署中扩大或缩小 pod 的功能。

使用 kubectl autoscale 命令,我们可以定义给定部署应该运行的最小 pod 数量,以及部署可以扩展到的最大 pod 数量以及 CPU 百分比等扩展标准。

k scale deploy/nginx --replicas=6
k autoscale deploy/nginx --min=3 --max=9 --cpu-percent=80

网络策略

在 Kubernetes 集群中,默认情况下所有 pod 都可以与所有 pod 通信,这在某些实现中可能是一个安全问题。

为了解决这个问题,Kubernetes 引入了网络策略来允许或拒绝基于 pod 标签的流量,这些标签是 pod 规范的一部分。

下面的示例拒绝在所有命名空间中运行的 Pod 的 Ingress 和 Egress 流量。

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: example
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Egress
  - Ingress

下面的示例拒绝在所有命名空间中运行的 Pod 的 Ingress 和 Egress 流量。 但它允许访问在端口 53 上运行的 DNS 解析服务。

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Egress
  - Ingress
  egress:
  - to:
    ports:
      - port: 53
        protocol: TCP
      - port: 53
        protocol: UDP

以下示例拒绝对 AWS EC2 实例中 IP 地址“169.256.169.256”上运行的元数据服务器的 Egress 访问。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name:cloud-metadata-deny
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to:
      - ipBlock: 
          cidr: 0.0.0.0/0
          except:
          - 169.256.169.256/32

下面的示例允许 Egress 访问 AWS EC2 实例中在 IP 地址“169.256.169.256”上运行的元数据服务器。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: cloud-metadata-accessor
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: metadata-accessor
  policyTypes:
  - Egress
  egress:
  - to:
    - ipBlock:
        cidr: 169.256.169.256/32

使用 Kubesec 进行静态分析

Kubesec 是一个静态分析工具,用于分析 YAML 文件以查找文件问题。

kubesec scan pod.yaml

# Using online kubesec API
curl -sSX POST --data-binary @pod.yaml https://v2.kubesec.io/scan

# Running the API locally
kubesec http 8080 &

kubesec scan pod.yaml -o pod_report.json -o json

使用 Trivvy 进行漏洞扫描

Trivvy 是一种漏洞扫描工具,可扫描容器映像以查找安全问题。

trivy image nginx:1.18.0
trivy image --severity CRITICAL nginx:1.18.0
trivy image --severity CRITICAL, HIGH nginx:1.18.0
trivy image --ignore-unfixed nginx:1.18.0

# Scanning image tarball
docker save nginx:1.18.0 > nginx.tar
trivy image --input archive.tar

# Scan and output results to file
trivy image --output python_alpine.txt python:3.10.0a4-alpine
trivy image --severity HIGH --output /root/python.txt python:3.10.0a4-alpine

# Scan image tarball
trivy image --input alpine.tar --format json --output /root/alpine.json

如何删除不需要的服务

The systemctl exposes the capabilities to start, stop, enable, disable and list services running on a Linux Virtual Machine.
systemctl 提供了启动、停止、启用、禁用和列出在 Linux 虚拟机上运行的服务的功能。

列出服务:

systemctl list-units --type service

停止服务:

systemctl stop apache2

禁用服务:

systemctl disable apache2

删除服务:

apt remove apache2

运行时类

Kubernetes 在 v1.12 版本中引入了 RuntimeClass 功能,用于选择容器运行时配置。 容器运行时配置用于运行 pod 的底层容器。

大多数 Kubernetes 集群使用 dockershim 作为运行容器的运行时类,但您可以使用不同的容器运行时。

dockershim 在 Kubernetes 版本 v1.20 中已被弃用,并将在 v1.24 中删除。

如何创建运行时类:

apiversion: node.k8s.io/v1beta1
kind: RuntimeClass
metadata:
  name: gvisor
handler: runsc

如何为任何给定的 pod 使用运行时类:

apiVersion: v1
kind: Pod
metadata:
  labels:
    run: nginx
  name: nginx
spec:
  runtimeClassName: gvisor
  containers:
  - name: nginx
    image: nginx 

RBAC 命令

在 Kubernetes 中,

基于角色的访问控制(RBAC)命令提供了一种基于单个用户或服务帐户的角色来调节对 Kubernetes 资源的访问的方法。(来源

以下是创建角色的方法:

kubectl create role developer --resource=pods --verb=create,list,get,update,delete --namespace=development

如何创建角色绑定:

kubectl create rolebinding developer-role-binding --role=developer --user=faizan --namespace=development

如何验证:

kubectl auth can-i update pods --namespace=development --as=faizan

如何创建集群角色:

kubectl create clusterrole pvviewer-role --resource=persistentvolumes --verb=list

以及如何创建与服务帐户的 Clusterrole 绑定关联:

kubectl create clusterrolebinding pvviewer-role-binding --clusterrole=pvviewer-role --serviceaccount=default:pvviewer

集群维护

您可以使用 kubectl drain 命令从给定节点中删除所有正在运行的工作负载(pod)。

您使用 kubectl cordon 命令来封锁节点以将其标记为可调度。

并且您使用 kubectl uncordon 命令将节点设置为可调度,这意味着控制器管理器可以将新 pod 调度到给定节点。

如何排空所有 pod 的节点:

kubectl drain node-1

如何排空节点并忽略守护程序集:

kubectl drain node01 --ignore-daemonsets

如何强制排空节点:

kubectl drain node02 --ignore-daemonsets --force

如何将一个节点标记为不可调度,这样就不能在这个节点上调度新的 Pod:

kubectl cordon node-1

标记节点可调度

kubectl uncordon node-1

CKS 考试技巧

Kubernetes `kubectl get` 命令为用户提供了一个输出标志,`-o` 或 `--output`,这有助于我们以 JSON、yaml、wide 或 custom-columns 的形式格式化输出。

JSON 和 JSONPath

如何以 JSON Object 的形式输出所有 pod 的内容:

kubectl get pods -o json

JSONPath 从 JSON 对象输出一个特定的键:

kubectl get pods -o=jsonpath='{@}'
kubectl get pods -o=jsonpath='{.items[0]}'

.items[*] 用于我们有多个对象的地方,例如具有 pod 配置的多个容器:

# For list of items use .items[*]
k get pods -o 'jsonpath={.items[*].metadata.labels.version}'
# For single item
k get po busybox -o jsonpath='{.metadata}'
k get po busybox -o jsonpath="{['.metadata.name', '.metadata.namespace']}{'\n'}"

该命令使用 JSONPath 返回节点的内部 IP:

kubectl get nodes -o=jsonpath='{.items[*].status.addresses[?(@.type=="InternalIP")].address}'

该命令检查特定键的相等性:

kubectl get pod api-stag-765797cf-lrd8q -o=jsonpath='{.spec.volumes[?(@.name=="api-data")].persistentVolumeClaim.claimName}'
kubectl get pod -o=jsonpath='{.items[*].spec.tolerations[?(@.effect=="NoSchedule")].key}'

自定义列有助于输出特定字段:

kubectl get pods -o='custom-columns=PODS:.metadata.name,Images:.spec.containers[*].image'

CKS 考试题目

CKS 考试涵盖与 Kubernetes 生态系统中的安全性相关的主题。Kubernetes 安全是一个庞大的话题,一篇文章难以涵盖,因此本文包含了考试中涉及的一些主题。

如何保护和强化容器镜像

在设计容器镜像以运行您的代码时,请特别注意保护和强化措施,以防止黑客攻击和特权升级攻击。 在构建容器镜像时请记住以下几点:

  1. 使用特定的包版本,如alpine:3.13
  2. 不要以 root 身份运行 - 使用 USER <username> 来阻止 root 访问。
  3. 使用 readOnlyRootFilesystem: truesecurityContext 中将文件系统设为只读
  4. 使用 RUN rm -rf /bin/* 删除 shell 访问

如何最小化操作系统占用空间

容器层

指令 RUNCOPYADD创建容器层。 其他指令创建临时中间图像并且不增加构建的大小。 创建图层的说明会增加结果图像的大小。

典型的 Dockerfile 如下所示。它使用RUN指令添加一个单层。

FROM ubuntu

RUN apt-get update && apt-get install -y golang-go

CMD ["sh"]

多阶段构建

多阶段构建利用 Dockerfile 中的多个FROM语句。FROM 指令标志着构建的一个新阶段。它结合了多个FROM语句,允许利用以前的构建,以便有选择地将二进制文件复制到新的构建阶段,省略不必要的二进制文件。生成的 Docker 映像的大小要小得多,攻击面也大大减少。

FROM ubuntu:20.04 AS build
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y golang-go
COPY app.go .
RUN CGO_ENABLED=0 go build app.go

FROM alpine:3.13
RUN chmod a-w /etc
RUN addgroup -S appgroup && adduser -S appuser -G appgroup -h /home/appuser
RUN rm -rf /bin/*
COPY --from=build /app /home/appuser/
USER appuser
CMD ["/home/appuser/app"]

如何限制节点访问

访问控制文件包含有关 Linux 操作系统中用户/组的敏感信息。

#Stores information about the UID/GID, user shell, and home directory for a user
/etc/passwd
#Stores the user password in a hashed format
/etc/shadow
#Stores information about the group a user belongs
/etc/group
#Stored information about the Sudoers present in the system
/etc/sudoers

禁用用户帐户有助于通过禁用给定用户帐户的登录来保护对节点的访问。

usermod -s /bin/nologin <username>

禁用“root”用户帐户具有特殊意义,因为 root 帐户具有所有功能。

usermod -s /bin/nologin root

以下是如何添加具有主目录和 shell 的用户:

adduser --home /opt/faizanbashir --shell /bin/bash --uid 2328 --ingroup admin faizanbashir
useradd -d /opt/faizanbashir -s /bin/bash -G admin -u 2328 faizanbashir

如何删除用户帐户:

userdel <username>

如何删除群组:

groupdel <groupname>

如何将用户添加到组:

adduser <username> <groupname>

如何从组中删除用户:

#deluser faizanbashir admin
deluser <username> <groupname>

如何为用户设置密码:

passwd <username>

如何将用户提升为 sudoer:

vim /etc/sudoers
>>>
faizanbashir ALL=(ALL:ALL) ALL

如何在没有密码的情况下启用 sudo:

vim /etc/sudoers
>>>
faizanbashir ALL=(ALL) NOPASSWD:ALL

visudo
usermod -aG sudo faizanbashir
usermod faizanbashir -G admin

SSH加固

如何禁用SSH

/etc/ssh/sshd_config 中给出的配置可用于保护对 Linux 节点的 SSH 访问。 将 PermitRootLogin 设置为 no 会禁用节点上的 root 登录。

要强制使用密钥登录并禁用使用密码登录节点,您可以将“PasswordAuthentication”设置为“no”。

vim /etc/ssh/sshd_config
>>
PermitRootLogin no
PasswordAuthentication no
<<
# Restart SSHD Service
systemctl restart sshd

如何设置root用户不登录:

usermod -s /bin/nologin root

SSH 复制用户密钥/无密码 SSH:

ssh-copy-id -i ~/.ssh/id_rsa.pub faizanbashir@node01
ssh faizanbashir@node01

如何删除过时的包和服务

以下是列出在 Ubuntu 机器上运行的所有服务的方法:

systemctl list-units --type service
systemctl list-units --type service --state running

如何停止、禁用和删除服务:

systemctl stop apache2
systemctl disable apache2
apt remove apache2

如何限制内核模块

在 Linux 中,内核模块是可以根据需要加载和卸载到内核中的代码片段。 它们无需重新启动系统即可扩展内核的功能。 模块可以配置为内置或可加载的。

如何列出所有内核模块:

lsmod

如何手动将模块加载到内核中:

modprobe pcspkr

如何将模块列入黑名单:(参考:CIS Benchmarks -> 3.4 Uncommon Network Protocols)

cat /etc/modprobe.d/blacklist.conf
>>>
blacklist sctp
blacklist dccp

# Shutdown for changes to take effect
shutdown -r now

# Verify
lsmod | grep dccp

如何识别和禁用开放端口

如何检查开放端口:

netstat -an | grep -w LISTEN
netstat -natp | grep 9090

nc -zv <hostname|IP> 22
nc -zv <hostname|IP> 10-22

ufw deny 8080

如何检查端口使用情况:

/etc/services | grep -w 53

这是[开放端口列表]的参考文档(https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#control-plane-node-s)。

如何限制网络访问

如何识别端口上运行的服务:

systemctl status ssh
cat /etc/services | grep ssh
netstat -an | grep 22 | grep -w LISTEN

UFW防火墙

Uncomplicated Fire Wall (UFW) 是一个在 Arch Linux、Debian 或 Ubuntu 中管理防火墙规则的工具。 UFW 允许您允许和阻止给定端口和来自给定来源的流量。

以下是安装 UFW 防火墙的方法:

apt-get update
apt-get install ufw
systemctl enable ufw
systemctl start ufw
ufw status
ufw status numbered

如何允许所有出站和入站连接:

ufw default allow outgoing
ufw default allow incoming

如何允许规则:

ufw allow 22
ufw allow 1000:2000/tcp
ufw allow from 172.16.238.5 to any port 22 proto tcp
ufw allow from 172.16.238.5 to any port 80 proto tcp
ufw allow from 172.16.100.0/28 to any port 80 proto tcp

如何拒绝规则:

ufw deny 8080

如何启用和激活防火墙:

ufw enable

如何删除规则:

ufw delete deny 8080
ufw delete <rule-line>

如何重置规则:

ufw reset

Linux 系统调用

Linux 系统调用用于从用户空间向 Linux 内核发出请求。 例如,在创建文件时,用户空间向 Linux 内核发出创建文件的请求。

内核空间有以下内容:

  • Kernel Code
  • Kernel Extensions
  • Device Drivers

如何使用 Strace 跟踪系统调用

以下是使用 strace 跟踪系统调用的方法:

which strace
strace touch /tmp/error.log

如何获取服务的PID:

pidof sshd
strace -p <pid>

如何列出操作期间进行的所有系统调用:

strace -c touch /tmp/error.log

如何合并列出的系统调用:(计数和总结)

strace -cw ls /

如何遵循 PID 并进行整合:

strace -p 3502 -f -cw

AquaSec Tracee

AquaSec Tracee 由 Aqua Security 创建,它使用 eBPF 来跟踪容器中的事件。 Tracee 在运行时直接在内核空间中使用 eBPF(Extended Berkeley Packet Filter),而不会干扰内核源代码或加载任何内核模块。

  • 二进制存储在/tmp/tracee
  • 如果使用具有 --privileged 能力的容器运行,则需要以只读模式访问以下内容:
    • /tmp/tracee -> 默认工作区
    • /lib/modules -> 内核头文件
    • /usr/src -> 内核头文件

如何让 Docker 容器中的 Tracee 变得有趣:

docker run --name tracee --rm --privileged --pid=host \
  -v /lib/modules/:/lib/modules/:ro -v /usr/src/:/usr/src/ro \
  -v /tmp/tracee:/tmp/tracee aquasec/tracee:0.4.0 --trace comm=ls

# 列出主机上所有新进程的系统调用
docker run --name tracee --rm --privileged --pid=host \
  -v /lib/modules/:/lib/modules/:ro -v /usr/src/:/usr/src/ro \
  -v /tmp/tracee:/tmp/tracee aquasec/tracee:0.4.0 --trace pid=new

# 列出来自任何新容器的系统调用
docker run --name tracee --rm --privileged --pid=host \
  -v /lib/modules/:/lib/modules/:ro -v /usr/src/:/usr/src/ro \
  -v /tmp/tracee:/tmp/tracee aquasec/tracee:0.4.0 --trace container=new

如何使用 Seccomp 限制系统调用

SECCOMP – 安全计算模式 – 是一种 Linux 内核级别的功能,您可以将其用于沙箱应用程序以仅使用它们需要的系统调用。

如何检查对 seccomp 的支持:

grep -i seccomp /boot/config-$(uname -r)

如何测试更改系统时间:

docker run -it --rm docker/whalesay /bin/sh
# date -s '19 APR 2013 22:00:00'

ps -ef

如何检查任何 PID 的 seccomp 状态:

grep -i seccomp /proc/1/status

Seccomp 模式:

  • 模式 0:禁用
  • 模式一:严格
  • 模式2:过滤

以下配置用于将系统调用列入白名单。 白名单配置文件是安全的,但必须有选择地启用系统调用,因为它默认阻止所有系统调用。

{
  "defaultAction": "SCMP_ACT_ERRNO",
  "architectures": [
    "SCMP_ARCH_X86_64",
    "SCMP_ARCH_X86",
    "SCMP_ARCH_X32"
  ],
  "syscalls": [
    {
      "names": [
        "<syscall-1>",
        "<syscall-2>",
        "<syscall-3>"
      ],
      "action": "SCMP_ACT_ALLOW"
    }
  ]
}

以下配置用于将系统调用列入黑名单。 黑名单配置文件比白名单具有更大的攻击面。

{
  "defaultAction": "SCMP_ACT_ALLOW",
  "architectures": [
    "SCMP_ARCH_X86_64",
    "SCMP_ARCH_X86",
    "SCMP_ARCH_X32"
  ],
  "syscalls": [
    {
      "names": [
        "<syscall-1>",
        "<syscall-2>",
        "<syscall-3>"
      ],
      "action": "SCMP_ACT_ERRNO"
    }
  ]
}

Docker seccomp 配置文件阻止了 x86 架构上 300 多个系统调用中的 60 个。

如何在 Docker 中使用 seccomp 配置文件:

docker run -it --rm --security-opt seccomp=/root/custom.json docker/whalesay /bin/sh

如何允许容器的所有系统调用:

docker run -it --rm --security-opt seccomp=unconfined docker/whalesay /bin/sh

# Verify
grep -i seccomp /proc/1/status

# Output should be:
Seccomp:         0

如何使用 Docker 容器获取容器运行时相关信息:

docker run r.j3ss.co/amicontained amicontained

Kubernetes 中的 Seccomp

安全计算模式(SECCOMP)是 Linux 内核的一项功能。 您可以使用它来限制容器内可用的操作。 Seccomp 文档

如何在 Kubernetes 中运行 amicontained:

kubectl run amicontained --image r.j3ss.co/amicontained amicontained -- amicontained

v1.20 版本开始,Kubernetes 默认不实现 seccomp。

Kubernetes 中的 Seccomp 'RuntimeDefault' docker 配置文件:

apiVersion: v1
kind: Pod
metadata:
  labels:
    run: amicontained
  name: amicontained
spec:
  securityContext:
    seccompProfile:
      type: RuntimeDefault
  containers:
  - args:
    - amicontained
    image: r.j3ss.co/amicontained
    name: amicontained
    securityContext:
      allowPrivilegeEscalation: false

kubelets 中的默认 seccomp 位置

/var/lib/kubelet/seccomp

如何在节点中创建 seccomp 配置文件:

mkdir -p /var/lib/kubelet/seccomp/profiles

# 添加配置文件进行审计
vim /var/lib/kubelet/seccomp/profiles/audit.json
>>>
{
  defaultAction: "SCMP_ACT_LOG"
}

# 添加违规配置文件(默认阻止所有系统调用,不会让任何东西运行)

vim /var/lib/kubelet/seccomp/profiles/violation.json

>>>
{
  defaultAction: "SCMP_ACT_ERRNO"
}

Local seccomp profile – this file should exist locally on a node to be able to work:

...
securityContext:
  seccompProfile:
    type: Localhost
    localhostProfile: profiles/audit.json
...

上述配置文件将使系统调用能够保存到文件中。

grep syscall /var/log/syslog

如何将系统调用号映射到系统调用名称:

grep -w 35 /usr/include/asm/unistd_64.h

# OR
grep -w 35 /usr/include/asm-generic/unistd.h

AppArmor

AppArmor 是一个 Linux 安全模块,用于将程序限制在一组有限的资源中。

如何安装 AppArmor 工具:

apt-get install apparmor-utils

如何检查 AppArmor 是否正在运行和启用:

systemctl status apparmor

cat /sys/module/apparmor/parameters/enabled
Y

AppArmor 配置文件存储在:

cat /etc/apparmor.d/root.add_data.sh

如何列出 AppArmor 配置文件:

cat /sys/kernel/security/apparmor/profiles

如何拒绝所有文件写入配置文件:

profile apparmor-deny-write flags=(attach_disconnected) {
  file,
  # Deny all file writes.
  deny /** w,
}

如何拒绝写入 /proc 文件:

profile apparmor-deny-proc-write flags=(attach_disconnected) {
  file,
  # Deny all file writes.
  deny /proc/* w,
}

如何拒绝重新挂载根 FS:

profile apparmor-deny-remount-root flags=(attach_disconnected) {

  # Deny all file writes.
  deny mount options=(ro, remount) -> /,
}

如何查看个人资料状态:

aa-status

配置文件加载模式

  • Enforce,监控和执行规则
  • Complain,不会强制执行规则,但会将它们记录为事件
  • Unconfined,不会强制执行或记录事件

如何检查配置文件是否有效:

apparmor_parser /etc/apparmor.d/root.add_data.sh

如何禁用配置文件:

apparmor_parser -R /etc/apparmor.d/root.add_data.sh
ln -s /etc/apparmor.d/root.add_data.sh /etc/apparmor.d/disable/

如何生成个人资料并回答以下一系列问题:

aa-genprof /root/add_data.sh

如何为命令生成配置文件:

aa-genprof curl

如何从日志中禁用配置文件:

aa-logprof

如何在 Kubernetes 中使用 AppArmor

要将 AppArmor 与 Kubernetes 一起使用,必须满足以下先决条件:

  • Kubernetes 版本应该大于 1.4
  • 应启用 AppArmor 内核模块
  • AppArmor 配置文件应该加载到内核中
  • 应支持容器运行时

Kubernetes 中的示例用法:

apiVersion: v1
kind: Pod
metadata:
  name: ubuntu-sleeper
  annotations:
    container.apparmor.security.beta.kubernetes.io/<container-name>: localhost/<profile-name>
spec:
  containers:
  - name: ubuntu-sleeper
    image: ubuntu
    command: ["sh", "-c", "echo 'Sleeping for an hour!' && sleep 1h"]

注意:容器应在包含 AppArmor 配置文件的节点中运行。

Linux 功能

Linux 功能特性将可用于以“root”用户身份运行的进程的权限分解为更小的权限组。 这样,以“root”权限运行的进程可以被限制为仅获得执行其操作所需的最小权限。

Docker 支持 Linux 功能作为 Docker 运行命令的一部分:使用 --cap-add--cap-drop。 默认情况下,容器启动时具有默认允许且可以删除的多个功能。 其他权限可以手动添加。

--cap-add--cap-drop 都支持 ALL 值,以允许或删除所有功能。 默认情况下,Docker 容器运行 14 种功能。

  • Kernel < 2.2
    • Privileged Process
    • Unprivileged Process
  • Kernel >= 2.2
    • Privileged Process
      • CAP_CHOWN
      • CAP_SYS_TIME
      • CAP_SYS_BOOT
      • CAP_NET_ADMIN

有关 Linux 功能的完整列表,请参阅此文档

如何检查命令需要哪些功能:

getcap /usr/bin/ping

如何获得进程能力:

getpcaps <pid>

如何添加安全功能:

apiVersion: v1
kind: Pod
metadata:
  name: ubuntu-sleeper
spec:
  containers:
  - name: ubuntu-sleeper
    image: ubuntu
    command: ["sleep", "1000"]
    securityContext:
      capabilities:
        add: ["SYS_TIME"]
        drop: ["CHOWN"]

如何准备考试

CKS 被认为是一项非常艰难的考试。 但根据我的经验,我认为,只要练习足够好,并且如果你理解考试涵盖的概念,两小时内就会很容易掌握。

你肯定需要了解底层的 Kubernetes 概念。 由于 CKS 的先决条件是通过 CKA 考试,因此在尝试 CKS 之前,您应该对 Kubernetes 及其运作方式有深入的了解。

此外,要通过 CKS,您需要了解容器编排带来的威胁和安全隐患。

引入 CKS 考试表明容器的安全性不容轻视。安全机制应始终到位,以阻止对 Kubernetes 集群的攻击。

特斯拉加密货币黑客事件 是由于一个未受保护的 Kubernetes 控制面板造成的,揭示了与 Kubernetes 或任何其他容器编排引擎相关的风险。Hackerone 有一个 Kubernetes 赏金页面 列出了标准 Kubernetes 集群中使用的源代码仓库。

练习,练习,再练习!

练习是破解考试的关键,我个人发现 KodeKloud 和 Killer.sh 的考试模拟器对我帮助很大。

我没有像准备 CKA 考试那样多的时间来准备 CKS 考试,但是我在日常工作中正在研究 Kubernetes,所以我对它已经非常熟悉了。

实践是成功的关键。祝考试顺利!

您可以在 faizanbashir.me阅读这篇文章和其他文章