
Eks Recon
- 6 installs
- 39 repo stars
- Updated August 4, 2026
- aws-samples/sample-apex-skills
eks-recon is a Claude Code skill that performs read-only reconnaissance of an EKS cluster to discover its compute, IaC, CI/CD, addons, networking, and security posture.
About
This skill performs read-only reconnaissance of an EKS cluster environment. It detects the compute strategy (Karpenter, MNG, Auto Mode, Fargate), IaC tooling, CI/CD pipelines, addon inventory, networking, security posture, and observability. A developer runs it to gather cluster context before planning an upgrade, migration, or any EKS decision.
- Discovers EKS cluster environment: compute strategy, IaC, CI/CD, addons, networking, security
- Read-only reconnaissance run before upgrades, migrations, or any EKS decision
- Prefers the EKS MCP Server, falls back to AWS CLI and kubectl
Eks Recon by the numbers
- 6 all-time installs (skills.sh)
- Ranked #870 of 1,039 Cloud & Infrastructure skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
eks-recon capabilities & compatibility
- Capabilities
- devops
- Works with
- aws · kubernetes
- Use cases
- devops · research
- Pricing
- Bring your own API key
What eks-recon says it does
EKS cluster reconnaissance and environment discovery.
When in doubt about cluster state, run recon first.
npx skills add https://github.com/aws-samples/sample-apex-skills --skill eks-reconAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 6 |
|---|---|
| repo stars | ★ 39 |
| Last updated | August 4, 2026 |
| Repository | aws-samples/sample-apex-skills ↗ |
What it does
Run read-only reconnaissance on an EKS cluster to inventory compute, IaC, CI/CD, addons, and security.
Who is it for?
Gathering EKS cluster context before an upgrade, migration, or any cluster decision.
Skip if: Upgrade readiness scoring, operational maturity ratings, or architecture design documents.
When should I use this skill?
Someone asks about their EKS cluster, plans an upgrade or migration, or needs cluster context.
What you get
A read-only inventory report of the cluster's compute, IaC, CI/CD, addons, networking, and security.
- Cluster reconnaissance report
- Detected compute, IaC, CI/CD, addon, networking, and security inventory
By the numbers
- 3 recon modes (Full, Selective, Targeted Query)
Files
EKS Reconnaissance
Discover everything about an EKS cluster environment. Run this skill to gather comprehensive cluster context before making any decisions, changes, or recommendations.
When to Use This Skill
Run this skill when the user:
- Asks about their EKS cluster ("what's my cluster running?", "tell me about my setup")
- Plans an upgrade, migration, or architecture change
- Needs cluster context before any EKS-related decision
- Wants to document or review their cluster state
- Asks questions like "what version am I on?" or "am I using Karpenter?"
- Is about to modify their cluster (recon first to understand current state)
Also trigger this skill when:
- User mentions an EKS cluster name and seems to need context
- Another workflow needs cluster information as input
- You need to understand the cluster before giving recommendations
Do NOT use this skill for:
- Upgrade readiness scoring or deprecated API checks — questions like "score my upgrade readiness", "are there deprecated APIs blocking my upgrade", "can I safely upgrade to 1.33", "readiness score", or "breaking changes that would block a version bump" belong to
eks-upgrade-check. Recon discovers what version you're on; it does NOT assess whether you're ready to move to the next version. - Operational audits with maturity ratings — questions like "run an operational excellence audit", "rate each area GREEN/AMBER/RED", or "audit my cluster's operational posture" belong to
eks-operation-review. Recon inventories what exists; it does NOT score operational maturity or produce rated assessments. - Architecture design documents or Mermaid diagrams — questions like "create a security architecture document", "generate Mermaid diagrams for our EKS cluster", or "design document" belong to
eks-design. Recon discovers current state; it does NOT produce design artifacts or architectural diagrams. - Creating or modifying cluster resources (this is read-only)
- Troubleshooting specific issues (use
eks-best-practices) - Learning about EKS concepts (use
eks-best-practices)
Prerequisites
MCP Server (Preferred)
This skill works best with the EKS MCP Server configured. Check if MCP tools are available:
If tools like `list_eks_resources`, `describe_eks_resource`, `list_k8s_resources` are available:
-> MCP Mode: Use MCP tools (pre-authorized, richer output)
If MCP tools are NOT available:
-> CLI Mode: Fall back to AWS CLI + kubectl (requires explicit permission)MCP Mode benefits:
- Pre-authorized read-only operations (no permission prompts)
- Richer output with better formatting
- Single tool call instead of piped commands
CLI Mode limitations:
- Requires user permission for each command
- May need kubeconfig setup
- Some detection patterns are less reliable
Required for CLI Mode
| Tool | Required For |
|---|---|
aws CLI | Cluster-level detection (describe-cluster, list-nodegroups, list-addons) |
kubectl | K8s resource detection (deployments, CRDs, service accounts) |
helm | Helm release inventory (optional) |
MCP Troubleshooting
401 Unauthorized on K8s API calls (list_k8s_resources, read_k8s_resource):
The MCP server can access EKS APIs (clusters, nodegroups, addons) but may lack Kubernetes API access. This happens when the MCP server's IAM role doesn't have an EKS access entry.
Solutions (choose one):
1. Grant MCP access: Create an EKS access entry for the MCP server's IAM role.
Surface these commands to the user — do NOT execute them. These are persistent IAM writes and violate the read-only contract of this skill.
aws eks create-access-entry \
--cluster-name <cluster> \
--region <region> \
--principal-arn <mcp-server-role-arn> \
--type STANDARD
aws eks associate-access-policy \
--cluster-name <cluster> \
--region <region> \
--principal-arn <mcp-server-role-arn> \
--policy-arn arn:aws:eks::aws:cluster-access-policy/AmazonEKSViewPolicy \
--access-scope type=clusterIf the user confirms and has permission, they can run these themselves out-of-band.
2. Fall back to kubectl: If user has local kubectl access, use CLI commands instead:
"MCP K8s access returned 401. I'll use kubectl instead if you have it configured locally."
Empty results from EKS API calls:
- Verify cluster name and region are correct
- Check if the cluster exists:
aws eks list-clusters --region <region>
---
Reconnaissance Modes
| Mode | When to Use | What Happens |
|---|---|---|
| Full Recon | First engagement with cluster | Runs all modules, generates complete report |
| Selective Recon | Know what you need | Run specific modules (e.g., compute + iac) |
| Targeted Query | Quick answer | "Is this cluster using Karpenter?" |
How to Invoke
Full reconnaissance:
"Run EKS reconnaissance on clustermy-clusterinus-west-2"
Selective reconnaissance:
"Run EKS recon but only check compute and IaC"
Targeted query:
"What IaC tool manages cluster my-cluster?"---
Modules and Reference Loading
Load only the references needed for the user's request — this keeps context focused. references/cluster-basics.md is always loaded first by every module; it provides the shared cluster context all other modules depend on. For targeted queries, load only the matching row(s); for full recon, load all references in parallel. When uncertain, ask the user or default to full recon.
| Module | Intent / when to use | Reference file | Agent file |
|---|---|---|---|
| Cluster Basics | Always loaded first by every module (name, region, version, platform version, endpoint) | cluster-basics.md | — |
| Compute | Karpenter, nodes, scaling, Auto Mode, node groups, Fargate, self-managed | compute.md | compute-recon.md |
| Networking | VPC, ingress, CNI, service mesh, load balancer, connectivity | networking.md | networking-recon.md |
| Security | IAM, IRSA, Pod Identity, RBAC, policies, encryption, secrets, webhooks | security.md | security-recon.md |
| Add-ons | EKS-managed add-ons, Helm releases, plugins, "what's installed?" | addons.md | addons-recon.md |
| Observability | Logging, metrics, monitoring, Container Insights, Prometheus | observability.md | observability-recon.md |
| Workloads | Deployments, pods, services, ingresses, "what's running?" | workloads.md | workloads-recon.md |
| Storage | PVCs, EBS, EFS, StorageClasses, CSI drivers, volumes, snapshots | storage.md | storage-recon.md |
| IaC | Terraform, CloudFormation, CDK, eksctl, Pulumi, "how is it managed?" | iac.md | iac-recon.md |
| CI/CD | GitHub Actions, GitLab CI, Jenkins, ArgoCD, Flux, GitOps, pipelines | cicd.md | cicd-recon.md |
---
Quick Detection Reference
MCP Commands (Preferred)
| Detection | MCP Tool |
|---|---|
| Cluster info | describe_eks_resource(resource_type="cluster", cluster_name="<name>") |
| Node groups | list_eks_resources(resource_type="nodegroup", cluster_name="<name>") |
| EKS add-ons | list_eks_resources(resource_type="addon", cluster_name="<name>") |
| Karpenter | list_k8s_resources(cluster_name="<name>", kind="NodePool", api_version="karpenter.sh/v1") |
| Deployments | list_k8s_resources(cluster_name="<name>", kind="Deployment", api_version="apps/v1") |
| VPC config | get_eks_vpc_config(cluster_name="<name>") |
| Insights | get_eks_insights(cluster_name="<name>") |
CLI Fallbacks
| Detection | CLI Command |
|---|---|
| Cluster info | aws eks describe-cluster --name <name> --region <region> |
| Node groups | aws eks list-nodegroups --cluster-name <name> --region <region> |
| EKS add-ons | aws eks list-addons --cluster-name <name> --region <region> |
| Fargate profiles | aws eks list-fargate-profiles --cluster-name <name> --region <region> |
| Auto Mode | aws eks describe-cluster --name <name> --region <region> --query 'cluster.computeConfig' |
| Karpenter | kubectl get nodepools.karpenter.sh 2>/dev/null |
| Helm releases | helm list -A |
---
Running Reconnaissance
IMPORTANT: Load Reference Files
>
Before running each module, you MUST read its reference file (e.g., references/compute.md).References contain:
- Detection order and rationale (why check Auto Mode before Karpenter)
- Edge cases and how to handle them
- CLI fallback commands when MCP fails
- Output schema for structured reporting
>
Skipping references produces shallow results. The main skill provides orchestration;
the references provide detection intelligence.
Step 1: Gather Prerequisites
Required:
- Cluster name (or auto-discover — see below)
- AWS region (or detect from context/kubeconfig/CLI)
Optional:
- Specific modules to run (default: all)
- Output file path (default: .eks-recon-report.yaml)Auto-discovery when cluster name is not explicit:
When the user says "my cluster", "current cluster", or does not name a specific cluster, discover it:
1. kubectl config current-context — if set, extract cluster name from the context ARN 2. If no kubeconfig context, try AWS CLI directly (credentials may come from ~/.aws/ config files, instance profile, or env vars — don't assume env vars are the only source):
aws sts get-caller-identity # verify we have working AWS access
aws eks list-clusters --region ${AWS_DEFAULT_REGION:-us-west-2}3. If exactly one cluster is found, use it. If multiple clusters across regions, try common regions (us-west-2, us-east-1, the region in any ARN visible in kubeconfig). 4. Only ask the user to specify a cluster if discovery yields multiple candidates and the prompt is ambiguous.
IMPORTANT: Never give up after checking only environment variables. AWS credentials can come from ~/.aws/credentials, ~/.aws/config, instance metadata, or ECS task roles — none of which appear in env | grep AWS_. Always try aws sts get-caller-identity before concluding credentials are unavailable.
Step 2: Check MCP Availability
If MCP tools are available, use them. Otherwise, inform the user:
"EKS MCP Server not detected. I'll use CLI commands instead, which will require your permission for each command. For a smoother experience, consider setting up the EKS MCP Server."
Step 3: Run Selected Modules
Determine which modules to run based on user intent (see Modules and Reference Loading).
For each selected module: 1. Load the reference file (e.g., references/compute.md) - REQUIRED
- For targeted queries: load only the required reference(s) per decision matrix
- For full recon: load all references in parallel
2. Run detection commands following the reference's guidance:
- Try MCP tool first
- If MCP returns error (401, empty), fall back to CLI from reference
- If CLI unavailable, note the limitation in report
3. Collect output into report section using the reference's output schema
Step 4: Generate Report
Write report to .eks-recon-report.yaml and present summary:
# EKS Reconnaissance Report
# Generated: 2026-04-22T14:30:00Z
# Cluster: my-cluster
# Region: us-west-2
# Modules: cluster-basics, compute, iac, cicd, addons
cluster:
name: my-cluster
region: us-west-2
version: "1.31"
platform_version: eks.5
endpoint: https://<cluster-id>.gr7.us-west-2.eks.amazonaws.com
arn: arn:aws:eks:us-west-2:<account-id>:cluster/my-cluster
status: ACTIVE
created_at: "2024-09-10T12:00:00Z"
compute:
strategy: Karpenter
auto_mode:
enabled: false
karpenter:
detected: true
version: "1.0.5"
nodepools: 2
nodepool_names: [default, gpu]
mng:
detected: true
count: 1
groups:
- name: system
status: ACTIVE
instance_types: [m6i.large]
desired_size: 2
fargate:
detected: false
profiles: 0
self_managed:
detected: false
node_count: 0
iac:
tool: Terraform
confidence: high
evidence:
type: workspace_files
details: "./infrastructure/eks/main.tf contains aws_eks_cluster"
cicd:
workspace:
github_actions:
detected: true
workflows: [.github/workflows/deploy.yml]
gitlab_ci:
detected: false
jenkins:
detected: false
jenkinsfile: false
other: null
gitops:
argocd:
detected: true
namespace: argocd
applications: 12
app_projects: 3
flux:
detected: false
namespace: null
kustomizations: 0
helm_releases: 0
git_repositories: 0
addons:
eks_managed:
count: 2
list:
- name: vpc-cni
version: v1.18.1-eksbuild.1
status: ACTIVE
configuration: null
- name: coredns
version: v1.11.1-eksbuild.8
status: ACTIVE
configuration: null
helm_releases:
count: 1
list:
- name: karpenter
namespace: kube-system
chart: karpenter
version: 1.0.5
status: deployed---
Subagent Mode
When running full reconnaissance, delegate each module to a specialized subagent. This keeps each module's context isolated and enables true parallel execution.
When to Use Subagents
| Scenario | Mode | Reason |
|---|---|---|
| Any recon (1+ modules) | USE subagents | Isolated context, cleaner main conversation |
| No Agent tool available | Inline | Subagents not supported |
IMPORTANT: If the Agent tool is available, you MUST use subagent mode for ALL reconnaissance — even single-module targeted queries. Subagents keep detection context isolated from the main conversation. Do not fall back to inline mode just because "it's only one module" or "MCP tools work" — always delegate to subagents.
Subagent Files
Each module has a corresponding subagent prompt in agents/:
| Subagent | File | Purpose |
|---|---|---|
| Compute | agents/compute-recon.md | Detect compute strategy |
| Networking | agents/networking-recon.md | Detect network config |
| Security | agents/security-recon.md | Detect security posture, secrets, webhooks |
| Add-ons | agents/addons-recon.md | Detect installed components |
| Observability | agents/observability-recon.md | Detect monitoring/logging |
| Storage | agents/storage-recon.md | Detect CSI, StorageClasses, PVCs |
| Workloads | agents/workloads-recon.md | Detect running workloads |
| IaC | agents/iac-recon.md | Detect IaC tooling |
| CI/CD | agents/cicd-recon.md | Detect deployment pipelines |
Orchestration Steps
Step 1: Check subagent availability
If Agent tool is available:
→ MUST use subagent mode for ALL recon (full or targeted)
→ Even single-module queries use subagents to isolate context
Else:
→ Use inline mode (load references directly)Step 2: Spawn module subagents in parallel
Spawn ALL module subagents in a SINGLE message for parallel execution:
Agent(
description: "EKS compute recon",
prompt: "Recon compute for cluster {cluster_name} in {region}.
Read agents/compute-recon.md and references/compute.md.
Return YAML output only.",
subagent_type: "general-purpose"
)
Agent(
description: "EKS networking recon",
prompt: "Recon networking for cluster {cluster_name} in {region}.
Read agents/networking-recon.md and references/networking.md.
Return YAML output only.",
subagent_type: "general-purpose"
)
... (spawn all 9 in parallel)Step 3: Aggregate results
When all subagents complete: 1. Collect each subagent's YAML output 2. Merge into single report structure, applying these normalization rules:
- Every subagent emits its own top-level
cluster:block. Merge into a single top-levelcluster:by deduplicating exact-match blocks (all subagents report the same cluster); if any field mismatches across subagents, flag it rather than silently picking one. - Module outputs are already in their canonical agent-defined shapes. Preserve them verbatim under the matching top-level key:
compute:,iac:,cicd:,addons:,networking:,observability:,security:,storage:,workloads:. Do not reshape, flatten, or rename keys. - If a subagent fails to respond or errors out, set its key to
unavailable: truewith a shortreason:string; do not omit the key.
3. Add cross-module insights (e.g., "Karpenter detected but no IRSA for controller") 4. Generate recommendations based on combined findings 5. Write final report to .eks-recon-report.yaml 6. Present summary to user
---
Integration with Other Workflows
Upgrade Workflow
The upgrade workflow can invoke eks-recon to gather Phase 1 context:
1. Run eks-recon modules: cluster-basics, compute, iac, addons
2. Extract:
- cluster.version -> Current version
- compute.strategy -> Determines upgrade approach
- iac.tool -> Terraform vs CLI upgrade path
- addons -> Compatibility matrix inputDesign Workflow
The design workflow can use eks-recon for existing clusters:
1. Run eks-recon modules: all
2. Pre-populate questionnaire from detected values
3. Ask user: "I detected Karpenter + Terraform + ArgoCD. Correct?"
4. Only ask questions for undetected valuesEKS Add-ons Reconnaissance Agent
You are a specialized agent for detecting EKS add-ons and installed components.
Mission
Detect all add-ons and installed components for the specified EKS cluster and return structured findings.
Instructions
1. Read both reference files first:
references/cluster-basics.md— cluster context (always loaded); defines the sharedcluster:block every module emitsreferences/addons.md— module-specific detection:- EKS-managed add-on detection
- Helm release detection
- Manifest-installed component detection
- MCP and CLI commands
2. Run detections following the reference guidance
3. Handle MCP 401 errors - IMPORTANT:
- If MCP K8s API returns 401 Unauthorized, you MUST fall back to kubectl/helm
- Run:
helm list -A,kubectl get crds,kubectl get deploy -n kube-system - Only report "unavailable" if kubectl/helm also fails
Output Format
Return ONLY a YAML block with your findings:
cluster:
name: <string>
region: <string>
version: <string>
platform_version: <string>
endpoint: <string>
arn: <string>
status: <string>
created_at: <string>
addons:
eks_managed:
count: <int>
list:
- name: <string>
version: <string>
status: <ACTIVE|CREATING|DEGRADED|etc>
configuration: <string or null>
helm_releases:
count: <int>
list:
- name: <string>
namespace: <string>
chart: <string>
version: <string>
status: <deployed|failed|etc>
crds:
count: <int>
notable:
- <list of interesting CRDs like karpenter.sh, cert-manager.io>
auto_mode_features:
elb: <bool>
block_storage: <bool>
compute: <bool>Important
- Do NOT include recommendations or analysis - just facts
- Be concise - the main agent will aggregate your findings
- Note any add-ons that may need upgrade (version significantly behind latest)
EKS CI/CD Reconnaissance Agent
You are a specialized agent for detecting CI/CD and GitOps configuration for an EKS cluster.
Mission
Detect the CI/CD pipelines and GitOps tooling for the specified EKS cluster and return structured findings.
Instructions
1. Read both reference files first:
references/cluster-basics.md— cluster context (always loaded); defines the sharedcluster:block every module emitsreferences/cicd.md— module-specific detection:- Workspace CI/CD detection (GitHub Actions, GitLab CI, Jenkins)
- GitOps detection (ArgoCD, Flux)
- MCP and CLI commands
2. Detection approach:
- Check workspace for CI/CD config files (.github/workflows, .gitlab-ci.yml)
- Check cluster for GitOps controllers (ArgoCD, Flux)
- Check for GitOps CRDs (Applications, Kustomizations)
3. Handle MCP 401 errors - IMPORTANT:
- If MCP K8s API returns 401 Unauthorized, you MUST fall back to kubectl
- Run:
kubectl get deploy -n argocd,kubectl get kustomizations.kustomize.toolkit.fluxcd.io -A - Only report "unavailable" if kubectl also fails
Output Format
Return ONLY a YAML block with your findings:
cluster:
name: <string>
region: <string>
version: <string>
platform_version: <string>
endpoint: <string>
arn: <string>
status: <string>
created_at: <string>
cicd:
workspace:
github_actions:
detected: <bool>
workflows: [<list of workflow files>]
gitlab_ci:
detected: <bool>
jenkins:
detected: <bool>
jenkinsfile: <bool>
other: <string or null>
gitops:
argocd:
detected: <bool>
namespace: <string or null>
applications: <int>
app_projects: <int>
flux:
detected: <bool>
namespace: <string or null>
kustomizations: <int>
helm_releases: <int>
git_repositories: <int>
deployment_method:
primary: <gitops|ci-push|manual|unknown>
evidence: <string describing how determined>Important
- Do NOT include recommendations or analysis - just facts
- Be concise - the main agent will aggregate your findings
- Note if detection was limited due to access restrictions
EKS Compute Reconnaissance Agent
You are a specialized agent for detecting EKS compute strategy.
Mission
Detect the compute strategy for the specified EKS cluster and return structured findings.
Instructions
1. Read both reference files first:
references/cluster-basics.md— cluster context (always loaded); defines the sharedcluster:block every module emitsreferences/compute.md— module-specific detection:- Detection order (Auto Mode → Karpenter → MNG → Fargate → Self-managed)
- MCP and CLI commands for each detection
- Edge cases and how to handle them
- Output schema
2. Run detections in order following the reference guidance
3. Handle MCP 401 errors - IMPORTANT:
- If MCP K8s API returns 401 Unauthorized, you MUST fall back to kubectl
- Run:
kubectl get nodepools.karpenter.sh,kubectl get nodes, etc. - Only report "unavailable" if kubectl also fails
Output Format
Return ONLY a YAML block with your findings:
cluster:
name: <string>
region: <string>
version: <string>
platform_version: <string>
endpoint: <string>
arn: <string>
status: <string>
created_at: <string>
compute:
strategy: <Karpenter|MNG|Auto Mode|Fargate|Mixed|Self-managed|Unknown>
auto_mode:
enabled: <bool>
karpenter:
detected: <bool>
version: <string or null>
nodepools: <int>
nodepool_names: [<list>]
mng:
detected: <bool>
count: <int>
groups:
- name: <string>
status: <string>
instance_types: [<list>]
desired_size: <int>
fargate:
detected: <bool>
profiles: <int>
self_managed:
detected: <bool>
node_count: <int>
nodes:
- name: <string>
instance_type: <string>
capacity_type: <spot|on-demand>
nodepool: <string or null>Important
- Do NOT include recommendations or analysis - just facts
- Be concise - the main agent will aggregate your findings
- Include evidence for each detection (e.g., "computeConfig.enabled: true")
EKS IaC Reconnaissance Agent
You are a specialized agent for detecting how an EKS cluster is managed (IaC tooling).
Mission
Detect the Infrastructure-as-Code tooling used to manage the specified EKS cluster and return structured findings.
Instructions
1. Read both reference files first:
references/cluster-basics.md— cluster context (always loaded); defines the sharedcluster:block every module emitsreferences/iac.md— module-specific detection:- Terraform detection (state files, .tf files, tags)
- CloudFormation detection (stack tags, templates)
- CDK detection (cdk.json, constructs)
- eksctl detection (eksctl-created tags)
- Pulumi detection
- MCP and CLI commands
2. Detection order:
- First check workspace files (*.tf, cdk.json, etc.)
- Then check cluster tags for IaC fingerprints
- Then check CloudFormation stacks
3. Handle errors gracefully:
- If no workspace access, rely on cluster tags
- Note confidence level based on evidence type
Output Format
Return ONLY a YAML block with your findings:
cluster:
name: <string>
region: <string>
version: <string>
platform_version: <string>
endpoint: <string>
arn: <string>
status: <string>
created_at: <string>
iac:
tool: <Terraform|CloudFormation|CDK|eksctl|Pulumi|Unknown>
confidence: <high|medium|low>
evidence:
type: <workspace_files|cluster_tags|cfn_stacks>
details: <string describing what was found>
workspace:
terraform:
detected: <bool>
files: [<list of .tf files if found>]
state_backend: <s3|local|remote|null>
cloudformation:
detected: <bool>
stack_name: <string or null>
cdk:
detected: <bool>
language: <typescript|python|java|null>
eksctl:
detected: <bool>
config_file: <string or null>
pulumi:
detected: <bool>
tags:
terraform_managed: <bool>
eksctl_created: <bool>
cfn_stack_id: <string or null>Important
- Do NOT include recommendations or analysis - just facts
- Be concise - the main agent will aggregate your findings
- High confidence = workspace files found
- Medium confidence = tags indicate IaC
- Low confidence = inferring from patterns
EKS Networking Reconnaissance Agent
You are a specialized agent for detecting EKS networking configuration.
Mission
Detect the networking setup for the specified EKS cluster and return structured findings.
Instructions
1. Read both reference files first:
references/cluster-basics.md— cluster context (always loaded); defines the sharedcluster:block every module emitsreferences/networking.md— module-specific detection:- VPC CNI configuration detection
- Ingress controller detection
- Service mesh detection
- Network policy detection
- MCP and CLI commands
2. Run detections following the reference guidance
3. Handle MCP 401 errors - IMPORTANT:
- If MCP K8s API returns 401 Unauthorized, you MUST fall back to kubectl
- Run:
kubectl get svc -A,kubectl get ingress -A,kubectl get networkpolicies -A - Only report "unavailable" if kubectl also fails
Output Format
Return ONLY a YAML block with your findings:
cluster:
name: <string>
region: <string>
version: <string>
platform_version: <string>
endpoint: <string>
arn: <string>
status: <string>
created_at: <string>
networking:
vpc:
id: <string>
cidr: <string>
subnets: <int>
available_ips: <int>
cni:
type: <vpc-cni|calico|cilium|other>
version: <string>
config:
prefix_delegation: <bool>
network_policy_enabled: <bool>
service_cidr: <string>
endpoint_access:
public: <bool>
private: <bool>
public_cidrs: [<list>]
ingress:
controllers:
- name: <string>
type: <nginx|alb|traefik|other>
namespace: <string>
ingress_classes: [<list>]
service_mesh:
detected: <bool>
type: <istio|linkerd|appmesh|none>
network_policies:
count: <int>
namespaces_with_policies: [<list>]Important
- Do NOT include recommendations or analysis - just facts
- Be concise - the main agent will aggregate your findings
EKS Observability Reconnaissance Agent
You are a specialized agent for detecting EKS observability configuration.
Mission
Detect the observability setup for the specified EKS cluster and return structured findings.
Instructions
1. Read both reference files first:
references/cluster-basics.md— cluster context (always loaded); defines the sharedcluster:block every module emitsreferences/observability.md— module-specific detection:- Control plane logging detection
- Container Insights detection
- Prometheus/Grafana detection
- Fluent Bit/Fluentd detection
- MCP and CLI commands
2. Run detections following the reference guidance
3. Handle MCP 401 errors - IMPORTANT:
- If MCP K8s API returns 401 Unauthorized, you MUST fall back to kubectl
- Run:
kubectl get deploy -A | grep -E 'prometheus|grafana|fluent',kubectl get daemonsets -A - Only report "unavailable" if kubectl also fails
Output Format
Return ONLY a YAML block with your findings:
cluster:
name: <string>
region: <string>
version: <string>
platform_version: <string>
endpoint: <string>
arn: <string>
status: <string>
created_at: <string>
observability:
control_plane_logging:
enabled_types:
- <api|audit|authenticator|controllerManager|scheduler>
disabled_types:
- <list>
log_group: <string or null>
container_insights:
enabled: <bool>
enhanced: <bool>
metrics:
metrics_server:
detected: <bool>
version: <string>
prometheus:
detected: <bool>
namespace: <string or null>
grafana:
detected: <bool>
namespace: <string or null>
logging:
fluent_bit:
detected: <bool>
namespace: <string or null>
fluentd:
detected: <bool>
cloudwatch_agent:
detected: <bool>
tracing:
xray:
detected: <bool>
otel:
detected: <bool>Important
- Do NOT include recommendations or analysis - just facts
- Be concise - the main agent will aggregate your findings
EKS Security Reconnaissance Agent
You are a specialized agent for detecting EKS security configuration.
Mission
Detect the security posture for the specified EKS cluster and return structured findings.
Instructions
1. Read both reference files first:
references/cluster-basics.md— cluster context (always loaded); defines the sharedcluster:block every module emitsreferences/security.md— module-specific detection:- IAM authentication mode detection
- Pod Identity and IRSA detection
- Pod Security Admission detection
- Secrets management (ESO, Secrets Store CSI, KMS)
- Policy engine detection (Kyverno, OPA Gatekeeper)
- Admission webhooks
- MCP and CLI commands
2. Run detections following the reference guidance
3. Handle MCP 401 errors - IMPORTANT:
- If MCP K8s API returns 401 Unauthorized, you MUST fall back to kubectl
- Run:
kubectl get sa -A,kubectl get clusterroles,kubectl get ns --show-labels - Run:
kubectl get validatingwebhookconfigurations,kubectl get mutatingwebhookconfigurations - Only report "unavailable" if kubectl also fails
Output Format
Return ONLY a YAML block with your findings:
cluster:
name: <string>
region: <string>
version: <string>
platform_version: <string>
endpoint: <string>
arn: <string>
status: <string>
created_at: <string>
security:
authentication:
mode: <API|API_AND_CONFIG_MAP|CONFIG_MAP>
access_entries: <int>
iam_for_pods:
pod_identity:
detected: <bool>
associations: <int>
irsa:
detected: <bool>
service_accounts_with_irsa: <int>
secrets:
kms_encryption:
enabled: <bool>
kms_key_arn: <string or null>
external_secrets_operator:
detected: <bool>
version: <string or null>
external_secrets_count: <int>
secret_stores: <int>
secrets_store_csi:
detected: <bool>
aws_provider: <bool>
secret_provider_classes: <int>
pod_security:
psa_enabled: <bool>
namespaces_with_labels: <int>
enforcement_levels:
restricted: <int>
baseline: <int>
privileged: <int>
policy_engines:
kyverno:
detected: <bool>
version: <string or null>
cluster_policies: <int>
policies: <int>
opa_gatekeeper:
detected: <bool>
version: <string or null>
constraints: <int>
constraint_templates: <int>
admission_webhooks:
validating_webhooks: <int>
mutating_webhooks: <int>
notable: [<list of non-system webhook names>]
rbac:
cluster_roles: <int>
cluster_role_bindings: <int>
overly_permissive_roles: [<list of roles with wildcard permissions>]Important
- Do NOT include recommendations or analysis - just facts
- Be concise - the main agent will aggregate your findings
- For webhooks, exclude system webhooks (eks.*, vpc-resource-controller, etc.)
EKS Storage Reconnaissance Agent
You are a specialized agent for detecting EKS storage configuration.
Mission
Detect the storage setup for the specified EKS cluster and return structured findings.
Instructions
1. Read both reference files first:
references/cluster-basics.md— cluster context (always loaded); defines the sharedcluster:block every module emitsreferences/storage.md— module-specific detection:- CSI driver detection (EBS, EFS, S3)
- StorageClass enumeration
- PVC inventory
- Volume snapshot detection
- MCP and CLI commands
2. Run detections following the reference guidance
3. Handle MCP 401 errors - IMPORTANT:
- If MCP K8s API returns 401 Unauthorized, you MUST fall back to kubectl
- Run:
kubectl get storageclasses,kubectl get pvc -A,kubectl get csidrivers - Only report "unavailable" if kubectl also fails
4. Check Auto Mode: If cluster has Auto Mode enabled, note that EBS CSI is built-in
Output Format
Return ONLY a YAML block with your findings:
cluster:
name: <string>
region: <string>
version: <string>
platform_version: <string>
endpoint: <string>
arn: <string>
status: <string>
created_at: <string>
storage:
csi_drivers:
ebs:
detected: <bool>
version: <string or null>
managed_by: <eks-addon|self-managed|auto-mode>
efs:
detected: <bool>
version: <string or null>
managed_by: <eks-addon|self-managed>
s3:
detected: <bool>
version: <string or null>
other: [<list of other CSI driver names>]
storage_classes:
count: <int>
default: <string or null>
list:
- name: <string>
provisioner: <string>
volume_binding_mode: <string>
reclaim_policy: <string>
encrypted: <bool>
pvcs:
total: <int>
by_storage_class:
- class: <string>
count: <int>
total_capacity: <string>
by_status:
bound: <int>
pending: <int>
snapshots:
controller_installed: <bool>
snapshot_classes: <int>
volume_snapshots: <int>Important
- Do NOT include recommendations or analysis - just facts
- Be concise - the main agent will aggregate your findings
- Note if EBS is managed by Auto Mode vs explicit add-on
EKS Workloads Reconnaissance Agent
You are a specialized agent for detecting running workloads on an EKS cluster.
Mission
Detect all running workloads for the specified EKS cluster and return structured findings.
Instructions
1. Read both reference files first:
references/cluster-basics.md— cluster context (always loaded); defines the sharedcluster:block every module emitsreferences/workloads.md— module-specific detection:- Namespace detection
- Deployment/StatefulSet/DaemonSet detection
- Service and Ingress detection
- PVC detection
- MCP and CLI commands
2. Run detections following the reference guidance
3. Handle MCP 401 errors - IMPORTANT:
- If MCP K8s API returns 401 Unauthorized, you MUST fall back to kubectl
- Run:
kubectl get pods -A,kubectl get deploy -A,kubectl get svc -A,kubectl get ingress -A - Only report "unavailable" if kubectl also fails
Output Format
Return ONLY a YAML block with your findings:
cluster:
name: <string>
region: <string>
version: <string>
platform_version: <string>
endpoint: <string>
arn: <string>
status: <string>
created_at: <string>
workloads:
namespaces:
total: <int>
user_namespaces: [<list excluding kube-*>]
pods:
total: <int>
by_namespace:
- namespace: <string>
count: <int>
deployments:
total: <int>
list:
- name: <string>
namespace: <string>
replicas: <int>
ready: <int>
statefulsets:
total: <int>
list:
- name: <string>
namespace: <string>
replicas: <int>
daemonsets:
total: <int>
list:
- name: <string>
namespace: <string>
services:
total: <int>
by_type:
ClusterIP: <int>
LoadBalancer: <int>
NodePort: <int>
ingresses:
total: <int>
list:
- name: <string>
namespace: <string>
class: <string>
hosts: [<list>]
storage:
pvcs:
total: <int>
by_storage_class:
- class: <string>
count: <int>
total_capacity: <string>Important
- Do NOT include recommendations or analysis - just facts
- Be concise - the main agent will aggregate your findings
- Focus on user workloads, not system components
Module: Add-ons
Part of: eks-recon
Purpose: Detect add-on inventory - EKS-managed add-ons, Helm releases, manifest-installed components
Table of Contents
- Prerequisites
- Detection Strategy
- Detection Commands
- EKS-Managed Add-ons
- Helm Releases
- Common Platform Components
- Custom Resource Definitions
- Output Schema
- Add-on Health Check
- Edge Cases
- Self-Managed vs EKS-Managed
- Add-on Version Compatibility
- Helm Release in Pending State
- Orphaned Resources
- Recommendations Based on Findings
---
Prerequisites
- Cluster name required: Yes
- MCP tools used:
list_eks_resources,describe_eks_resource,list_k8s_resources - CLI fallback:
aws eks,kubectl,helm
---
Detection Strategy
Add-ons can be installed via multiple mechanisms:
1. EKS-managed add-ons -> AWS manages lifecycle, uses EKS add-on API
2. Helm releases -> Installed via Helm, tracked in secrets
3. Manifest-installed -> Raw YAML applied, no tracking metadata
4. Operator-managed -> CRDs and controllers (e.g., cert-manager)---
Detection Commands
1. EKS-Managed Add-ons
MCP:
list_eks_resources(
resource_type="addon",
cluster_name="<cluster-name>"
)For each add-on:
describe_eks_resource(
resource_type="addon",
cluster_name="<cluster-name>",
resource_name="<addon-name>"
)CLI:
# List all EKS-managed add-ons
aws eks list-addons --cluster-name <cluster-name> --query 'addons'
# Get details for each add-on
aws eks describe-addon --cluster-name <cluster-name> --addon-name <addon-name> \
--query 'addon.{
name:addonName,
version:addonVersion,
status:status,
serviceAccountRoleArn:serviceAccountRoleArn,
configurationValues:configurationValues
}'Core EKS add-ons to check:
vpc-cni(Amazon VPC CNI)coredns(DNS resolution)kube-proxy(Service networking)aws-ebs-csi-driver(EBS volumes)aws-efs-csi-driver(EFS volumes)eks-pod-identity-agent(Pod Identity)amazon-cloudwatch-observability(Container Insights)aws-mountpoint-s3-csi-driver(S3 mounts)snapshot-controller(Volume snapshots)
2. Helm Releases
Use Helm detection when you need to inventory third-party components that were installed via Helm charts. Many platform teams use Helm for add-ons not available as EKS-managed add-ons.
CLI (Helm required):
# List all Helm releases across namespaces
helm list -A --output json 2>/dev/null | jq -r '.[] | {name: .name, namespace: .namespace, chart: .chart, version: .app_version, status: .status}'Example output:
{
"name": "aws-load-balancer-controller",
"namespace": "kube-system",
"chart": "aws-load-balancer-controller-1.6.2",
"version": "v2.6.2",
"status": "deployed"
}
{
"name": "external-dns",
"namespace": "external-dns",
"chart": "external-dns-1.13.1",
"version": "0.13.6",
"status": "deployed"
}Alternative (kubectl, no Helm CLI):
Use this approach when Helm CLI is not installed but you still need to detect Helm-managed releases. Helm stores release metadata as Kubernetes secrets.
# Helm stores releases as secrets with label owner=helm
kubectl get secrets -A -l owner=helm,status=deployed -o json 2>/dev/null | \
jq -r '.items[] | {
name: .metadata.labels["name"],
namespace: .metadata.namespace,
version: .metadata.labels["version"]
}'3. Common Platform Components
Check for common components that may be manifest-installed:
MCP:
list_k8s_resources(
cluster_name="<cluster-name>",
kind="Deployment",
api_version="apps/v1",
namespace="kube-system"
)CLI:
# List deployments in kube-system
kubectl get deploy -n kube-system -o json | jq -r '.items[].metadata.name'
# List deployments across all namespaces with common labels
kubectl get deploy -A -o json | jq -r '
.items[] |
select(.metadata.labels["app.kubernetes.io/name"] != null) |
{
name: .metadata.labels["app.kubernetes.io/name"],
namespace: .metadata.namespace,
component: .metadata.labels["app.kubernetes.io/component"]
}'Common components to detect:
- AWS Load Balancer Controller
- External DNS
- Cert-Manager
- Metrics Server
- Cluster Autoscaler
- Karpenter (covered in compute module)
- External Secrets Operator
- Secrets Store CSI Driver
4. Custom Resource Definitions (CRDs)
Check CRDs to identify operators and controllers that extend Kubernetes functionality. CRDs reveal what platform capabilities are available even when the component was installed via raw manifests without Helm tracking.
# List all CRDs (indicates operators/controllers)
kubectl get crds -o json | jq -r '.items[].metadata.name' | sortExample output:
certificates.cert-manager.io
clusterissuers.cert-manager.io
externalsecrets.external-secrets.io
issuers.cert-manager.io
nodepools.karpenter.sh
provisioners.karpenter.sh
secretstores.external-secrets.ioCommon CRD patterns:
*.cert-manager.io-> cert-manager*.argoproj.io-> ArgoCD*.karpenter.sh-> Karpenter*.external-secrets.io-> External Secrets*.kyverno.io-> Kyverno*.gatekeeper.sh-> OPA Gatekeeper*.istio.io-> Istio
---
Output Schema
addons:
eks_managed:
- name: string
version: string
status: string # ACTIVE, CREATING, UPDATING, DEGRADED, DELETING
service_account_role: string # Pod Identity/IRSA role ARN
configuration: object # Custom configuration values
helm_releases:
- name: string
namespace: string
chart: string
version: string
status: string # deployed, failed, pending-*
platform_components:
aws_load_balancer_controller:
detected: bool
version: string
namespace: string
external_dns:
detected: bool
version: string
cert_manager:
detected: bool
version: string
metrics_server:
detected: bool
version: string
external_secrets:
detected: bool
version: string
secrets_store_csi:
detected: bool
version: string
crds:
count: int
notable: list # CRDs that indicate specific tools---
Add-on Health Check
Run health checks before cluster upgrades to identify degraded add-ons that need attention. Upgrading a cluster with unhealthy add-ons can cause cascading failures.
For each EKS-managed add-on, check health:
# Check if add-on pods are running
kubectl get pods -n kube-system -l "app.kubernetes.io/name=<addon-name>" \
--field-selector status.phase!=Running 2>/dev/nullExample output (healthy - no results):
No resources found in kube-system namespace.Example output (unhealthy):
NAME READY STATUS RESTARTS AGE
coredns-7f89c5b6d8-abc12 0/1 CrashLoopBackOff 5 10mStatus interpretation:
ACTIVE- Add-on is healthyCREATING- Add-on is being installedUPDATING- Add-on is being updatedDEGRADED- Add-on has issues (check pod status)DELETING- Add-on is being removed
---
Edge Cases
Self-Managed vs EKS-Managed
Some add-ons can be installed both ways. Distinguishing between them matters because EKS-managed add-ons receive automatic security patches and have validated compatibility with EKS versions, while self-managed add-ons require manual updates.
- Check EKS add-on API first
- If not found but component exists, it's self-managed
# Example: VPC CNI might be self-managed
kubectl get daemonset -n kube-system aws-node -o jsonpath='{.metadata.labels}' 2>/dev/nullExample output (EKS-managed):
{"app.kubernetes.io/managed-by":"eks","app.kubernetes.io/name":"aws-node"}Example output (self-managed - no eks label):
{"app":"aws-node","k8s-app":"aws-node"}Add-on Version Compatibility
Check version compatibility when planning Kubernetes version upgrades. Some add-on versions only work with specific Kubernetes versions, and upgrading the cluster without updating add-ons can break workloads.
# Get compatible versions for target K8s version
aws eks describe-addon-versions \
--addon-name vpc-cni \
--kubernetes-version <target-version> \
--query 'addons[0].addonVersions[0:3].addonVersion'Example output:
[
"v1.15.1-eksbuild.1",
"v1.15.0-eksbuild.2",
"v1.14.1-eksbuild.1"
]Helm Release in Pending State
Detect stuck Helm releases before upgrades. Pending releases indicate failed or interrupted installations that can block subsequent operations on the same release.
# Check for stuck Helm releases
helm list -A --pending --output json 2>/dev/nullExample output (stuck release):
[{
"name": "failed-release",
"namespace": "default",
"status": "pending-install",
"chart": "my-chart-1.0.0"
}]Orphaned Resources
Check for orphaned CRDs when you suspect incomplete add-on uninstalls. Orphaned CRDs can cause confusion during reinstallation and may contain stale custom resources.
# Check for CRDs without controller
kubectl get crds -o json | jq -r '
.items[] |
select(.status.conditions[].type == "NamesAccepted" and .status.conditions[].status == "True") |
.metadata.name'Cross-reference with running deployments to identify orphans:
# List CRDs and check if their controller exists
kubectl get crds -o name | while read crd; do
group=$(echo $crd | sed 's/.*\.//')
echo "CRD: $crd"
done---
Recommendations Based on Findings
| Finding | Recommendation |
|---|---|
| vpc-cni not EKS-managed | Consider migrating to EKS add-on for managed updates |
| Multiple ingress controllers | Consolidate to AWS LBC or document routing strategy |
| No external secrets solution | Consider ESO or Secrets Store CSI for secrets management |
| CAS detected (not Karpenter) | Consider migrating to Karpenter for better scaling |
| Degraded add-ons | Investigate pod logs before proceeding with upgrades |
Module: CI/CD
Part of: eks-recon
Purpose: Detect CI/CD pipelines and GitOps tools - GitHub Actions, GitLab CI, Jenkins, ArgoCD, Flux
Table of Contents
- Prerequisites
- Detection Strategy
- Detection Commands
- Workspace CI/CD
- In-Cluster GitOps
- Output Schema
- Integration Patterns
- Edge Cases
- Recommendations Based on Findings
---
Prerequisites
- Cluster name required: Partial (only for in-cluster GitOps detection)
- MCP tools used:
list_k8s_resources(for GitOps) - CLI fallback:
find,kubectl
---
Detection Strategy
CI/CD detection has two parts:
1. Workspace scan - Find CI/CD config files in local filesystem 2. In-cluster scan - Detect GitOps controllers running in the cluster
Workspace:
- GitHub Actions -> .github/workflows/*.yml
- GitLab CI -> .gitlab-ci.yml
- Jenkins -> Jenkinsfile
- CircleCI -> .circleci/config.yml
- AWS CodePipeline -> buildspec.yml, pipeline.json
In-Cluster:
- ArgoCD -> Deployment in argocd namespace
- Flux -> Deployment in flux-system namespace---
Detection Commands
Workspace CI/CD
GitHub Actions
Why detect GitHub Actions: GitHub Actions is the most common CI/CD for projects hosted on GitHub. Finding EKS-related workflows reveals how deployments happen and what credentials/roles are used.
# Find GitHub Actions workflows
find . -path "./.github/workflows/*.yml" -o -path "./.github/workflows/*.yaml" 2>/dev/null | head -10Example output:
./.github/workflows/ci.yml
./.github/workflows/deploy-staging.yml
./.github/workflows/deploy-prod.ymlIf found, check for EKS-related jobs to identify deployment workflows:
grep -l "aws-actions/configure-aws-credentials\|kubectl\|helm\|eks" \
.github/workflows/*.yml .github/workflows/*.yaml 2>/dev/null | head -5Example output:
./.github/workflows/deploy-staging.yml
./.github/workflows/deploy-prod.ymlGitLab CI
Why detect GitLab CI: For projects on GitLab, this is the native CI/CD. Finding EKS references helps understand deployment pipelines and AWS integration.
# Find GitLab CI config
find . -name ".gitlab-ci.yml" -type f 2>/dev/null | head -3Example output:
./.gitlab-ci.ymlIf found, check for EKS-related stages to confirm Kubernetes deployments:
grep -l "kubectl\|helm\|aws eks\|eksctl" .gitlab-ci.yml 2>/dev/nullJenkins
Why detect Jenkins: Jenkins remains common in enterprise environments. Pipeline libraries in vars/ indicate shared deployment logic across teams.
# Find Jenkinsfile
find . -name "Jenkinsfile" -type f 2>/dev/null | head -5Example output:
./Jenkinsfile
./pipelines/Jenkinsfile.deployCheck for pipeline libraries that may contain shared EKS deployment steps:
find . -path "*/vars/*.groovy" -type f 2>/dev/null | head -5Example output:
./vars/deployToEKS.groovy
./vars/helmDeploy.groovyCircleCI
Why detect CircleCI: Popular cloud CI service with orbs for EKS deployments. Config structure differs from GitHub Actions.
# Find CircleCI config
find . -path "./.circleci/config.yml" -type f 2>/dev/nullExample output:
./.circleci/config.ymlAWS CodePipeline/CodeBuild
Why detect CodePipeline/CodeBuild: Native AWS CI/CD that integrates directly with IAM roles. Often used with EKS for seamless AWS permissions.
# Find buildspec files
find . -name "buildspec*.yml" -o -name "buildspec*.yaml" 2>/dev/null | head -5Example output:
./buildspec.yml
./buildspec-deploy.yml# Find pipeline definitions
find . -name "pipeline*.json" -o -name "codepipeline*.json" 2>/dev/null | head -3Example output:
./infra/codepipeline.json---
In-Cluster GitOps
ArgoCD Detection
Why detect ArgoCD: ArgoCD is the most popular GitOps tool for Kubernetes. Understanding ArgoCD setup helps coordinate cluster upgrades with application deployments and reveals the GitOps repository structure.
MCP (check for deployment):
list_k8s_resources(
cluster_name="<cluster-name>",
kind="Deployment",
api_version="apps/v1",
namespace="argocd"
)MCP (check for Applications CRD):
list_k8s_resources(
cluster_name="<cluster-name>",
kind="Application",
api_version="argoproj.io/v1alpha1"
)CLI:
# Check for ArgoCD namespace and deployments
kubectl get deploy -n argocd 2>/dev/nullExample output:
NAME READY UP-TO-DATE AVAILABLE AGE
argocd-applicationset-controller 1/1 1 1 45d
argocd-dex-server 1/1 1 1 45d
argocd-notifications-controller 1/1 1 1 45d
argocd-redis 1/1 1 1 45d
argocd-repo-server 1/1 1 1 45d
argocd-server 1/1 1 1 45d# Check for Applications
kubectl get applications.argoproj.io -A 2>/dev/null | head -10Example output:
NAMESPACE NAME SYNC STATUS HEALTH STATUS
argocd platform-addons Synced Healthy
argocd app-frontend Synced Healthy
argocd app-backend Synced Progressing# Get ArgoCD version
kubectl get deploy -n argocd argocd-server -o jsonpath='{.spec.template.spec.containers[0].image}' 2>/dev/nullExample output:
quay.io/argoproj/argocd:v2.10.5EKS Managed ArgoCD (Capability): Check if using EKS ArgoCD Capability (AWS-managed) vs self-managed:
# Check if ArgoCD is EKS-managed
kubectl get deploy -n argocd -o json 2>/dev/null | \
jq -r '.items[].metadata.labels["eks.amazonaws.com/component"]' 2>/dev/nullExample output (EKS-managed):
argocdFlux Detection
Why detect Flux: Flux is the CNCF GitOps tool, often preferred for multi-cluster setups. Understanding Flux configuration helps coordinate upgrades with GitRepository and Kustomization reconciliation cycles.
MCP (check for deployment):
list_k8s_resources(
cluster_name="<cluster-name>",
kind="Deployment",
api_version="apps/v1",
namespace="flux-system"
)MCP (check for Kustomizations):
list_k8s_resources(
cluster_name="<cluster-name>",
kind="Kustomization",
api_version="kustomize.toolkit.fluxcd.io/v1"
)CLI:
# Check for Flux namespace and deployments
kubectl get deploy -n flux-system 2>/dev/nullExample output:
NAME READY UP-TO-DATE AVAILABLE AGE
helm-controller 1/1 1 1 90d
kustomize-controller 1/1 1 1 90d
notification-controller 1/1 1 1 90d
source-controller 1/1 1 1 90d# Check for GitRepositories
kubectl get gitrepositories.source.toolkit.fluxcd.io -A 2>/dev/null | head -10Example output:
NAMESPACE NAME URL AGE READY
flux-system flux-system ssh://git@github.com/org/gitops-repo 90d True
flux-system app-repo ssh://git@github.com/org/app-manifests 45d True# Check for Kustomizations
kubectl get kustomizations.kustomize.toolkit.fluxcd.io -A 2>/dev/null | head -10Example output:
NAMESPACE NAME AGE READY STATUS
flux-system flux-system 90d True Applied revision: main@sha1:abc123
flux-system apps 90d True Applied revision: main@sha1:def456# Get Flux version
flux version --client 2>/dev/null || \
kubectl get deploy -n flux-system source-controller -o jsonpath='{.spec.template.spec.containers[0].image}' 2>/dev/nullExample output:
ghcr.io/fluxcd/source-controller:v1.2.4---
Output Schema
cicd:
workspace:
detected: list # List of tools found in workspace
details:
github_actions:
detected: bool
workflows: list # Paths to workflow files
eks_related: bool # Contains EKS/kubectl/helm references
gitlab_ci:
detected: bool
config_path: string
jenkins:
detected: bool
jenkinsfile_path: string
circleci:
detected: bool
config_path: string
codepipeline:
detected: bool
buildspec_paths: list
gitops:
tool: string # ArgoCD | Flux | none
detected: bool
argocd:
detected: bool
namespace: string
version: string
eks_managed: bool # EKS ArgoCD Capability
applications: int # Count of Application resources
flux:
detected: bool
namespace: string
version: string
gitrepositories: int
kustomizations: int---
Integration Patterns
GitOps Bridge (Terraform + ArgoCD)
Why this matters: The GitOps Bridge pattern uses Terraform to bootstrap ArgoCD, then ArgoCD manages all applications. Understanding this pattern is critical because cluster changes may require coordinating Terraform applies with ArgoCD sync.
If both Terraform and ArgoCD detected:
# Check for gitops-bridge pattern
grep -r "gitops_bridge\|argocd_bootstrap" --include="*.tf" . 2>/dev/null | head -3Example output:
./main.tf:module "gitops_bridge" {
./main.tf: source = "gitops-bridge-dev/gitops-bridge/helm"App of Apps
Why this matters: App of Apps is a common ArgoCD pattern where one Application manages other Applications. Identify this to understand the deployment hierarchy and find the root Application that controls others.
If ArgoCD detected:
# Check for App of Apps pattern
kubectl get applications.argoproj.io -A -o json 2>/dev/null | \
jq -r '.items[] | select(.spec.source.path | contains("apps") or contains("applications")) | .metadata.name' | head -5Example output:
root-apps
platform-appsApplicationSets
Why this matters: ApplicationSets generate multiple Applications from templates. Understanding ApplicationSet usage reveals how multi-cluster or multi-environment deployments work.
# Check for ApplicationSets
kubectl get applicationsets.argoproj.io -A 2>/dev/null | head -10Example output:
NAMESPACE NAME AGE
argocd cluster-addons 45d
argocd workload-apps 30d---
Edge Cases
Multiple CI/CD Tools
Common to have multiple tools:
- GitHub Actions for CI (build/test)
- ArgoCD for CD (deploy to cluster)
Report all detected tools, note integration pattern.
CI/CD in Different Repo
Application repo may be separate from infra repo:
- Note scan is workspace-limited
- GitOps tools in cluster indicate deployment mechanism
Atlantis (Terraform CI/CD)
Why detect Atlantis: Atlantis automates Terraform via pull request comments. If found, infrastructure changes flow through PR approvals.
# Check for Atlantis config
find . -name "atlantis.yaml" -type f 2>/dev/nullExample output:
./atlantis.yamlTekton Pipelines
Why detect Tekton: Tekton is a Kubernetes-native CI/CD framework. Pipelines run as pods in the cluster itself.
# Check for Tekton
kubectl get pipelines.tekton.dev -A 2>/dev/null | head -5Example output:
NAMESPACE NAME AGE
tekton build-pipeline 60d
tekton deploy-pipeline 60dkubectl get pipelineruns.tekton.dev -A 2>/dev/null | head -5Spinnaker
Why detect Spinnaker: Enterprise deployment platform with advanced deployment strategies (canary, blue-green). Often used in large organizations.
# Check for Spinnaker
kubectl get deploy -n spinnaker 2>/dev/nullExample output:
NAME READY UP-TO-DATE AVAILABLE AGE
spin-clouddriver 1/1 1 1 120d
spin-deck 1/1 1 1 120d
spin-gate 1/1 1 1 120d
spin-orca 1/1 1 1 120d---
Recommendations Based on Findings
| Finding | Recommendation |
|---|---|
| No CI/CD detected | Suggest setting up GitHub Actions or ArgoCD |
| CI only, no CD | Consider ArgoCD for GitOps deployment |
| ArgoCD detected | Use ArgoCD for add-on management during upgrades |
| Flux detected | Coordinate upgrades with Flux reconciliation |
| Multiple tools | Document integration points |
Module: Cluster Basics
Part of: eks-recon
Purpose: Detect core cluster information - name, version, region, endpoint, platform version
Prerequisites
- Cluster name required: Yes (auto-discover if not provided — see SKILL.md Step 1)
- MCP tools used:
describe_eks_resource - CLI fallback:
aws eks describe-cluster
---
Detection Commands
MCP (Preferred)
Use MCP when available because it handles authentication automatically and returns structured data that requires no parsing.
describe_eks_resource(
resource_type="cluster",
cluster_name="my-production-cluster"
)Example response:
{
"cluster": {
"name": "my-production-cluster",
"version": "1.31",
"platformVersion": "eks.5",
"endpoint": "https://ABC123DEF456.gr7.us-west-2.eks.amazonaws.com",
"arn": "arn:aws:eks:us-west-2:123456789012:cluster/my-production-cluster",
"status": "ACTIVE",
"createdAt": "2024-06-15T10:30:00Z"
}
}Extract from response:
cluster.name-> Cluster namecluster.version-> Kubernetes version (check for upgrade eligibility)cluster.platformVersion-> EKS platform version (indicates patch level)cluster.endpoint-> API server endpoint (needed for kubectl config)cluster.arn-> Cluster ARN (extract region from this)cluster.status-> Cluster status (verify ACTIVE before proceeding)cluster.createdAt-> Creation timestamp (useful for audit reports)
CLI Fallback
Use CLI when MCP tools are unavailable or when running from a bastion host with AWS credentials configured.
aws eks describe-cluster \
--name my-production-cluster \
--region us-west-2 \
--query 'cluster.{
name:name,
version:version,
platformVersion:platformVersion,
endpoint:endpoint,
arn:arn,
status:status,
createdAt:createdAt
}'Example output:
{
"name": "my-production-cluster",
"version": "1.31",
"platformVersion": "eks.5",
"endpoint": "https://ABC123DEF456.gr7.us-west-2.eks.amazonaws.com",
"arn": "arn:aws:eks:us-west-2:123456789012:cluster/my-production-cluster",
"status": "ACTIVE",
"createdAt": "2024-06-15T10:30:00.000000+00:00"
}---
Region Detection
When the user does not specify a region, detect it using these methods in order:
1. Extract from cluster ARN (if already known): Parse arn:aws:eks:<region>:<account>:cluster/<name> 2. Check kubeconfig context: Run kubectl config current-context and parse the region 3. Query AWS config: Run aws configure get region 4. Prompt the user: Ask explicitly as a last resort
---
Output Schema
cluster:
name: string # Cluster name - use for all subsequent API calls
region: string # AWS region - required for CLI commands
version: string # Kubernetes version (e.g., "1.31") - check EKS docs for EOL dates
platform_version: string # EKS platform version (e.g., "eks.5") - higher = more patches
endpoint: string # API server endpoint URL - needed for kubectl configuration
arn: string # Full cluster ARN - use for IAM policies and cross-account access
status: string # ACTIVE, CREATING, UPDATING, DELETING - proceed only if ACTIVE
created_at: string # ISO timestamp - useful for compliance and audit reports---
Edge Cases
Handle Cluster Not Found
When describe-cluster returns ResourceNotFoundException, troubleshoot in this order:
1. Verify the cluster name spelling matches exactly (case-sensitive) 2. Confirm the region is correct by listing clusters: aws eks list-clusters --region <region> 3. Check IAM permissions - the caller needs eks:DescribeCluster permission
Handle Transitional States
When the cluster status is not ACTIVE, take these actions:
| Status | Action |
|---|---|
CREATING | Wait for creation to complete before running recon |
UPDATING | Proceed with caution - some data may be incomplete during upgrades |
DELETING | Abort recon immediately - cluster is being terminated |
Handle Private Clusters
When endpoint access is private-only:
1. Verify MCP tool connectivity first - the MCP server may have VPC access 2. For CLI access, connect through a VPN or bastion host within the VPC 3. Record in the report: endpoint_access: private to flag this for operators
Module: Compute
Part of: eks-recon
Purpose: Detect compute strategy - Karpenter, Managed Node Groups, Auto Mode, Fargate, self-managed
Table of Contents
- Prerequisites
- Detection Strategy
- Detection Commands
- Auto Mode Detection
- Karpenter Detection
- Managed Node Group Detection
- Fargate Detection
- Self-Managed Node Detection
- Output Schema
- Strategy Determination Logic
- Edge Cases
---
Prerequisites
- Cluster name required: Yes
- MCP tools used:
describe_eks_resource,list_eks_resources,list_k8s_resources - CLI fallback:
aws eks,kubectl
---
Detection Strategy
Run detections in this order because later strategies depend on ruling out earlier ones:
1. Auto Mode -> If enabled, strategy is "Auto Mode" (may have MNG for system)
2. Karpenter -> Check for NodePool CRDs and controller
3. MNG -> List managed node groups
4. Fargate -> List Fargate profiles
5. Self-managed -> Nodes without MNG labelsWhy this order matters:
- Auto Mode can coexist with MNG for system workloads, so check it first
- Karpenter clusters often have a bootstrap MNG that should not define the strategy
- Fargate-only clusters are rare; check MNG before assuming Fargate-only
- Self-managed is the fallback when no managed solution is detected
Determine the final strategy:
- Single method detected -> Use that method
- Multiple methods detected -> Report "Mixed" and detail which methods
- Nothing detected -> Report "Self-managed" or "Unknown"
---
Detection Commands
1. Auto Mode Detection
Check Auto Mode first because it fundamentally changes how the cluster provisions compute. Auto Mode clusters let EKS manage nodes automatically, so you may not see traditional node groups.
MCP:
describe_eks_resource(
resource_type="cluster",
cluster_name="<cluster-name>"
)
-> Check response for cluster.computeConfig.enabledCLI:
aws eks describe-cluster \
--name <cluster-name> \
--query 'cluster.computeConfig.enabled'Example output (Auto Mode enabled):
trueExample output (Auto Mode not enabled):
nullInterpret the result: true = Auto Mode enabled, false or null = Not using Auto Mode
2. Karpenter Detection
Detect Karpenter to identify clusters using just-in-time node provisioning. Karpenter is common in cost-optimized or scale-heavy clusters because it provisions nodes faster than Cluster Autoscaler.
MCP (check for NodePools):
list_k8s_resources(
cluster_name="<cluster-name>",
kind="NodePool",
api_version="karpenter.sh/v1"
)If empty, try v1beta1 (older Karpenter versions use this API):
list_k8s_resources(
cluster_name="<cluster-name>",
kind="NodePool",
api_version="karpenter.sh/v1beta1"
)MCP (check for controller):
list_k8s_resources(
cluster_name="<cluster-name>",
kind="Deployment",
api_version="apps/v1",
namespace="kube-system",
label_selector="app.kubernetes.io/name=karpenter"
)CLI:
# Check for NodePools
kubectl get nodepools.karpenter.sh 2>/dev/null
# Check for controller deployment
kubectl get deploy -n kube-system -l app.kubernetes.io/name=karpenter -o json 2>/dev/null | \
jq -r '.items[0].spec.template.spec.containers[0].image'Example output (Karpenter detected):
NAME NODECLASS
default default
gpu-pool gpu-nodesExample controller image:
public.ecr.aws/karpenter/controller:1.0.5Extract version: Parse the image tag from the controller deployment to report the Karpenter version.
3. Managed Node Group Detection
Detect Managed Node Groups (MNG) to identify AWS-managed EC2 capacity. MNGs are the most common compute strategy and handle node lifecycle, patching, and scaling automatically.
MCP:
list_eks_resources(
resource_type="nodegroup",
cluster_name="<cluster-name>"
)CLI:
aws eks list-nodegroups --cluster-name <cluster-name> --query 'nodegroups'Example output:
["system-ng", "app-ng-spot", "app-ng-ondemand"]For each node group, get details to understand instance types and scaling configuration:
MCP:
describe_eks_resource(
resource_type="nodegroup",
cluster_name="<cluster-name>",
resource_name="<nodegroup-name>"
)CLI:
aws eks describe-nodegroup \
--cluster-name <cluster-name> \
--nodegroup-name <nodegroup-name> \
--query 'nodegroup.{
name:nodegroupName,
status:status,
amiType:amiType,
instanceTypes:instanceTypes,
desiredSize:scalingConfig.desiredSize,
minSize:scalingConfig.minSize,
maxSize:scalingConfig.maxSize
}'Example output:
{
"name": "app-ng-spot",
"status": "ACTIVE",
"amiType": "AL2_x86_64",
"instanceTypes": ["m5.large", "m5a.large", "m5d.large"],
"desiredSize": 3,
"minSize": 1,
"maxSize": 10
}4. Fargate Detection
Detect Fargate profiles to identify serverless compute. Fargate eliminates node management entirely - pods run on AWS-managed infrastructure. Use this when you see no nodes or need to understand which namespaces run serverless.
MCP: Not available, use CLI
CLI:
aws eks list-fargate-profiles --cluster-name <cluster-name> --query 'fargateProfileNames'Example output:
["fp-default", "fp-kube-system"]For each profile, get selectors to understand which pods run on Fargate:
aws eks describe-fargate-profile \
--cluster-name <cluster-name> \
--fargate-profile-name <profile-name> \
--query 'fargateProfile.{
name:fargateProfileName,
status:status,
selectors:selectors
}'Example output:
{
"name": "fp-default",
"status": "ACTIVE",
"selectors": [
{"namespace": "default"},
{"namespace": "app", "labels": {"fargate": "true"}}
]
}5. Self-Managed Node Detection
Detect self-managed nodes when other strategies are not found. Self-managed nodes are EC2 instances joined to the cluster manually or via custom automation (Terraform, CloudFormation ASGs). These require manual patching and lifecycle management.
MCP:
list_k8s_resources(
cluster_name="<cluster-name>",
kind="Node",
api_version="v1"
)CLI:
# Find nodes without the MNG label (indicates self-managed)
kubectl get nodes -o json | jq -r '
.items[] |
select(.metadata.labels["eks.amazonaws.com/nodegroup"] == null) |
.metadata.name'Example output (self-managed nodes found):
ip-10-0-1-50.ec2.internal
ip-10-0-2-75.ec2.internalExample output (no self-managed nodes):
(empty - all nodes belong to MNGs or Karpenter)---
Output Schema
compute:
strategy: string # Karpenter | MNG | Auto Mode | Fargate | Mixed | Self-managed | Unknown
auto_mode:
enabled: bool
karpenter:
detected: bool
version: string # e.g., "1.0.5"
api_version: string # v1 or v1beta1
nodepools: int # Count of NodePool resources
nodepool_names: list # Names of NodePools
mng:
detected: bool
count: int
groups:
- name: string
status: string
ami_type: string
instance_types: list
desired_size: int
min_size: int
max_size: int
fargate:
detected: bool
profiles: int
profile_names: list
self_managed:
detected: bool
node_count: int---
Strategy Determination Logic
if auto_mode.enabled:
if mng.detected and mng.count > 0:
strategy = "Auto Mode" # Auto Mode may have MNG for system workloads
else:
strategy = "Auto Mode"
elif karpenter.detected and karpenter.nodepools > 0:
if mng.detected and mng.count > 0:
strategy = "Mixed"
note = "Karpenter for workloads, MNG for system"
else:
strategy = "Karpenter"
elif mng.detected and mng.count > 0:
if fargate.detected:
strategy = "Mixed"
note = "MNG + Fargate"
else:
strategy = "MNG"
elif fargate.detected:
strategy = "Fargate"
elif self_managed.detected:
strategy = "Self-managed"
else:
strategy = "Unknown"---
Edge Cases
Handle these special scenarios to provide accurate compute reporting.
Cluster Autoscaler vs Karpenter
Check for Cluster Autoscaler when Karpenter is not detected. CAS is the legacy autoscaling solution and affects how you interpret MNG scaling behavior.
kubectl get deploy -n kube-system cluster-autoscaler 2>/dev/nullWhy this matters: If CAS is present, MNG scaling is automated. If neither CAS nor Karpenter is present, MNGs use static sizing only.
Bottlerocket Nodes
Identify Bottlerocket nodes by checking the AMI type. Bottlerocket is a security-hardened OS that affects troubleshooting (no SSH, read-only filesystem).
Look for these values in amiType:
BOTTLEROCKET_x86_64BOTTLEROCKET_ARM_64
GPU Nodes
Detect GPU nodes for clusters running ML/AI workloads. GPU nodes require special scheduling consideration.
kubectl get nodes -l "nvidia.com/gpu" -o nameExample output:
node/ip-10-0-3-100.ec2.internalGraviton/ARM Nodes
Identify ARM-based Graviton nodes for cost optimization reporting. Graviton instances offer better price-performance but require ARM-compatible container images.
Look for these indicators:
amiType: AL2_ARM_64orAL2023_ARM_64_STANDARD- Instance types:
m6g,m7g,c6g,c7g,r6g,r7g
Module: IaC (Infrastructure as Code)
Part of: eks-recon
Purpose: Detect IaC tooling - Terraform, CloudFormation, CDK, eksctl, Pulumi
Table of Contents
- Prerequisites
- Detection Strategy
- Detection Commands
- 1. Terraform Detection
- 2. CloudFormation Detection
- 3. CDK Detection
- 4. eksctl Detection
- 5. Pulumi Detection
- 6. Tag-Based Detection (Fallback)
- Output Schema
- Confidence Determination
- Edge Cases
---
Prerequisites
- Cluster name required: No (workspace scan), Yes (for tag verification)
- MCP tools used: None (filesystem scan)
- CLI fallback:
find,grep,aws cloudformation
---
Detection Strategy
IaC detection is primarily workspace-based. Scan the local filesystem for IaC configuration files:
1. Terraform -> .tf files with aws_eks_cluster or module "eks"
2. CloudFormation -> .yaml/.json with AWS::EKS::Cluster
3. CDK -> cdk.json + package.json with aws-cdk
4. eksctl -> yaml files with kind: ClusterConfig
5. Pulumi -> Pulumi.yaml + aws providerConfidence scoring:
- High: IaC files found with cluster name matching target
- Medium: IaC files found but cluster name doesn't match
- Low: Only cluster tags suggest IaC tool
- Unknown: No evidence found
---
Detection Commands
1. Terraform Detection
Start with Terraform detection because it is the most common IaC tool for EKS clusters in production environments.
# Find Terraform files with EKS resources
find . -name "*.tf" -type f 2>/dev/null | head -50 | \
xargs grep -l "aws_eks_cluster\|module.*eks" 2>/dev/null | head -10Example output:
./infrastructure/eks/main.tf
./infrastructure/eks/cluster.tf
./modules/eks-cluster/main.tfIf files found, extract details to determine which module or resource configuration is used:
# Check for terraform-aws-modules/eks
grep -r "source.*terraform-aws-modules/eks" --include="*.tf" . 2>/dev/null | head -5
# Check for cluster name in tf files
grep -r "cluster_name\s*=" --include="*.tf" . 2>/dev/null | head -5
# Check for tfvars
find . -name "*.tfvars" -type f 2>/dev/null | head -5Example output:
./infrastructure/eks/main.tf: source = "terraform-aws-modules/eks/aws"
./infrastructure/eks/main.tf: cluster_name = "my-production-cluster"
./infrastructure/eks/terraform.tfvarsTerraform state check (optional) - Use this to verify if Terraform has been applied:
# Check if state exists
find . -name "terraform.tfstate" -o -name ".terraform" -type d 2>/dev/null | head -32. CloudFormation Detection
Check for CloudFormation templates when Terraform is not found, or when the organization uses AWS-native tooling.
# Find CFN templates with EKS resources
find . \( -name "*.yaml" -o -name "*.yml" -o -name "*.json" \) -type f 2>/dev/null | head -50 | \
xargs grep -l "AWS::EKS::Cluster\|AWSTemplateFormatVersion" 2>/dev/null | head -10Example output:
./cloudformation/eks-cluster.yaml
./templates/infrastructure.yamlCheck for deployed stacks (if cluster name known) - This confirms the stack was actually deployed:
# List stacks with EKS resources
aws cloudformation list-stacks \
--stack-status-filter CREATE_COMPLETE UPDATE_COMPLETE \
--query 'StackSummaries[?contains(StackName, `eks`) || contains(StackName, `EKS`)].StackName'Example output:
[
"eks-production-cluster",
"eks-nodegroup-stack"
]3. CDK Detection
Check for AWS CDK projects when the codebase uses TypeScript, Python, or other CDK-supported languages. CDK is common in organizations with strong development practices.
# Check for CDK project - cdk.json is the definitive marker
find . -name "cdk.json" -type f 2>/dev/null | head -3
# Check for CDK in package.json (TypeScript/JavaScript)
find . -name "package.json" -type f 2>/dev/null | head -10 | \
xargs grep -l "aws-cdk\|@aws-cdk" 2>/dev/null | head -5
# Check for CDK in requirements.txt (Python)
find . -name "requirements.txt" -type f 2>/dev/null | head -5 | \
xargs grep -l "aws-cdk" 2>/dev/null | head -3
# Check for cdk.out (synthesized templates) - indicates CDK has been synthesized
find . -name "cdk.out" -type d 2>/dev/null | head -3Example output:
./infra/cdk.json
./infra/package.json
./infra/cdk.out4. eksctl Detection
Check for eksctl when the cluster was created for development, testing, or quick deployments. eksctl is commonly used for simpler cluster setups.
# Find eksctl cluster configs
find . \( -name "eksctl*.yaml" -o -name "eksctl*.yml" -o -name "cluster*.yaml" -o -name "cluster*.yml" \) \
-type f 2>/dev/null | head -10 | \
xargs grep -l "kind:\s*ClusterConfig\|apiVersion:\s*eksctl.io" 2>/dev/null | head -5Example output:
./eksctl-config.yaml
./clusters/dev-cluster.yamlVerify with eksctl CLI (if available) - Confirms eksctl can manage this cluster:
# Check if eksctl recognizes the cluster
eksctl get cluster --name <cluster-name> --region <region> 2>/dev/nullExample output:
NAME REGION EKSCTL CREATED
my-dev-cluster us-west-2 True5. Pulumi Detection
Check for Pulumi when the organization uses infrastructure-as-real-code with TypeScript, Python, or Go. Pulumi is less common than Terraform but growing in adoption.
# Find Pulumi project files - Pulumi.yaml is the definitive marker
find . -name "Pulumi.yaml" -type f 2>/dev/null | head -3
# Check for AWS provider in Pulumi
find . -name "Pulumi.*.yaml" -type f 2>/dev/null | head -5 | \
xargs grep -l "aws:" 2>/dev/null | head -3
# Check for EKS in Pulumi code
find . \( -name "*.ts" -o -name "*.py" -o -name "*.go" \) -type f 2>/dev/null | head -50 | \
xargs grep -l "eks.Cluster\|pulumi_eks\|@pulumi/eks" 2>/dev/null | head -5Example output:
./pulumi/Pulumi.yaml
./pulumi/Pulumi.production.yaml
./pulumi/index.ts6. Tag-Based Detection (Fallback)
Use tag-based detection when workspace scan finds nothing. IaC tools often add identifying tags to the resources they create.
MCP:
describe_eks_resource(
resource_type="cluster",
cluster_name="<cluster-name>"
)
-> Check response for cluster.tagsCLI:
aws eks describe-cluster --name <cluster-name> \
--query 'cluster.tags' --output jsonExample output (Terraform-managed cluster):
{
"Environment": "production",
"terraform": "true",
"managed-by": "terraform"
}Example output (CloudFormation-managed cluster):
{
"aws:cloudformation:stack-name": "eks-production-cluster",
"aws:cloudformation:stack-id": "arn:aws:cloudformation:us-west-2:123456789012:stack/eks-production-cluster/abc123",
"aws:cloudformation:logical-id": "EKSCluster"
}Common IaC tags:
- Terraform:
terraform,tf-*,managed-by: terraform - CloudFormation:
aws:cloudformation:stack-name - CDK:
aws:cdk:* - Pulumi:
pulumi:*
---
Output Schema
iac:
tool: string # Terraform | CloudFormation | CDK | eksctl | Pulumi | CLI | unknown
confidence: string # high | medium | low
evidence: string # Path to files or reason for determination
details:
# Terraform-specific
terraform:
detected: bool
files: list # Paths to .tf files
module: string # e.g., "terraform-aws-modules/eks/aws"
state_backend: string # local | s3 | remote
# CloudFormation-specific
cloudformation:
detected: bool
templates: list # Paths to CFN templates
stack_name: string # Deployed stack name (if found)
# CDK-specific
cdk:
detected: bool
language: string # typescript | python | java | go
cdk_json_path: string
# eksctl-specific
eksctl:
detected: bool
config_files: list
# Pulumi-specific
pulumi:
detected: bool
project_path: string
language: string---
Confidence Determination
| Scenario | Confidence | Reasoning |
|---|---|---|
| IaC files found with matching cluster name | High | Direct evidence |
| IaC files found, cluster name in tfvars/config | High | Indirect but strong |
| IaC files found, no cluster name match | Medium | Files exist but may be different cluster |
| Only cluster tags suggest IaC | Low | Tags can be manually added |
| No evidence found | Unknown | Might be CLI-created or IaC elsewhere |
---
Edge Cases
Multiple IaC Tools Detected
If multiple tools are found (e.g., Terraform + CDK):
- Report primary tool as most likely (based on EKS-specific files)
- Note secondary tools in details
- Ask user to clarify if ambiguous
IaC in Different Directory
User may have IaC in a separate repo or directory:
- Note that scan is workspace-limited
- Suggest user point to IaC directory if known
GitOps-Managed IaC
IaC may be applied via GitOps (ArgoCD/Flux deploying Crossplane or ACK):
- Check for Crossplane XRDs/compositions
- Check for ACK resources
- Note as "GitOps + IaC"
No IaC (CLI-Created)
If no IaC evidence found:
- Cluster may have been created via
aws eks create-clusteror console - Note as "CLI or Console (no IaC detected)"
- Warn that upgrades will need manual CLI commands
Module: Networking
Part of: eks-recon
Purpose: Detect network configuration - VPC CNI, ingress controllers, service mesh, DNS
Table of Contents
- Prerequisites
- Detection Strategy
- Detection Commands
- 1. VPC CNI Configuration
- 2. Ingress Controllers
- 3. Service Mesh Detection
- 4. DNS Configuration
- 5. Network Policies
- Output Schema
- Edge Cases
- Recommendations Based on Findings
---
Prerequisites
- Cluster name required: Yes
- MCP tools used:
describe_eks_resource,get_eks_vpc_config,list_k8s_resources - CLI fallback:
aws eks,kubectl
---
Detection Strategy
Network configuration spans multiple layers:
1. VPC CNI -> Pod networking mode and configuration
2. Ingress -> How external traffic enters the cluster
3. Service Mesh -> Service-to-service communication
4. DNS -> CoreDNS configuration
5. Network Policies -> Pod-to-pod traffic control---
Detection Commands
1. VPC CNI Configuration
Why check this: VPC CNI mode directly impacts pod IP capacity and networking behavior. Prefix delegation can increase pods-per-node from ~29 to ~110 on m5.large. Custom networking is required when pod subnets differ from node subnets.
MCP:
describe_eks_resource(
resource_type="addon",
cluster_name="<cluster-name>",
resource_name="vpc-cni"
)get_eks_vpc_config(
cluster_name="<cluster-name>"
)CLI:
# Get VPC CNI add-on status
aws eks describe-addon --cluster-name <cluster-name> --addon-name vpc-cni \
--query 'addon.{version:addonVersion,status:status,config:configurationValues}'
# Get CNI configuration from aws-node DaemonSet
kubectl get daemonset aws-node -n kube-system -o json | jq -r '
.spec.template.spec.containers[0].env |
map(select(.name | startswith("AWS_") or startswith("ENABLE_"))) |
from_entries'VPC CNI Mode Detection:
# Check for prefix delegation
kubectl get daemonset aws-node -n kube-system -o json | \
jq -r '.spec.template.spec.containers[0].env[] | select(.name=="ENABLE_PREFIX_DELEGATION") | .value'
# Check for custom networking
kubectl get eniconfigs.crd.k8s.amazonaws.com 2>/dev/null | head -5Modes:
- Secondary IP (default):
ENABLE_PREFIX_DELEGATIONnot set orfalse - Prefix Delegation:
ENABLE_PREFIX_DELEGATION=true - Custom Networking: ENIConfig CRDs exist
Example output (prefix delegation enabled):
{
"ENABLE_PREFIX_DELEGATION": "true",
"WARM_PREFIX_TARGET": "1",
"AWS_VPC_K8S_CNI_CUSTOM_NETWORK_CFG": "false"
}2. Ingress Controllers
Why check this: Ingress controllers determine how external traffic reaches cluster services. Multiple controllers may coexist (e.g., AWS LBC for ALB/NLB, nginx for internal routing). Understanding the ingress topology is essential for troubleshooting connectivity issues.
MCP:
list_k8s_resources(
cluster_name="<cluster-name>",
kind="Deployment",
api_version="apps/v1",
namespace="kube-system"
)CLI:
# AWS Load Balancer Controller
kubectl get deploy -n kube-system aws-load-balancer-controller 2>/dev/null
# NGINX Ingress Controller
kubectl get deploy -A -l "app.kubernetes.io/name=ingress-nginx" 2>/dev/null
# Traefik
kubectl get deploy -A -l "app.kubernetes.io/name=traefik" 2>/dev/null
# Kong
kubectl get deploy -A -l "app=kong" 2>/dev/null
# List all IngressClasses
kubectl get ingressclasses -o json | jq -r '.items[] | {name: .metadata.name, controller: .spec.controller}'Check for Gateway API:
# Gateway API CRDs
kubectl get crds | grep -E "gateways|httproutes|grpcroutes" 2>/dev/null
# Gateway resources
kubectl get gateways.gateway.networking.k8s.io -A 2>/dev/null | head -10Example output (IngressClasses):
{"name": "alb", "controller": "ingress.k8s.aws/alb"}
{"name": "nginx", "controller": "k8s.io/ingress-nginx"}3. Service Mesh Detection
Why check this: Service meshes add mTLS, observability, and traffic management at the application layer. Detecting mesh presence explains sidecar containers, elevated resource usage, and additional CRDs. The mesh type affects troubleshooting approaches.
Istio:
# Check for Istio control plane
kubectl get deploy -n istio-system istiod 2>/dev/null
# Check for Istio sidecar injection
kubectl get ns -l istio-injection=enabled -o name 2>/dev/null
# Get Istio version
kubectl get deploy -n istio-system istiod -o jsonpath='{.spec.template.spec.containers[0].image}' 2>/dev/null
# Check for ambient mode
kubectl get daemonset -n istio-system ztunnel 2>/dev/nullAWS App Mesh:
# Check for App Mesh controller
kubectl get deploy -n appmesh-system appmesh-controller 2>/dev/null
# Check for virtual services
kubectl get virtualservices.appmesh.k8s.aws -A 2>/dev/null | head -5Linkerd:
# Check for Linkerd
kubectl get deploy -n linkerd linkerd-destination 2>/dev/nullExample output (Istio detected):
NAME READY UP-TO-DATE AVAILABLE AGE
istiod 2/2 2 2 45dnamespace/default
namespace/production
namespace/staging4. DNS Configuration
Why check this: CoreDNS is critical for service discovery. Misconfigured DNS causes intermittent connectivity failures. NodeLocal DNSCache improves DNS performance and reduces CoreDNS load. Custom Corefile entries may indicate special routing requirements.
MCP:
describe_eks_resource(
resource_type="addon",
cluster_name="<cluster-name>",
resource_name="coredns"
)CLI:
# CoreDNS deployment
kubectl get deploy -n kube-system coredns -o json | jq '{
replicas: .spec.replicas,
version: .spec.template.spec.containers[0].image
}'
# CoreDNS ConfigMap (custom configuration)
kubectl get configmap -n kube-system coredns -o yaml 2>/dev/null
# Check for NodeLocal DNSCache
kubectl get daemonset -n kube-system node-local-dns 2>/dev/nullExample output (CoreDNS info):
{
"replicas": 2,
"version": "602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/coredns:v1.10.1-eksbuild.6"
}5. Network Policies
Why check this: Network policies enforce pod-to-pod traffic rules. Their absence means all pods can communicate freely, which may violate security requirements. Calico and Cilium extend native Kubernetes policies with cluster-wide and advanced L7 rules.
# Check if any network policies exist
kubectl get networkpolicies -A 2>/dev/null | wc -l
# List network policies by namespace
kubectl get networkpolicies -A -o json | jq -r '.items | group_by(.metadata.namespace) | map({namespace: .[0].metadata.namespace, count: length})'Calico/Cilium Network Policies:
# Calico
kubectl get globalnetworkpolicies.crd.projectcalico.org 2>/dev/null | head -5
kubectl get networkpolicies.crd.projectcalico.org -A 2>/dev/null | head -5
# Cilium
kubectl get ciliumnetworkpolicies -A 2>/dev/null | head -5Example output (network policy count by namespace):
[
{"namespace": "production", "count": 12},
{"namespace": "staging", "count": 8},
{"namespace": "kube-system", "count": 3}
]---
Output Schema
networking:
vpc_cni:
version: string
status: string
mode: string # secondary-ip | prefix-delegation | custom-networking
custom_networking:
enabled: bool
eniconfigs: int # Count of ENIConfig resources
prefix_delegation:
enabled: bool
security_groups_for_pods:
enabled: bool
ingress:
controllers:
- name: string
type: string # aws-lb | nginx | traefik | kong | other
namespace: string
version: string
ingress_classes: list
gateway_api:
enabled: bool
gateways: int
service_mesh:
detected: string # istio | appmesh | linkerd | none
istio:
detected: bool
version: string
mode: string # sidecar | ambient
injection_namespaces: list
appmesh:
detected: bool
virtual_services: int
dns:
coredns:
version: string
replicas: int
custom_config: bool
nodelocal_dns:
enabled: bool
network_policies:
count: int
namespaces_with_policies: int
calico:
detected: bool
global_policies: int
cilium:
detected: bool---
Edge Cases
Multiple Ingress Controllers
Common to have both AWS LBC and nginx:
- AWS LBC for external traffic (ALB/NLB)
- nginx for internal routing
Note both and document IngressClass usage.
VPC CNI Custom Configuration
Check for non-default settings:
# Security Groups for Pods
kubectl get daemonset aws-node -n kube-system -o json | \
jq '.spec.template.spec.containers[0].env[] | select(.name=="ENABLE_POD_ENI")'
# External SNAT
kubectl get daemonset aws-node -n kube-system -o json | \
jq '.spec.template.spec.containers[0].env[] | select(.name=="AWS_VPC_K8S_CNI_EXTERNALSNAT")'IP Address Exhaustion Risk
# Check available IPs in subnets (requires subnet IDs from cluster)
aws ec2 describe-subnets --subnet-ids <ids> \
--query 'Subnets[*].[SubnetId,AvailableIpAddressCount,CidrBlock]'Private Cluster Networking
# Check endpoint access configuration
aws eks describe-cluster --name <cluster-name> \
--query 'cluster.resourcesVpcConfig.{
endpointPublicAccess:endpointPublicAccess,
endpointPrivateAccess:endpointPrivateAccess,
publicAccessCidrs:publicAccessCidrs
}'---
Recommendations Based on Findings
| Finding | Recommendation |
|---|---|
| Secondary IP mode, high pod density | Consider prefix delegation for more IPs per node |
| No ingress controller | Consider AWS LBC for ALB/NLB integration |
| Multiple ingress controllers | Document routing strategy, consider consolidation |
| No network policies | Add network policies for security isolation |
| No service mesh | Consider Istio or App Mesh for observability/security |
Module: Observability
Part of: eks-recon
Purpose: Detect observability stack - metrics, logging, tracing configuration
Table of Contents
- Prerequisites
- Detection Strategy
- Detection Commands
- 1. Metrics Collection
- 2. Logging Configuration
- 3. Tracing
- 4. Application Signals (APM)
- Output Schema
- Edge Cases
- Recommendations Based on Findings
---
Prerequisites
- Cluster name required: Yes
- MCP tools used:
describe_eks_resource,list_k8s_resources - CLI fallback:
aws eks,kubectl,aws logs
---
Detection Strategy
Observability has three pillars (plus control plane logging):
1. Metrics -> Container Insights, Prometheus, Datadog, etc.
2. Logging -> CloudWatch, FluentBit, OpenSearch, etc.
3. Tracing -> X-Ray, ADOT, Jaeger, etc.
4. Control Plane -> API server, audit, authenticator logsWhy detect each pillar:
| Pillar | Why It Matters |
|---|---|
| Metrics | Understand resource utilization, HPA scaling decisions, capacity planning |
| Logging | Debug application issues, audit security events, compliance requirements |
| Tracing | Diagnose latency in distributed systems, identify service dependencies |
| Control Plane | Investigate API failures, audit access, debug networking issues |
---
Detection Commands
1. Metrics Collection
Start with metrics detection to understand how the cluster tracks resource usage and supports autoscaling. Most clusters have at least one metrics solution.
Container Insights (CloudWatch):
Use Container Insights when you need AWS-native monitoring with automatic CloudWatch integration. This is the simplest option for teams already using AWS observability tools.
MCP:
describe_eks_resource(
resource_type="addon",
cluster_name="<cluster-name>",
resource_name="amazon-cloudwatch-observability"
)CLI:
# Check for CloudWatch add-on
aws eks describe-addon --cluster-name <cluster-name> \
--addon-name amazon-cloudwatch-observability 2>/dev/null
# Alternative: Check for CloudWatch agent DaemonSet
kubectl get daemonset -n amazon-cloudwatch cloudwatch-agent 2>/dev/null
# Check for Fluent Bit (CloudWatch integration)
kubectl get daemonset -n amazon-cloudwatch fluent-bit 2>/dev/nullExample output (add-on installed):
{
"addon": {
"addonName": "amazon-cloudwatch-observability",
"clusterName": "prod-cluster",
"status": "ACTIVE",
"addonVersion": "v1.5.0-eksbuild.1"
}
}Example output (not installed):
An error occurred (ResourceNotFoundException) when calling the DescribeAddon operationPrometheus (Self-Managed):
Use Prometheus when you need flexible metrics collection with PromQL queries, custom recording rules, or Grafana dashboards. Common in teams with existing Prometheus expertise.
# Check for Prometheus deployment
kubectl get deploy -n prometheus prometheus-server 2>/dev/null || \
kubectl get deploy -n monitoring prometheus-server 2>/dev/null || \
kubectl get statefulset -n prometheus prometheus-server 2>/dev/null
# Check for kube-prometheus-stack (Helm)
helm list -A --filter "prometheus\|kube-prometheus" 2>/dev/null
# Check for Prometheus Operator
kubectl get deploy -A -l "app.kubernetes.io/name=prometheus-operator" 2>/dev/nullExample output (Prometheus detected):
NAME READY UP-TO-DATE AVAILABLE AGE
prometheus-server 1/1 1 1 45dAmazon Managed Prometheus (AMP):
Check for AMP when you need managed Prometheus with automatic scaling and AWS integration. Look for aps-workspaces URLs in remote write configurations.
# Check for ADOT or Prometheus remote write config
kubectl get configmap -A -o json | jq -r '
.items[] |
select(.data | to_entries | .[] | .value | contains("aps-workspaces")) |
{namespace: .metadata.namespace, name: .metadata.name}'Example output (AMP configured):
{
"namespace": "prometheus",
"name": "prometheus-config"
}Grafana:
# Check for Grafana deployment
kubectl get deploy -A -l "app.kubernetes.io/name=grafana" 2>/dev/null
# Check for Amazon Managed Grafana (external, check workspace)
# Note: AMG workspaces are external to clusterOther Metrics Tools:
Third-party tools like Datadog and New Relic provide unified observability platforms. Check for these when the team uses a commercial APM solution.
# Datadog
kubectl get daemonset -n datadog datadog-agent 2>/dev/null
# New Relic
kubectl get daemonset -A -l "app.kubernetes.io/name=nri-bundle" 2>/dev/null
# Metrics Server (required for HPA - almost always present)
kubectl get deploy -n kube-system metrics-server 2>/dev/nullExample output (Metrics Server):
NAME READY UP-TO-DATE AVAILABLE AGE
metrics-server 1/1 1 1 120d2. Logging Configuration
Detect logging configuration to understand how application and cluster logs are collected and where they are sent. Control plane logging is critical for debugging and compliance.
Control Plane Logging:
Always check control plane logging first. Missing audit logs is a security/compliance gap.
# Check which control plane logs are enabled
aws eks describe-cluster --name <cluster-name> \
--query 'cluster.logging.clusterLogging[*].{types:types,enabled:enabled}'Example output (all logs enabled):
[
{
"types": ["api", "audit", "authenticator", "controllerManager", "scheduler"],
"enabled": true
}
]Example output (no logs enabled - flag this):
[
{
"types": ["api", "audit", "authenticator", "controllerManager", "scheduler"],
"enabled": false
}
]Fluent Bit / Fluentd:
Fluent Bit (lightweight) and Fluentd (feature-rich) are the most common log forwarders. Check their ConfigMaps to determine where logs are being sent.
# Fluent Bit DaemonSet
kubectl get daemonset -A -l "app.kubernetes.io/name=fluent-bit" 2>/dev/null
# Fluentd DaemonSet
kubectl get daemonset -A -l "app=fluentd" 2>/dev/null
# Check Fluent Bit ConfigMap for destinations
kubectl get configmap -n amazon-cloudwatch fluent-bit-config -o yaml 2>/dev/null | \
grep -E "cloudwatch|opensearch|s3|kinesis" || trueExample output (Fluent Bit detected):
NAMESPACE NAME DESIRED CURRENT READY AGE
amazon-cloudwatch fluent-bit 3 3 3 60dOpenSearch / Elasticsearch:
# Check for OpenSearch endpoint in configs
kubectl get configmap -A -o json | jq -r '
.items[] |
select(.data | to_entries | .[] | .value | contains("opensearch") or contains("elasticsearch")) |
{namespace: .metadata.namespace, name: .metadata.name}'Loki:
# Check for Loki deployment
kubectl get deploy -A -l "app.kubernetes.io/name=loki" 2>/dev/null
kubectl get statefulset -A -l "app.kubernetes.io/name=loki" 2>/dev/null3. Tracing
Tracing is essential for debugging latency in microservices architectures. Without tracing, diagnosing cross-service issues requires correlating logs manually.
AWS X-Ray / ADOT:
ADOT (AWS Distro for OpenTelemetry) is the AWS-recommended approach for tracing. It can send traces to X-Ray, Jaeger, or other backends.
# Check for ADOT collector
kubectl get deploy -A -l "app.kubernetes.io/name=aws-otel-collector" 2>/dev/null
# Check for X-Ray daemon
kubectl get daemonset -A -l "app=xray-daemon" 2>/dev/null
# Check ADOT add-on
aws eks describe-addon --cluster-name <cluster-name> --addon-name adot 2>/dev/nullExample output (ADOT add-on installed):
{
"addon": {
"addonName": "adot",
"clusterName": "prod-cluster",
"status": "ACTIVE",
"addonVersion": "v0.88.0-eksbuild.1"
}
}Jaeger:
Jaeger is a popular open-source tracing backend. Check for it when the team uses a self-managed tracing solution.
# Check for Jaeger
kubectl get deploy -A -l "app.kubernetes.io/name=jaeger" 2>/dev/null
kubectl get deploy -A -l "app=jaeger" 2>/dev/nullTempo:
Grafana Tempo is often used with Grafana and Loki for a unified observability stack.
# Check for Grafana Tempo
kubectl get deploy -A -l "app.kubernetes.io/name=tempo" 2>/dev/null
kubectl get statefulset -A -l "app.kubernetes.io/name=tempo" 2>/dev/null4. Application Signals (APM)
Application Signals provides automatic instrumentation for common frameworks. Check for this when the team wants APM without modifying application code.
# Check for CloudWatch Application Signals
kubectl get deploy -n amazon-cloudwatch cloudwatch-agent-operator 2>/dev/null
# Check for auto-instrumentation
kubectl get instrumentations.opentelemetry.io -A 2>/dev/nullExample output (auto-instrumentation configured):
NAMESPACE NAME AGE ENDPOINT
default java-app 30d http://adot-collector:4317---
Output Schema
observability:
metrics:
container_insights:
enabled: bool
addon_version: string
prometheus:
detected: bool
type: string # self-managed | amp | operator
namespace: string
version: string
grafana:
detected: bool
type: string # self-managed | amg
namespace: string
metrics_server:
detected: bool
version: string
other_tools: list # datadog, newrelic, etc.
logging:
control_plane:
enabled: bool
log_types: list # api, audit, authenticator, controllerManager, scheduler
application:
tool: string # fluent-bit | fluentd | promtail | none
destination: string # cloudwatch | opensearch | loki | s3
namespace: string
log_destinations:
cloudwatch: bool
opensearch: bool
s3: bool
loki: bool
tracing:
tool: string # xray | adot | jaeger | tempo | none
adot:
detected: bool
version: string
xray:
detected: bool
jaeger:
detected: bool
tempo:
detected: bool
apm:
application_signals:
enabled: bool
auto_instrumentation:
enabled: bool
namespaces: list---
Edge Cases
Multiple Metrics Solutions
Common to have:
- Metrics Server (for HPA)
- Prometheus (for detailed metrics)
- Container Insights (for AWS integration)
Note all and their purposes.
Log Aggregation Outside Cluster
Logs may go to:
- External CloudWatch in different account
- Third-party SaaS (Datadog, Splunk)
- Self-managed OpenSearch/ELK
Check Fluent Bit/Fluentd configs for destinations.
Control Plane Logging Not Enabled
# Check if any logs are enabled
aws eks describe-cluster --name <cluster-name> \
--query 'cluster.logging.clusterLogging[?enabled==`true`].types'If empty, flag as security/compliance gap.
ADOT vs Self-Managed Collectors
# Check if using ADOT add-on or self-managed
aws eks describe-addon --cluster-name <cluster-name> --addon-name adot 2>/dev/null
# vs
kubectl get deploy -A -l "app=opentelemetry-collector" 2>/dev/null---
Recommendations Based on Findings
| Finding | Recommendation |
|---|---|
| No metrics solution | Enable Container Insights or deploy Prometheus |
| No control plane logs | Enable all log types for debugging/audit |
| No tracing | Consider ADOT for distributed tracing |
| Multiple overlapping tools | Consolidate to reduce overhead |
| No metrics server | Deploy for HPA functionality |
| Application Signals not enabled | Consider for APM capabilities |
Module: Security
Part of: eks-recon
Purpose: Detect security posture - IAM model, Pod Security, policy engines, secrets management
Table of Contents
- Prerequisites
- Detection Strategy
- Detection Commands
- 1. IAM Model Detection
- 2. Pod Security Standards (PSS)
- 3. Policy Engine Detection
- 4. Secrets Management
- 5. Image Security
- 6. RBAC Summary
- Output Schema
- Edge Cases
- Recommendations Based on Findings
---
Prerequisites
- Cluster name required: Yes
- MCP tools used:
describe_eks_resource,list_k8s_resources,list_eks_resources - CLI fallback:
aws eks,kubectl
---
Detection Strategy
Security posture covers multiple dimensions:
1. IAM Model -> Pod Identity vs IRSA vs node role
2. Pod Security -> PSA labels, PSS enforcement
3. Policy Engine -> Kyverno, OPA Gatekeeper, or none
4. Secrets -> ESO, Secrets Store CSI, native secrets
5. Image Security -> ECR scanning, admission control
6. RBAC -> Role/ClusterRole analysis---
Detection Commands
1. IAM Model Detection
Detect which IAM model the cluster uses for workload authentication. This determines how pods access AWS services:
- Pod Identity (recommended): AWS-native, simplest to manage, supports cross-account without OIDC providers
- IRSA: Established pattern using OIDC, widely adopted but more complex setup
- Node role: Legacy approach where all pods share the node's IAM role - security risk
Pod Identity:
MCP:
describe_eks_resource(
resource_type="addon",
cluster_name="<cluster-name>",
resource_name="eks-pod-identity-agent"
)CLI:
# Check if Pod Identity agent is installed
aws eks describe-addon --cluster-name <cluster-name> --addon-name eks-pod-identity-agent 2>/dev/null
# List Pod Identity associations
aws eks list-pod-identity-associations --cluster-name <cluster-name> \
--query 'associations[*].{namespace:namespace,serviceAccount:serviceAccount,roleArn:roleArn}'Example output (Pod Identity enabled):
{
"addon": {
"addonName": "eks-pod-identity-agent",
"status": "ACTIVE",
"addonVersion": "v1.3.4-eksbuild.1"
}
}IRSA (IAM Roles for Service Accounts):
MCP:
list_k8s_resources(
cluster_name="<cluster-name>",
kind="ServiceAccount",
api_version="v1"
)CLI:
# Find service accounts with IRSA annotation
kubectl get sa -A -o json | jq -r '
.items[] |
select(.metadata.annotations["eks.amazonaws.com/role-arn"] != null) |
{
namespace: .metadata.namespace,
name: .metadata.name,
role: .metadata.annotations["eks.amazonaws.com/role-arn"]
}'Example output (IRSA configured):
{
"namespace": "kube-system",
"name": "aws-load-balancer-controller",
"role": "arn:aws:iam::123456789012:role/AWSLoadBalancerControllerRole"
}
{
"namespace": "external-secrets",
"name": "external-secrets",
"role": "arn:aws:iam::123456789012:role/ExternalSecretsRole"
}Determine IAM Model:
if pod_identity_associations > 0:
if irsa_service_accounts > 0:
model = "mixed"
else:
model = "Pod Identity"
elif irsa_service_accounts > 0:
model = "IRSA"
else:
model = "node-role" # Using node IAM role (not recommended)2. Pod Security Standards (PSS)
Check Pod Security Admission (PSA) enforcement. PSA replaced PodSecurityPolicy in Kubernetes 1.25+. Use this detection to understand which namespaces enforce security constraints on pods:
- restricted: Heavily restricted, follows hardening best practices
- baseline: Minimally restrictive, prevents known privilege escalations
- privileged: Unrestricted (default if no label set)
CLI:
# Check PSA labels on namespaces
kubectl get ns -o json | jq -r '
.items[] |
{
namespace: .metadata.name,
enforce: .metadata.labels["pod-security.kubernetes.io/enforce"],
warn: .metadata.labels["pod-security.kubernetes.io/warn"],
audit: .metadata.labels["pod-security.kubernetes.io/audit"]
} |
select(.enforce != null or .warn != null or .audit != null)'Example output (PSA configured):
{
"namespace": "production",
"enforce": "restricted",
"warn": "restricted",
"audit": "restricted"
}
{
"namespace": "monitoring",
"enforce": "baseline",
"warn": "restricted",
"audit": null
}Summary:
# Count namespaces by enforcement level
kubectl get ns -o json | jq -r '
.items |
group_by(.metadata.labels["pod-security.kubernetes.io/enforce"]) |
map({level: .[0].metadata.labels["pod-security.kubernetes.io/enforce"] // "none", count: length})'3. Policy Engine Detection
Identify if a policy engine enforces admission control beyond PSA. Policy engines provide fine-grained control over what resources can be created:
- Kyverno: Kubernetes-native, policies written in YAML, easier learning curve
- OPA Gatekeeper: Uses Rego language, more powerful but steeper learning curve
- Running both adds complexity - recommend consolidating to one
Kyverno:
# Check for Kyverno deployment
kubectl get deploy -n kyverno kyverno-admission-controller 2>/dev/null
# Get Kyverno version
kubectl get deploy -n kyverno -o json 2>/dev/null | \
jq -r '.items[0].spec.template.spec.containers[0].image'
# Count policies
kubectl get clusterpolicies.kyverno.io 2>/dev/null | wc -l
kubectl get policies.kyverno.io -A 2>/dev/null | wc -lExample output (Kyverno detected):
NAME READY AGE
kyverno-admission-controller 1/1 45d
# Version: ghcr.io/kyverno/kyverno:v1.11.4
# ClusterPolicies: 12
# Policies: 3OPA Gatekeeper:
# Check for Gatekeeper deployment
kubectl get deploy -n gatekeeper-system gatekeeper-controller-manager 2>/dev/null
# Get Gatekeeper version
kubectl get deploy -n gatekeeper-system -o json 2>/dev/null | \
jq -r '.items[0].spec.template.spec.containers[0].image'
# Count constraints
kubectl get constraints 2>/dev/null | wc -l
kubectl get constrainttemplates 2>/dev/null | wc -lExample output (Gatekeeper detected):
NAME READY AGE
gatekeeper-controller-manager 1/1 90d
# Version: openpolicyagent/gatekeeper:v3.15.0
# ConstraintTemplates: 8
# Constraints: 154. Secrets Management
Determine how the cluster manages sensitive data. Native Kubernetes secrets are base64-encoded (not encrypted at rest by default), so most production clusters use external solutions:
- External Secrets Operator (ESO): Syncs secrets from AWS Secrets Manager/Parameter Store to K8s secrets
- Secrets Store CSI Driver: Mounts secrets directly as volumes, avoids creating K8s Secret objects
- KMS encryption: Encrypts etcd secrets at rest (cluster-level, not a secrets solution itself)
External Secrets Operator (ESO):
# Check for ESO deployment
kubectl get deploy -n external-secrets external-secrets 2>/dev/null
# Count ExternalSecrets
kubectl get externalsecrets.external-secrets.io -A 2>/dev/null | wc -l
# Check SecretStores
kubectl get secretstores.external-secrets.io -A 2>/dev/null | head -5
kubectl get clustersecretstores.external-secrets.io 2>/dev/null | head -5Example output (ESO detected):
NAME READY AGE
external-secrets 1/1 60d
# ExternalSecrets: 24
# SecretStores (namespaced): 4
# ClusterSecretStores: 1Secrets Store CSI Driver:
# Check for Secrets Store CSI
kubectl get daemonset -n kube-system secrets-store-csi-driver 2>/dev/null
# Check for AWS provider
kubectl get daemonset -n kube-system secrets-store-csi-driver-provider-aws 2>/dev/null
# Count SecretProviderClasses
kubectl get secretproviderclasses -A 2>/dev/null | wc -lExample output (Secrets Store CSI detected):
NAME DESIRED CURRENT READY AGE
secrets-store-csi-driver 3 3 3 45d
secrets-store-csi-driver-provider-aws 3 3 3 45d
# SecretProviderClasses: 8KMS Encryption:
# Check if secrets encryption is enabled
aws eks describe-cluster --name <cluster-name> \
--query 'cluster.encryptionConfig[*].{resources:resources,keyArn:provider.keyArn}'Example output (KMS encryption enabled):
[
{
"resources": ["secrets"],
"keyArn": "arn:aws:kms:us-west-2:123456789012:key/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111"
}
]5. Image Security
Assess container image security posture. Check whether images come from trusted registries and if admission policies enforce image requirements:
- ECR usage: Private registry with built-in vulnerability scanning
- Admission policies: Kyverno/Gatekeeper rules that enforce image signing, registries, or tags
ECR Scanning:
# Check if ECR is used (look for ECR URLs in pods)
kubectl get pods -A -o json | jq -r '
.items[].spec.containers[].image |
select(contains(".ecr.") or contains("ecr.aws"))' | sort -u | head -10Example output (ECR images found):
123456789012.dkr.ecr.us-west-2.amazonaws.com/my-app:v1.2.3
123456789012.dkr.ecr.us-west-2.amazonaws.com/api-service:latest
public.ecr.aws/aws-observability/aws-otel-collector:v0.35.0Image Policy Enforcement:
# Check for image policies in Kyverno
kubectl get clusterpolicies.kyverno.io -o json 2>/dev/null | \
jq -r '.items[] | select(.spec.rules[].match.resources.kinds[] == "Pod") | .metadata.name'
# Check for Gatekeeper image constraints
kubectl get constraints -o json 2>/dev/null | \
jq -r '.items[] | select(.spec.match.kinds[].kinds[] == "Pod") | .metadata.name'6. RBAC Summary
Analyze RBAC configuration to identify overly permissive roles. Focus on:
- Wildcard permissions: Roles with
*on resources and verbs grant unlimited access - cluster-admin bindings: Should be minimal and well-documented
- High role/binding counts may indicate RBAC sprawl needing cleanup
# Count ClusterRoles and ClusterRoleBindings
kubectl get clusterroles | wc -l
kubectl get clusterrolebindings | wc -l
# Find overly permissive ClusterRoles
kubectl get clusterroles -o json | jq -r '
.items[] |
select(.rules[]?.resources[]? == "*" and .rules[]?.verbs[]? == "*") |
.metadata.name'
# Check for cluster-admin bindings
kubectl get clusterrolebindings -o json | jq -r '
.items[] |
select(.roleRef.name == "cluster-admin") |
{name: .metadata.name, subjects: .subjects}'Example output (RBAC findings):
# ClusterRoles: 87
# ClusterRoleBindings: 52
# Overly permissive roles:
super-admin-role
legacy-operator-role
# cluster-admin bindings:
{
"name": "cluster-admin-binding",
"subjects": [
{"kind": "User", "name": "admin@example.com"}
]
}
{
"name": "eks-console-dashboard-full-access-binding",
"subjects": [
{"kind": "Group", "name": "eks-console-dashboard-full-access-group"}
]
}---
Output Schema
security:
iam:
model: string # Pod Identity | IRSA | mixed | node-role
pod_identity:
enabled: bool
associations: int # Count of Pod Identity associations
irsa:
enabled: bool
service_accounts: int # Count of SAs with IRSA annotation
pod_security:
psa_enabled: bool
enforcement:
restricted: int # Namespaces enforcing restricted
baseline: int # Namespaces enforcing baseline
privileged: int # Namespaces enforcing privileged
none: int # Namespaces with no PSA labels
policy_engine:
tool: string # kyverno | gatekeeper | both | none
kyverno:
detected: bool
version: string
cluster_policies: int
policies: int
gatekeeper:
detected: bool
version: string
constraint_templates: int
constraints: int
secrets:
approach: string # eso | secrets-store-csi | native | mixed
kms_encryption: bool
kms_key_arn: string
external_secrets:
detected: bool
external_secrets: int
secret_stores: int
secrets_store_csi:
detected: bool
aws_provider: bool
secret_provider_classes: int
image_security:
ecr_used: bool
private_registries: list
admission_policies: bool # Image policies exist
rbac:
cluster_roles: int
cluster_role_bindings: int
overly_permissive_roles: list
cluster_admin_bindings: list---
Edge Cases
Mixed IAM Model
Many clusters transition from IRSA to Pod Identity gradually:
- Note both are in use
- List which service accounts use which method
- Recommend completing migration
No PSA Labels
Namespaces without PSA labels run in unrestricted mode:
- Flag security risk
- Recommend at minimum
baselineenforcement
Multiple Policy Engines
Some clusters run both Kyverno and Gatekeeper:
- Note complexity risk
- Check for conflicting policies
GuardDuty Integration
# Check if GuardDuty EKS Runtime Monitoring is enabled
aws guardduty list-detectors --query 'DetectorIds'
# Then check features for each detector
aws guardduty get-detector --detector-id <id> \
--query 'Features[?Name==`EKS_RUNTIME_MONITORING`]'Admission Webhooks
Identify validating and mutating admission webhooks to understand what policies are enforced at admission time. Webhooks can block or modify resources before they're persisted.
CLI:
# List validating webhooks (exclude system webhooks)
kubectl get validatingwebhookconfigurations -o json | jq '[
.items[] |
select(.metadata.name | test("^(eks|vpc-resource|aws-)") | not) |
{name: .metadata.name, webhooks: [.webhooks[].name], failurePolicy: .webhooks[0].failurePolicy}
]'
# List mutating webhooks (exclude system webhooks)
kubectl get mutatingwebhookconfigurations -o json | jq '[
.items[] |
select(.metadata.name | test("^(eks|vpc-resource|aws-)") | not) |
{name: .metadata.name, webhooks: [.webhooks[].name], failurePolicy: .webhooks[0].failurePolicy}
]'
# Count all webhooks
kubectl get validatingwebhookconfigurations --no-headers | wc -l
kubectl get mutatingwebhookconfigurations --no-headers | wc -lExample output (validating webhooks):
[
{
"name": "kyverno-resource-validating-webhook-cfg",
"webhooks": ["validate.kyverno.svc"],
"failurePolicy": "Fail"
},
{
"name": "cert-manager-webhook",
"webhooks": ["webhook.cert-manager.io"],
"failurePolicy": "Fail"
}
]Notable webhooks to look for:
kyverno-*- Kyverno policy enforcementgatekeeper-*- OPA Gatekeeper constraintscert-manager-webhook- Certificate managementaws-load-balancer-webhook- ALB controller validation
---
Recommendations Based on Findings
| Finding | Recommendation |
|---|---|
| node-role IAM model | Migrate to Pod Identity for least-privilege |
| IRSA only | Consider Pod Identity for simpler management |
| No PSA labels | Apply at least baseline enforcement |
| No policy engine | Consider Kyverno for policy-as-code |
| KMS encryption not enabled | Enable for compliance requirements |
| No secrets solution | Implement ESO or Secrets Store CSI |
| Overly permissive RBAC | Review and tighten role permissions |
| Many mutating webhooks | Review for performance impact on API server |
Related skills
FAQ
Is it read-only?
Yes; the skill only discovers current state and does not create or modify cluster resources.
How does it access the cluster?
It prefers the EKS MCP Server for pre-authorized read-only operations and falls back to AWS CLI and kubectl in CLI mode.