惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Tailwind CSS Blog
S
Secure Thoughts
D
Darknet – Hacking Tools, Hacker News & Cyber Security
T
Tor Project blog
T
Tenable Blog
Know Your Adversary
Know Your Adversary
Webroot Blog
Webroot Blog
V
Vulnerabilities – Threatpost
WordPress大学
WordPress大学
S
Security @ Cisco Blogs
J
Java Code Geeks
S
SegmentFault 最新的问题
A
Arctic Wolf
Simon Willison's Weblog
Simon Willison's Weblog
T
Threatpost
Forbes - Security
Forbes - Security
爱范儿
爱范儿
T
The Blog of Author Tim Ferriss
S
Securelist
MongoDB | Blog
MongoDB | Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
月光博客
月光博客
Blog — PlanetScale
Blog — PlanetScale
博客园 - 【当耐特】
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
SecWiki News
SecWiki News
aimingoo的专栏
aimingoo的专栏
腾讯CDC
U
Unit 42
Google DeepMind News
Google DeepMind News
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
大猫的无限游戏
大猫的无限游戏
Latest news
Latest news
I
InfoQ
V2EX - 技术
V2EX - 技术
The Cloudflare Blog
V
V2EX
The Register - Security
The Register - Security
博客园 - Franky
Security Archives - TechRepublic
Security Archives - TechRepublic
Security Latest
Security Latest
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
云风的 BLOG
云风的 BLOG
Jina AI
Jina AI
Microsoft Security Blog
Microsoft Security Blog
小众软件
小众软件
N
Netflix TechBlog - Medium
量子位
M
MIT News - Artificial intelligence

lvbibir's Blog

shell | 磁盘空间分析脚本 Linux cat 和 tee 命令写入文件 python | 使用 uv 管理你的 python 环境 Claude Code 完整配置指南 windows | mihomo 内核独立部署指南 linux | 磁盘扩容 wsl | 释放长久运行占用的磁盘空间 mysql | 线程上限问题处理 麒麟 7.6 安装谷歌 OTP 认证模块 suse 12sp5 升级 openssh 及 openssl suse 12sp5 部署 mysql 5.7 《谁的青春不迷茫》 docker | centos7 部署 docker vim | 基础配置和使用 windows | rime 输入法 & 雾凇方案 shell | sshpass 批量传输文件及执行命令 wsl | 原生 linux 方式安装 docker nodejs | fnm + pnpm 开发环境配置 wsl | 安装配置 miniconda 虚拟环境 wsl | 自动更新系统代理 wsl | bashrc 环境变量不正确加载的处理方法 wsl | win10 安装 wsl2 troubleshooting | ssh 成功但是 scp 失败 linux | 常用命令总结 docker 部署 piclist shell | 检测网站存活并自动钉钉告警 Zabbix | 监控端口连通性并自动追踪 TCP 路由 windows | 自定义开机快速启动项 windows | miniconda 配置 python 虚拟环境 Zabbix | 监控主机到指定 ip 的流量大小 shell | centos 初始化 loki (二) 部署 loki (一) 简介 prometheus (六) Alertmanager prometheus (五) 记录规则与告警规则 prometheus (四) 黑盒监控 prometheus (三) 服务发现 prometheus (二) 静态配置 prometheus (一) 简介及部署 traefik (四) TraefikService 服务 traefik (三) Middleware 中间件 traefik (二) ingressRoute 路由 traefik (一) 简介、部署和配置 kubernetes | Gateway API 简介及部署 linux | dns 配置文件中 search 和 options ndots 详解 kubernetes | command args 和 dockerfile 中的 ENTRYPOINT CMD kubernetes | statefulset 控制器详解 docker | dockerfile 最佳实践 docker | dockerfile 指令详解 linux | kill 命令详解以及 linux 中的信号 troubleshooting | elasticsearch 安装插件报错 shell | if 条件判断 docker | 下载外网镜像的几种方式 python | 鬼谷子数学问题 steam挂刀教程 linux | history 命令的格式化输出 shell | 将本地镜像批量推送到 harbor windows | hosts 文件修复 kubernetes | configmap & secret kubernetes | service & ingress kubernetes | 存储 kubernetes | 滚动升级和自动伸缩 kubernetes | 控制器 kubernetes | 日志 kubernetes | 调度 kubernetes | pod kubernetes | 杂记 linux | set 命令详解 ceph | openeuler 部署 ceph-v16 ceph | ceph-v16 离线安装解决方案 pxe 如何应对复杂的服务器硬件环境 python | 批量修改目录下文件名 《微习惯》 ceph | openeuler (aarch64) 部署 ceph-v16 troubleshooting | glibc 误升级后修复 pxe 安装配置大全 《人间失格》 跑步日常 [置顶] Hello, hugo! shell | 检索某 url 中所有文件的内容 shell | 不同执行方式的区别 shell | 开启 debug 模式 vscode | 常见问题 windows & linux 多网卡时设置默认路由以及添加静态路由 mysql (二) 主从复制原理 GTID 并行复制 mysql (一) 部署 mysql | 杂记 cicd | jenkins 部署 mall-swarm 项目 httpd 源码打包编译成 rpm 包 openssl 源码打包编译成 rpm 包 centos7 | 修改网卡名称 ceph | pool pg_num 配置 docker | 脚本方式批量导出/导入镜像 centos 密码尝试次数过多问题处理 centos7 | 升级内核至 5.10 CVE-1999-0526 ceph | centos7 部署 ceph-v12 python | 修改 pip 源 troubleshooting | 安装 cloud-init 后导致 ssh 连接失败 windows | autohotkey 常用脚本
kubernetes | RBAC 鉴权和 NetworkPolicy
lvbibir · 2022-10-07 · via lvbibir's Blog

