在本指南中,我们将探讨使用 Amazon Elastic Kubernetes Service (EKS) 时需关注的一些最佳实践,以及如何优化应用程序工作负载、加强安全配置、简化集群操作,同时充分利用 AWS 强大的云基础设施。
1、 增强网络安全
? 阻止对 EKS 集群节点组的 SSH/RDP 远程访问
禁用对您的 EKS 集群节点组的 SSH/RDP 远程访问可以大大防止未经授权的访问和潜在的违规行为。它还降低了不良行为者接管您的基础设施的风险,并保护您的 EKS 集群资源和敏感数据的安全。
使用 AWS CLI 实现这一点,在创建 EKS 集群节点组时,避免在 create-nodegroup 命令中使用--remote-access 选项。
# 使用 --remote-access 选项:
aws eks create-nodegroup
--region us-east-1
--cluster-name my-cluster
--nodegroup-name my-nodegroup-1
--instance-types m5.large
--subnets subnet-xxxxxx subnet-yyyyy
--remote-access ec2SshKey="my-ssh-key-1",sourceSecurityGroups="sg-XXXXX"
--node-role arn:aws:iam::XYXYXYXY:role/my-eks-node-role
# 移除 --remote-access 选项后:
aws eks create-nodegroup
--region us-east-1
--cluster-name my-cluster
--nodegroup-name my-nodegroup-1
--instance-types m5.large
--subnets subnet-xxxxxx subnet-yyyyy
--node-role arn:aws:iam::XYXYXYXY:role/my-eks-node-role
然而,如果您真的需要远程访问,应在个案基础上启用它,同时采取额外的预防措施,比如使用强身份验证,通过安全组确保安全的网络连接,并定期检查访问日志以查找任何可疑活动。
? 阻止对 EKS 集群端点的公共访问
在启动新的 EKS 集群时,会自动在 Kubernetes API 服务器上生成一个公共端点,以便 Kubernetes 管理工具(例如 kubectl)可以与您的 EKS 集群通信。由于这个 API 服务器端点可以从互联网公开访问,这种配置使您的 EKS 集群暴露于各种恶意活动和攻击。
作为最佳实践,必须通过使用 update-cluster-config 命令中的 endpointPublicAccess=false 选项来撤销对 EKS 集群端点的公共访问。但是,您仍然可以设置 endpointPrivateAccess=true 以保持对 EKS 集群的私有访问(例如,从 VPC 内的 EC2 堡垒主机运行的 kubectl 命令),特别是用于执行集群管理操作。
禁用 EKS 集群的公共访问并仅启用私有访问
aws eks update-cluster-config
--region us-east-1
--name my-cluster
--resources-vpc-config
endpointPublicAccess=false,endpointPrivateAccess=true,publicAccessCidrs=["10.0.0.20/32"]
对于高级配置,请阅读有关 Amazon EKS 集群端点访问控制的更多信息。
? 使用 EKS 安全组限制不必要的入口流量
避免在 EKS 安全组中打开所有端口,因为这可能会暴露给使用端口扫描器和探测技术来识别应用程序和服务并发起恶意活动(如暴力攻击)的攻击者。在大多数情况下,仅允许在 TCP 端口 443(HTTPS)上的入站流量就足够了。
可以使用 describe-security-groups 命令检查与安全组关联的入站/入口规则,并使用 revoke-security-group-ingress 命令撤销任何不必要的入口规则。如果 TCP 端口 443(HTTPS)未打开,可以使用 authorize-security-group-ingress 命令将缺少的入口规则添加到安全组。
# 检查入站/入口规则
aws ec2 describe-security-groups
--region us-east-1
--group-ids sg-xxxxx
--query 'SecurityGroups[*].IpPermissions'
# 撤销不符合规定的入口规则(例如,在 TCP 端口 22 上撤销 SSH 流量)
aws ec2 revoke-security-group-ingress
--region us-east-1
--group-id sg-xxxxx
--protocol tcp
--port 22
--cidr 0.0.0.0/0
# 允许在 TCP 端口 443 上的入站流量
aws ec2 authorize-security-group-ingress
--region us-east-1
--group-id sg-xxxxx
--protocol tcp
--port 443
--cidr 10.10.1.0/24
? 加强 EKS 集群节点组的 IAM 角色策略
为了运行 kubelet 并与各种其他 API 进行交互,每个工作节点都被分配了一个 IAM 角色。这个 IAM 角色消除了每个节点上单独凭证的需要,并简化了提供细粒度权限的过程。同时,确保这些 IAM 角色只拥有它们执行的任务所需的必要权限,遵循最小权限原则。
以下命令可用于删除不符合规定的 IAM 角色策略并附加一个新的策略。
删除策略
aws iam delete-role-policy
--role-name my-node-group-role
--policy-name my-old-policy
附加策略
aws iam attach-role-policy
--role-name my-node-group-role
--policy-name my-new-policy
? 限制 Kubernetes RBAC
不仅在 IAM 中,而且在 Kubernetes RBAC 中限制权限,减少攻击面并遵循“最小权限原则” —— 特别是,通过 aws-auth ConfigMap 和 Kubernetes roles 和 clusterroles 授予的权限要最小化,以降低凭证被泄露的风险。
? 通过与 OpenID Connect 身份提供者集成来验证 Kubernetes API 调用
OpenID Connect (OIDC) 提供了一种安全和灵活的方式来验证和授权应用程序和系统中的用户。OIDC 提供者可以用作 IAM 的替代品,配置对 EKS 集群的认证后,您可以创建 Kubernetes roles 和 clusterroles 来分配权限给角色,然后使用 Kubernetes rolebindings 和 clusterrolebindings 将角色绑定到身份。请注意,您只能将一个 OIDC 身份提供者关联到您的集群。有关说明,请阅读有关从 OpenID Connect 身份提供者验证您集群的用户。
? 使用 EKS CNI 策略(AWS 管理)访问网络资源
允许 Kubernetes CNI(容器网络接口)执行诸如列表、描述和修改 VPC ENIs(弹性网络接口)等基本任务
使用 VPC CNI 插件()代表集群,确保 EKS 环境中适当的网络功能和通信。有关额外说明,请阅读有关为 Kubernetes 配置 Amazon VPC CNI 插件。
附加策略
aws iam attach-role-policy
--role-name AmazonEKSVPCCNIRole
--policy-arn arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy
? 使用 ECR 只读策略(AWS 管理)访问 ECR 存储库
为 EKS 集群节点组附加 AmazonEC2ContainerRegistryReadOnly AWS 管理策略,以仅授予从 ECR 存储库读取和检索容器镜像的权限,不允许对 ECR 进行任何不必要的操作。
附加策略
aws iam attach-role-policy
--role-name AmazonEKSECRReadRole
--policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
? 使用 EKS 集群策略(AWS 管理)管理 AWS 资源
为 EKS 集群角色附加 AmazonEKSClusterPolicy AWS 管理策略,以提供 Kubernetes 需要代表您管理资源的权限。它确保了安全的访问控制和集群操作,与 AWS 服务的无缝集成,以及 AWS 的定期更新。
附加策略
aws iam attach-role-policy
--role-name AWSEKSClusterRole
--policy-arn arn:aws:iam::aws:policy/AmazonEKSClusterPolicy
? 使用 KMS 为 EKS Kubernetes Secrets 启用信封加密
默认情况下,所有的 Kubernetes secrets 都以明文形式存储在 Kubernetes 后端数据库 —— etcd 中。任何有访问 Kubernetes 主节点权限的人都可以通过在后端查看来查看 secrets,这是一个巨大的安全隐患。为了增加一层安全性,使用 KMS 密钥对这些 Kubernetes secrets 实施信封加密(即用另一个密钥加密密钥)。这将使用数据加密密钥 (DEK) 加密明文 Kubernetes secrets,并使用 kms:encrypt 加密 DEK 后再存储在 etcd 中。KMS 可以支持客户管理的密钥 (CMKs)、AWS 管理的密钥或 AWS 拥有的密钥进行加密 —— 通常,CMKs 是最推荐的选项。
在 AWS EKS 上,KMS 可以直接与 Kubernetes Secrets 结合使用,使用信封加密并将主密钥存储在 KMS 中。
要实施此策略,请阅读有关使用 AWS KMS 密钥和 EKS 加密提供者支持的信封加密的更多信息。
2、启用日志记录和监控
? 设置 EKS 控制平面日志记录
确保为所有 EKS 集群激活控制平面日志,这使得可以发布 API、审计、控制器管理器、调度器和认证器日志到 AWS CloudWatch Logs。通过这种设置,可以收集各种日志类型,包括 API 服务器日志、审计日志、认证器日志(特定于 AWS EKS)、控制器管理器日志和调度器日志。另外,请注意,这些日志类型中的每一种都对应于 Kubernetes 控制平面内的关键组件。有关说明,请阅读有关启用和禁用控制平面日志。
# 启用 AWS EKS 控制平面日志记录
aws eks update-cluster-config
--region us-east-1
--name my-cluster
--logging '{"clusterLogging":[{"types":["api","audit","authenticator","controllerManager","scheduler"],"enabled":true}]}'
? 在 GuardDuty 中设置 EKS 审计日志监控
使用 GuardDuty 等工具对 EKS 集群上的活动进行审计,以寻找可疑的变更,这是一个重要的安全措施。GuardDuty 支持安全监控功能,包括监控来自 EKS 集群的 Kubernetes 审计日志并分析它们以寻找潜在的恶意和可疑活动。它直接从 Amazon EKS 控制平面日志记录功能消费 Kubernetes 审计日志事件,并捕获用户、使用 Kubernetes API 的应用程序和控制平面的按时间顺序的活动。
# 启用 EKS 审计日志监控
aws guardduty update-detector
--detector-id xxxxxxxxxxx
--features '[{"Name" : "EKS_AUDIT_LOGS", "Status" : "ENABLED"}]'
此外,您还可以考虑使用 TrendMicro Cloud Conformity 的实时威胁监控和分析 (RTMA) 引擎等外部 EKS 监控工具,该引擎积极识别您的 AWS 账户内的 Amazon EKS 配置调整,并确保及时审计和检测 AWS EKS 服务级别的更改。
? 为 Kubernetes API 调用设置 CloudTrail 日志记录
确保为所有 EKS 集群激活 CloudTrail 日志记录,以捕获和记录所有 Kubernetes API 调用。它将记录所有重要的集群操作(例如 CreateCluster、DeleteCluster)并为每个事件生成详细的日志条目,包括有关负责此类操作的 IAM 身份和使用的凭据的信息。有关确切的步骤和说明,请阅读有关使用 AWS CloudTrail 记录 Amazon EKS API 调用。
3、维护健康的 EKS 集群
? 为所有 pod 启用就绪和存活探针
就绪探针确定 pod 是否准备好服务流量。当 pod 未准备好时,它将从服务中移除,但仍在运行。就绪探针对于避免将流量发送到仍在初始化或遇到问题的 pod 至关重要。
存活探针验证 pod 是否存活并正确运行。如果存活探针失败,Kubernetes 将重新启动 pod。存活探针对于检测和从 pod 变得无响应或在运行时进入错误状态的情况中恢复至关重要。
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-deployment
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web-container
image: nginx:latest
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 10
periodSeconds: 15
在 Kubernetes 中实现这些就绪和存活探针对于维护应用程序健康和确保高可用性至关重要。通过定义这些探针,Kubernetes 可以自动检查 pod 的响应性,并在必要时采取纠正措施。
? 启用 pod 反亲和性以确保跨多个工作节点分布 pod 副本
跨多个工作节点分布具有多个副本的 pod 工作负载对于确保 Kubernetes 集群的高可用性和容错性至关重要。通过利用 Kubernetes 反亲和性特性,pod 会自动调度在不同的工作节点上,最小化单个节点故障影响所有应用程序 pod 的风险。
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-deployment
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- web
topologyKey: "kubernetes.io/hostname"
containers:
- name: web-container
image: nginx:latest
在上面的示例中,使用 podAntiAffinity 字段指定带有标签 app: web 的 pod 应该分布在不同的工作节点上(topologyKey: "kubernetes.io/hostname")。通过在多个节点上部署多个副本,Kubernetes 确保对节点故障的弹性,并提高应用程序的整体可用性和可靠性。
? 为 pod 启用 CPU 和内存资源请求和限制
为每个 pod 应用适当的资源请求和限制对于优化资源利用和维护 AWS EKS 中的集群稳定性至关重要。没有适当的分配,资源浪费会随着时间的推移累积,导致效率低下和性能瓶颈。利用 Kubernetes 的垂直 Pod 自动缩放 (VPA) 可以帮助自动化这一过程,根据历史使用数据调整资源请求。虽然 VPA 可能需要 pod 驱逐以进行更改,但即将到来的 Kubernetes 更新旨在解决这一限制。通过机器学习技术补充 Kubernetes 自动缩放,对实时容量利用进行细粒度分析,确保高效的资源管理,提高您的 EKS 集群的整体性能和可扩展性。
apiVersion: v1
kind: Pod
metadata:
name: web-pod
spec:
containers:
- name: web-container
image: nginx:latest
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 200m
memory: 256Mi
? 在多个可用区部署工作节点
将工作节点配置为跨多个可用区部署对于增强 AWS EKS 集群的弹性和可用性至关重要。通过在区域之间分布工作节点,可以减轻单个区域故障的影响,防止整个集群停机。这是通过配置 AWS 自动扩展组 (ASGs) 跨越多个可用区来实现的。
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: multi-asgs
region: us-west-2
nodeGroups:
- name: ng1
instanceType: m5.xlarge
availabilityZones:
- us-west-2a
- name: ng2
instanceType: m5.xlarge
availabilityZones:
- us-west-2b
- name: ng3
instanceType: m5.xlarge
availabilityZones:
- us-west-2c
? 保持 EKS 集群的 Kubernetes 版本为最新
确保所有 EKS 集群都运行在最新稳定版本的 Kubernetes 上。这种方法提供了访问最新功能、设计更新、错误修复、增强的安全和改进的性能。理想情况下,这些版本检查必须定期进行(例如每季度一次 —— 因为 Kubernetes 大约每 3 个月发布一个新次版本)。有关与 EKS 兼容的 Kubernetes 版本,请阅读有关 Amazon EKS Kubernetes 版本。
# 检查集群版本
aws eks describe-cluster
--region us-east-1
--name my-cluster
--query 'cluster.version'
# 更新集群版本
aws eks update-cluster-version
--region us-east-1
--name my-cluster
--kubernetes-version 1.24
不及时更新 Kubernetes 版本可能会导致更高的扩展支持成本。例如,从 2024 年 4 月 1 日开始,为了提供对旧版 Kubernetes 版本的扩展支持,您将被收取每个集群每小时 0.60 美元的费用,而不是通常的 0.10 美元(每月 400 美元+)。这是一个不必要的成本,定期按计划更新 Kubernetes 版本是正确的做法。
对于 EKS 上旧版 Kubernetes 版本的扩展支持,定价将是近 6 倍。
? 将 CoreDNS 插件版本与 EKS 集群的 Kubernetes 版本相匹配
当启动一个新的 EKS 集群时,为了高可用性的目的,默认会部署 2 个 CoreDNS 副本(不考虑节点数量)。由于这些 CoreDNS pod 充当集群 DNS,为集群中的所有 pod 提供名称解析,其版本必须始终是最新的,并且与集群的 Kubernetes 版本兼容。
可以使用 describe-addon 和 update-addon 命令检查和更新 CoreDNS 版本到合适的值。
# 检查 CoreDNS 插件版本
aws eks describe-addon --cluster-name my-cluster --addon-name coredns
# 更新 CoreDNS 插件版本
aws eks update-addon
--region us-east-1
--cluster-name my-cluster
--addon-name coredns
--addon-version v1.11.1-eksbuild.6
--resolve-conflicts PRESERVE
要找到兼容的版本对,请阅读有关使用 CoreDNS Amazon EKS 插件的更多信息:https://docs.aws.amazon.com/eks/latest/userguide/managing-coredns.html
结论
通过遵循这些指导方针,您可以确保您的 EKS 环境是安全的、高可用的,并针对性能进行了优化。采纳这些实践,以解锁 AWS EKS 的全部潜力,并推动您的云原生之旅取得成功。