K8S集群ImagePolicyWebhook配置

ImagePolicyWebhook用于限制节点调用某个镜像

  1. 环境查看
    系统环境
# cat /etc/redhat-release 
Rocky Linux release 9.3 (Blue Onyx)
# uname -a
Linux Rocky9K8SMaster003021 5.14.0-362.18.1.el9_3.0.1.x86_64 #1 SMP PREEMPT_DYNAMIC Sun Feb 11 13:49:23 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux

软件环境

# kubectl version
Client Version: v1.30.2
Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3
Server Version: v1.25.16
WARNING: version difference between client (1.30) and server (1.25) exceeds the supported minor version skew of +/-1
  1. 配置
    本次已限制nginx镜像为例
    安装go
# yum -y install go

编写go语言用于限制nginx

# cat webhook.go 
package main

import (
"encoding/json"
"fmt"
"log"
"net/http"
"strings"
)

// AdmissionReview 是 Webhook 接收到的请求的结构
type AdmissionReview struct {
Request struct {
Kind       string `json:"kind"`
Object     struct {
Spec struct {
Containers []struct {
Name  string `json:"name"`
Image string `json:"image"`
} `json:"containers"`
} `json:"spec"`
} `json:"object"`
} `json:"request"`
}

type AdmissionResponse struct {
UID     string `json:"uid"`
Allowed bool   `json:"allowed"`
Result  struct {
Message string `json:"message"`
} `json:"status"`
}

func validate(w http.ResponseWriter, r *http.Request) {
var admissionReview AdmissionReview
decoder := json.NewDecoder(r.Body)
if err := decoder.Decode(&admissionReview); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}

// 默认 AdmissionResponse
response := AdmissionResponse{
UID:     admissionReview.Request.Kind,
Allowed: true,
}

// 检查容器镜像
for _, container := range admissionReview.Request.Object.Spec.Containers {
if strings.Contains(container.Image, "nginx") {
// 如果镜像是 nginx,拒绝请求
response.Allowed = false
response.Result.Message = fmt.Sprintf("Forbidden image: %s", container.Image)
break
}
}

// 将结果返回给 Kubernetes API Server
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(&response); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}

func main() {
http.HandleFunc("/validate", validate)
port := "443" // Webhook 通常监听 HTTPS 端口
log.Printf("Starting Webhook server on port %s", port)
log.Fatal(http.ListenAndServeTLS(":"+port, "/etc/webhook/cert/cert.pem", "/etc/webhook/cert/key.pem", nil))
}

初始化go

# go mod init image-policy-webhook

初始之后会在当前目录生成以下文件

# cat go.mod 
module image-policy-webhook

go 1.22.7

自建证书

# openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes -subj "/CN=webhook.default.svc"

在当前目录生成key.pem和cert.pem证书
编写Dockerfile文件

# cat Dockerfile 
# 基础镜像使用 golang
FROM golang:1.22-alpine AS builder

# 设置工作目录
WORKDIR /app

# 将本地代码复制到容器中
COPY . .
RUN mkdir -p /etc/webhook/cert
ADD key.pem /etc/webhook/cert/
ADD cert.pem /etc/webhook/cert/
# 编译 Go 程序
RUN go build -o webhook .

# 使用更小的基础镜像
FROM alpine:latest

RUN mkdir -p /etc/webhook/cert
ADD key.pem /etc/webhook/cert/
ADD cert.pem /etc/webhook/cert/
# 安装所需的 CA 证书等依赖
RUN apk add --no-cache ca-certificates

# 复制编译好的程序
COPY --from=builder /app/webhook /webhook

# 配置容器启动命令
CMD ["/webhook"]

打包镜像推送至私有仓库

#  docker build -t you-harbor-url/image-policy-webhook .
#  docker push you-harbor-url/image-policy-webhook .

部署deployment

# cat webhook-deployment.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: image-policy-webhook
spec:
  replicas: 1
  selector:
    matchLabels:
      app: image-policy-webhook
  template:
    metadata:
      labels:
        app: image-policy-webhook
    spec:
      containers:
        - name: image-policy-webhook
          image: your-harbor-url/image-policy-webhook:latest
          ports:
            - containerPort: 443
---
apiVersion: v1
kind: Service
metadata:
  name: image-policy-webhook
spec:
  ports:
    - port: 443
      targetPort: 443
  selector:
    app: image-policy-webhook

部署

# kubectl apply -f webhook-deployment.yaml 

部署ValidatingWebhookConfiguration

# cat image-policy-webhook-configuration.yaml 
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: image-policy-webhook
webhooks:
  - name: imagepolicy.webhook.example.com
    clientConfig:
      service:
        name: image-policy-webhook
        namespace: default
        path: "/validate/images"
      caBundle: 
    rules:
      - operations: ["CREATE", "UPDATE"]
        apiGroups: [""]
        apiVersions: ["v1"]
        resources: ["pods"]
    admissionReviewVersions: ["v1"]
    sideEffects: None

部署

#  kubectl apply -f image-policy-webhook-configuration.yaml

部署完毕之后使用以下Pod测试

#  cat nginx-pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: test-pod
spec:
  containers:
  - name: nginx
    image: nginx:latest

部署拒绝提示如下

# kubectl apply -f nginx-pod.yaml 
Error from server (InternalError): error when creating "nginx-pod.yaml": Internal error occurred: failed calling webhook "imagepolicy.webhook.example.com": failed to call webhook: Post "https://image-policy-webhook.default.svc:443/validate/images?timeout=10s": dial tcp 10.43.55.46:443: connect: connection refused

注意:

k8s集群版本需要1.19以上,在1.13版本测试无法部署
部署限制执行已经调度的nginx镜像不受影响

posted @   minseo  阅读(39)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
历史上的今天:
2023-11-21 Vscode怎么指定Python解释器
点击右上角即可分享
微信分享提示