0 前言

基于 centos7.9docker-ce-20.10.18kubelet-1.22.3-0

  • 客户端要想访问 K8s 集群 API Server,一般需要 CA 证书、Token 或者用户名 + 密码
  • 如果 Pod 访问,需要 ServiceAccount

K8S 安全控制框架主要由下面 3 个阶段进行控制,每一个阶段都支持插件方式,通过 API Server 配置来启用插件。

  1. Authentication(鉴权)
  2. Authorization(授权)
  3. Admission Control(准入控制)

image-20221007174309826

1.1 鉴权 (Authentication)

三种客户端身份认证:

  • HTTPS 证书认证:基于 CA 证书签名的数字证书认证
  • HTTP Token 认证:通过一个 Token 来识别用户
  • HTTP Base 认证:用户名 + 密码的方式认证

RBAC(Role-Based Access Control,基于角色的访问控制):负责完成授权(Authorization)工作。

RBAC 根据 API 请求属性,决定允许还是拒绝。

比较常见的授权维度:

  • user:用户名
  • group:用户分组
  • 资源,例如 pod、deployment
  • 资源操作方法:get,list,create,update,patch,watch,delete
  • 命名空间
  • API 组

1.3 准入控制 (Admission Control)

Adminssion Control 实际上是一个准入控制器插件列表,发送到 API Server 的请求都需要经过这个列表中的每个准入控制器插件的检查,检查不通过,则拒绝请求

2 RBAC

https://kubernetes.io/zh-cn/docs/reference/access-authn-authz/rbac/

2.1 基础概念

RBAC(Role-Based Access Control,基于角色的访问控制),允许通过 Kubernetes API 动态配置策略。

角色

  • Role:授权特定命名空间的访问权限
  • ClusterRole:授权所有命名空间的访问权限

角色绑定

  • RoleBinding:将角色绑定到主体(即 subject)
  • ClusterRoleBinding:将集群角色绑定到主体

主体(subject)

  • User:用户
  • Group:用户组
  • ServiceAccount:服务账号

2022年10月7日184036

2.2 示例

为 Amadeus 用户授权 default 命名空间 Pod 读取权限

2.2.1 新建用户

新建一个 k8s 用户大概可以分为以下几步:

  • 签发用户证书
    • 生成用户的证书 key
    • 通过用户的证书 key,生成用户的证书请求 (csr)
    • 通过 k8s api 的 ca 证书去签发用户的证书请求,生成用户的证书 (crt)
  • 生成 kubeconfig 配置文件
    • kubectl config set-cluster //集群配置
    • kubectl config set-credentials //用户配置
    • kubectl config set-context //context 配置
    • kubectl config use-context //使用 context
  • 使用新创建的用户
    • kubectl –kubecofig=path // 通过参数指定
    • KUBECONFIG=path kubectl // 通过环境变量指定,path 可以指定多个,用 : 连接,从而将多个配置文件合并在一起使用

2.2.2 签发用户证书

