Steampipe: El cuchillo suizo de SQL para travesuras en la nube

Steampipe: El cuchillo suizo de SQL para travesuras en la nube

El Desafío de Visibilidad en la Nube de DevSecOps

Tu infraestructura en la nube se está expandiendo más rápido de lo que tu equipo de seguridad puede auditarla. Cada implementación, cada evento de autoescalado, cada recurso creado por un desarrollador potencialmente introduce brechas de seguridad. Necesitas visibilidad en tiempo real en todo tu entorno multi-nube, pero las herramientas de seguridad tradicionales te ofrecen instantáneas puntuales, no el monitoreo continuo que requiere el DevSecOps moderno.

Aquí es donde Steampipe se convierte en tu multiplicador de fuerza DevSecOps, transformando complejas APIs de la nube en consultas SQL que se integran perfectamente con tus flujos de trabajo de automatización y cumplimiento existentes.

Steampipe: Inteligencia de Seguridad en la Nube Impulsada por SQL

Piensa en Steampipe como si tu infraestructura en la nube se convirtiera en una enorme base de datos consultable. Cada recurso, cada configuración, cada ajuste de seguridad a través de AWS, Azure, GCP y más de 50 otras plataformas se convierte en una tabla que puedes consultar, unir y analizar usando una sintaxis SQL familiar.

Pero esto no se trata solo de consultas, se trata de habilitar Política como Código a escala empresarial. ¿Quieres validar tu cumplimiento con el CIS Kubernetes Benchmark en 15 clústeres? Eso es una consulta SQL. ¿Necesitas auditar permisos IAM en múltiples cuentas de AWS para el cumplimiento SOC2? Consulta SQL. ¿Quieres identificar la desviación de configuración en tu infraestructura gestionada por Terraform? Ya entiendes la idea.

Steampipe transforma la seguridad en la nube de una respuesta reactiva a incidentes en una gobernanza proactiva y automatizada que se integra directamente en tus flujos de trabajo de CI/CD y cumplimiento.

Despliegue DevSecOps Empresarial

Steampipe está diseñado para operaciones DevSecOps a escala empresarial con soporte para despliegues en contenedores, infraestructura como código e integración CI/CD.

Instalación Prioritaria en Contenedores (Recomendada)

Para entornos de producción DevSecOps, despliega Steampipe como un servicio en contenedores:

# Dockerfile para despliegue empresarial de Steampipe
FROM turbot/steampipe:latest

# Instalar plugins requeridos para monitoreo empresarial multi-nube
RUN steampipe plugin install aws azure gcp kubernetes terraform \
    github gitlab docker oci helm vault consul nomad

# Copiar configuración empresarial
COPY steampipe.spc /home/steampipe/.steampipe/config/
COPY enterprise-queries/ /opt/steampipe/queries/
COPY compliance-policies/ /opt/steampipe/policies/

# Configurar usuario de servicio para consultas automatizadas
USER steampipe
WORKDIR /opt/steampipe

# Comando predeterminado para integración CI/CD
CMD ["steampipe", "service", "start", "--host=0.0.0.0", "--port=9193"]

Despliegue de Kubernetes para Escalabilidad

Desplegar Steampipe como un servicio de Kubernetes para monitoreo de seguridad en la nube a nivel empresarial:

# steampipe-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: steampipe-security-service
  namespace: devsecops
spec:
  replicas: 3
  selector:
    matchLabels:
      app: steampipe
  template:
    metadata:
      labels:
        app: steampipe
    spec:
      serviceAccountName: steampipe-sa
      containers:
        - name: steampipe
          image: your-registry/steampipe-enterprise:latest
          ports:
            - containerPort: 9193
          env:
            - name: STEAMPIPE_LOG_LEVEL
              value: 'info'
            - name: STEAMPIPE_DATABASE_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: steampipe-db-secret
                  key: password
          volumeMounts:
            - name: steampipe-config
              mountPath: /home/steampipe/.steampipe/config
              readOnly: true
            - name: cloud-credentials
              mountPath: /home/steampipe/.aws
              readOnly: true
      volumes:
        - name: steampipe-config
          configMap:
            name: steampipe-enterprise-config
        - name: cloud-credentials
          secret:
            secretName: cloud-access-credentials
---
apiVersion: v1
kind: Service
metadata:
  name: steampipe-service
  namespace: devsecops
spec:
  selector:
    app: steampipe
  ports:
    - port: 9193
      targetPort: 9193
  type: ClusterIP

Configuración de Plugins Empresariales

