TL;DR
- hardeneks là Python CLI của AWS sample, runs 100+ check trên EKS cluster đang chạy, dựa trên EKS Best Practices Guides chính chủ AWS. Open-source MIT, install qua
pip.- Tôi chạy hardeneks ở CI (PR-level) thay vì weekly cron — catch misconfiguration trước khi merge thay vì sau khi prod đã sai. Trade-off: cần test cluster ephemeral hoặc dev cluster cho mỗi PR.
- Khác kube-bench: kube-bench check CIS Benchmark cho control plane (Kubernetes nói chung). hardeneks check best-practice EKS-specific — IRSA, VPC CNI, IMDSv2 trên node, AWS Load Balancer Controller config.
- Khác kube-hunter: kube-hunter là pen-test tool (red team) — nó tìm exploit. hardeneks là posture tool (blue team) — nó tìm misconfig. Hai mục đích khác nhau, không thay nhau.
- Finding thực tế lần đầu chạy trên cluster 8 tháng tuổi: 47 issue HIGH/MEDIUM. Top 3: pod chạy
runAsNonRoot: false, không network policy default-deny, IAM role node group dùngAmazonEKSWorkerNodePolicymở quá rộng.- Không thay Wiz/Prisma: hardeneks scan từ trong cluster (kubeconfig-based), không có view cross-account hay container runtime. Pair với CNAPP cho coverage đầy đủ.
- Output JSON dễ pipe vào jq — tôi parse rồi gate PR: HIGH count > 0 thì block, MEDIUM thì warn, LOW chỉ log.
Vì sao một tool sample AWS lại đáng dùng trong production
Đa số “sample” repo của aws-samples không production-ready — chúng được viết để minh họa concept, không để vận hành lâu dài. hardeneks là exception. Repo có ~956 star, ~30 contributor, commit gần đây trong tháng, document đầy đủ. Quan trọng hơn: nó implement EKS Best Practices Guides — tài liệu chính thức AWS publish và update liên tục. Khi guide đổi, hardeneks update theo. Đây là một trong rất ít công cụ tự động hóa guide đó.
Tôi đã chạy hardeneks 14 tháng trên 3 EKS cluster (staging, prod-asia, prod-global) — đây là note sau quá trình đó.
hardeneks check gì — bốn nhóm chính
Khi hardeneks chạy, nó load kubeconfig context hiện tại rồi quét 4 category:
| Category | Số check | Ví dụ |
|---|---|---|
| Security | ~35 | Pod security standard, runAsNonRoot, capabilities, network policy, image scanning, IRSA |
| Reliability | ~25 | Horizontal pod autoscaler, PDB, multi-AZ node group, readiness probe |
| Scalability | ~20 | VPC CNI config, IP pre-warming, cluster autoscaler/karpenter setup |
| Cluster upgrade | ~15 | Deprecated API usage, EKS version skew, addon version |
| Cost optimization | ~10 | Spot node group, right-sizing, unused PVC |
Tổng ~100+ check. Mỗi check có severity (HIGH/MEDIUM/LOW), description, remediation link tới EKS Best Practices Guide.
Install:
pip install hardeneks
# Hoặc với pipx (recommend cho CLI tool)
pipx install hardeneks
Chạy:
# Quét toàn bộ namespace
hardeneks --region ap-southeast-1 --cluster-name production
# Chỉ một namespace
hardeneks --region ap-southeast-1 --cluster-name production \
--namespace payments
# Output JSON cho CI
hardeneks --region ap-southeast-1 --cluster-name production \
--export-html report.html \
--export-txt report.txt
Output mặc định là rich text table trên terminal — đẹp khi xem, nhưng pipeline cần JSON. Dùng --export-txt hoặc --export-html cho output file (hỗ trợ JSON qua flag tương tự, kiểm tra version).
Quan điểm: scan ở PR, không phải weekly cron
Đây là điểm tôi khác đa số tutorial bạn đọc trên internet về EKS security scanner. Mặc định mọi blog post nói “set up weekly cron, gửi report cho Slack”. Tôi không làm vậy. Lý do:
1. Weekly cron là detect-after-the-fact. Khi cron bắt được misconfig, nó đã ở prod. Bạn vào fix thì hoặc (a) cần maintenance window, hoặc (b) phải rollback PR đã merge từ lâu — rủi ro cao.
2. PR-level scan dịch trách nhiệm sang author. Dev mở PR thêm Deployment mới chạy runAsNonRoot: false? CI báo ngay trong 2 phút, dev sửa luôn trong review session. Không leak vào main.
3. Compliance scan-trend đẹp hơn. Auditor không hỏi “tuần trước scan thế nào”, họ hỏi “khi bạn deploy có check không”. PR check trả lời câu hỏi sau.
Setup tôi dùng — GitHub Actions tạo ephemeral EKS namespace cho mỗi PR, apply manifest, chạy hardeneks, tear down:
# .github/workflows/eks-security-pr.yml
name: EKS security check
on:
pull_request:
paths:
- 'k8s/**'
- 'helm/**'
jobs:
hardeneks:
runs-on: ubuntu-latest
permissions:
id-token: write # OIDC cho AWS
contents: read
pull-requests: write # comment lên PR
steps:
- uses: actions/checkout@v4
- name: Configure AWS
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123:role/github-ci-eks
aws-region: ap-southeast-1
- name: Update kubeconfig (dev cluster)
run: |
aws eks update-kubeconfig \
--name dev-eks --region ap-southeast-1
- name: Create ephemeral namespace
run: |
export NS=pr-${{ github.event.number }}
kubectl create ns $NS || true
helm upgrade --install pr-test ./helm/myapp \
--namespace $NS --wait --timeout 5m
- name: Install hardeneks
run: pipx install hardeneks
- name: Run scan
run: |
export NS=pr-${{ github.event.number }}
hardeneks --region ap-southeast-1 \
--cluster-name dev-eks \
--namespace $NS \
--export-txt /tmp/report.txt || true
- name: Gate on HIGH severity
run: |
HIGH=$(grep -c "│ HIGH" /tmp/report.txt || echo 0)
MED=$(grep -c "│ MEDIUM" /tmp/report.txt || echo 0)
echo "::notice::HIGH=$HIGH MEDIUM=$MED"
if [ "$HIGH" -gt 0 ]; then
echo "::error::$HIGH HIGH-severity findings — block merge"
exit 1
fi
- name: Cleanup
if: always()
run: |
export NS=pr-${{ github.event.number }}
kubectl delete ns $NS --ignore-not-found
Trade-off: cần một dev EKS cluster luôn sẵn sàng (khoảng $73/tháng cho control plane + node). Trong setup của tôi cluster này cũng dùng cho integration test khác nên cost được share. Nếu chỉ dùng cho hardeneks scan, cost không hợp lý — fallback về weekly cron.
hardeneks vs kube-bench vs kube-hunter — bảng đối chiếu
Cả ba thường được nhắc cùng nhau nhưng làm khác nhau:
| Tool | Mục đích | Scope | Trigger |
|---|---|---|---|
| kube-bench (aquasecurity/kube-bench) | CIS Kubernetes Benchmark check | Control plane + node | Chạy trên node (DaemonSet) |
| kube-hunter (aquasecurity/kube-hunter) | Active pen-test tool — tìm exploit | External (active scan) hoặc internal pod | Manual trước go-live |
| hardeneks | AWS EKS best-practice check | EKS-specific config (IRSA, CNI, addon) | CI hoặc cron |
Cách tôi pair cả ba:
- kube-bench: chạy DaemonSet permanent, gửi metric Prometheus. Trigger alert khi node mới join không pass benchmark. Đây là compliance-focused (CIS).
- kube-hunter: chạy một lần khi pre-production go-live, hoặc khi rotate node OS image lớn. Pen-test mode
--remote <api-server>từ ngoài cluster. - hardeneks: PR-level như trên. Best-practice focused, EKS-specific.
Cả ba không trùng phạm vi. kube-bench tells “is your CIS config right”. kube-hunter tells “can attacker exploit something now”. hardeneks tells “are you using EKS the way AWS recommends”.
Finding đầu tiên trên cluster 8 tháng tuổi — 47 issue
Lần đầu chạy hardeneks trên một staging cluster đã có từ trước, output 47 issue HIGH/MEDIUM. Sắp xếp theo frequency:
1. runAsNonRoot: false trên 14 deployment (HIGH). Đa số image Docker Hub mặc định chạy root. Fix: thêm securityContext vào Deployment hoặc Pod Security Standard restricted ở namespace level. Lần đầu sửa làm break 3 image — phải build lại Dockerfile với USER 1000.
2. Không có NetworkPolicy default-deny (HIGH). Mọi pod có thể nói chuyện với mọi pod khác. Vulns rất phổ biến trên cluster mặc định. Fix: apply default-deny NetworkPolicy ở mỗi namespace, sau đó thêm rule allow explicit. Cần Calico/Cilium CNI hoặc VPC CNI có hỗ trợ NetworkPolicy (ENABLE_POD_ENI=true + ENABLE_NETWORK_POLICY=true từ VPC CNI 1.14+).
3. IAM role node group dùng AmazonEKSWorkerNodePolicy + AmazonEC2ContainerRegistryReadOnly mặc định (HIGH). Hai policy này cho phép node call EC2 và ECR. Nếu pod chiếm được node identity (qua IMDSv1 hoặc hostPath escape), nó pull mọi image ECR và mô tả mọi EC2 trong account. Fix: dùng IRSA cho pod identity, hạn chế node role chỉ instance metadata + ECR pull cụ thể. Bài aws-iam-access-key-auto-rotation nói thêm về least-privilege IAM.
4. IMDSv1 cho phép trên node (HIGH). EKS managed node group mặc định httpTokens: optional (cho phép cả v1). Bypass dễ — curl http://169.254.169.254/latest/meta-data/iam/security-credentials/ từ pod compromise → role credential. Fix: metadataOptions.httpTokens: required trong launch template hoặc node group config.
5. Không có Pod Disruption Budget (MEDIUM). Khi rolling update node, pod bị evict cùng lúc → downtime. Fix: PDB minAvailable: 1 cho mọi Deployment > 1 replica.
6. Container imagePullPolicy: Always trên image tag latest (MEDIUM). Cả hai sai pattern — latest không reproducible, Always tăng pull rate vào ECR. Fix: pin image tag (SHA-256 digest tốt nhất), policy IfNotPresent.
47 issue đó sửa hết trong 6 tuần. Sau khi sửa, hardeneks ra HIGH = 0, MEDIUM = 4 (chấp nhận được, có exception note).
Limitation — hardeneks không thay CNAPP
hardeneks là posture management tool chạy từ kubeconfig — nó không có những thứ sau:
- Cross-cluster, cross-account view: muốn xem 5 EKS cluster cùng lúc? hardeneks không có UI tổng hợp. Pair với Wiz, Prisma Cloud, hoặc Lacework.
- Runtime threat detection: pod chạy curl về C2 server, hardeneks không biết. Cần Falco hoặc Sysdig.
- Container image scan: image có CVE không, hardeneks không quét layer. Cần Trivy ở CI hoặc ECR scan-on-push.
- Secret scan: không quét secret leak trong manifest. Cần gitleaks hoặc trufflehog.
- Compliance report (SOC 2, PCI): hardeneks không sinh ra compliance pack. CIS scan thì kube-bench làm. SOC 2 thì cần Drata/Vanta hoặc tự build evidence pipeline.
Đặt đúng vị trí: hardeneks là “fast feedback loop cho EKS config” — không phải CNAPP, không phải SIEM. Khi cluster < 5 và team đang build security posture, nó là entry point tốt với cost = $0.
Skip rule hợp lý — không phải sai
Một số rule hardeneks có thể không phù hợp context của bạn. Ví dụ rule check “use Fargate” — nếu team đã quyết định không dùng Fargate (cost, customization), rule này chỉ làm nhiễu. Skip cách standard qua config file ~/.hardeneks.yaml:
ignore-checks:
- check_use_of_fargate
- check_irsa_namespace_restriction_for_kube_system
- check_for_efs_csi_driver
Một file skip-rules.yaml check-in repo cũng giúp audit — security team review từng skip có lý do gì, ai approve. Quan trọng: đừng skip để bypass HIGH severity finding mà chưa fix root cause. Skip phải kèm với justification document.
Bottom line
hardeneks là một trong số ít công cụ tự động hóa AWS EKS Best Practices Guides đúng nghĩa, miễn phí, code đọc được. Vị trí của nó là “EKS-specific posture check” — không thay CNAPP enterprise nhưng đủ cho team < 10 cluster muốn bắt đầu có baseline. Cách tôi dùng — chạy ở PR thay vì weekly cron — yêu cầu một dev cluster luôn sẵn sàng, nhưng đổi lại catch misconfig trước khi vào main. Sau 14 tháng vận hành, không có incident nào liên quan đến EKS misconfig pass qua check. Cluster cũng pass kube-bench CIS Benchmark Level 2 lần đầu chỉ với 3 exception. Đây là một trong vài tool tôi recommend không cần suy nghĩ cho team mới onboard EKS.
Checklist trước production
- hardeneks chạy thành công local với kubeconfig đúng cluster
- Dev/staging EKS cluster luôn sẵn để PR scan có target
- GitHub Actions OIDC role đã setup, có quyền
eks:DescribeCluster+ read namespace - Ephemeral namespace per PR — cleanup luôn
always()để tránh orphan - Gate threshold: HIGH = 0 block merge, MEDIUM > 5 warn, LOW chỉ log
-
~/.hardeneks.yamlskip-rule check-in repo, có justification trong PR - Pair với kube-bench DaemonSet (CIS) + Trivy (image scan) + Falco (runtime)
- Document quy trình “accept finding” — phải có ticket Jira link
- Cập nhật hardeneks quý 1 lần (
pipx upgrade hardeneks) - Mock test PR với deployment intentionally bad — đảm bảo gate hoạt động
- Khi onboard cluster mới, scan trước go-live, fix HIGH trước route prod traffic
Cạm bẫy thường gặp
1. Chạy hardeneks với kubeconfig của user, không phải CI role. User có quyền cluster-admin sẽ scan được mọi thứ. CI role chỉ có quyền read sẽ miss một số check. Tạo IAM role chuyên cho hardeneks (cluster-admin trong dev, read-only trong prod).
2. Lúc scan namespace ephemeral cho PR, một số check vẫn quét cluster-wide (network policy default-deny, IRSA setup cluster). Output sẽ flag finding “cluster-level” không liên quan PR. Filter trong CI script — chỉ gate trên namespace-scoped finding.
3. pip install hardeneks đôi khi conflict với dependency project khác. Dùng pipx để isolation.
4. EKS version skew giữa CLI và cluster. hardeneks ổn với EKS 1.24+. Cluster cũ hơn có thể miss check liên quan addon mới (Karpenter, EKS Pod Identity).
5. Một số check yêu cầu addon hoạt động (ví dụ check EBS CSI driver, Load Balancer Controller). Nếu chưa install những addon đó, check sẽ fail với lý do “not found” — không phải security issue. Mark là expected.