欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

kubernetes如何使用自有的用户系统

程序员文章站 2024-03-19 14:40:28
...

kubernetes如何使用自有的用户系统

K8s 支持基于第三方的webhook token 的认证方式,有了这套机制可以可以让k8s使用公司现有的用户管理系统无需维护多套。

要支持webhook token 认证需要对api server 进行一下配置

  • --authentication-token-webhook-config-file 描述如何调用远程认证服务器的配置文件

  • --authentication-token-webhook-cache-ttl 认证的缓存时间,默认2分钟。

配置文件使用Kubeconfig 文件格式

# api 版本
apiVersion: v1
#  api 类型
kind: Config
# 远程服务器信息
clusters:
  - name: name-of-remote-authn-service
    cluster:
      certificate-authority: /path/to/ca.pem         # 验证远程服务的CA
      server: https://authn.example.com/authenticate #  远程服务器地址

#  users 指代 API 服务的 Webhook 配置
users:
  - name: name-of-api-server
    user:
      client-certificate: /path/to/cert.pem # Webhook 插件要使用的证书
      client-key: /path/to/key.pem          # 与证书匹配的**

# kubeconfig 文件需要一个上下文(Context),此上下文用于本 API 服务器
current-context: webhook
contexts:
- context:
    cluster: name-of-remote-authn-service
    user: name-of-api-server
  name: webhook

当用户调用 api server 服务使用token 时,身份认证webhook 会用POST请求发送一个JSON 序列化的对象到远程服务器。该对象是 authentication.k8s.io/v1beta1Token Review 对象,其中包含了Token 信息。

POST 请求的Body 如下:

{
  "apiVersion": "authentication.k8s.io/v1beta1",
  "kind": "TokenReview",
  "spec": {
    "token": "<持有者令牌>"
  }
}

拿到了k8s 发送的请求 我们必须填充该请求的status 字段,标记该登录请求是否成功。如果成功 需要返回以下内容

{
  "apiVersion": "authentication.k8s.io/v1beta1",
  "kind": "TokenReview",
  "status": {
    "authenticated": true,
    "user": {
      "username": "[email protected]",
      "uid": "42",
      "groups": [
        "developers",
        "qa"
      ],
      "extra": {
        "extrafield1": [
          "extravalue1",
          "extravalue2"
        ]
      }
    }
  }
}

若不成功 则将authenticated 置成false。

认证服务器

根据以上信息,我们就可以实现我们的认证服务器了。下面代码是一个基于github验证token的认证方式,根据上文:

STEP 1: 解析请求的body,并获取到token

STEP 2: 将获取的token 发送到github 进行认证

STEP 3: 将github返回的用户信息组装成 TokenReview 的status 并返回

package main

import (
	"context"
	"encoding/json"
	"github.com/google/go-github/github"
	"golang.org/x/oauth2"
	authentication "k8s.io/api/authentication/v1"
	"log"
	"net/http"
)

func authenticate(w http.ResponseWriter,r *http.Request)  {
	// 1. 解析请求体中的body,获取token
	decoder := json.NewDecoder(r.Body)
	var tr authentication.TokenReview
	err := decoder.Decode(&tr)
	if err != nil {
		log.Println("[Error]", err.Error())
		w.WriteHeader(http.StatusBadRequest)
		json.NewEncoder(w).Encode(map[string]interface{}{
			"apiVersion": "authentication.k8s.io/v1beta1",
			"kind":       "TokenReview",
			"status": authentication.TokenReviewStatus{
				Authenticated: false,
			},
		})
		return 
	}
	// 2. token 发送到github 进行验证
	log.Println("receiving request")
	ts := oauth2.StaticTokenSource(
		&oauth2.Token{AccessToken: tr.Spec.Token},
		)

	cli := oauth2.NewClient(context.TODO(),ts)
	client := github.NewClient(cli)
	user, _, err := client.Users.Get(context.TODO(),"")
	if err != nil {
		log.Println("[Error]", err.Error())
		w.WriteHeader(http.StatusBadRequest)
		json.NewEncoder(w).Encode(map[string]interface{}{
			"apiVersion": "authentication.k8s.io/v1beta1",
			"kind":       "TokenReview",
			"status": authentication.TokenReviewStatus{
				Authenticated: false,
			},
		})
	}
	// 3. 验证成功 获取用户信息,并填充到status 字段
	log.Printf("[Success] login as %s", *user.Login)
	w.WriteHeader(http.StatusOK)
	trs := authentication.TokenReviewStatus{
		Authenticated: true,
		User: authentication.UserInfo{
			Username: *user.Login,
			UID:      *user.Login,
		},
	}
	json.NewEncoder(w).Encode(map[string]interface{}{
		"apiVersion": "authentication.k8s.io/v1beta1",
		"kind":       "TokenReview",
		"status":     trs,
	})
}

func main()  {
	http.HandleFunc("/authenticate", authenticate)
	log.Fatal(http.ListenAndServe(":3000",nil))
}

配置api server

启动上述项目(本地地址为 8.11.0.186:3000);然后去修改api server 的配置,因为api server是以容器的方式运行,因此需要将配置文件进容器中。