Instalar y configurar plugins para una cobertura integral multi-nube:

# Proveedores de nube principales
steampipe plugin install aws azure gcp

# Plataformas de contenedores y orquestación
steampipe plugin install kubernetes docker oci

# Infraestructura como Código
steampipe plugin install terraform consul vault nomad

# Integración de la cadena de herramientas DevSecOps
steampipe plugin install github gitlab jenkins splunk prometheus grafana

# Marcos de cumplimiento y seguridad
steampipe plugin install crowdstrike qualys tenable rapid7

# Configurar acceso multi-cuenta
steampipe connection import aws-accounts.spc
steampipe connection import azure-subscriptions.spc
steampipe connection import gcp-projects.spc

Integración de Pipeline CI/CD

Configurar Steampipe para validación de seguridad automatizada en tus pipelines de despliegue:

# .github/workflows/security-compliance.yml
name: Cumplimiento de Seguridad Automatizado
on:
  schedule:
    - cron: '0 */6 * * *' # Cada 6 horas
  push:
    branches: [main]
    paths: ['infrastructure/**', 'k8s/**']

jobs:
  security-validation:
    runs-on: ubuntu-latest
    container:
      image: turbot/steampipe:latest
    steps:
      - name: Configurar Acceso a la Nube
        run: |
          # Configurar acceso a AWS
          aws configure set aws_access_key_id ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws configure set aws_secret_access_key ${{ secrets.AWS_SECRET_ACCESS_KEY }}

          # Configurar acceso a Azure
          az login --service-principal -u ${{ secrets.AZURE_CLIENT_ID }} \
            -p ${{ secrets.AZURE_CLIENT_SECRET }} \
            --tenant ${{ secrets.AZURE_TENANT_ID }}

      - name: Instalar Plugins Empresariales
        run: |
          steampipe plugin install aws azure gcp kubernetes terraform
  - name: Ejecutar Validación de Cumplimiento
    run: |
      # Validación del Benchmark CIS Kubernetes
      steampipe query \
        "select * from kubernetes_pod where security_context is null" \
        --output json > cis-k8s-violations.json
        
      # Mejores prácticas de seguridad de AWS
      steampipe query \
        "select * from aws_s3_bucket where acl like '%public%'" \
        --output json > aws-security-violations.json
        
      # Inventario de recursos multi-nube
      steampipe query \
        "select 'aws' as cloud, instance_id as resource, region from aws_ec2_instance
         union all
         select 'azure' as cloud, name as resource, location from azure_compute_virtual_machine
         union all  
         select 'gcp' as cloud, name as resource, zone from gcp_compute_instance" \
        --output json > multi-cloud-inventory.json

  - name: Generar Informe de Cumplimiento
    run: |
      # Generar resumen ejecutivo
      steampipe dashboard --dashboard compliance-overview \
        --export compliance-report.pdf

  - name: Subir Artefactos de Cumplimiento
    uses: actions/upload-artifact@v3
    with:
      name: informes-de-cumplimiento
      path: |
        *.json
        *.pdf

## Tu Primera Consulta: Bienvenido al Lado Oscuro

Comencemos con algo simple. Enciende Steampipe y veamos qué tipo de caos digital has creado:

