# k8s-webhook-auth **Repository Path**: wilds/k8s-webhook-auth ## Basic Information - **Project Name**: k8s-webhook-auth - **Description**: k8s webhook authn - **Primary Language**: Go - **License**: MulanPSL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-02-06 - **Last Updated**: 2024-02-27 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # k8s-webhook-auth ## 介绍 k8s webhook auth ``` { "apiVersion": "authentication.k8s.io/v1beta1", "kind": "TokenReview", "spec": { "token": "<持有者令牌>" } } ``` ``` { "apiVersion": "authentication.k8s.io/v1beta1", "kind": "TokenReview", "status": { "authenticated": true, "user": { "username": "water@126.com", "uid": "42", "groups": [ "developers", "qa" ], "extra": { "extrafield1": [ "extravalue1", "extravalue2" ] } } } } ``` ## 安装[OpenLDAP](https://www.openldap.org/) - slapd - stand-alone LDAP daemon (server) openldap配置涉及到密码、域名、管理员,我的域名是wilds.com ``` [root@openfuyao-0004 sample-apiserver]# yum install -y openldap openldap-clients openldap-servers [root@openfuyao-0004 sample-apiserver]# systemctl start slapd [root@openfuyao-0004 sample-apiserver]# systemctl enable slapd # 生成密码123456 [root@openfuyao-0004 sample-apiserver]# slappasswd New password: Re-enter new password: {SSHA}eFUdko66sOf4FEQMktueoXrlYzmx92HS # 备份/etc/openldap [root@openfuyao-0004 etc]# tar -zcvf openldap.tgz openldap/ ``` 默认配置文件位于/etc/openldap/slapd.d,文件格式为LDAP Input Format(LDIF),ldap目录特定的格式。 ## [证书生成](https://kubernetes.io/zh-cn/docs/tasks/tls/managing-tls-in-a-cluster/) 为通过 DNS 访问的 Kubernetes 服务创建 TLS 证书. ### 创建证书签名请求 ``` cat < 其中webhook-auth{ServiceName}.auth{Namespace}.svc.cluster.local是服务的DNS名称,webhook-auth{PodName}.authh{Namespace}.pod.cluster.local是Pod的DNS名称。 ### 创建证书签名请求(CSR)对象发送到Kubernetes API 使用以下命令创建CSR清单(YAML格式),并发送到API服务器: ``` cat < 在步骤1中创建的server.csr是base64编码并存储在.spec.request字段中的。你还要求提供 “digital signature(数字签名)”, “密钥加密(key encipherment)” 和 “服务器身份验证(server auth)” 密钥用途,由kubernetes.io/kube-apiserver-client签名程序签名的证书。你也可以要求使用特定的signerName。可参阅[支持的签署者名称](https://kubernetes.io/zh-cn/docs/reference/access-authn-authz/certificate-signing-requests/#signers)。 在API server中可以看到这些CSR处于Pending状态。执行下面的命令你将可以看到: ``` kubectl describe csr webhook-auth.auth Name: webhook-auth.auth Labels: Annotations: ... CreationTimestamp: Sat, 17 Feb 2024 18:03:03 +0800 Requesting User: kubernetes-admin Signer: wilds.io/webhook-auth-signer Status: Pending Subject: Common Name: webhook-auth.auth.pod.cluster.local Serial Number: Subject Alternative Names: DNS Names: webhook-auth.auth.svc.cluster.local webhook-auth.auth.pod.cluster.local Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Synced 2m3s csr-controller Synced successfully ``` ### 批准证书签名请求(CSR) 证书签名请求的批准或是通过自动批准过程完成,或由集群管理员一次性完成。如果你被授权批准证书请求,可以使用kubectl来手动完成此操作;例如: ``` kubectl certificate approve webhook-auth.auth certificatesigningrequest.certificates.k8s.io/webhook-auth.auth approved ``` 现在应该能看到如下输出: ``` kubectl get csr NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION webhook-auth.auth 5m38s wilds.io/webhook-auth-signer kubernetes-admin Approved ``` ### 签名证书签名请求(CSR) 接下来,你将扮演证书签署者角色,颁发证书并将其上传到API服务器。 签名者通常会使用其SignerName查看对象的CertificateSigningRequest API,检查它们是否已被批准,为这些请求签署证书,并使用已颁发的证书更新API对象状态。 #### 创建证书颁发机构 你需要授权在新证书上提供数字签名。 首先,通过运行以下命令创建签名证书: ``` cat < 说明:这使用命令行工具jq在.status.certificate字段中填充base64编码的内容。如果你没有jq工具,你还可以将JSON输出保存到文件中,手动填充此字段,然后上传结果文件。 批准CSR并上传签名证书后,运行: ``` kubectl get csr ``` 输入类似于: ``` NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION webhook-auth.auth 16m wilds.io/webhook-auth-signer kubernetes-admin Approved,Issued ``` ### 下载证书并使用它 现在,作为请求用户,你可以通过运行以下命令下载颁发的证书并将其保存到server.crt文件中: CSR被签署并获得批准后,你应该看到以下内容: ``` kubectl get csr webhook-auth.auth -o jsonpath='{.status.certificate}' \ | base64 --decode > server.crt ``` 现在你可以将server.crt和server-key.pem填充到Secret中,稍后你可以将其挂载到Pod中(例如,用于提供HTTPS的网络服务器)。 ``` kubectl create secret tls webhook-auth-server --cert server.crt --key server-key.pem -n auth secret/webhook-auth-server created ``` 最后,你可以将ca.pem填充到ConfigMap并将其用作信任根来验证服务证书: ``` kubectl create configmap webhook-auth-serving-ca --from-file ca.crt=ca.pem -n auth configmap/webhook-auth-serving-ca created ``` ## [APIServer添加认证服务](https://kubernetes.io/zh-cn/docs/reference/access-authn-authz/authentication/#webhook-token-authentication) 使用Webhook进行认证,需要在kube-apiserver里开启,参数如下: ``` # 指向一个配置文件,描述如何访问远程Webhook服务 --authentication-token-webhook-config-file ``` 配置文件使用kubeconfig文件格式。文件中,clusters指代远程服务,users指代远程API服务Webhook(APIServer)。配置如下: ``` # mkdir /etc/kubernetes/webhook # cat > webhook-config.yaml < webhook-config.yaml < certificate-authority-data/client-certificate-data/client-key-data为上面生成的证书 在kube-apiserver中添加配置参数 - 增加volume: webhook-config - `- --authentication-token-webhook-config-file=/etc/config/webhook-config.yaml` - `dnsPolicy: ClusterFirstWithHostNet` ``` # mkdir /etc/kubernetes/backup # cp /etc/kubernetes/manifests/kube-apiserver.yaml /etc/kubernetes/backup/kube-apiserver.yaml # cd /etc/kubernetes/manifests/ # cat kube-apiserver.yaml apiVersion: v1 kind: Pod metadata: annotations: kubeadm.kubernetes.io/kube-apiserver.advertise-address.endpoint: 192.168.100.36:6443 creationTimestamp: null labels: component: kube-apiserver tier: control-plane name: kube-apiserver namespace: kube-system spec: containers: - command: - kube-apiserver - --advertise-address=192.168.100.36 - --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 - --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-issuer=https://kubernetes.default.svc.cluster.local - --service-account-key-file=/etc/kubernetes/pki/sa.pub - --service-account-signing-key-file=/etc/kubernetes/pki/sa.key - --service-cluster-ip-range=10.96.0.0/12 - --tls-cert-file=/etc/kubernetes/pki/apiserver.crt - --tls-private-key-file=/etc/kubernetes/pki/apiserver.key - --authentication-token-webhook-config-file=/etc/config/webhook-config.yaml image: registry.k8s.io/kube-apiserver:v1.29.0 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 8 httpGet: host: 192.168.100.36 path: /livez port: 6443 scheme: HTTPS initialDelaySeconds: 10 periodSeconds: 10 timeoutSeconds: 15 name: kube-apiserver readinessProbe: failureThreshold: 3 httpGet: host: 192.168.100.36 path: /readyz port: 6443 scheme: HTTPS periodSeconds: 1 timeoutSeconds: 15 resources: requests: cpu: 250m startupProbe: failureThreshold: 24 httpGet: host: 192.168.100.36 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 - name: webhook-config mountPath: /etc/config readOnly: true hostNetwork: true dnsPolicy: ClusterFirstWithHostNet priority: 2000001000 priorityClassName: system-node-critical securityContext: seccompProfile: type: RuntimeDefault volumes: - hostPath: path: /etc/ssl/certs type: DirectoryOrCreate name: ca-certs - hostPath: path: /etc/pki type: DirectoryOrCreate name: etc-pki - hostPath: path: /etc/kubernetes/pki type: DirectoryOrCreate name: k8s-certs - hostPath: path: /etc/kubernetes/webhook type: DirectoryOrCreate name: webhook-config status: {} ``` ## build ``` git clone https://gitee.com/wilds/k8s-webhook-auth.git cd k8s-webhook-auth/ go mod tidy go mod vendor # cd ./cmd/webhook-auth # go build -o ../../artifacts/image/webhook-auth # cd ../../artifacts/image/ go build -o ./artifacts/image/webhook-auth ./... docker build -t webhook-auth:latest ./artifacts/image/ ctr -n k8s.io images rm docker.io/library/webhook-auth:latest ctr -n k8s.io images rm wilds.io/webhook-auth:latest docker save -o webhook-auth.tar webhook-auth:latest ctr -n k8s.io images import webhook-auth.tar ctr -n k8s.io i tag docker.io/library/webhook-auth:latest wilds.io/webhook-auth:latest crictl images ls | grep webhook-auth ``` ## 测试Github认证 1. 在github上获取Token:Setting->Developer settings->Personal access tokens->Generate new token 2. 配置kubeconfig,添加user ``` # cat ~/.kube/config apiVersion: v1 ...... users: - name: water user: token: basic:admin:admin - name: water user: token: github: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 ``` 3. 用water用户进行访问 ``` # kubectl get pod --user=water # 认证通过,权限不足 Error from server (Forbidden): pods is forbidden: User "" cannot list resource "pods" in API group "" in the namespace "default" # 以下错误还不情况是什么原因,host上启动进程是可以的 error: You must be logged in to the server (Unauthorized) [webhook.go:85] Get "https://api.github.com/user": tls: failed to verify certificate: x509: certificate signed by unknown authority ``` 4. 用wilds用户进行访问 ``` [root@openfuyao-0004 .kube]# kubectl --user=wilds get pod -n auth NAME READY STATUS RESTARTS AGE webhook-auth-75cb47cb9c-rpdzf 1/1 Running 0 8m19s ``` 5. 使用定制kubeconfig访问 ``` # cat > webhook-config.yaml < GET /auth HTTP/2 > Host: webhook-auth.auth.pod.cluster.local > User-Agent: curl/7.66.0 > Accept: */* > Content-Type: application/json > Authorization: Bearer github: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 > Content-Length: 149 > * We are completely uploaded and fine * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4): * Connection state changed (MAX_CONCURRENT_STREAMS == 250)! < HTTP/2 200 < content-type: text/plain; charset=utf-8 < content-length: 210 < date: Sun, 18 Feb 2024 12:31:56 GMT < {"kind":"TokenReview","apiVersion":"authentication.k8s.io/v1","metadata":{"creationTimestamp":null},"spec":{"token":"github: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"},"status":{"authenticated":true,"user":{}}} * Connection #0 to host 127.0.0.1 left intact ``` ## Webhook后端处理身份验证 可以对http使用基本身份验证,对https使用证书。 当kube api服务器与webhook通信时,它将向webhook webserver提供客户端证书以对其自身进行身份验证。 需要在webhook api服务器中安装cacert,才能成功验证kuernetes api服务器。 用于生成客户端证书并将该客户端证书添加到kubeconfig文件中的相同证书。 ### 基本身份验证 ``` apiVersion: v1 kind: Config preferences: {} clusters: - name: example-cluster cluster: server: http://127.0.0.1 users: - name: example-user user: username: some-user password: some-password contexts: - name: example-context context: cluster: example-cluster user: example-user current-context: example-context ``` ### 证书身份验证 ``` apiVersion: v1 kind: Config preferences: {} clusters: - name: example-cluster cluster: certificate-authority-data: server: https://127.0.0.1 users: - name: example-user user: client-certificate-data: client-key-data: contexts: - name: example-context context: cluster: example-cluster user: example-user current-context: example-context ``` ## ref - [k8s-webhook-cert-manager](https://github.com/newrelic/k8s-webhook-cert-manager) - [双向TLS认证的REST Service](https://www.jianshu.com/p/55c1540438f5) - [使用TLS/SSL证书的两种方法及实践](https://www.dandelioncloud.cn/article/details/1598290174230609921)