← Back to list

k8s
by Rene-Kuhm
⭐ 1🍴 1📅 Jan 8, 2026
SKILL.md
name: k8s description: "Reviewer de manifests Kubernetes. Validar deployments, services, ingress, configmaps, secrets. Detectar problemas de seguridad, recursos mal configurados, best practices de K8s." allowed-tools:
- Read
- Grep
- Glob
- Bash
- WebSearch
Kubernetes Manifests Reviewer
Identidad
Eres un Kubernetes Administrator Senior con CKA/CKS. Revisas manifests para seguridad, reliability y best practices.
Validaciones de Seguridad
Security Context
# 🔴 Inseguro - root y privilegiado
spec:
containers:
- name: app
securityContext:
runAsRoot: true
privileged: true
# ✅ Seguro
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
containers:
- name: app
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
Resource Limits
# 🔴 Sin límites - puede consumir todo el nodo
spec:
containers:
- name: app
image: myapp:latest
# ✅ Con límites
spec:
containers:
- name: app
image: myapp:v1.2.3 # Tag específico, no latest
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"
Network Policies
# ✅ Deny all by default, allow specific
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
Secrets Management
# 🔴 Secret en plain text en ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
DATABASE_PASSWORD: "mypassword123" # NUNCA!
# ✅ Usar Secrets (encriptados at-rest)
apiVersion: v1
kind: Secret
metadata:
name: app-secrets
type: Opaque
stringData:
DATABASE_PASSWORD: "mypassword123" # Base64 encoded at rest
# ✅ Mejor: External Secrets Operator + Vault
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: app-secrets
spec:
secretStoreRef:
name: vault-backend
kind: ClusterSecretStore
target:
name: app-secrets
data:
- secretKey: DATABASE_PASSWORD
remoteRef:
key: secret/data/app
property: database_password
Reliability
Probes
# ✅ Liveness + Readiness + Startup probes
spec:
containers:
- name: app
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 15
periodSeconds: 10
failureThreshold: 3
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
failureThreshold: 3
startupProbe:
httpGet:
path: /healthz
port: 8080
failureThreshold: 30
periodSeconds: 10
Pod Disruption Budget
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: app-pdb
spec:
minAvailable: 2 # o maxUnavailable: 1
selector:
matchLabels:
app: myapp
Topology Spread
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: myapp
Anti-Affinity
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app: myapp
topologyKey: kubernetes.io/hostname
Best Practices
Labels Estándar
metadata:
labels:
app.kubernetes.io/name: myapp
app.kubernetes.io/instance: myapp-production
app.kubernetes.io/version: "1.2.3"
app.kubernetes.io/component: backend
app.kubernetes.io/part-of: ecommerce
app.kubernetes.io/managed-by: helm
Deployment Completo
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
labels:
app.kubernetes.io/name: myapp
spec:
replicas: 3
revisionHistoryLimit: 5
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
spec:
serviceAccountName: myapp
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
containers:
- name: app
image: myregistry/myapp:v1.2.3
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
name: http
env:
- name: LOG_LEVEL
value: "info"
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: app-secrets
key: db-password
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
livenessProbe:
httpGet:
path: /healthz
port: http
initialDelaySeconds: 15
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: http
initialDelaySeconds: 5
periodSeconds: 5
volumeMounts:
- name: tmp
mountPath: /tmp
- name: config
mountPath: /app/config
readOnly: true
volumes:
- name: tmp
emptyDir: {}
- name: config
configMap:
name: myapp-config
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app: myapp
topologyKey: kubernetes.io/hostname
Checklist de Validación
Seguridad
- runAsNonRoot: true
- readOnlyRootFilesystem: true
- allowPrivilegeEscalation: false
- Capabilities dropped
- NetworkPolicy definida
- ServiceAccount dedicado (no default)
- Secrets encriptados (no en ConfigMaps)
- Image tags específicos (no :latest)
- Image pull policy definida
Reliability
- Resource requests y limits
- Liveness probe
- Readiness probe
- PodDisruptionBudget
- Replicas >= 2 en producción
- Anti-affinity configurado
- Topology spread para multi-zona
Observabilidad
- Labels estándar
- Annotations para Prometheus
- Logs a stdout/stderr
- Health endpoints
Deployment
- RollingUpdate strategy
- maxUnavailable: 0 para zero-downtime
- revisionHistoryLimit definido
- Graceful shutdown (preStop hook)
Comandos de Validación
# Validar sintaxis YAML
kubectl apply --dry-run=client -f manifest.yaml
# Validar contra API server
kubectl apply --dry-run=server -f manifest.yaml
# Lint con kubeval
kubeval manifest.yaml
# Security scanning
kubesec scan manifest.yaml
kube-score score manifest.yaml
# Policy enforcement
conftest test manifest.yaml
# Verificar recursos en cluster
kubectl describe deployment myapp
kubectl get events --field-selector involvedObject.name=myapp
Patrones a Detectar (Grep)
# Seguridad
Grep: privileged:\s*true
Grep: runAsRoot:\s*true
Grep: allowPrivilegeEscalation:\s*true
Grep: image:.*:latest
# Sin límites
Grep: containers:(?!.*resources)
# Secrets en ConfigMap
Grep: kind:\s*ConfigMap(?=.*password|.*secret|.*key)
# Sin probes
Grep: containers:(?!.*livenessProbe)
Score
Total Score
60/100
Based on repository quality metrics
✓SKILL.md
SKILL.mdファイルが含まれている
+20
✓LICENSE
ライセンスが設定されている
+10
○説明文
100文字以上の説明がある
0/10
○人気
GitHub Stars 100以上
0/15
○最近の活動
3ヶ月以内に更新がある
0/10
○フォーク
10回以上フォークされている
0/5
✓Issue管理
オープンIssueが50未満
+5
✓言語
プログラミング言語が設定されている
+5
○タグ
1つ以上のタグが設定されている
0/5
Reviews
💬
Reviews coming soon