這幾天跟客戶聊到 Amazon EKS 的安全性配置,其中一項我覺得很有趣而且多數人很容易忽略的問題就是「EC2 Metadata」訪問權限,在預設情況下 Kubernetes Pod 是能夠訪問 EC2 metadata 服務,而 EC2 metadata 是 Worker node 存有大量機敏資訊的一個服務,例如 IAM credential、IP Addresses、Instance ID 等等。在這個系列中作者將會特別探討有關於安全相關的設置。
Running test pod
# pod-amazonlinux.yaml
apiVersion: v1
kind: Pod
metadata:
name: amazonlinux
spec:
containers:
- name: amazonlinux
image: public.ecr.aws/amazonlinux/amazonlinux:latest
command: ["/bin/sh", "-ec", "while :; do echo '.'; sleep 5 ; done"]
一開始先測試一下跑一個 Amazon Linux Pod 來訪問 EC2 Metadata 確認這個安全性問題的影響範圍
$ kubetctl apply -f pod-amazonlinux.yaml
$ kubectl get pod
再來透過 pod 來拿 EC2 Metadata 的資訊,我們直搗黃龍拿最有安全疑慮的 IAM credential 試試看
$ kubectl exec --stdin --tty amazonlinux -- curl http://169.254.169.254/latest/meta-data/iam/security-credentials/{RoleName}/
{
"AccessKeyId" : "ASIA...",
"SecretAccessKey" : "7nJs3...",
"Token" : "IQoJb3JpZ2l...+DxeQesYCUQ==",
"Expiration" : "2022-02-22T01:41:11Z"
}
假設 pod 被拿到 shell 之後如果 EC2 Metadata 沒有阻擋好,而 Worker node 的 IAM 也沒有將權限限縮好,那麼這把 Key 外流出去就會非常危險。
Install Calico Network Policy Engine for EKS
在 Kubernetes 中要實現 Network policy 必須採用 network plugin 來實現 pod-to-any 的安全性,在 AWS 文件中已經有 Calico add-on 的安裝方法,所以在這篇我們直接採納作為 Network policy plugin:
$ helm repo add projectcalico https://docs.projectcalico.org/charts
$ helm repo update
$ helm install calico projectcalico/tigera-operator --version v3.22.0
Network Policy:Disable access EC2 metadata for Pod
# disable-ec2-metadata.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-pod-access-ec2-metadata
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 0.0.0.0/0
except:
- 169.254.169.254/32
定義 NetworkPolicy
不允許 Egress 訪問 169.254.169.254/32 (IMDSv1)
$ kubectl apply -f disable-ec2-metadata.yaml -n {namespace}
在部署 NetworkPolicy
時特別注意是無法跨 namespace 的,所以每一個 namespace 都必須部署。
再次使用 pod 訪問 EC2 metadata 時應該已無法正確拿到 metadata。
$ kubectl exec --stdin --tty amazonlinux -- curl http://169.254.169.254/latest/meta-data/iam/security-credentials/{RoleName}/
curl: (28) Failed to connect to 169.254.169.254 port 80 after 132085 ms: Connection timed out