```bash
steampipe query

Esto te lleva a un shell SQL que está conectado a tus APIs de nube. Es como psql pero para nubes, y mucho más peligroso.

Encontrando Tus Instancias EC2 (Las Obvias)

-- Veamos qué instancias EC2 estás ejecutando
SELECT
  instance_id,
  instance_type,
  state,
  region,
  tags
FROM aws_ec2_instance
WHERE state = 'running';

El Momento “Oh Shit”: Recursos Públicos

-- Encontrar instancias RDS accesibles públicamente
-- (Alerta de spoiler: probablemente tengas algunas)
SELECT
  db_instance_identifier,
  engine,
  publicly_accessible,
  endpoint_address,
  region
FROM aws_rds_db_instance
WHERE publicly_accessible = true;
-- Cubos S3 que básicamente están regalando datos gratis
SELECT
  name,
  region,
  acl,
  policy_std
FROM aws_s3_bucket
WHERE acl LIKE '%public%'
   OR policy_std::text LIKE '%"Principal": "*"%';

Consultas Avanzadas: Donde Comienza la Verdadera Diversión

Una vez que te sientas cómodo con las consultas básicas, puedes comenzar a construir reglas de CIEM (Gestión de Derechos de Infraestructura en la Nube) más sofisticadas. Piensa en estas como “chequeos de realidad de seguridad” para tu nube.

La Consulta “¿Quién Tiene Acceso de Root?”

-- Encuentra usuarios de IAM que básicamente poseen tu cuenta de AWS
SELECT
  u.name as user_name,
  u.create_date,
  STRING_AGG(p.policy_name, ', ') as attached_policies
FROM aws_iam_user u
JOIN aws_iam_user_attached_policy p ON u.name = p.user_name
WHERE p.policy_arn = 'arn:aws:iam::aws:policy/AdministratorAccess'
   OR p.policy_name LIKE '%Admin%'
GROUP BY u.name, u.create_date
ORDER BY u.create_date DESC;

El detective de “Recursos no utilizados que están consumiendo tu presupuesto”

-- Instancias EC2 que no han sido tocadas en mucho tiempo
SELECT
  instance_id,
  instance_type,
  launch_time,
  state,
  ROUND(EXTRACT(epoch FROM (NOW() - launch_time))/86400) as days_running,
  region
FROM aws_ec2_instance
WHERE state = 'running'
  AND launch_time < NOW() - INTERVAL '30 days'
  AND instance_id NOT IN (
    SELECT DISTINCT instance_id
    FROM aws_cloudwatch_metric_statistic_data_point
    WHERE timestamp > NOW() - INTERVAL '7 days'
      AND metric_name = 'CPUUtilization'
      AND average > 5  -- Más del 5% de uso de CPU
  )
ORDER BY days_running DESC;

El “Salón de la Vergüenza de los Grupos de Seguridad”

-- Grupos de seguridad que son básicamente "¡bienvenidos todos!"
SELECT
  group_id,
  group_name,
  description,
  vpc_id,
  region,
  ip_permissions
FROM aws_ec2_security_group,
  jsonb_array_elements(ip_permissions) as perm
WHERE perm->>'IpProtocol' = '-1'  -- Todos los protocolos
   OR (
     perm->'IpRanges' @> '[{"CidrIp": "0.0.0.0/0"}]'::jsonb
     AND (
       perm->'FromPort' IS NULL
       OR perm->>'FromPort' IN ('22', '3389', '80', '443')
     )
   );

Creando Reglas CIEM Personalizadas: Construyendo Tu Imperio de Seguridad

Ahora vamos a entrar en lo realmente divertido: crear reglas personalizadas que te ayuden a mantener un cierto orden en el caos de tu nube.

Regla 1: El “Detector de Minería de Criptomonedas”

-- Instancias que podrían estar minando criptomonedas
-- (Alto uso de CPU, tipos de instancia sospechosos, funcionando 24/7)
CREATE VIEW sospechoso_minado_cripto AS
SELECT
  e.instance_id,
  e.instance_type,
  e.region,
  e.launch_time,
  ROUND(EXTRACT(epoch FROM (NOW() - e.launch_time))/86400) as dias_funcionando,
  e.tags
FROM aws_ec2_instance e
WHERE e.state = 'running'
  AND e.instance_type IN ('m5.large', 'm5.xlarge', 'c5.large', 'c5.xlarge', 'c5.2xlarge')
  AND e.launch_time < NOW() - INTERVAL '7 days'
  AND (e.tags IS NULL OR NOT (e.tags ? 'Environment' OR e.tags ? 'Project'));

Regla 2: La “Auditoría de Cuenta de Servicio Privilegiada”

-- Cuentas de servicio con privilegios de administrador (generalmente una mala señal)
CREATE VIEW cuentas_de_servicio_sobreprivilegiadas AS
SELECT
  u.name,
  u.path,
  u.create_date,
  CASE
    WHEN u.password_last_used IS NULL THEN 'Nunca ha iniciado sesión'
    ELSE u.password_last_used::text
  END as last_login,
  STRING_AGG(p.policy_name, ', ') as admin_policies
FROM aws_iam_user u
JOIN aws_iam_user_attached_policy p ON u.name = p.user_name
WHERE (u.name LIKE '%service%' OR u.name LIKE '%app%' OR u.name LIKE '%system%')
  AND (
    p.policy_arn LIKE '%Administrator%'
    OR p.policy_arn LIKE '%PowerUser%'
    OR p.policy_name LIKE '%Admin%'
  )
GROUP BY u.name, u.path, u.create_date, u.password_last_used;

Regla 3: “La fuga de datos que está por suceder”

-- Cubos S3 con combinaciones peligrosas
CREATE VIEW candidatos_fuga_datos AS
SELECT
  b.nombre,
  b.región,
  b.versioning_enabled,
  b.server_side_encryption_configuration,
  CASE
    WHEN b.policy_std::text LIKE '%"Principal": "*"%' THEN 'Lectura pública'
    WHEN b.acl LIKE '%public%' THEN 'ACL pública'
    ELSE 'Verificar manualmente'
  END as tipo_exposición,
  CASE
    WHEN b.server_side_encryption_configuration IS NULL THEN 'Sin cifrado'
    ELSE 'Cifrado'
  END as estado_cifrado
FROM aws_s3_bucket b
WHERE (
  b.policy_std::text LIKE '%"Principal": "*"%'
  OR b.acl LIKE '%public%'
)
AND (
  b.nombre LIKE '%backup%'
  OR b.nombre LIKE '%data%'
  OR b.nombre LIKE '%logs%'
  OR b.nombre LIKE '%private%'
);

Consultas Multi-Nube: Porque el Bloqueo de Proveedor es para los que se Rinden

Una de las superpotencias de Steampipe es consultar a través de múltiples proveedores de nube en una sola consulta. Aquí es donde las cosas se ponen realmente interesantes:

Inventario de Recursos Cruzados en la Nube

SELECT ‘Azure’ as provider, service_name as service, SUM(pre_tax_cost) as monthly_cost FROM azure_cost_management WHERE usage_date_time >= date_trunc(‘month’, CURRENT_DATE) GROUP BY service_name

UNION ALL

SELECT ‘GCP’ as provider, service_description as service, SUM(cost) as monthly_cost FROM gcp_billing_export WHERE usage_start_time >= date_trunc(‘month’, CURRENT_DATE) GROUP BY service_description )

SELECT * FROM cloud_costs;


### El "Quién está gastando qué" Auditoría Multi-Nube

```sql
-- Comparar costos entre proveedores (requiere APIs de gestión de costos)
WITH costos_nube AS (
  SELECT
    'AWS' as proveedor,
    servicio,
    SUM(monto_costo_sin_mezclar) as costo_mensual
  FROM aws_costo_por_servicio_mensual
  WHERE periodo_inicio >= date_trunc('month', CURRENT_DATE)
  GROUP BY servicio

  UNION ALL

  SELECT
    'Azure' as proveedor,
    nombre_servicio as servicio,
    SUM(costo_antes_de_impuestos) as costo_mensual
  FROM azure_gestion_de_costos
  WHERE fecha_hora_uso >= date_trunc('month', CURRENT_DATE)
  GROUP BY nombre_servicio

  UNION ALL

  SELECT
    'GCP' as proveedor,
    descripcion_servicio as servicio,
    SUM(costo) as costo_mensual
  FROM gcp_exportacion_facturacion
  WHERE tiempo_inicio_uso >= date_trunc('month', CURRENT_DATE)
  GROUP BY descripcion_servicio
)

