内容简介:这是题为《Securing Kubernetes for Cloud Native Applications》系列文章的最后一篇,这个系列文章中,我们讨论了构成kubernetes集群每个层的安全性方面。在终结篇中,我们将讨论容器工作负载本身的安全性。我们如何确保容器内容的完整性?我们如何知道容器内部实际上是什么?让我们从Secrets(秘钥)开始。通常,在Kubernetes集群上运行的云原生应用程序需要访问敏感信息,并且需要提供Secrets以响应来自托管该信息的系统的查询。Secrets可以是任何东西
【Kubernetes安全系列终结篇】管理Kubernetes容器工作负载的安全性
这是题为《Securing Kubernetes for Cloud Native Applications》系列文章的最后一篇,这个系列文章中,我们讨论了构成kubernetes集群每个层的安全性方面。在终结篇中,我们将讨论容器工作负载本身的安全性。我们如何确保容器内容的完整性?我们如何知道容器内部实际上是什么?让我们从Secrets(秘钥)开始。
保护Secrets
通常,在Kubernetes集群上运行的云原生应用程序需要访问敏感信息,并且需要提供Secrets以响应来自托管该信息的系统的查询。Secrets可以是任何东西,但通常是密码,X.509证书,SSH密钥或OAuth令牌。我们可能想要采用简单的路径并将Secrets存储在容器的镜像中,以便在需要时可以随时使用它。然而,如果我们这样做,它可能会"泪流满面"。撇开这种方法的脆弱性,更重要的是,将Secrets暴露给不应该暴露的实体的可能性将是巨大的。镜像定义通常需要向广大受众提供,并且经常由源代码控制系统管理,这可能潜在地导致Secrets的无意暴露。有一个被广泛接受的格言,Secrets应始终保持在容器镜像之外。这也遵循将容器配置保留在容器之外的Twelve-Factor App方法,允许我们为不同的目标环境使用不同的Secrets,同时为每个环境使用相同的容器镜像。
这引出了一个问题:我们如何为在Kubernetes集群中运行的容器化应用程序提供Secrets? 由于它们的敏感性,Kubernetes提供了一个专用的API资源对象来处理Secrets,称为(不出所料) Secret
。 然后,可以在需要访问它们的Pod的Spec中引用封装在Secret对象中的秘密数据: 最好是通过卷装入,而不是通过环境变量。
重要的是要确保对Secret的访问严格限于那些需要使用它的实体(用户和Pod),它不是通过网络未加密传输的,并且当存储在磁盘上时(静止状态)它是不可访问或可读的。 在之前的文章中,我们了解了如何使用身份验证和授权(RBAC)控制对API对象(如Secrets)的访问,以及使用TLS加密集群组件之间的通信的需求。 这满足了其中两个原则,包括配置节点授权和kubelet通过API访问Secret的场景,但是需要确保Secret在静止状态时无法访问或可读。
静态加密
与所有API对象一样,Secrets存储在Kubernetes的分布式状态数据库etcd中,只需用base64编码。 实际上,这使得有权访问etcd的人可以使用Secrets,因此应该小心控制对etcd的访问,并且应该使用TLS对etcd实例之间的通信进行加密。 然而,在静止状态时,当etcd将其数据库写入磁盘时,Secrets以未加密的方式存储,易受未经授权访问主机文件系统的任何人的攻击。
幸运的是,可以使用 --experimental-encryption-provider-config
参数配置API服务器以加密Secret对象(或任何其他资源对象),该参数指定配置文件的位置,该文件确定对象将被如何加密。 本质上,API服务器使用在配置文件本身(通常是AES-CBC加密)中提供的密钥,或者由进程外密钥管理服务(KMS)提供程序(如Azure)对对象进行加密/解密,亦或者密钥保管库或AWS KMS。 如果使用配置文件中定义的本地密钥,确保文件具有适当限制的权限非常重要。
使用外部Secrets存储
使用Kubernetes Secrets API和用于加密静态Secrets的机制可能足以满足您组织的风险控制,但如果您的要求超出Kubernetes提供的要求,则可以使用更安全的解决方案。
Hashicorp的Vault是一个完全专注于Secrets管理的解决方案,包括创建,存储,撤销,轮换,生命周期(租赁)和范围。在发出客户端可用于访问存储的Secrets的令牌之前,Vault要求客户端对其中一种身份验证方法进行身份验证。令牌包含定义客户端可以访问和不能访问的策略。
对于Kubernetes,Vault具有特定的身份验证方法,该方法依赖于与Pod的服务帐户关联的令牌。当Pod尝试使用Vault进行身份验证时,Vault会访问API服务器的TokenReview API,以便验证令牌。经过身份验证后,Vault会向Pod发出一个令牌,其中包含服务帐户的相关范围。这使得pod能够在令牌的租约期间安全地检索Secrets。
镜像内容
我们知道在镜像中存储Secrets是禁忌,但在容器镜像中还应该注意什么呢? 这是一个引出许多不同意见的主题,但一个不可避免的事实是,您添加到镜像越多,利用从镜像派生的容器的机会就越多。
最小化镜像
在理想的世界中,我们可以使用应用程序二进制文件以及二进制文件所依赖的任何相关依赖项来创建镜像。 事实上,没有什么可以阻止我们通过使用scratch作为FROM Dockerfile指令的参数来省略镜像(我们构建我们自己的镜像的镜像),并将静态链接的二进制文件复制到镜像中。 可能没有其他依赖项,在这种情况下,镜像将包含单个文件,以及一些描述容器如何运行的元数据。 这对于镜像分发速度(镜像仓库的推/拉)非常有用,并且可以显着减少派生容器内的攻击面。
基础镜像
然而,这可能并不总是可行或不实际,在这种情况下,我们需要警惕我们对基础镜像的选择。最好的方法是构建你自己的基础镜像,因为你不依赖于第三方制作的基础镜像 - 如果你已经制作了镜像,你就知道其中的确切内容。然而,制作你自己的基础镜像是有代价的 - 这是一个在内容维护方面需要相当大的努力的过程,这可能使它变得令人望而却步,并且如果做得不好,可能会使你的镜像不那么安全。
然后,下一个最佳方法是使用操作系统供应商支持的镜像,或者使用由社区策划的Docker Hub注册表中的官方镜像库。如果您的组织使用基于订阅的分发(例如RHEL或SLES),则可能适合使用您信任的内容,利用所提供的支持,并使用这些供应商提供的镜像。
切勿盲目使用您之前未经过审查的不受信任来源的镜像,尤其是在生产环境中。
镜像扫描
无论您从何处获取镜像,最终您都将依赖该镜像内容的完整性。但是,我们永远无法保证我们创建或使用的软件没有漏洞,这适用于我们使用的镜像内容。例如,Bash二进制文件中的Shellshock错误在2014年发现之前隐藏了25年,许多 Docker 镜像自动包含Bash二进制文件!这意味着我们需要了解现有镜像中可能存在的漏洞,甚至是那些已经用于在Kubernetes集群中派生运行容器的漏洞。
检测镜像中的这些漏洞是一个非常重要的问题,但是有许多 工具 已经出现以应对问题。我们在之前的文章Clair中提到了一个备受推崇的开源示例,它是容器镜像的静态漏洞分析器。无论是开源世界还是商业解决方案,如JFrog Xray,都有很多替代方案。一个有趣的免费镜像扫描工具是Aqua Security的MicroScanner,它允许您在构建镜像时扫描镜像。
镜像扫描对于保持容器工作负载的安全至关重要,并且可以确保您的镜像定期通过信誉良好的工具进行扫描,因此请花时间评估满足您需求的最佳解决方案。
提供链保证
如果我们能够在构建容器镜像之前确保构成容器镜像的组件提供链的完整性,那就更好了。 它永远不会消除定期和一致地扫描我们的镜像是否存在漏洞的需要,但是我们越早发现问题,他们越不可能通过网络进入生产工作负载的镜像。
Snyk帮助识别和修复应用程序依赖项中的漏洞,而Grafeas和in-toto通过应用CI/CD管道的安全原则和策略来帮助保护整个提供链。
镜像起源
一旦我们确定我们打算用于容器工作负载的镜像内容合理,我们就应该对我们的工作负载是安全的有很大的信心。 然而,如果我们允许随机镜像用于容器,或者如果我们允许自己被欺骗使用的镜像不是我们认为的那样,那么这种信心就会破灭。 出于这个原因,通过强制控制可以使用哪些镜像,从哪些特定来源检查图像的来源,并检查镜像是否是它看起来是最符合我们利益的。这是另一个难以解决的问题。
镜像策略
确保起源的一种方法是定义使用定义Pod容器的镜像的策略。例如,我们可能希望通过摘要而不是标记来专门引用镜像,这将确保我们可以使用非常特定的镜像版本。标签是可变的,这意味着在一段时间内,镜像标签可以表示完全不同的镜像内容。然而,镜像的摘要对于其内容是唯一的,这意味着我们可以确定我们正在处理已知内容的镜像。另一个策略示例可能是我们希望确保只使用存储在位于组织防火墙范围内的镜像仓库中的镜像。无论要求是什么,重要的是能够强制执行我们定义的策略,这样我们就不会最终使用我们不应该使用的镜像。
为此,Kubernetes有一个内置的ImagePolicyWebhook许可控制器,它依赖于外部后端来授权使用为Pod容器定义的镜像。如果配置正确 - 在允许pod进入群集之前 - 后端将发送一个ImageReview对象,其中包含容器镜像的详细信息,根据其配置的策略允许或禁止容器镜像。
尽管在Kubernetes中可以轻松获得镜像策略的机制,但是后端实现很少,并且它在很大程度上是未使用的功能。相反,更多通用动态许可解决方案倾向于被使用,其中可以实施镜像策略,以及与pod配置的其他方面相关的策略。一种越来越流行的定义动态接纳策略的技术是利用开放策略代理(OPA),这是一个实现通用策略引擎的云原生计算基础(CNCF)项目。 OPA通过在授权客户端(在本例中为Kubernetes)提供的数据的上下文中评估以其自己的语言Rego定义的策略 - 然后基于评估的策略返回二进制允许/禁止结果。基于OPA的准入控制器的示例是kubernetes-policy-controller。
可信镜像
虽然我们可以确保我们使用策略只从受信任的位置下载镜像,但我们不能断然说我们下载的是我们认为的那么安全。我们可能信任容器镜像的作者,并且基于该信任,我们可能想要将镜像用于Pod的容器。但是,我们没有办法确保作者的镜像没有被篡改,在他们发起推送该镜像到镜像仓库之间,到我们完成从该镜像中拉出该镜像的时刻。我们应当考虑如何安全地更新软件,这是一个普遍公认的问题。
更新框架(TUF)是由CNCF托管的规范,系统和项目,用于保护打包软件更新的分发。 TUF规范描述了一种允许发布者对其打包内容进行数字签名的系统,以便消费者可以验证相同内容的完整性和来源。Notary-另一个CNCF项目,是TUF的开源实现,允许我们为容器镜像建立这种起源链接。
Docker引擎可以配置为将镜像推送到具有支持的Notary服务器和签名者(Docker Content Trust)的镜像仓库,并从中提取镜像,但Kubernetes没有抽象的用户界面,这使得它很难使用。它本质上也是二进制的,要么所有镜像都需要信任,要么都不需要信任。 Portieris是一个开源的Kubernetes准入控制器,在Kubernetes集群中实现与Notary的镜像内容信任时,允许更小细粒度的方法。策略在ImagePolicy或ClusterImagePolicy对象中定义,该对象允许为特定镜像存储库启用内容信任,包括要求镜像应由特定可信签署者签名。当在Kubernetes集群中使用容器镜像时,这为应用内容信任时提供了更大的灵活性。
自动化
在本文中,我们一直在讨论在整个工作流程中考虑安全性的必要性,而不仅仅是在部署时。让我们明确指出安全性需要“向左移”,并且与构建,测试和可观察性一样,也是CI/CD管道的一部分。 它需要被事先处理而不是事后的想法,并且需要关注过程和文化。
总结
这是题为《Securing Kubernetes for Cloud Native Applications》系列文章的最后一篇文章,我们讲了很多内容。我们已经看到安全性需要仔细考虑并应用于包含Kubernetes集群的堆栈中的所有层,这不仅可以确保我们涵盖安全的各个方面,还可以为我们提供“深度防御”所需的冗余”。我们还看到,明智地应用最佳实践安全控制使我们能够在管理对敏感资源的访问时采用“最小权限原则”。最后,我们已经讨论了在部署之前,安全性需要如何遍及整个工作流程,而不是它是最后一步的活动。
安全性很难,但并非不可能,它应该与制作一流的云原生应用程序的其他因素一样受到关注。一定要投入必要的技能来做到公正,或者与已经进行了投资的组织合作,并获得大规模生产Kubernetes集群所带来的实际见解。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 阿里云容器服务:负载均衡与容器的关系
- (编辑中)深信服容器云的负载均衡实现
- 6大能力升级,自研容器网络和负载均衡能力大大增强 博云容器云产品最新升级
- Kube-OVN 1.1 发布!容器多网卡,Hairpin 负载均衡器,一键安装脚本
- 3分钟了解负载均衡,分清二层负载均衡和三层负载均衡
- 负载均衡策略之有限负载一致性哈希
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。