控制Azure Kubernetes服务(AKS)群集中的资源部署可能很快变得非常具有挑战性。例如,对生产环境进行更改可能会给应用程序带来不良的漏洞。通过为Kubernetes创建自定义的准入网络钩子,我们可以定义自定义策略来规范资源到集群的部署。
Kubernetes生态系统并不完全没有可用于管理集群资源的解决方案。OPA Gatekeeper是一种这样的解决方案,通常用于在Kubernetes集群上实施策略。Azure Kubernetes服务的Azure策略(AKS)扩展了Gatekeeper,以集中且一致的方式在您的群集上应用策略。Gatekeeper和Azure策略是使用Kubernetes的准入网络挂钩功能构建的。
您可以将Azure策略安装为AKS的扩展。它具有几个可以在群集上启用的内置策略。这种策略的一个示例是强制Pod只侦听允许的端口列表。我已经两次提到入学网钩了。让我们详细讨论它。
动态入场控制 福州APP开发
Kubernetes 1.9版引入了两个代码包,它们允许您编写自定义接纳插件:ValidatingAdmissionWebhook
和MutatingAdmissionWebhook
。这些插件为您提供了很大的灵活性,可以直接集成到资源接纳过程中。准入webhook /控制器是Kubernetes API服务器在对象持久化之前调用的一段代码。它在将请求(例如,创建容器)持久保存在etcd(或其他对象存储)中之前,但在请求经过身份验证和授权之后才生效。
Kubernetes中包含了多个准入控制器,它们涵盖了一系列功能。一种这样的准入控制器是NamespaceExists
:如果您尝试在尚不存在的命名空间中创建资源,则会引发错误。
AMutatingAdmissionWebhook
允许您修改资源以符合条件,然后再进入集群的数据平面。例如,您可以创建一个自定义的Webhook,以检查所创建的Ingress资源是否仅实施HTTPS。如果没有,则Webhook可以修改Ingress资源的传入规范,以便进行修改。
AValidatingAdmissionWebhook
允许您验证资源是否符合您的自定义规则定义的预期条件。例如,您可以指定一个要求,即每个正在创建的Pod都应定义其CPU和内存要求。如果没有,您可以拒绝Pod创建请求,并且不会创建该请求。在本文中,我们将构建一个ValidatingAdmissionWebhook
使用Azure函数并将其用于控制AKS上的部署。验证准入webhook不能变异资源,因此它们可以并行运行以接受或拒绝请求。
Gatekeeper和Azure策略是一个验证许可Webhook,它会拦截每个创建或更新Kubernetes对象的请求,并根据其是否满足指定的约束来接受或拒绝该请求。建立ValidatingAdmissionWebhook或MutatingAdmissionWebhook比想象的要容易。在这两种情况下,Kubernetes API服务器都使用AdmissionReview
主体中的对象向您的Webhook发出POST请求。处理完请求后,您的Webhook会以AdmissionReview
对象也是如此。AdmissionReview类型具有一个响应字段和一个请求字段,API服务器和Webhook会适当地使用它们。处理传入的AdmissionReview请求时,您将阅读请求字段。使用AdmissionReview响应响应请求时,将填充响应字段并包括集群生成的唯一标识符(UID)。群集使用此UID对请求进行版本控制。
传入的AdmissionReview的主体包含JSON形式的原始规范,用于创建,更新或删除的对象。该规范包含与Kubernetes API服务器执行请求的API操作时将看到的数据相同的数据。您可以在Kubernetes文档中阅读有关动态准入控制的更多信息。
使动态准入控制无服务器
使用Azure策略是在AKS群集上实施约束的一种干净且推荐的方法。但是,在某些情况下,您可能希望构建自定义准入网络钩子以实施法规以仅启动集群中的已批准资源。我最近在无服务器日ANZ上介绍了如何使用Azure Functions实现准入webhooks。建立准入webhooks的无服务器模型使您能够扩展部署认证过程,还使您能够利用Azure Functions的内置绑定来连接各种服务,而无需编写任何代码。
在本次会议中,我介绍了一个这样的场景:在该场景中,我编写了带有Azure函数的验证准入Webhook,并将自定义管理策略应用于Kubernetes中的部署。我还使用了本机Azure Azure Twilio绑定将SMS更新发送给SRE / Ops团队,通知他们所请求的部署是成功还是失败。我建议您观看本次会议,以了解为Kubernetes编写自定义验证Webhooks的过程。我在Azure Function Webhook中实现的策略如下。
- 如果副本的数量少于三个,则阻止部署,并向Ops团队发送错误丰富的SMS通知。
- 如果开发人员将新应用程序添加到集群,则通过丰富的SMS消息通知Ops团队。
- 如果开发人员更新了群集上的现有应用程序,请通过丰富的SMS消息通知Ops团队。
尽管使用外部无服务器服务的方法在EKS(AWS)和GKE(Google Cloud)中可以很好地使用,但在AKS中却不起作用。准入控制器是Kubernetes API服务器的一部分,因此由Azure管理。Azure中的防火墙策略不允许API服务器访问任何外部HTTP终结点。但是,API服务器可以与群集内的服务进行通信,这是Istio,NGINX等服务必须具备的功能才能正常工作。
如果您已观看了上一个视频(它将帮助您进一步了解本文),则必须注意我们不能使用Azure Functions的基于令牌的安全功能。通过将流量通过群集中运行的服务路由到外部准入控制无服务器功能,您不仅可以实施所需的任何安全措施,而且还可以在集群内服务本身中实施自定义策略。
解决方案概述
下图显示了我们的无服务器Webhook的体系结构。会议上提出的体系结构上唯一的增加(提示:观看视频)是一个集群内反向代理,该代理将每个请求从API服务器转发到Azure函数。
让我引导您完成请求和响应路径。
- 开发人员请求API服务器创建,更新或删除部署。
- API服务器通过一系列准入控制器(包括我们的自定义验证Webhook)运行请求。该请求到达了我们的反向代理服务。
- 反向代理服务将请求转发到Azure函数,该函数对请求执行一系列检查。
- 在最终确定接受或拒绝请求的决定之后,Azure Function会向Twilio发出呼叫,以将SMS消息发送到预配置的Ops Team移动电话号码。
- Twilio将请求的SMS发送到Ops团队的手机号码。
- Azure Function将结果返回到反向代理。
- 反向代理将响应提供给API服务器。
- API服务器将响应返回给开发人员。
让我们一次构建和部署体系结构中的每个组件。
Azure功能
让我们首先使用AZ CLI创建资源组。如果有任何冲突,请使用自定义值替换此处的任何AZ CLI指令的自变量值。
az group create --name dac-demo-rg --location澳大利亚东部
我们将利用与会话中相同的Azure函数(提示:视频)。请按照视频中的说明来了解应用程序代码和部署该功能的步骤。您可以从以下链接下载示例应用程序的源代码。
一旦您的功能启动并运行,我们将创建逆向代理服务,准入控制器将在每个部署请求上调用该逆向代理服务。
AKS集群
现在创建一个AKS集群。使用以下AZ CLI命令在您先前创建的资源组中创建低成本AKS群集。
AZ AKS创建-n DAC-演示--node计数 1 --node-VM-尺寸Standard_B2s --load平衡器-SKU基本--node-osdisk尺寸 32 --resource组DAC-演示-RG - generate-ssh-keys az aks get-credentials --resource-group dac-demo-rg --name dac-demo
执行完先前的命令后,您可以使用kubectl CLI来操作AKS集群。现在让我们构建反向代理并将其部署到该集群。
反向代理
从以下链接下载反向代理应用程序的源代码。
我在Go中实现了反向代理服务。如果您还不熟悉Golang,可以用您选择的语言编写相同的实现。我还在这里发布了反向代理应用程序的图像:az-fx-k8s-dac:latest
让我们跳到反向代理的实现。导航到main.go
文件并main
与我一起检查功能。
func main(){
如果 err:= envconfig 。进程(“ DAC_PROXY_”,配置);err != nil {
日志。紧急(“无法加载配置”,err)
}
日志。Infoln(配置)
服务器:= GetAdmissionValidationServer(配置。ListenOn)
如果 err:= 服务器。ListenAndServeTLS(配置。TlsCert,配置。TlsKey); err != nil {
日志。紧急(“监听器失败”,err)
}
}
函数中的第一条指令从环境变量(以string前缀DAC_PROXY_
)读取配置,如果环境变量不可用,则从默认值读取。该结构Config
包含配置键和默认值。在实现中,如果要使用我发布的容器映像或要使用程序而不进行任何更改,则必须覆盖Azure函数的URL。为此,将一个环境变量添加DAC_PROXY_DacFxUrl
到您的Pod。您可以在此处找到有关将环境变量注入到pod的详细信息。
输入 Config struct {
ListenOn 字符串 `default:“ 0.0.0.0:8080”`
TlsCert 字符串 `default:“ / etc / az-fx-proxy / certs / cert.pem”
TlsKey 字符串 `default:“ / etc / az-fx-proxy / certs / key.pem”`
DacFxUrl 字符串 `default:“ https://dac-demo-fx.azurewebsites.net/api/AdmissionControlFx”
}
下一组指令将配置服务器。动态准入控制Webhook的关键要求之一是其地址方案必须为“ https”(URL必须以“ https://”开头)。我向功能添加了TLS证书及其密钥作为参数server.ListenAndServeTLS
来满足此要求。稍后,我们将使用脚本在Kubernetes机密中创建和存储这些证书,并将该机密作为卷安装到此应用程序。
让我们检查负责将传入请求转发到我们先前部署的Azure功能的代码。
func GetAdmissionValidationServer(listenOn 字符串)* http 。服务器{
var mux * http 。ServeMux = http 。NewServeMux()
多路复用器。HandleFunc(“ /”,reverseProxyHandler)
服务器:= &http 。服务器{
处理程序:多路复用器,
地址: listenOn,
}
退货 服务器
}
FUNC reverseProxyHandler(RES HTTP 。ResponseWriter,REQ * HTTP 。请求){
日志。Infoln(“发送请求功能”)
的processRequest(配置。DacFxUrl,RES,REQ)
}
FUNC 的processRequest(目标 串,水库 HTTP 。ResponseWriter,REQ * HTTP 。请求){
dacFxUrl,_:= url 。解析(目标)
代理:= httputil 。NewSingleHostReverseProxy(dacFxUrl)
REQ 。网址。主机 = dacFxUrl 。主办
REQ 。网址。Scheme = dacFxUrl 。方案
REQ 。主机 = dacFxUrl 。主办
代理人。ServeHTTP(res,req)
}
我们只需要公开一个能够从准入控制器接收POST请求的端点。该GetAdmissionValidationServer
函数定义了此端点的处理程序。请求处理程序将请求转发到Azure函数。请注意,我们的功能接受来自互联网的匿名流量,如下所示。
[ FunctionName(“ AdmissionControlFx”)]
公共 静态 异步 任务< IActionResult > 运行(
[ HttpTrigger(AuthorizationLevel。匿名,“ post”,Route = null)]
HttpRequest 请求,
[ TwilioSms(AccountSidSetting = “ TwilioAccountSid”,AuthTokenSetting =
“ TwilioAuthToken”,来自 = “ +19166193571”)]
ICollector < CreateMessageOptions > twilioSms)
但是,您可以轻松更改AuthorizationLevel
函数的,以便函数仅在包含适当的API密钥的情况下接受请求。您可以在Microsoft文档中阅读有关在HTTP触发的Azure函数上授权操作的更多信息。
如果更改了Azure函数的授权级别,请对该processRequest
函数进行更改,以添加以x-functions-key
函数的API密钥作为值命名的标头。更改之后,标头将被注入到Azure函数的每个请求中。
您可以使用存储库中存在的Dockerfile来构建和发布应用程序的容器映像。否则,您可以使用我发布到DockerHub的容器映像。
部署和测试Webhook
部署反向代理和启用Webhook有两个步骤。第一步,我们将发布Webhook所需的证书。接下来,我们将自定义webhook规范部署到AKS。
发布证书
导航到generate-certificates.sh
名为规格的文件夹中的文件。该脚本会生成新的TLS / SSL证书并对其进行签名。请注意,证书中指定的公用名(CN)应该是您的服务的本地主机名。
感谢我的朋友塔伦·帕比(Tarun Pabbi),他帮助我编写了此脚本。
#创建CA证书和密钥
openssl req -nodes -new -x509 -keyout ca.key -out ca.crt -subj “ / CN = Admission Controller Demo CA”
#生成反向代理的私钥
openssl genrsa -out key.pem 2048
#生成私钥的证书签名请求(CSR),并使用CA的私钥对其进行签名。
OpenSSL的REQ -new -key key.pem -subj “/CN=az-fx-dac-rp.default.svc” \ | OpenSSL的X509 -req -CA ca.crt -CAkey的ca.key -CAcreateserial 退房手续cert.pem
#API服务器需要B64编码的CA证书,以确保请求来自正确的来源。
openssl base64 -in ca.crt -out b64ca.crt
#生成的证书包含换行符,需要删除。
猫b64ca.crt | tr -d '\ n' > b64ca-formatted.crt
先前代码清单中的命令集将生成反向代理使用的证书。现在,我们将使用以下命令在AKS集群中将生成的证书作为机密发布。
#将证书秘密存储
kubectl创建秘密通用dac-rp-cert --from-file = cert.pem --from-file = key.pem
接下来,我们会将dac-rp-cert
密码作为卷安装到反向代理服务中。执行该脚本generate-certificate.sh
还会创建CA证书的Base64编码副本。我们将在下一个规范中使用此证书,以用于部署准入webhook。
部署无服务器准入Webhook
我们是本练习的最后部分。我希望您很高兴看到结果。浏览至dac-rp-spec.yaml
规格文件夹中的文件。前两个规范将反向代理部署到我们的集群。请注意,服务的名称必须与您在证书的“通用名称(CN)”字段中指定的名称相同。
我想请您注意我们如何将dac-rp-cert
机密作为卷装到吊舱中。该卷的路径与反向代理将在其中查找TLS证书和密钥的位置相同。
apiVersion v1
种类服务
元数据
名称 az-fx-dac-rp
标签
应用程式 az-fx-dac-rp
规格
端口
名称 https
端口443
targetPort 8080
选择器
应用程式 az-fx-dac-rp
---
apiVersion apps / v1
种类部署
元数据
名称 az-fx-dac-rp
标签
应用程式 az-fx-dac-rp
规格
选择器
matchLabels
应用程式 az-fx-dac-rp
复制品1
模板
元数据
名称 az-fx-dac-rp
标签
应用程式 az-fx-dac-rp
规格
容器
名称 az-fx-dac-rp
图片 rahulrai / az-fx-k8s-dac 最新
imagePullPolicy 始终
端口
containerPort 8080
资源
限制
内存 50Mi
cpu 300m
要求
内存 50Mi
cpu 300m
volumeMounts
名称 dac-certs
mountPath / etc / az-fx-proxy / certs
readOnly 是
securityContext
readOnlyRootFilesystem true
卷数
名称 dac-certs
机密
secretName dac-rp-cert
现在是规范中最关键的部分。以下规范将我们的验证Webhook部署到Kubernetes。如果您对本规范不熟悉,建议您再次在YouTube上观看课程的相关部分。简而言之,此策略将仅影响在名称空间中创建或更新部署的请求。
apiVersion admissionregistration.k8s.io/v1
种类 ValidatingWebhookConfiguration
元数据
名称合规
网络挂钩
名称 compliance.custom.azure.com
clientConfig
服务内容
名称 az-fx-dac-rp
命名空间默认
路径“ /”
端口443
caBundle “ <从b64-formatted.crt复制的值>”
规则
apiGroups “应用”
apiVersions “ *”
操作“创建” “更新”
资源“部署”
范围“命名空间”
秒30
failurePolicy 失败
sideEffects 无
admissionReviewVersions “V1” “v1beta1”
使用以下命令将该规范文件部署到您的集群。
kubectl应用-f dac-rp-spec.yaml
成功部署后,我们现在可以测试我们的Webhook。你准备好了吗?
测试Webhook
我们将使用测试规范文件-alpine-spec.yaml来测试我们的webhook。下载此规范,以便您可以对其进行更改并应用几次。最初,如果副本数少于3,我们将尝试触发Azure功能的验证规则,该规则会使部署失败。
kind 命名空间
apiVersion v1
元数据
名称 app-ns
---
apiVersion apps / v1
种类部署
元数据
名称高山部署
命名空间 app-ns
标签
app 高山
规格
选择器
matchLabels
app 高山
复制品2
模板
元数据
标签
app 高山
规格
容器
名称我的高山容器
图片高山3.9.1
端口
containerPort 80
要测试规格,请执行以下命令。
kubectl apply -f alpine-spec.yaml
我将展示每个案例的测试用例和SMS的屏幕截图。我使用PC上的Your Phone Windows 10应用程序执行许多操作,包括接收SMS。您也应该尝试!
情况1:副本计数<3
情况2:成功部署
replicas
将先前规范中的属性值更改为大于或等于3的数字。进行更改后,再次应用规范。
将图像的名称更改为,alpine:3
以便重新应用规范会触发更新。
通过此测试,我们涵盖了我们在Azure功能中实现的所有方案。
结论
通过创建具有Azure功能和反向代理的无服务器准入Webhook,我们获得了对群集的高度控制。现在,我们可以使用无服务器架构以可伸缩,高度可用和安全的方式拒绝不合规的部署。您可以通过使用ValidatingAdmissionWebhook和MutatingAdmissionWebhook API操作Kubernetes对象来扩展此解决方案,以解决更多问题。
我喜欢无服务器解决方案,因为如果要在多个Kubernetes群集上持续执行策略(包括开发机和DevOps管道),它可以帮助您简化策略。我希望本文为您提供基础,以继续为您的AKS项目构建功能。