본문으로 건너뛰기

Ops Security Audit

AWS/EKS security audit skill.

Description

Performs comprehensive security audits including IAM, network security, and compliance.

Trigger Keywords

  • "security audit"
  • "security check"
  • "compliance"
  • "security review"

Audit Domains

1. IAM & Authentication

  • IRSA/Pod Identity configuration audit
  • RBAC Role and Binding review
  • aws-auth ConfigMap analysis
  • Least privilege assessment

2. Network Security

  • Security Group rules review
  • Network Policy coverage
  • VPC Endpoint configuration
  • Public endpoint exposure

3. Compliance

  • CIS Kubernetes Benchmark checks
  • AWS security best practices
  • Pod Security Standards
  • Secret management

Quick Audit Commands

# Privileged containers
kubectl get pods -A -o json | jq '[.items[] | select(.spec.containers[].securityContext.privileged==true) | {name:.metadata.name,ns:.metadata.namespace}]'

# Pods running as root
kubectl get pods -A -o json | jq '[.items[] | select(.spec.securityContext.runAsUser==0 or .spec.containers[].securityContext.runAsUser==0) | {name:.metadata.name,ns:.metadata.namespace}]'

# Network policy coverage
kubectl get networkpolicies -A
kubectl get namespaces -o json | jq '.items[].metadata.name' | while read ns; do echo "$ns: $(kubectl get networkpolicies -n $(echo $ns | tr -d '"') 2>/dev/null | wc -l) policies"; done

# Public services
kubectl get svc -A -o json | jq '[.items[] | select(.spec.type=="LoadBalancer") | {name:.metadata.name,ns:.metadata.namespace,type:.spec.type}]'

CIS Benchmark Checklist Detail

Control Plane (AWS Managed)

AWS manages these for EKS - verify they're enabled:

#CheckVerification Command
1.1API server audit loggingaws eks describe-cluster --name $CLUSTER_NAME --query 'cluster.logging'
1.2RBAC enabledAlways enabled on EKS
1.3Admission controllersPodSecurity, ResourceQuota active

Worker Nodes

#CheckCommandExpected
4.1kubelet authenticationCheck kubelet configanonymous-auth=false
4.2kubelet authorizationCheck kubelet configmode=Webhook
4.3Protect kubelet certificateskubectl get nodes -o json | jq '.items[].status.daemonEndpoints'Port 10250 only

Workload Security

#CheckCommandExpected
5.1No privileged containerskubectl get pods -A -o json | jq '[.items[] | select(.spec.containers[].securityContext.privileged==true)]'Empty (except system)
5.2No root containersCheck securityContextrunAsNonRoot=true
5.3No hostNetworkCheck pod spechostNetwork=false
5.4No hostPIDCheck pod spechostPID=false
5.5No hostIPCCheck pod spechostIPC=false
5.6Read-only root FSCheck securityContextreadOnlyRootFilesystem=true
5.7Drop ALL capabilitiesCheck securityContextcapabilities.drop=["ALL"]

Network Security

#CheckCommandExpected
6.1Network policieskubectl get networkpolicies -AAll namespaces covered
6.2Private endpointCheck cluster configprivateAccess=true
6.3Restricted public accessCheck publicAccessCidrsNot 0.0.0.0/0

IAM Audit Detail

IRSA Verification

Check All Service Account Annotations

# List all IRSA-annotated service accounts
kubectl get sa -A -o json | jq '.items[] | select(.metadata.annotations["eks.amazonaws.com/role-arn"] != null) | {namespace:.metadata.namespace, name:.metadata.name, role:.metadata.annotations["eks.amazonaws.com/role-arn"]}'

Verify Trust Policies

# For each IRSA role, verify trust policy is scoped correctly
ROLE_NAME=<role-name>
aws iam get-role --role-name $ROLE_NAME --query 'Role.AssumeRolePolicyDocument'

# Trust policy should:
# 1. Limit to specific OIDC provider
# 2. Limit to specific namespace:serviceaccount
# 3. Use StringEquals (not StringLike) where possible

Check IRSA Permissions

# List all policies attached to an IRSA role
aws iam list-attached-role-policies --role-name $ROLE_NAME
aws iam list-role-policies --role-name $ROLE_NAME

# Check for overly permissive policies
aws iam get-role-policy --role-name $ROLE_NAME --policy-name <policy> | jq '.PolicyDocument.Statement[] | select(.Action=="*" or .Resource=="*")'

Pod Identity Checks

# List all Pod Identity associations
aws eks list-pod-identity-associations --cluster-name $CLUSTER_NAME

# Check each association
for assoc_id in $(aws eks list-pod-identity-associations --cluster-name $CLUSTER_NAME --query 'associations[].associationId' --output text); do
aws eks describe-pod-identity-association --cluster-name $CLUSTER_NAME --association-id $assoc_id
done

RBAC Analysis Commands

Overly Permissive Roles

# Find cluster-admin bindings
kubectl get clusterrolebindings -o json | jq '.items[] | select(.roleRef.name=="cluster-admin") | {name:.metadata.name, subjects:.subjects}'