可以使用 openssl 或者 cfssl 进行签发,任选一种

[root@k8s-node1 ~]# mkdir -p /etc/kubernetes/users/Amadeus
[root@k8s-node1 ~]# cd /etc/kubernetes/users/Amadeus/

openssl

# 创建用户证书 key
[root@k8s-node1 Amadeus]# openssl genrsa -out Amadeus.key 2048
# 创建用户证书请求 (csr),-subj 指定组和用户,其中 O 是组名,CN 是用户名
[root@k8s-node1 Amadeus]# openssl req -new -key Amadeus.key -out Amadeus.csr -subj "/O=hello/CN=Amadeus"
# 生成用户的证书 (crt),使用 k8s 的 ca 签发用户证书
[root@k8s-node1 Amadeus]# openssl x509 -req -in Amadeus.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out Amadeus.crt -days 3650

[root@k8s-node1 Amadeus]# ls
Amadeus.crt  Amadeus.csr  Amadeus.key

cfssl

下载 cfssl 工具

wget --no-check-certificate https://github.com/cloudflare/cfssl/releases/download/1.2.0/cfssl_linux-amd64
wget --no-check-certificate https://github.com/cloudflare/cfssl/releases/download/1.2.0/cfssljson_linux-amd64
wget --no-check-certificate https://github.com/cloudflare/cfssl/releases/download/1.2.0/cfssl-certinfo_linux-amd64
chmod a+x cfssl*
mv cfssl_linux-amd64 /usr/bin/cfssl
mv cfssljson_linux-amd64 /usr/bin/cfssljson
mv cfssl-certinfo_linux-amd64 /usr/bin/cfssl-certinfo

[root@k8s-node1 ~]# cfssl version
Version: 1.2.0
Revision: dev
Runtime: go1.6

创建 ca-config.json 证书文件

cat > ca-config.json <<EOF
{
  "signing": {
    "default": {
      "expiry": "87600h"
    },
    "profiles": {
      "kubernetes": {
        "usages": [
            "signing",
            "key encipherment",
            "server auth",
            "client auth"
        ],
        "expiry": "87600h"
      }
    }
  }
}
EOF

Amadeus-csr.json 证书文件

cat > Amadeus-csr.json <<EOF
{
  "CN": "Amadeus",
  "hosts": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "BeiJing",
      "L": "BeiJing",
      "O": "k8s",
      "OU": "System"
    }
  ]
}
EOF

生成证书

[root@k8s-node1 ~]# cfssl gencert -ca=/etc/kubernetes/pki/ca.crt -ca-key=/etc/kubernetes/pki/ca.key -config=ca-config.json -profile=kubernetes Amadeus-csr.json | cfssljson -bare Amadeus
# 生成时会有警告,可以忽略,是因为提供的信息不是很全
[root@k8s-node1 ~]# ls Amadeus*
# 生成如下三个文件
Amadeus.csr      # csr
Amadeus-key.pem  # key
Amadeus.pem      # crt

配置 kubeconfig 配置文件

生成 kubeconfig 文件,并将 cluster 信息添加进去

kubectl config set-cluster kubernetes \
--certificate-authority=/etc/kubernetes/pki/ca.crt \
--embed-certs=true \
--server=https://1.1.1.1:6443 \
--kubeconfig=Amadeus.kubeconfig

# --embed-certs=true 表示将证书写入etcd

为 kubeconfig 配置文件添加用户配置:设置用户证书 (crt) 和证书 key

kubectl config set-credentials Amadeus \
--client-key=Amadeus-key.pem \
--client-certificate=Amadeus.pem \
--embed-certs=true \
--kubeconfig=Amadeus.kubeconfig

为 kubeconfig 配置文件添加 context

kubectl config set-context Amadeus@kubernetes \
--cluster=kubernetes \
--user=Amadeus \
--kubeconfig=Amadeus.kubeconfig

为 kubeconfig 配置文件设置使用的 context

kubectl config use-context Amadeus@kubernetes --kubeconfig=Amadeus.kubeconfig

查看生成的配置文件

# KUBECONFIG=./Amadeus.kubeconfig kubectl config view
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: DATA+OMITTED
    server: https://1.1.1.1:6443
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    user: Amadeus
  name: Amadeus@kubernetes
current-context: Amadeus@kubernetes
kind: Config
preferences: {}
users:
- name: Amadeus
  user:
    client-certificate-data: REDACTED
    client-key-data: REDACTED