SELECT * FROM costos_nube;

SELECT ‘Azure’ as provider, meter_category as service, SUM(cost) as monthly_cost FROM azure_consumption_usage_detail WHERE billing_period_start >= date_trunc(‘month’, CURRENT_DATE) GROUP BY meter_category ) SELECT provider, service, monthly_cost FROM cloud_costs WHERE monthly_cost > 100 — Solo mostrar servicios que cuestan más de $100/mes ORDER BY monthly_cost DESC;


## Casos de Uso de Enterprise DevSecOps

### Escenario 1: Validación Automática de Cumplimiento para SOC2 Tipo II

**Desafío**: Demostrar monitoreo continuo de cumplimiento a través de infraestructura multi-nube para auditoría SOC2.

**Solución**: Consultas de cumplimiento automatizadas integradas en la canalización CI/CD con generación de rastro de auditoría.

```sql
-- SOC2 CC6.1: Controles de Acceso Lógico
-- Consulta para validar que todas las bases de datos de producción tienen habilitado el registro de acceso
CREATE VIEW soc2_database_access_controls AS
SELECT
  'aws-rds' as service,
  db_instance_identifier as resource_id,
  region,
  CASE
    WHEN enabled_cloudwatch_logs_exports IS NOT NULL
    THEN 'CUMPLE: Registro de auditoría habilitado'
    ELSE 'NO CUMPLE: Falta registro de auditoría'
  END as compliance_status,
  'SOC2-CC6.1' as control_id,
  NOW() as assessment_timestamp
FROM aws_rds_db_instance
WHERE tags->>'Environment' = 'production'

UNION ALL

SELECT
  'azure-sql' as service,
  name as resource_id,
  location as region,
  CASE
    WHEN auditing_policy_state = 'Enabled'
    THEN 'CUMPLE: Registro de auditoría habilitado'
    ELSE 'NO CUMPLE: Falta registro de auditoría'
  END as compliance_status,
  'SOC2-CC6.1' as control_id,
  NOW() as assessment_timestamp
FROM azure_sql_database
WHERE tags->>'Environment' = 'production';

— SOC2 CC6.7: Controles de Transmisión de Datos — Validar cifrado en tránsito para todos los servicios de cara al público CREATE VIEW soc2_encryption_in_transit AS SELECT ‘aws-elb’ as service, load_balancer_arn as resource_id, region, CASE WHEN scheme = ‘internet-facing’ AND EXISTS (SELECT 1 FROM jsonb_array_elements(listeners) l WHERE l->>‘Protocol’ = ‘HTTPS’) THEN ‘CUMPLE: HTTPS aplicado’ WHEN scheme = ‘internet-facing’ THEN ‘NO CUMPLE: Tráfico HTTP permitido’ ELSE ‘NO APLICA: Balanceador de carga interno’ END as compliance_status, ‘SOC2-CC6.7’ as control_id, NOW() as assessment_timestamp FROM aws_elbv2_load_balancer WHERE tags->>‘Environment’ = ‘production’;


**Script de Automatización para Cumplimiento Continuo:**

```bash
#!/bin/bash
# continuous-compliance-monitoring.sh