# Find roles with wildcard permissions
kubectl get clusterroles -o json | jq '.items[] | select(.rules[].verbs[] == "*" or .rules[].resources[] == "*") | .metadata.name'

# Check specific user/SA permissions
kubectl auth can-i --list --as=system:serviceaccount:<ns>:<sa>

aws-auth ConfigMap Audit

# View current mappings
kubectl get configmap aws-auth -n kube-system -o yaml

# Check for:
# 1. Unnecessary admin mappings
# 2. Stale role ARNs
# 3. Overly broad group mappings (system:masters)

Access Entry Audit (EKS API)

# List all access entries
aws eks list-access-entries --cluster-name $CLUSTER_NAME

# Check each entry
for principal in $(aws eks list-access-entries --cluster-name $CLUSTER_NAME --query 'accessEntries[]' --output text); do
echo "=== $principal ==="
aws eks list-associated-access-policies --cluster-name $CLUSTER_NAME --principal-arn $principal
done

IAM Security Best Practices Checklist

CheckCommandExpected
No wildcard IAM policiesCheck IRSA role policiesNo * in Action/Resource
Trust policy scopedCheck AssumeRolePolicyDocumentSpecific namespace:SA
No stale IRSA rolesCross-reference SA and rolesAll roles have active SAs
Minimal cluster-adminCheck ClusterRoleBindingsOnly essential bindings
Pod Identity preferredCheck associations vs IRSAMigrated where possible
Audit logging enabledCheck cluster configauthenticator + audit enabled

Pod Security Standards Guide

Comparison Table

FeaturePrivilegedBaselineRestricted
hostNetworkAllowedNot allowedNot allowed
hostPIDAllowedNot allowedNot allowed
hostIPCAllowedNot allowedNot allowed
privilegedAllowedNot allowedNot allowed
capabilitiesAll allowedDrop someMust drop ALL, only add NET_BIND_SERVICE
hostPathAllowedLimitedNot allowed
runAsNonRootNo requirementNo requirementRequired (true)
runAsUserNo requirementNo requirementMust be non-zero
seccompProfileNo requirementNo requirementRuntimeDefault or Localhost
allowPrivilegeEscalationNo requirementNo requirementMust be false

Enforcement Commands

# Check namespace labels for Pod Security Standards
kubectl get ns -o json | jq '.items[] | {name:.metadata.name, labels:.metadata.labels}' | grep -A3 "pod-security"

# Apply restricted policy to namespace
kubectl label namespace <ns> pod-security.kubernetes.io/enforce=restricted
kubectl label namespace <ns> pod-security.kubernetes.io/warn=restricted
kubectl label namespace <ns> pod-security.kubernetes.io/audit=restricted
apiVersion: v1
kind: Pod
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: app
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL

Network Security Audit

Security Group Audit

EKS Cluster Security Groups

# Get cluster security group
CLUSTER_SG=$(aws eks describe-cluster --name $CLUSTER_NAME --query 'cluster.resourcesVpcConfig.clusterSecurityGroupId' --output text)

# Check rules
aws ec2 describe-security-group-rules --filter Name=group-id,Values=$CLUSTER_SG --query 'SecurityGroupRules[].{Direction:IsEgress,Protocol:IpProtocol,FromPort:FromPort,ToPort:ToPort,Source:CidrIpv4,SourceSG:ReferencedGroupInfo.GroupId}'

Node Security Groups

# Find node security groups
aws ec2 describe-instances \
--filters Name=tag:eks:cluster-name,Values=$CLUSTER_NAME \
--query 'Reservations[].Instances[].SecurityGroups[].GroupId' --output text | sort -u | while read sg; do
echo "=== $sg ==="
aws ec2 describe-security-group-rules --filter Name=group-id,Values=$sg --query 'SecurityGroupRules[?!IsEgress].{Protocol:IpProtocol,FromPort:FromPort,ToPort:ToPort,Source:CidrIpv4,SourceSG:ReferencedGroupInfo.GroupId}'
done

Security Group Red Flags

FindingRiskRemediation
Inbound 0.0.0.0/0 on non-443/80HIGHRestrict to specific CIDRs
Outbound 0.0.0.0/0 all portsMEDIUMRestrict to necessary services
SSH (22) open to 0.0.0.0/0CRITICALUse SSM Session Manager instead
Unused security groupsLOWClean up stale SGs

Network Policy Audit

Coverage Assessment

# Namespaces without network policies
for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
policies=$(kubectl get networkpolicies -n $ns 2>/dev/null | tail -n +2 | wc -l)
if [ "$policies" -eq "0" ]; then
echo "WARNING: $ns has no network policies"
fi
done

Default Deny Policy Template

# Apply to every namespace for zero-trust
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress

VPC Endpoint Audit

# List existing VPC endpoints
aws ec2 describe-vpc-endpoints --filters Name=vpc-id,Values=<vpc-id> --query 'VpcEndpoints[].{Service:ServiceName,Type:VpcEndpointType,State:State}'