2.2.3 创建 RBAC 权限策略

使 Amadeus 用户有权限查看 default 命名空间下的 pod

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""] # api组,置空为核心组
  resources: ["pods"] # 资源
  verbs: ["get", "watch", "list"] # 对资源的操作
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: default
subjects:
- kind: User
  name: Amadeus # 绑定的用户名
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

2.2.4 测试验证

[root@k8s-node1 ~]# kubectl apply -f demo-rbac.yml
role.rbac.authorization.k8s.io/pod-reader created
rolebinding.rbac.authorization.k8s.io/read-pods created

# pod可以正常查看
[root@k8s-node1 ~]# cp /etc/kubernetes/users/Amadeus/Amadeus.kubeconfig  /root/
[root@k8s-node1 ~]# KUBECONFIG=/root/Amadeus.kubeconfig kubectl get pods -n default
NAME                                      READY   STATUS    RESTARTS      AGE
bar-664fbc5498-kz4sr                      1/1     Running   0             18h
bar-664fbc5498-r74vl                      1/1     Running   0             18h
bar-664fbc5498-smqxm                      1/1     Running   0             18h
......

# 其他资源都没有权限
[root@k8s-node1 ~]# KUBECONFIG=/root/Amadeus.kubeconfig kubectl get nodes
Error from server (Forbidden): nodes is forbidden: User "Amadeus" cannot list resource "nodes" in API group "" at the cluster scope
[root@k8s-node1 ~]# KUBECONFIG=/root/Amadeus.kubeconfig kubectl get deployments
Error from server (Forbidden): deployments.apps is forbidden: User "Amadeus" cannot list resource "deployments" in API group "apps" in the namespace "default"

给该用户增加查看、创建和删除 deployment 的权限,但 pod 的权限依旧只有查看

[root@k8s-node1 ~]# vim demo-rbac.yml
# 在rbac.yaml中增加如下规则
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs: ["get", "watch", "list", "create", "delete"]

[root@k8s-node1 ~]# kubectl apply -f demo-rbac.yml
role.rbac.authorization.k8s.io/pod-reader configured
rolebinding.rbac.authorization.k8s.io/read-pods unchanged

# 操作 deployment
[root@k8s-node1 ~]# KUBECONFIG=/root/Amadeus.kubeconfig kubectl create deployment my-dep --image=nginx:1.22.1 --replicas=3
deployment.apps/my-dep created
[root@k8s-node1 ~]# KUBECONFIG=/root/Amadeus.kubeconfig kubectl get pods -l app=my-dep
NAME                    READY   STATUS    RESTARTS   AGE
my-dep-bc4cb798-4kbkq   1/1     Running   0          15s
my-dep-bc4cb798-jdzq7   1/1     Running   0          15s
my-dep-bc4cb798-lhm8p   1/1     Running   0          15s
[root@k8s-node1 ~]# KUBECONFIG=/root/Amadeus.kubeconfig kubectl delete deployment my-dep
deployment.apps "my-dep" deleted

3 网络策略 (Network Policy)

官方文档

3.1 基础概念

网络策略(Network Policy),用于限制 Pod 出入流量,提供 Pod 级别和 Namespace 级别网络访问控制。

一些应用场景:

  • 应用程序间的访问控制。例如微服务 A 允许访问微服务 B,微服务 C 不能访问微服务 A
  • 开发环境命名空间不能访问测试环境命名空间 Pod
  • 当 Pod 暴露到外部时,需要做 Pod 白名单
  • 多租户网络环境隔离

Pod 网络入口方向隔离:

  • 基于 Pod 级网络隔离:只允许特定对象访问 Pod(使用标签定义),允许白名单上的 IP 地址或者 IP 段访问 Pod
  • 基于 Namespace 级网络隔离:多个命名空间,A 和 B 命名空间 Pod 完全隔离。

Pod 网络出口方向隔离:

  • 拒绝某个 Namespace 上所有 Pod 访问外部
  • 基于目的 IP 的网络隔离:只允许 Pod 访问白名单上的 IP 地址或者 IP 段
  • 基于目标端口的网络隔离:只允许 Pod 访问白名单上的端

3.2 示例一

只允许 default 命名空间中携带 run=client1 标签的 Pod 访问 default 命名空间携带 app=web 标签的 Pod 的 80 端口,无法 ping 通

