# AKS — Azure Kubernetes Service: Workload Identity, HPA y Configuración Segura

Referencia de patrones para clusters AKS con Workload Identity, escalado automático y seguridad.

---

## 1. Crear cluster AKS con configuración segura

```bash
# Cluster con Workload Identity habilitado (OBLIGATORIO para acceder a servicios Azure)
az aks create \
    --resource-group mi-rg \
    --name mi-cluster-aks \
    --location eastus \
    --node-count 3 \
    --min-count 2 \
    --max-count 10 \
    --enable-cluster-autoscaler \
    --node-vm-size Standard_D4s_v3 \
    --enable-oidc-issuer \
    --enable-workload-identity \
    --network-plugin azure \
    --network-policy calico \
    --enable-addons monitoring \
    --workspace-resource-id $LOG_ANALYTICS_ID \
    --generate-ssh-keys
```

**Opciones clave:**
- `--enable-oidc-issuer` y `--enable-workload-identity`: habilitan Workload Identity
  para que los pods accedan a Azure sin montar archivos de credenciales
- `--network-policy calico`: habilita NetworkPolicy de Kubernetes para aislar pods
- `--enable-addons monitoring`: integración automática con Azure Monitor y Log Analytics
- `--enable-cluster-autoscaler`: escala los nodos según la demanda real

---

## 2. Node Pools — separación de cargas de trabajo

```bash
# Node pool para producción (siempre disponible)
az aks nodepool add \
    --resource-group mi-rg \
    --cluster-name mi-cluster-aks \
    --name produccion \
    --node-count 2 \
    --min-count 2 \
    --max-count 20 \
    --enable-cluster-autoscaler \
    --node-vm-size Standard_D4s_v3 \
    --node-taints env=produccion:NoSchedule \
    --labels env=produccion

# Node pool para jobs/workers (puede escalar a cero)
az aks nodepool add \
    --resource-group mi-rg \
    --cluster-name mi-cluster-aks \
    --name workers \
    --node-count 0 \
    --min-count 0 \
    --max-count 10 \
    --enable-cluster-autoscaler \
    --node-vm-size Standard_D8s_v3 \
    --node-taints workload=batch:NoSchedule \
    --labels workload=batch
```

---

## 3. Workload Identity — acceso seguro a Azure desde pods

Workload Identity vincula una Kubernetes Service Account (KSA) con una
Azure Managed Identity. Los pods usan la KSA y Azure autentica usando
la identidad vinculada. Sin archivos de credenciales, sin rotación manual.

```bash
# 1. Crear User-Assigned Managed Identity
az identity create \
    --name mi-api-identity \
    --resource-group mi-rg

# Capturar IDs necesarios
IDENTITY_CLIENT_ID=$(az identity show \
    --name mi-api-identity \
    --resource-group mi-rg \
    --query clientId -o tsv)

IDENTITY_OBJECT_ID=$(az identity show \
    --name mi-api-identity \
    --resource-group mi-rg \
    --query principalId -o tsv)

# 2. Obtener el OIDC Issuer URL del cluster
OIDC_ISSUER=$(az aks show \
    --resource-group mi-rg \
    --name mi-cluster-aks \
    --query "oidcIssuerProfile.issuerUrl" -o tsv)

# 3. Crear la federación entre la KSA y la Managed Identity
az identity federated-credential create \
    --name mi-api-federated-credential \
    --identity-name mi-api-identity \
    --resource-group mi-rg \
    --issuer $OIDC_ISSUER \
    --subject "system:serviceaccount:mi-namespace:mi-api-ksa" \
    --audience api://AzureADTokenExchange

# 4. Otorgar permisos a la Managed Identity
az keyvault set-policy \
    --name mi-vault \
    --object-id $IDENTITY_OBJECT_ID \
    --secret-permissions get list
```

```yaml
# Kubernetes Service Account con anotación de Workload Identity
apiVersion: v1
kind: ServiceAccount
metadata:
  name: mi-api-ksa
  namespace: mi-namespace
  annotations:
    azure.workload.identity/client-id: "CLIENT_ID_DE_LA_MANAGED_IDENTITY"
```