创建存放配置文件的文件夹

mkdir  /etc/config/
cd /etc/config/

编辑配置文件web hook-config.json 注意将server 地址修改为上述项目的地址

{
  "kind": "Config",
  "apiVersion": "v1",
  "preferences": {},
  "clusters": [
    {
      "name": "github-authn",
      "cluster": {
        "server": "http://8.11.0.186:3000/authenticate"
      }
    }
  ],
  "users": [
    {
      "name": "authn-apiserver",
      "user": {
        "token": "secret"
      }
    }
  ],
  "contexts": [
    {
      "name": "webhook",
      "context": {
        "cluster": "github-authn",
        "user": "authn-apiserver"
      }
    }
  ],
  "current-context": "webhook"
}

修改/etc/kubernetes/manifests/kube-apiserver.yaml 文件。 主要是将配置文件进来,并启动命令添加- --authentication-token-webhook-config-file=/etc/config/webhook-config.json,全文如下。

apiVersion: v1
kind: Pod
metadata:
  annotations:
    kubeadm.kubernetes.io/kube-apiserver.advertise-address.endpoint: 8.15.0.7:6443
  creationTimestamp: null
  labels:
    component: kube-apiserver
    tier: control-plane
  name: kube-apiserver
  namespace: kube-system
spec:
  containers:
  - command:
    - kube-apiserver
    - --advertise-address=8.15.0.7
    - --allow-privileged=true
    - --authorization-mode=Node,RBAC
    - --client-ca-file=/etc/kubernetes/pki/ca.crt
    - --enable-admission-plugins=NodeRestriction
    - --enable-bootstrap-token-auth=true
    - --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt
    - --etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt
    - --etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key
    - --etcd-servers=https://127.0.0.1:2379
    - --insecure-port=0
    - --kubelet-client-certificate=/etc/kubernetes/pki/apiserver-kubelet-client.crt
    - --kubelet-client-key=/etc/kubernetes/pki/apiserver-kubelet-client.key
    - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
    - --proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.crt
    - --proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client.key
    - --requestheader-allowed-names=front-proxy-client
    - --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt
    - --requestheader-extra-headers-prefix=X-Remote-Extra-
    - --requestheader-group-headers=X-Remote-Group
    - --requestheader-username-headers=X-Remote-User
    - --secure-port=6443
    - --service-account-key-file=/etc/kubernetes/pki/sa.pub
    - --service-cluster-ip-range=10.96.0.0/16
    - --runtime-config=authentication.k8s.io/v1beta1=true
    - --authentication-token-webhook-config-file=/etc/config/webhook-config.json
    - --tls-cert-file=/etc/kubernetes/pki/apiserver.crt
    - --tls-private-key-file=/etc/kubernetes/pki/apiserver.key
    image: registry.aliyuncs.com/k8sxio/kube-apiserver:v1.19.2
    imagePullPolicy: IfNotPresent
    livenessProbe:
      failureThreshold: 8
      httpGet:
        host: 8.15.0.7
        path: /livez
        port: 6443
        scheme: HTTPS
      initialDelaySeconds: 10
      periodSeconds: 10
      timeoutSeconds: 15
    name: kube-apiserver
    readinessProbe:
      failureThreshold: 3
      httpGet:
        host: 8.15.0.7
        path: /readyz
        port: 6443
        scheme: HTTPS
      periodSeconds: 1
      timeoutSeconds: 15
    resources:
      requests:
        cpu: 250m
    startupProbe:
      failureThreshold: 24
      httpGet:
        host: 8.15.0.7
        path: /livez
        port: 6443
        scheme: HTTPS
      initialDelaySeconds: 10
      periodSeconds: 10
      timeoutSeconds: 15
    volumeMounts:
    - mountPath: /etc/ssl/certs
      name: ca-certs
      readOnly: true
    - mountPath: /etc/pki
      name: etc-pki
      readOnly: true
    - mountPath: /etc/kubernetes/pki
      name: k8s-certs
      readOnly: true
    - mountPath: /etc/config
      name: webhook-config
      readOnly: true
  hostNetwork: true
  priorityClassName: system-node-critical
  volumes:
  - hostPath:
      path: /etc/ssl/certs
      type: DirectoryOrCreate
    name: ca-certs
  - hostPath:
      path: /etc/pki
      type: DirectoryOrCreate
    name: etc-pki
  - hostPath:
      path: /etc/config
      type: DirectoryOrCreate
    name: webhook-config
  - hostPath:
      path: /etc/kubernetes/pki
      type: DirectoryOrCreate
    name: k8s-certs

验证

  1. 去github 申请一个token

  2. 修改kubeconfig 添加一个user

    - name: vic
      user: 
        token:  xxxx
    
  3. 调用获取pod 命令。 报错的原因是没有给该用户配置权限。但k8s 确实识别出对应的用户了。创建个role 和rolebinding 绑定下就可以了,这里不再缀述。

$ kubectl get po --user vic
Error from server (Forbidden): pods is forbidden: User "Archer1A" cannot list resource "pods" in API group "" in the namespace "webhook-demo"