[root@k8s-node1 ~]# kubectl create deployment web --image=nginx:1.22.1
[root@k8s-node1 ~]# kubectl run client1 --image=busybox:1.28 -- sleep 36000
[root@k8s-node1 ~]# kubectl run client2 --image=busybox:1.28 -- sleep 36000
[root@k8s-node1 ~]# kubectl get pods --show-labels
NAME                                      READY   STATUS    RESTARTS        AGE    LABELS
client1                                   1/1     Running   0               69s    run=client1
client2                                   1/1     Running   0               62s    run=client2
web-bc7cc9f65-5mg9d                       1/1     Running   0               2m3s   app=web,pod-template-hash=bc7cc9f65

networkpolicy.yaml 示例

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: web
  policyTypes:
  - Ingress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          project: default
    - podSelector:
        matchLabels:
          run: client1
    ports:
    - protocol: TCP
      port: 80

测试验证

[root@k8s-node1 ~]# kubectl apply -f networkpolicy.yaml
[root@k8s-node1 ~]# kubectl get networkpolicy
[root@k8s-node1 ~]# kubectl get pods  web-bc7cc9f65-hdhr2 -o jsonpath='{.metadata.annotations.cni\.projectcalico\.org\/podIP}'
10.244.169.169/32

[root@k8s-node1 ~]# kubectl exec -it client1 -- telnet 10.244.169.169 80
Connected to 10.244.169.169

[root@k8s-node1 ~]# kubectl exec -it client2 -- telnet 10.244.169.169 80
# 超时无法联通

[root@k8s-node1 ~]# kubectl delete -f networkpolicy.yaml

3.3 示例二

ns1 命名空间下所有 pod 可以互相访问,也可以访问其他命名空间 Pod,但其他命名空间不能访问 ns1 命名空间 Pod。

[root@k8s-node1 ~]# kubectl create ns ns1
[root@k8s-node1 ~]# kubectl run ns1-client1 --image=busybox -n ns1 -- sleep 36000
[root@k8s-node1 ~]# kubectl run ns1-client2 --image=busybox -n ns1 -- sleep 36000
[root@k8s-node1 ~]# kubectl get pods -n ns1 -o wide
NAME          READY   STATUS    RESTARTS   AGE   IP               NODE        NOMINATED NODE   READINESS GATES
ns1-client1   1/1     Running   0          78s   10.244.169.168   k8s-node2   <none>           <none>
ns1-client2   1/1     Running   0          70s   10.244.107.212   k8s-node3   <none>           <none>
[root@k8s-node1 ~]# kubectl get pods -o wide
NAME                                      READY   STATUS    RESTARTS        AGE   IP               NODE        NOMINATED NODE   READINESS GATES
client1                                   1/1     Running   0               51s   10.244.169.171   k8s-node2   <none>           <none>
client2                                   1/1     Running   0               26m   10.244.107.238   k8s-node3   <none>           <none>

networkpolicy.yaml

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-from-other-namespaces
  namespace: ns1
spec:
  podSelector: {} # 置空表示默认所有Pod
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector: {} # 置空表示拒绝所有

验证

[root@k8s-node1 ~]# kubectl apply -f networkpolicy.yaml
[root@k8s-node1 ~]# kubectl get networkpolicy -n ns1

# ns1命名空间内pod可以互通
[root@k8s-node1 ~]# kubectl exec -it ns1-client1 -n ns1 -- ping 10.244.107.212 # ns1-client2
PING 10.244.107.212 (10.244.107.212): 56 data bytes
64 bytes from 10.244.107.212: seq=0 ttl=62 time=0.900 ms
64 bytes from 10.244.107.212: seq=1 ttl=62 time=0.651 ms

# default命名空间的pod无法访问ns1命名空间的pod
[root@k8s-node1 ~]# kubectl exec -it client1 -- ping 10.244.107.212 # ns1-client2

# ns1命名空间的pod可以正常访问default命名空间的pod
[root@k8s-node1 ~]# kubectl exec -it ns1-client1 -n ns1 -- ping 10.244.169.171 # client1
PING 10.244.169.171 (10.244.169.171): 56 data bytes
64 bytes from 10.244.169.171: seq=0 ttl=63 time=0.119 ms
64 bytes from 10.244.169.171: seq=1 ttl=63 time=0.067 ms

[root@k8s-node1 ~]# kubectl delete -f networkpolicy.yaml

以上