# Recommended endpoints for EKS
# - com.amazonaws.REGION.ec2
# - com.amazonaws.REGION.ecr.api
# - com.amazonaws.REGION.ecr.dkr
# - com.amazonaws.REGION.s3
# - com.amazonaws.REGION.sts
# - com.amazonaws.REGION.logs
# - com.amazonaws.REGION.elasticloadbalancing

Cluster Endpoint Access

# Check endpoint access configuration
aws eks describe-cluster --name $CLUSTER_NAME --query 'cluster.resourcesVpcConfig.{publicAccess:endpointPublicAccess,privateAccess:endpointPrivateAccess,publicCIDRs:publicAccessCidrs}'

# Best practice: Private access + restricted public CIDRs
# Never: Public access from 0.0.0.0/0 in production

AWS EKS Security Best Practices

Identity & Access

  • Use IRSA or Pod Identity (never node IAM role for workloads)
  • Scope IRSA trust policies to specific namespace:serviceaccount
  • Minimize cluster-admin ClusterRoleBindings
  • Enable EKS access entries (migrate from aws-auth)
  • Rotate IAM credentials regularly
  • Enable MFA for human users

Network

  • Enable VPC endpoints for AWS services
  • Use private cluster endpoint (or restrict public CIDRs)
  • Deploy network policies in all namespaces
  • Use Security Groups for Pods where needed
  • Enable VPC Flow Logs for audit

Data Protection

  • Enable EKS secrets encryption with KMS
  • Use encrypted EBS volumes (gp3 with KMS)
  • Use IRSA for Secrets Manager/Parameter Store access
  • Never store secrets in ConfigMaps
  • Use external-secrets-operator for secret rotation

Monitoring & Audit

  • Enable control plane logging (api + audit + authenticator)
  • Enable Container Insights
  • Set up CloudTrail for AWS API auditing
  • Create alarms for security events
  • Enable GuardDuty EKS protection

Runtime Security

  • Use Bottlerocket or AL2023 (minimal OS)
  • Enable Pod Security Standards (Restricted)
  • Deploy admission webhooks (OPA/Kyverno)
  • Scan container images (ECR scanning, Trivy)
  • Use read-only root filesystems

Quick Compliance Check Script

#!/bin/bash
echo "=== EKS Security Quick Check ==="
CLUSTER=$1

echo "--- Endpoint Access ---"
aws eks describe-cluster --name $CLUSTER --query 'cluster.resourcesVpcConfig.{public:endpointPublicAccess,private:endpointPrivateAccess,cidrs:publicAccessCidrs}'

echo "--- Logging ---"
aws eks describe-cluster --name $CLUSTER --query 'cluster.logging.clusterLogging[?enabled==`true`].types[]'

echo "--- Encryption ---"
aws eks describe-cluster --name $CLUSTER --query 'cluster.encryptionConfig'

echo "--- Privileged Containers ---"
kubectl get pods -A -o json | jq '[.items[] | select(.spec.containers[].securityContext.privileged==true) | {name:.metadata.name,ns:.metadata.namespace}] | length'

echo "--- Root Containers ---"
kubectl get pods -A -o json | jq '[.items[] | select(.spec.securityContext.runAsUser==0) | {name:.metadata.name,ns:.metadata.namespace}] | length'

echo "--- Network Policies ---"
kubectl get networkpolicies -A --no-headers | wc -l

echo "--- cluster-admin Bindings ---"
kubectl get clusterrolebindings -o json | jq '[.items[] | select(.roleRef.name=="cluster-admin") | .metadata.name]'

Team Mode

"security audit" requests may trigger team-based parallel audits:

TriggerTeam NameComposition
Security audit requestops-security-auditiam + network + storage parallel audit

Usage Examples

Full Security Audit

Please run a cluster security audit.

Security Audit skill runs automatically:

  1. IAM/RBAC configuration review
  2. Network security review
  3. Compliance checklist verification
  4. Report findings by risk level

Specific Domain Audit

Please audit IRSA configuration.

Security Audit performs:

  1. OIDC provider verification
  2. Service Account annotation check
  3. Trust Policy analysis
  4. IAM Policy permissions review

Output Format

# Security Audit Report

## Summary
- Audit Date: [timestamp]
- Cluster: [name]
- Overall Risk: LOW / MEDIUM / HIGH / CRITICAL

## Findings

| # | Severity | Domain | Finding | Recommendation |
|---|----------|--------|---------|----------------|
| 1 | CRITICAL | IAM | [Finding] | [Fix] |
| 2 | HIGH | Network | [Finding] | [Fix] |

## Compliance Checklist
- [ ] No privileged containers in workloads
- [ ] All pods run as non-root
- [ ] Network policies in all namespaces
- [ ] IRSA/Pod Identity for all AWS access
- [ ] Secrets encrypted with KMS
- [ ] Control plane audit logging enabled
- [ ] VPC endpoints for AWS services
- [ ] Cluster endpoint private access

Reference Files

  • references/iam-audit.md - IAM, IRSA, Pod Identity, RBAC audit
  • references/network-security.md - Security Groups, Network Policies, VPC Endpoints
  • references/compliance-checklist.md - CIS Benchmark, best practices checklist