# Resultados de cumplimiento de exportación para el registro de auditoría
steampipe query "SELECT * FROM soc2_database_access_controls" \
  --output json \
  --output-file "compliance-reports/soc2-cc61-$(date +%Y%m%d-%H%M%S).json"

steampipe query "SELECT * FROM soc2_encryption_in_transit" \
  --output json \
  --output-file "compliance-reports/soc2-cc67-$(date +%Y%m%d-%H%M%S).json"

# Verificar recursos no conformes
NON_COMPLIANT=$(steampipe query \
  "SELECT COUNT(*) as violations FROM (
    SELECT * FROM soc2_database_access_controls WHERE compliance_status LIKE 'NON-COMPLIANT%'
    UNION ALL
    SELECT * FROM soc2_encryption_in_transit WHERE compliance_status LIKE 'NON-COMPLIANT%'
  ) violations" --output json | jq '.[0].violations')

if [ "$NON_COMPLIANT" -gt 0 ]; then
  echo "🚨 ALERTA DE CUMPLIMIENTO: $NON_COMPLIANT violaciones SOC2 detectadas"
  # Enviar alerta al equipo de cumplimiento
  curl -X POST "$SLACK_WEBHOOK_URL" \
    -H 'Content-type: application/json' \
    --data "{\"text\":\"Alerta de Cumplimiento SOC2: $NON_COMPLIANT violaciones detectadas en el entorno de producción\"}"
fi

Escenario 2: Detección de Deriva de Infraestructura como Código

Desafío: La infraestructura gestionada por Terraform se desvía del estado deseado, creando brechas de seguridad y cumplimiento.

Solución: Detección automática de deriva usando Steampipe para comparar el estado en vivo contra la configuración de Terraform.

-- Detectar buckets de S3 creados fuera de la gestión de Terraform
CREATE VIEW terraform_drift_s3_buckets AS
WITH terraform_managed_buckets AS (
  SELECT
    name as bucket_name,
    'managed' as management_status
  FROM terraform_resource
  WHERE type = 'aws_s3_bucket'
),
live_buckets AS (
  SELECT
    name as bucket_name,
    creation_date,
    tags
  FROM aws_s3_bucket
)
SELECT
  lb.bucket_name,
  lb.creation_date,
  lb.tags,
  CASE
    WHEN tmb.management_status IS NULL
    THEN 'DRIFT: Se detectó un bucket de S3 no gestionado'
    ELSE 'MANAGED: Controlado por Terraform'
  END as drift_status,
  'aws_s3_bucket' as resource_type
FROM live_buckets lb
LEFT JOIN terraform_managed_buckets tmb ON lb.bucket_name = tmb.bucket_name
WHERE lb.tags->>'Environment' = 'production';

