准入控制是k8s中用来提供安全控制的控制器,而动态控制是用户自定义的安全策略。
有两种动态准入控制,即变异和验证。
变异变异主要是修改。api调用完成后,k8s会根据ValidatingWebhookConfiguration中的条件发送给配置好的webhook服务,并根据业务逻辑修改webhook服务。比如著名的istio Sidecar注射就在这里。
ValidatingValidating主要是为了验证,主要是看是否符合条件聚类的要求。例如,对于高可用性,不允许设置副本数为1的部署类型请求。
下图显示了api请求-1的流程
许多编写webhook来创建证书的程序都被称为openssl。这里,我们使用rancher提供的脚本来自动生成证书。
1.将以下脚本另存为create_self-signed-cert.sh#!/bin/bash -ehelp(){ echo & # 39;================================================================ '回声& # 39;--ssl-domain:生成ssl证书所需的主域名。如果不指定,默认为www.rancher.local,如果是ip访问服务可以忽略;'回声& # 39;--ssl-trusted-ip:一般ssl证书只信任域名的访问请求。有时候需要使用ip来访问服务器,所以需要给ssl证书添加扩展IP。多个IP用逗号分隔;'回声& # 39;--ssl-trusted-domain:如果要访问多个域名,添加一个扩展域名(SSL_TRUSTED_DOMAIN)。多个扩展域名用逗号分隔;'回声& # 39;--SSL -size:SSL加密位数,默认为2048;'回声& # 39;--ssl-cn:国家代码(2个字母的代码),默认CN;'回声& # 39;用法示例:& # 39;回声& # 39;。/create _ self -signed -cert . sh --SSL -domain = www . test . com --SSL -trusted -domain = www . test 2 . com \ & # 39;回声& # 39;--ssl-trusted-ip=1.1.1.1,2.2.2.2,3 . 3 . 3 --SSL -size = 2048 --SSL -date = 3650 & # 39;回声& # 39;================================================================'}案例& quot1美元& quotin -h|--help)帮助;退出;;esacif[[$ 1 = = & # 39;']];然后帮忙;退出;fiCMDOPTS = & quot$ * & quot对于$CMDOPTS中的OPTSdo key = $(echo $ { OPTS } | awk -F & quot;= & quot'{ print $ 1 } & # 39)value = $(echo $ { OPTS } | awk -F & quot;= & quot'{ print $ 2 } & # 39)案例& quot$ key & quotin --SSL -DOMAIN)SSL _ DOMAIN = $ value;;--SSL -可信-IP)SSL _ TRUSTED _ IP = $ value;;--SSL -TRUSTED -DOMAIN)SSL _ TRUSTED _ DOMAIN = $ value;;--SSL -SIZE)SSL _ SIZE = $ value;;--SSL -DATE)SSL _ DATE = $ value;;--ca-DATE)CA _ DATE = $ value;;--SSL -CN)CN = $ value;;Esacdone# CA相关配置CA _ date = $ { CA _ date:-3650 } CA _ key = $ { CA _ key:-cakey . PEM } CA _ cert = $ { CA _ cert:-cacerts . PEM } CA _ domain = cattle -CA Ssl相关配置Ssl _ config = $ { Ssl _ config:-$ PWD/OpenSSL . CNF } Ssl _ domain = $ { Ssl _ domain:-& # 39;www . rancher . local & # 39;} SSL _ date = $ { SSL _ date:-3650 } SSL _ size = $ { SSL _ size:-2048 } # #国家代码(2个字母的代码),默认CN;CN = $ { CN:-CN } SSL _ KEY = $ SSL _ domain . keyssl _ CSR = $ SSL _ domain . csrssl _ CERT = $ SSL _ domain . crtecho -e & quot;\ 033[32m -----------------------------\ 033[0m & quot;echo -e & quot;\033[32m |生成SSL证书| \ 033[0m & quot;echo -e & quot;\ 033[32m -----------------------------\ 033[0m & quot;if[[-e ./$ { CA _ KEY }]];然后echo -e & quot;\033[32m ==== >1.发现CA私钥已经存在,并备份了“$ { CA _ KEY } & quot是“$ { CA _ KEY } & quot-bak,然后重新创建\ 033[0m & quot;mv $ { CA _ KEY } & quot$ { CA _ KEY } & quot-bak OpenSSL gen RSA -out $ { CA _ KEY } $ { SSL _ SIZE } else echo -e & quot;\033[32m ==== >1.生成新的CA私钥${ CA _ KEY } \ 033[0m & quot;OpenSSL gen RSA -out $ { CA _ KEY } $ { SSL _ SIZE } fiif[[-e ./$ { CA _ CERT }]];然后echo -e & quot;\033[32m ==== >2.如果发现CA证书存在,请首先备份它。是“$ { CA _ CERT } & quot-bak,然后重新创建\ 033[0m & quot;mv $ { CA _ CERT } & quot$ { CA _ CERT } & quot-bak OpenSSL req -x509 -sha 256 -new -nodes -KEY $ { CA _ KEY } -days $ { CA _ DATE } -out $ { CA _ CERT } -subj & quot;/C = $ { CN }/CN = $ { CA _ DOMAIN } & quot;else echo -e & quot;\033[32m ==== >2.生成新的CA证书${ CA _ CERT } \ 033[0m & quot;OpenSSL req -x509 -sha 256 -new -nodes -KEY $ { CA _ KEY } -days $ { CA _ DATE } -out $ { CA _ CERT } -subj & quot;/C = $ { CN }/CN = $ { CA _ DOMAIN } & quot;fiecho -e & quot;\033[32m ==== >3.生成Openssl配置文件${ SSL _ CONFIG } \ 033[0m & quot;cat & gt$ { SSL _ CONFIG } & lt& ltEOM[req]req _ extensions = v3 _ req distinguished _ name = req _ distinguished _ name[req _ distinguished _ name][v3 _ req]basic constraints = CA:false key usage =不可否认性,digitalSignature,keycharminxtendedkeyusage = client auth,serverauteomif[[-n $ { SSL _ TRUSTED _ IP } | | -n $ { SSL _ TRUSTED _ DOMAIN }]];然后cat & gt& gt$ { SSL _ CONFIG } & lt& lteom subject altname = @ alt _ names[alt _ names]EOM IFS = & quot;,& quot我在& quot中的DNS =($ { SSL _ TRUSTED _ DOMAIN })DNS+=($ { SSL _ DOMAIN })${!DNS[@]} & quot;;做回显DNS。$((I+1))= $ { DNS[$ I]} & gt;& gt$ { SSL _ CONFIG } done if[[-n $ { SSL _ TRUSTED _ IP }]];然后IP =($ { SSL _ TRUSTED _ IP })for I in & quot;${!IP[@]} & quot;;做回声IP。$((I+1))= $ { IP[$ I]} & gt;& gt$ { SSL _ CONFIG } done Fifi echo -e & quot;\033[32m ==== >4.生成服务SSL密钥${ SSL _ KEY } \ 033[0m & quot;OpenSSL gen RSA -out $ { SSL _ KEY } $ { SSL _ SIZE } echo -e & quot;\033[32m ==== >5.生成服务SSL CSR $ { SSL _ CSR } \ 033[0m & quot;OpenSSL req -sha 256 -new -KEY $ { SSL _ KEY } -out $ { SSL _ CSR } -subj & quot;/C = $ { CN }/CN = $ { SSL _ DOMAIN } & quot;-CONFIG $ { SSL _ CONFIG } echo -e & quot;\033[32m ==== >6.生成服务SSL证书${ SSL _ CERT } \ 033[0m & quot;OpenSSL x509 -sha 256 -req -in $ { SSL _ CSR } -CA $ { CA _ CERT } \ -CAkey $ { CA _ KEY } -cacreatesserial -out $ { SSL _ CERT } \ -days $ { SSL _ DATE } -extensions v3 _ req \ -extfile $ { SSL _ CONFIG } echo -e & quot;\033[32m ==== >7.证书已制作\ 033[0m & quot;回声回声-e & quot;\033[32m ==== >8.以YAML格式输出结果\ 033[0m & quot;回声& quot------------------------------------------------------------------------------5 & quot;回声& quotca _ key:| & quot;cat $ CA _ KEY | sed & # 39s/^//& # 39;回声回声& quotca _ cert:| & quot;cat $ CA _ CERT | sed & # 39s/^//& # 39;回声回声& quotSSL _ key:| & quot;cat $ SSL _ KEY | sed & # 39s/^//& # 39;回声回声& quotSSL _ CSR:| & quot;cat $ SSL _ CSR | sed & # 39s/^//& # 39;回声回声& quotSSL _ cert:| & quot;类别$ SSL _ CERT | sed & # 39s/^//& # 39;回声回声-e & quot;\033[32m ==== >9.将CA证书附加到证书文件\ 033[0m & quot;cat $ { CA _ CERT } & gt& gt$ { SSL _ CERT } echo & quotSSL _ cert:| & quot;cat $ SSL _ CERT | sed & # 39s/^//& # 39;回声回声-e & quot;\033[32m ==== >10.重命名服务证书\ 033[0m & quot;回声& quotcp ${SSL_DOMAIN}。key tls.key & quotcp ${SSL_DOMAIN}。key tls.keyecho & quotcp ${SSL_DOMAIN}。crt tls.crt & quotCP $ {SSL _ domain}。然后执行下面的命令。/create _ self -signed -cert . sh --SSL -domain = admission-example . admission -example . SVC . cluster . local --SSL -trusted -domain = admission -example,admission -example。admission -示例。SVC -SSL -trusted -IP = 127 . 0 . 0 . 13。一组证书和密钥。将在目录中生成密钥。
。crt是域名的证书。
Csr文件是证书申请文件。
ca的开头是根证书和密钥。
写入yaml文件,写入变异WebhookConfiguration和验证WebhookConfiguration。
API version:admissionregistration.k8s.io/ v1 kind:MutatingWebhookConfigurationmetadata:name:mutating -示例标签:app:admission -example web hooks:-name:admission -example . nature lr . cc client config:service:name:admission -示例命名空间:admission -示例路径:& quot/mutate & gt;端口:8080 #证书是base64编码的。CABundle: {{CA}}规则:-操作:[" CREATE & quot;]API groups:[& quot;应用程序& quot,& quot"]API versions:[& quot;v1 & quot]资源:[& quot;部署& quot,& quot服务& quot]admissionReviewVersions:[& quot;v1 & quot,& quotv1beta1 & quot]side effects:None # admission -web hook -示例:enabled仅在ns上生效。命名空间选择器:匹配标签:admission -web hook -示例:已启用---API版本:A dmissionregistration.k8s.io/ v1k ind:ValidatingWebhookConfigurationmetadata:name:validation -示例标签:app:admission -示例web hooks:-name:admission -example . na turelr . cc client config:service:name:admission -示例命名空间:admission -示例路径:& quot/验证& quot端口:8080 caBundle: {{CA}}规则:-操作:[& quot;创建& quot]API groups:[& quot;应用程序& quot,& quot"]API versions:[& quot;v1 & quot]资源:[& quot;部署& quot,& quot服务& quot]admissionReviewVersions:[& quot;v1 & quot,& quotv1beta1 & quot]副作用:无命名空间选择器:matchlabels:admission -web hook -示例:enabled development webhook开发了上面定义的两个接口,validate和mutate。
侦听的端口和上面配置的端口,并使用创建的证书。
...http。handle func(& quot;/验证& quot,验证)http。handle func(& quot;/mutate & gt;,突变)http。handle func(& quot;/ping & quot;,func(w http。ResponseWriter。请求){ fmt。Fprintln(w,& quot乓& quot)}) svr := http。服务器{地址:& quot:8080 & quot,ReadTimeout:时间。分钟,WriteTimeout:时间。分钟,} go func(){ if * key = = & quot;"| | * cert = = & quot"{ fmt。println(& quot;Http服务成功启动”)如果err := svr。ListenAndServe();呃!= nil { log。Fatalln(err) } } fmt。println(& quot;Https服务成功启动”)如果err := svr。ListenAndServeTLS(*cert,* key);呃!= nil {log。Fatalln(err) }()}实现mutate的部分,我们需要添加一个名为admission -example . naturelr . cc/status ":& quot;测试& quot这里的注释非常类似于使用kubectl,除了代码被返回到k8s。
Chimutate (w http.responsewriter,r * http . Request){//请求结构QAR: = Admissionv1。AdmissionReview {} _,_,err :=序列化程序。NewCodecFactory(运行时。NewScheme())。UniversalDeserializer()。解码(体,零,和。qar)checker(err)类型patch operation struct { Op string ` JSON:& quot;op & quot`路径字符串` JSON:& quot;路径& quot`值接口{ } ` JSON:& quot;值,忽略& quot`} p:= patch operation { Op:& quot;添加& quot,路径:& quot/元数据/注释& quot,Value:map[string]string { & quot;admission -example . nature lr . cc/status & quot;:& quot测试& quot},} patch,err:= JSON . marshal([]patch operation { p })checker(err)//返回给k8s的消息有:= & admissionv1。admission review { type meta:API meta v1。TypeMeta{ APIVersion: qar。APIVersion,种类:qar。Kind,},Response:& amp;准入v1。AdmissionResponse{ Allowed: true,Patch: patch,PatchType: func() *admissionv1。PatchType { pt := admissionv1。PatchTypeJSONPatch返回和。pt }(),UID: qar。Request.UID,},} resp,err := json。元帅检查器。println(& quot;响应:“,string(resp))w . Write Header(200)w . Write(resp)} Validate主要验证服务和部署中的标签是否有准入字段,如果没有,则拒绝访问。
fun validate(whttp . response writer,r * http . Request){//请求结构QAR: = Admissionv1。AdmissionReview {} _,_,err :=序列化程序。NewCodecFactory(运行时。NewScheme())。UniversalDeserializer()。解码(体,零,和。QA)checker(err//处理逻辑判断条件变量可用标签是否映射[string]字符串所需标签:= " admission & quotvar errMsg错误开关qar。request . kind . kind { case & gt;部署& quot:var deploy appsv1。err := json时的部署。解组(qar。Request.Object.Raw。部署);呃!= nil { log。println(& quot;无法解析格式: ",err)errMsg = err } available labels = deploy。标签案例& quot服务& quot:var服务核心v1。err := json时的服务。解组(qar。Request.Object.Raw。服务);呃!= nil { log。println(& quot;无法解析格式: ",err)errMsg = err } available labels = service。标签默认值:消息:= fmt。sprintln(& quot;未处理的类型: ",qar。Request.Kind.Kind)日志。Println(msg) errMsg = errors。New(msg) } var status *apimetav1。Status var允许的bool if _,ok:= available labels[required labels];!好|| errMsg!= nil { msg:= & quot;不合格的“如果err!= nil { msg = fmt。Sprintln(errMsg) } }状态= & ampapimetav1。状态{消息:消息,原因:apimetav1。StatusReason(msg),Code: 304,} allowed = false } else { Message:& quot;通过”,状态= & ampapimetav1。状态{原因:& quotPass”,代码:200,} allowed = true} //返回给k8s的消息是:= & admissionv1。admission review { type meta:API meta v1。TypeMeta{ APIVersion: qar。APIVersion,种类:qar。Kind,},Response:& amp;准入v1。AdmissionResponse{允许:允许,结果:状态,UID: qar。Request.UID,},} resp,err := json。元帅检查器。println(& quot;响应: ",string(resp))w . Write Header(200)w . Write(resp)完整的项目在https://github.com/NatureLR/admission-example.
测试在ns中创建的标签为admission -web hook -Example:Enabled的任何应用程序都会被发现拒绝。
它可以在部署用set标签标记后创建,并且部署有一个附加注释。
评论前必须登录!
注册