k8s与Admission--webhook admission

船火儿
• 阅读 4582

前言

Kubernetes 对 API 访问提供了三种安全访问控制措施:认证、授权和 Admission Control。认证解决用户是谁的问题,授权解决用户能做什么的问题,Admission Control 则是资源管理方面的作用。通过合理的权限管理,能够保证系统的安全可靠。

k8s与Admission--webhook admission

本文主要讲讲Admission中ValidatingAdmissionWebhook和MutatingAdmissionWebhook。

AdmissionWebhook

我们知道k8s在各个方面都具备可扩展性,比如通过cni实现多种网络模型,通过csi实现多种存储引擎,通过cri实现多种容器运行时等等。而AdmissionWebhook就是另外一种可扩展的手段。 除了已编译的Admission插件外,可以开发自己的Admission插件作为扩展,并在运行时配置为webhook。

Admission webhooks是HTTP回调,它接收Admission请求并对它们做一些事情。可以定义两种类型的Admission webhook,ValidatingAdmissionWebhook和MutatingAdmissionWebhook。

如果启用了MutatingAdmission,当开始创建一种k8s资源对象的时候,创建请求会发到你所编写的controller中,然后我们就可以做一系列的操作。比如我们的场景中,我们会统一做一些功能性增强,当业务开发创建了新的deployment,我们会执行一些注入的操作,比如敏感信息aksk,或是一些优化的init脚本。

而与此类似,只不过ValidatingAdmissionWebhook 是按照你自定义的逻辑是否允许资源的创建。比如,我们在实际生产k8s集群中,处于稳定性考虑,我们要求创建的deployment 必须设置request和limit。

如何实现自己的 AdmissionWebhook Server

前提条件

  • k8s版本需至少v1.9
  • 确保启用了 MutatingAdmissionWebhook and ValidatingAdmissionWebhook admission controllers
  • 确定 启用了admissionregistration.k8s.io/v1beta1

写一个 admission webhook server

官方提供了有个demo。大家可以详细研究,核心思想就是:
webhook处理apiservers发送的AdmissionReview请求,并将其决定作为AdmissionReview对象发送回去。

package main

import (
    "encoding/json"
    "flag"
    "fmt"
    "io/ioutil"
    "net/http"

    "k8s.io/api/admission/v1beta1"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/klog"
    // TODO: try this library to see if it generates correct json patch
    // https://github.com/mattbaird/jsonpatch
)

// toAdmissionResponse is a helper function to create an AdmissionResponse
// with an embedded error
func toAdmissionResponse(err error) *v1beta1.AdmissionResponse {
    return &v1beta1.AdmissionResponse{
        Result: &metav1.Status{
            Message: err.Error(),
        },
    }
}

// admitFunc is the type we use for all of our validators and mutators
type admitFunc func(v1beta1.AdmissionReview) *v1beta1.AdmissionResponse

// serve handles the http portion of a request prior to handing to an admit
// function
func serve(w http.ResponseWriter, r *http.Request, admit admitFunc) {
    var body []byte
    if r.Body != nil {
        if data, err := ioutil.ReadAll(r.Body); err == nil {
            body = data
        }
    }

    // verify the content type is accurate
    contentType := r.Header.Get("Content-Type")
    if contentType != "application/json" {
        klog.Errorf("contentType=%s, expect application/json", contentType)
        return
    }

    klog.V(2).Info(fmt.Sprintf("handling request: %s", body))

    // The AdmissionReview that was sent to the webhook
    requestedAdmissionReview := v1beta1.AdmissionReview{}

    // The AdmissionReview that will be returned
    responseAdmissionReview := v1beta1.AdmissionReview{}

    deserializer := codecs.UniversalDeserializer()
    if _, _, err := deserializer.Decode(body, nil, &requestedAdmissionReview); err != nil {
        klog.Error(err)
        responseAdmissionReview.Response = toAdmissionResponse(err)
    } else {
        // pass to admitFunc
        responseAdmissionReview.Response = admit(requestedAdmissionReview)
    }

    // Return the same UID
    responseAdmissionReview.Response.UID = requestedAdmissionReview.Request.UID

    klog.V(2).Info(fmt.Sprintf("sending response: %v", responseAdmissionReview.Response))

    respBytes, err := json.Marshal(responseAdmissionReview)
    if err != nil {
        klog.Error(err)
    }
    if _, err := w.Write(respBytes); err != nil {
        klog.Error(err)
    }
}

func serveAlwaysDeny(w http.ResponseWriter, r *http.Request) {
    serve(w, r, alwaysDeny)
}

func serveAddLabel(w http.ResponseWriter, r *http.Request) {
    serve(w, r, addLabel)
}

func servePods(w http.ResponseWriter, r *http.Request) {
    serve(w, r, admitPods)
}