— Detectar instancias EC2 con desviación de configuración CREATE VIEW terraform_drift_ec2_instances AS WITH terraform_instances AS ( SELECT attributes_json->>‘id’ as instance_id, attributes_json->>‘instance_type’ as tf_instance_type, attributes_json->>‘vpc_security_group_ids’ as tf_security_groups FROM terraform_resource WHERE type = ‘aws_instance’ ), live_instances AS ( SELECT instance_id, instance_type, security_groups, tags FROM aws_ec2_instance WHERE state = ‘running’ ) SELECT li.instance_id, li.instance_type as current_type, ti.tf_instance_type as terraform_type, CASE WHEN ti.instance_id IS NULL THEN ‘DESVIACIÓN: Instancia no en estado de Terraform’ WHEN li.instance_type != ti.tf_instance_type THEN ‘DESVIACIÓN: Tipo de instancia cambiado’ ELSE ‘CONFORME: Coincide con Terraform’ END as drift_status FROM live_instances li LEFT JOIN terraform_instances ti ON li.instance_id = ti.instance_id WHERE li.tags->>‘Environment’ = ‘production’;


### Escenario 3: Evaluación de la Postura de Seguridad Multi-Nube

**Desafío**: Mantener una postura de seguridad consistente en los entornos de AWS, Azure y GCP.

**Solución**: Evaluación de seguridad unificada en todos los proveedores de nube con puntuación estandarizada.

