不使用RBAC的鉴权方式

准备工作

参考文档:https://kubernetes.io/zh-cn/docs/reference/access-authn-authz/authorization/

根据文档,我们可以使用Webhook模式 实现自己的鉴权逻辑

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

实现自己的授权逻辑

根据文档,Webhook 模式需要一个 HTTP 配置文件,通过 --authorization-webhook-config-file=SOME_FILENAME 的参数声明。

webhook的配置文件是kubeconfig格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: v1
kind: Config
clusters:
- name: webhook
cluster:
insecure-skip-tls-verify: true
# 远程服务的查询 URL。必须使用 'https'。
server: https://localhost:9090/authorize
users:
- name: webhook-user

current-context: webhook
contexts:
- context:
cluster: webhook
user: webhook-user
name: webhook

启动apiserver的脚本需要修改,将授权模式改为webhook

新加的配置:

  • —authentication-token-webhook-config-file
  • —runtime-config=authorization.k8s.io/v1beta1=true
  • 将—authorization-mode 改为Webhook模式
1
2
3
4
5
6
7
8
9
10
11
12
go run -mod=mod cmd/kube-apiserver/apiserver.go \
--etcd-servers=http://127.0.0.1:2379 \
--service-account-issuer=https://kubernetes.default.svc.cluster.local \
--authorization-mode=Node,Webhook \
--authorization-webhook-config-file=./001/webhook/config \
--runtime-config=authorization.k8s.io/v1beta1=true \
--service-account-key-file=./certs/sa.pub \
--service-account-signing-key-file=./certs/sa.key \
--tls-cert-file=./certs/apiserver.crt \
--tls-private-key-file=./certs/apiserver.key \
--feature-gates=EphemeralContainers=true \
--service-cluster-ip-range=10.96.0.0/22

webhook服务的证书:

1
2
3
4
5
openssl genrsa -out server.key 2048

openssl req -new -key server.key -out certFile.csr

openssl x509 -req -days 365 -in certFile.csr -signkey server.key -out server.pem

authorize代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package main

import (
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
"io"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)

const (
AccessApiVersion = "authorization.k8s.io/v1beta1"
AccessKind = "SubjectAccessReview"
)

func authorizeRsp(allowed bool, reason string) *unstructured.Unstructured {
obj := &unstructured.Unstructured{}
obj.SetAPIVersion(AccessApiVersion)
obj.SetKind(AccessKind)
obj.Object["status"] = map[string]interface{}{
"allowed": allowed,
"reason": reason,
}

return obj
}

func main() {
r := gin.New()
r.POST("/authorize", func(c *gin.Context) {
b, err := io.ReadAll(c.Request.Body)
if err != nil {
c.AbortWithStatusJSON(400, authorizeRsp(false, err.Error()))
}
obj := &unstructured.Unstructured{}
err = json.Unmarshal(b, obj)
if err != nil {
c.AbortWithStatusJSON(400, authorizeRsp(false, err.Error()))
}
fmt.Println(string(b))
c.AbortWithStatusJSON(200, authorizeRsp(true, ""))
})
r.RunTLS(":9090", "./webhook/certs/server.pem", "./webhook/certs/server.key")

}

所有成功的请求全都放行

启动

使用client-go请求本地apiserver

上面的操作已经在本地启动了一个apiserver、etcd,使用自己的鉴权(所有请求放行)

现在我想知道 使用 client-go客户端 访问本地的apiserver是个什么效果

K8sClient.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package config

import (
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)

func K8sClient() *kubernetes.Clientset {
config := &rest.Config{
Host: "https://127.0.0.1:6443", // 只需要这个host即可
}
config.Insecure = true
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err.Error())
}
return clientset
}

test.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import (
"context"
"fmt"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/kubernetes/001/config"
)

func main() {
clientset := config.K8sClient()

// List all pods in the "default" namespace
list, err := clientset.CoreV1().Pods("default").List(context.Background(), metav1.ListOptions{})
if err != nil {
panic(err.Error())
}
for _, d := range list.Items {
fmt.Println(d.Name)
}
}

没啥问题

现在我想创建一个pod,看看啥效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
"context"
"fmt"

corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/kubernetes/001/config"
)

func main() {
clientset := config.K8sClient()

// create nginx pod
ngxPod := &corev1.Pod{}
ngxPod.Name = "nginx"
ngxPod.Namespace = "default"
ngxPod.Spec.Containers = []corev1.Container{
{Name: "nginx", Image: "nginx:latest"},
}
_, err := clientset.CoreV1().Pods("default").Create(context.Background(), ngxPod, metav1.CreateOptions{})
if err != nil {
panic(err.Error())
}

}

结果报错:

这个default账号作用:

  • 当在 Kubernetes 中创建一个 Pod 时,如果没有指定其他服务账户,default 服务账户的凭据会自动被挂载到该 Pod 中
  • 具有访问该namespace内的大多数资源的权限

这个default是由 controller-manager创建的

代码位置: pkg/controller/serviceaccount/serviceaccounts_controller.go:185

手动创建default sa