func serveAttachingPods(w http.ResponseWriter, r *http.Request) {
    serve(w, r, denySpecificAttachment)
}

func serveMutatePods(w http.ResponseWriter, r *http.Request) {
    serve(w, r, mutatePods)
}

func serveConfigmaps(w http.ResponseWriter, r *http.Request) {
    serve(w, r, admitConfigMaps)
}

func serveMutateConfigmaps(w http.ResponseWriter, r *http.Request) {
    serve(w, r, mutateConfigmaps)
}

func serveCustomResource(w http.ResponseWriter, r *http.Request) {
    serve(w, r, admitCustomResource)
}

func serveMutateCustomResource(w http.ResponseWriter, r *http.Request) {
    serve(w, r, mutateCustomResource)
}

func serveCRD(w http.ResponseWriter, r *http.Request) {
    serve(w, r, admitCRD)
}

func main() {
    var config Config
    config.addFlags()
    flag.Parse()

    http.HandleFunc("/always-deny", serveAlwaysDeny)
    http.HandleFunc("/add-label", serveAddLabel)
    http.HandleFunc("/pods", servePods)
    http.HandleFunc("/pods/attach", serveAttachingPods)
    http.HandleFunc("/mutating-pods", serveMutatePods)
    http.HandleFunc("/configmaps", serveConfigmaps)
    http.HandleFunc("/mutating-configmaps", serveMutateConfigmaps)
    http.HandleFunc("/custom-resource", serveCustomResource)
    http.HandleFunc("/mutating-custom-resource", serveMutateCustomResource)
    http.HandleFunc("/crd", serveCRD)
    server := &http.Server{
        Addr:      ":443",
        TLSConfig: configTLS(config),
    }
    server.ListenAndServeTLS("", "")
}

动态配置admission webhooks

您可以通过ValidatingWebhookConfigurationMutatingWebhookConfiguration动态配置哪些资源受入口webhooks的限制。

具体示例如下:

apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration
metadata:
  name: <name of this configuration object>
webhooks:
- name: <webhook name, e.g., pod-policy.example.io>
  rules:
  - apiGroups:
    - ""
    apiVersions:
    - v1
    operations:
    - CREATE
    resources:
    - pods
    scope: "Namespaced"
  clientConfig:
    service:
      namespace: <namespace of the front-end service>
      name: <name of the front-end service>
    caBundle: <pem encoded ca cert that signs the server cert used by the webhook>
  admissionReviewVersions:
  - v1beta1
  timeoutSeconds: 1

总结

最后我们来总结下 webhook Admission 的优势:

  • webhook 可动态扩展 Admission 能力,满足自定义客户的需求
  • 不需要重启 API Server,可通过创建 webhook configuration 热加载 webhook admission
点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
美凌格栋栋酱 美凌格栋栋酱
7个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Stella981 Stella981
3年前
Apache Shiro反序列化识别那些事
1.1关于ApacheShiroApacheshiro是一个Java安全框架,提供了认证、授权、加密和会话管理功能,为解决应⽤安全提供了相应的API:1.认证⽤用户身份识别,常被称为用户”登录”2.授权访问控制3.密码加密保护或隐藏数据防止被偷窥4.会话管理用户相关的时间敏感的状态1.2Shiro反序列化
Stella981 Stella981
3年前
Kerberos无约束委派的攻击和防御
 0x00前言简介当ActiveDirectory首次与Windows2000Server一起发布时,Microsoft就提供了一种简单的机制来支持用户通过Kerberos对Web服务器进行身份验证并需要授权用户更新后端数据库服务器上的记录的方案。这通常被称为Kerberosdoublehopissue(双跃点问题),
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
3年前
Redis未授权访问漏洞复现学习
0x00前言前段时间看到想复现学习一下,然后就忘了越临近考试越不想复习!在这里插入图片描述(https://oscimg.oschina.net/oscnet/ec73a943a3d9e18184946ee4c4ca290e14f.jpg)常见的未授权访问漏洞Redis未授权访问漏洞MongoDB未授权访问漏
Wesley13 Wesley13
3年前
mysql查询每个学生的各科成绩,以及总分和平均分
今天看一个mysql教程,看到一个例子,感觉里面的解决方案不是很合理。问题如下:有学生表:!在这里插入图片描述(https://oscimg.oschina.net/oscnet/07b001b0c6cb7e0038a9299e768fc00a0d3.png)成绩表:!在这里插入图片描述(https://oscimg.o
融云IM即时通讯 融云IM即时通讯
7个月前
融云 IM 干货丨云存储的安全措施有哪些?
云存储的安全措施云存储的安全性是确保数据机密性、完整性和可用性的关键。以下是一些常见的云存储安全措施:1.访问控制与权限管理身份认证:通过密码、多因素认证(如短信验证码、生物识别等)确认用户身份,确保只有授权用户才能访问云存储数据。基于角色的访问控制(RB