```yaml
# Deployment con Workload Identity
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mi-api
  namespace: mi-namespace
spec:
  selector:
    matchLabels:
      app: mi-api
      azure.workload.identity/use: "true"  # Label obligatorio
  template:
    metadata:
      labels:
        app: mi-api
        azure.workload.identity/use: "true"  # Label obligatorio en el pod
    spec:
      serviceAccountName: mi-api-ksa  # SA con anotación de Workload Identity
      containers:
        - name: api
          image: miregistry.azurecr.io/mi-api:latest
          resources:
            requests:
              cpu: "250m"
              memory: "256Mi"
            limits:
              cpu: "1"
              memory: "512Mi"
          env:
            - name: AZURE_TENANT_ID
              valueFrom:
                fieldRef:
                  fieldPath: metadata.annotations['azure.workload.identity/tenant-id']
            - name: KEY_VAULT_URL
              value: "https://mi-vault.vault.azure.net/"
```

---

## 4. Horizontal Pod Autoscaler (HPA)

```yaml
# HPA basado en CPU y memoria
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: mi-api-hpa
  namespace: mi-namespace
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: mi-api
  minReplicas: 2
  maxReplicas: 20
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70
    - type: Resource
      resource:
        name: memory
        target:
          type: Utilization
          averageUtilization: 80
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300  # Evita flapping
      policies:
        - type: Percent
          value: 25
          periodSeconds: 60
    scaleUp:
      stabilizationWindowSeconds: 0   # Escala hacia arriba inmediatamente
      policies:
        - type: Percent
          value: 100
          periodSeconds: 15
```

---

## 5. NetworkPolicy — aislar namespaces en AKS

```yaml
# Denegar todo tráfico por defecto y permitir solo lo necesario
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: denegar-todo-por-defecto
  namespace: mi-namespace
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress

---
# Permitir tráfico desde el ingress controller al API
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: permitir-ingress
  namespace: mi-namespace
spec:
  podSelector:
    matchLabels:
      app: mi-api
  policyTypes:
    - Ingress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: ingress-nginx
      ports:
        - protocol: TCP
          port: 8000

---
# Permitir DNS (obligatorio para que los pods resuelvan nombres)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: permitir-dns
  namespace: mi-namespace
spec:
  podSelector: {}
  policyTypes:
    - Egress
  egress:
    - ports:
        - protocol: UDP
          port: 53
        - protocol: TCP
          port: 53
```

---

## 6. Integración con Azure Container Registry (ACR)

```bash
# Vincular ACR al cluster AKS para pull automático sin credenciales
az aks update \
    --resource-group mi-rg \
    --name mi-cluster-aks \
    --attach-acr mi-registry

# Verificar que el cluster puede hacer pull de imágenes
az aks check-acr \
    --resource-group mi-rg \
    --name mi-cluster-aks \
    --acr mi-registry.azurecr.io
```

---

## 7. Checklist de seguridad AKS

- [ ] Workload Identity habilitado (`--enable-oidc-issuer --enable-workload-identity`)
- [ ] Network Policy habilitada (`--network-policy calico` o `azure`)
- [ ] Node pools separados para producción y workers/batch
- [ ] Todos los Deployments tienen `resources.requests` y `resources.limits`
- [ ] HPA configurado con `minReplicas >= 2` para servicios críticos
- [ ] ACR vinculado al cluster (no usar credenciales de registro en imagePullSecrets)
- [ ] Diagnostic settings configurados con Log Analytics (`--enable-addons monitoring`)
- [ ] Imágenes de contenedor con versión explícita (nunca `:latest` en producción)
- [ ] Private cluster habilitado para producción (`--enable-private-cluster`)

---

## 8. Comandos frecuentes

```bash
# Obtener credenciales del cluster
az aks get-credentials \
    --resource-group mi-rg \
    --name mi-cluster-aks

# Ver estado del cluster
kubectl get nodes -o wide
kubectl top nodes

# Ver pods con service account y namespace
kubectl get pods -n mi-namespace -o wide

# Verificar que Workload Identity está funcionando
kubectl exec -it deployment/mi-api -n mi-namespace -- \
    printenv | grep AZURE

# Ver logs en tiempo real con Azure Monitor
az aks show --resource-group mi-rg --name mi-cluster-aks \
    --query "addonProfiles.omsagent.config.logAnalyticsWorkspaceResourceID"

# Escalar manualmente un deployment (para emergencias)
kubectl scale deployment mi-api --replicas=5 -n mi-namespace
```