```sql
-- Cálculo de puntuación de seguridad multi-nube
CREATE VIEW multi_cloud_security_posture AS
WITH security_metrics AS (
  -- Métricas de Seguridad de AWS
  SELECT
    'aws' as cloud_provider,
    'encryption' as security_domain,
    COUNT(*) as total_resources,
    COUNT(*) FILTER (WHERE encrypted = true) as compliant_resources,
    ROUND(
      (COUNT(*) FILTER (WHERE encrypted = true)::float / COUNT(*)) * 100, 2
    ) as compliance_percentage
  FROM aws_ebs_volume
  WHERE tags->>'Environment' = 'production'

  UNION ALL

SELECT
    'aws' as cloud_provider,
    'public_access' as security_domain,
    COUNT(*) as total_resources,
    COUNT(*) FILTER (WHERE acl NOT LIKE '%public%') as compliant_resources,
    ROUND(
      (COUNT(*) FILTER (WHERE acl NOT LIKE '%public%')::float / COUNT(*)) * 100, 2
    ) as compliance_percentage
  FROM aws_s3_bucket

  UNION ALL

  -- Métricas de Seguridad de Azure
  SELECT
    'azure' as cloud_provider,
    'encryption' as security_domain,
    COUNT(*) as total_resources,
    COUNT(*) FILTER (WHERE encryption_at_rest_enabled = true) as compliant_resources,
    ROUND(
      (COUNT(*) FILTER (WHERE encryption_at_rest_enabled = true)::float / COUNT(*)) * 100, 2
    ) as compliance_percentage
  FROM azure_storage_account
  WHERE tags->>'Environment' = 'production'

  UNION ALL

  -- Métricas de Seguridad de GCP
  SELECT
    'gcp' as proveedor_nube,
    'acceso_público' as dominio_seguridad,
    COUNT(*) as total_recursos,
    COUNT(*) FILTER (WHERE public_access_prevention = 'enforced') as recursos_cumplidos,
    ROUND(
      (COUNT(*) FILTER (WHERE public_access_prevention = 'enforced')::float / COUNT(*)) * 100, 2
    ) as porcentaje_cumplimiento
  FROM gcp_storage_bucket
  WHERE labels->>'environment' = 'production'
)
SELECT
  proveedor_nube,
  dominio_seguridad,
  total_recursos,
  recursos_cumplidos,
  porcentaje_cumplimiento,
  CASE
    WHEN porcentaje_cumplimiento >= 95 THEN 'EXCELENTE'
    WHEN porcentaje_cumplimiento >= 85 THEN 'BUENO'
    WHEN porcentaje_cumplimiento >= 70 THEN 'NECESITA_MEJORAR'
    ELSE 'CRÍTICO'
  END as grado_seguridad,
  NOW() as marca_tiempo_evaluación
FROM métricas_seguridad
ORDER BY proveedor_nube, dominio_seguridad;

Consulta del Panel Ejecutivo:

-- Panel de seguridad ejecutivo - métricas de alto nivel
SELECT
  cloud_provider,
  AVG(compliance_percentage) as overall_security_score,
  COUNT(*) as assessed_domains,
  COUNT(*) FILTER (WHERE security_grade = 'CRITICAL') as critical_issues,
  COUNT(*) FILTER (WHERE security_grade = 'NEEDS_IMPROVEMENT') as improvement_areas
FROM multi_cloud_security_posture
GROUP BY cloud_provider
ORDER BY overall_security_score DESC;

Construyendo tu propio panel de Steampipe

¿Quieres convertir tus consultas en algo que parezca profesional? Steampipe tiene una función de panel que es sorprendentemente elegante:

Crear una configuración de panel

# dashboard.sp
dashboard "cloud_security_overview" {
  title = "Visión general de seguridad en la nube (AKA: ¿Qué tan mal está?)"

  container {
    chart {
      title = "Recursos Públicos por Tipo"
      sql   = <<-EOT
        SELECT
          'EC2' as resource_type,
          COUNT(*) as count
        FROM aws_ec2_instance
        WHERE state = 'running'
          AND public_ip_address IS NOT NULL

        UNION ALL

        SELECT
          'RDS' as resource_type,
          COUNT(*) as count
        FROM aws_rds_db_instance
        WHERE publicly_accessible = true

        UNION ALL

        SELECT
          'S3' as resource_type,
          COUNT(*) as count
        FROM aws_s3_bucket
        WHERE acl LIKE '%public%'
      EOT
      type  = "column"
    }
  }

  container {
    table {
      title = "Recursos de Alto Riesgo"
      sql   = <<-EOT
        SELECT
          resource_type,
          resource_id,
          risk_level,
          description
        FROM (
          SELECT
            'EC2' as resource_type,
            instance_id as resource_id,
            'HIGH' as risk_level,
            'Instancia pública con acceso SSH' as description
          FROM aws_ec2_instance e
          JOIN aws_ec2_security_group sg ON sg.group_id = ANY(e.security_groups)
          WHERE e.public_ip_address IS NOT NULL
            AND sg.ip_permissions::text LIKE '%"FromPort": 22%'
            AND sg.ip_permissions::text LIKE '%"0.0.0.0/0"%'
        ) as high_risk_resources
        ORDER BY risk_level DESC, resource_type
      EOT
    }
  }
}

Lanza tu Panel

steampipe dashboard --dashboard-listen=local

Navega a http://localhost:9194 y observa cómo tus violaciones de seguridad cobran vida en hermosos gráficos y tablas. Es como una película de desastre en tiempo real, pero para tu infraestructura.

Consejos Profesionales para el Dominio de Steampipe

1. Crear Vistas Reutilizables

En lugar de escribir consultas complejas repetidamente, crea vistas:

-- Guarda esto en ~/.steampipe/config/views.sql
CREATE VIEW my_public_resources AS
SELECT
  'EC2' as type,
  instance_id as id,
  region,
  public_ip_address as public_ip
FROM aws_ec2_instance
WHERE public_ip_address IS NOT NULL

UNION ALL

SELECT
  'RDS' as type,
  db_instance_identifier as id,
  region,
  endpoint_address as public_ip
FROM aws_rds_db_instance
WHERE publicly_accessible = true;

2. Automatiza con Scripts

Crea scripts bash que ejecuten tus consultas y envíen alertas:

#!/bin/bash
# security_check.sh

# Verificar nuevos recursos públicos
NEW_PUBLIC=$(steampipe query --output json "
  SELECT COUNT(*) as count
  FROM my_public_resources
  WHERE created_time > NOW() - INTERVAL '24 hours'
" | jq -r '.[0].count')

if [ "$NEW_PUBLIC" -gt 0 ]; then
  echo "ADVERTENCIA: ¡$NEW_PUBLIC nuevos recursos públicos detectados!"
  # Enviar a Slack, correo electrónico, o cualquier sistema de notificación que uses
fi

3. Control de versiones de tus consultas

Mantén tus reglas CIEM en repositorios git:

my-steampipe-rules/
├── queries/
│   ├── compliance/
│   │   ├── pci-dss.sql
│   │   ├── soc2.sql
│   │   └── gdpr.sql
│   ├── security/
│   │   ├── public-resources.sql
│   │   ├── overprivileged-users.sql
│   │   └── crypto-mining.sql
│   └── cost/
│       ├── unused-resources.sql
│       └── expensive-resources.sql
├── dashboards/
│   └── security-overview.sp
└── scripts/
    └── daily-security-check.sh

Historias de guerra del mundo real: Cuando Steampipe salva el día

El caso del misterioso minero de Bitcoin

Hace unos meses, llegó una factura de AWS que era un 300% más alta de lo normal. Usando Steampipe, identificamos rápidamente:

-- La consulta que encontró al culpable
SELECT
  instance_id,
  instance_type,
  launch_time,
  region,
  tags,
  ROUND(EXTRACT(epoch FROM (NOW() - launch_time))/3600) as hours_running
FROM aws_ec2_instance
WHERE state = 'running'
  AND instance_type IN ('c5.4xlarge', 'c5.9xlarge', 'c5.18xlarge')
  AND launch_time > '2024-01-01'
  AND (tags->>'Name' IS NULL OR tags->>'Name' = '')
ORDER BY hours_running DESC;

Resultado: Tres instancias c5.4xlarge ejecutándose durante 2 semanas seguidas sin etiquetas, sin monitoreo y con un uso de CPU sospechosamente alto. Alguien había dejado su operación de minería funcionando en la cuenta de desarrollo. Ups.

La Gran Fuga del Bucket S3 de 2024

Durante una auditoría de seguridad, necesitábamos evaluar rápidamente la exposición de datos en 47 cuentas de AWS:

-- La consulta que previno un incidente mayor
SELECT
  b.name,
  b.region,
  CASE
    WHEN b.policy_std::text LIKE '%"Principal": "*"%' THEN 'CRÍTICO: Acceso de lectura público'
    WHEN b.acl = 'public-read' THEN 'ALTO: ACL pública'
    WHEN b.acl = 'public-read-write' THEN 'CRÍTICO: Acceso de escritura público'
    ELSE 'Exposición desconocida'
  END as risk_level,
  b.creation_date
FROM aws_s3_bucket b
WHERE b.name LIKE '%prod%'
   OR b.name LIKE '%customer%'
   OR b.name LIKE '%backup%'
ORDER BY risk_level DESC;

Encontramos 12 buckets de producción con acceso de lectura público que contenían datos de clientes. Gracias a Steampipe, los arreglamos todos en una hora en lugar de las semanas que hubiera tomado manualmente.

El Futuro de la Gestión del Caos en la Nube

Steampipe representa algo hermoso: la democratización de la seguridad en la nube. No necesitas herramientas empresariales costosas ni un equipo de especialistas para entender lo que está sucediendo en tu infraestructura de nube. Solo necesitas habilidades en SQL y disposición para adentrarte en el caos.

A medida que los entornos de nube continúan volviéndose más complejos, herramientas como Steampipe se vuelven esenciales. Te dan el poder de hacer preguntas como:

  • “Muéstrame todos los recursos creados por ese contratista que se fue el mes pasado”
  • “¿Cuáles de mis bases de datos son accesibles desde internet?”
  • “¿Cuánto estoy gastando en recursos que nadie está usando?”
  • “¿Quién tiene la capacidad de eliminar toda mi infraestructura?”

Estas no son solo preguntas técnicas, son preguntas críticas para el negocio que pueden ahorrarte dinero, prevenir brechas de seguridad y ayudarte a dormir mejor por la noche.

Comenzando: Tu viaje de seguridad en la nube comienza

¿Listo para comenzar tu propia expedición de arqueología en la nube? Aquí tienes tu tarea:

  1. Instala Steampipe y al menos un plugin de nube
  2. Ejecuta las consultas básicas en este post contra tu infraestructura
  3. Prepárate para estar horrorizado por lo que encuentres
  4. Crea tu primera regla CIEM personalizada para algo específico de tu entorno
  5. Configura la monitorización automatizada para tus reglas de seguridad más críticas
  6. Comparte tus hallazgos con tu equipo (te lo agradecerán más tarde)

Recuerda: El objetivo no es lograr una seguridad perfecta en la nube (eso es imposible). El objetivo es entender tu caos lo suficientemente bien como para gestionarlo eficazmente.

Y oye, si encuentras algún minero de Bitcoin funcionando en tu infraestructura, al menos ahora sabes cómo encontrarlos rápidamente. 😄

Palabras Finales: Abraza el Caos

La infraestructura en la nube es inherentemente caótica. Los recursos se crean, se olvidan, se modifican y se abandonan. Las permisos se acumulan como polvo digital. Los grupos de seguridad se multiplican como conejos.

Pero con Steampipe, al menos puedes entender tu caos. Puedes consultarlo, visualizarlo, y tal vez incluso domarlo un poco.

Así que adelante, ejecuta algunas consultas y descubre qué misterios digitales acechan en tus cuentas en la nube. Solo no me culpes cuando descubras que alguien ha estado minando Dogecoin en tus clústeres de producción.

¡Feliz consulta, y que tu SQL sea siempre sintácticamente correcto! 🚀


¿Tienes consultas interesantes de Steampipe o historias de guerra? Contáctame - siempre estoy buscando nuevas formas de abusar de SQL para propósitos de seguridad en la nube.