DevSecOps: mejores prácticas para garantizar la seguridad en todo el proceso de desarrollo

DevSecOps: mejores prácticas para garantizar la seguridad en todo el proceso de desarrollo

Devops es un enfoque que busca integrar y automatizar las actividades de desarrollo, prueba, implementación y operación de software, con el objetivo de entregar productos de calidad de manera más rápida y eficiente. Sin embargo, la seguridad no siempre se considera una prioridad en DevOps, lo que puede resultar en vulnerabilidades, riesgos e incidentes que comprometen la confiabilidad, disponibilidad e integridad de los sistemas y datos.

La seguridad en DevOps, o DevSecOps, es una forma de incorporar la seguridad en todo el ciclo de vida de DevOps, desde la planificación hasta la operación, pasando por el diseño, codificación, prueba e implementación. El objetivo de la seguridad en DevOps es crear una cultura de colaboración entre los equipos de desarrollo, operación y seguridad, así como aplicar herramientas y prácticas que garanticen la protección del software y los datos en todas las fases del proceso.

En este artículo, presentaremos algunas de las mejores prácticas para implementar la seguridad en DevOps, así como ejemplos de código que ilustran cómo aplicarlas. Las prácticas son:

  • Definir requisitos y estándares de seguridad;
  • Realizar análisis estáticos y dinámicos del código;
  • Utilizar contenedores y orquestadores seguros;
  • Implementar pipelines de integración y entrega continua con seguridad;
  • Monitorear y responder a incidentes de seguridad.

Definir requisitos y estándares de seguridad

La primera práctica para garantizar la seguridad en DevOps es definir los requisitos y estándares de seguridad que deben seguir los equipos involucrados en el proceso. Estos requisitos y estándares deben estar alineados con las políticas, normas y regulaciones de la organización, así como con las mejores prácticas del mercado.

Los requisitos y estándares de seguridad deben cubrir aspectos como:

  • La identificación y clasificación de los activos críticos (sistemas, datos, servicios, etc.);
  • La definición de los niveles de confidencialidad, integridad y disponibilidad esperados para cada activo;
  • La especificación de los controles de seguridad necesarios para cada activo (cifrado, autenticación, autorización, auditoría, etc.);
  • La definición de las responsabilidades y roles de los equipos de desarrollo, operación y seguridad;
  • La documentación de políticas y procedimientos de seguridad (cómo gestionar contraseñas, claves, certificados, logs, respaldos, etc.).

Un ejemplo de código que se puede usar para definir requisitos y estándares de seguridad es el uso de archivos YAML (Yet Another Markup Language) para describir las configuraciones de seguridad de los sistemas. YAML es un formato simple y legible para representar datos estructurados. Por ejemplo, el siguiente archivo YAML define algunos requisitos y estándares de seguridad para un sistema web:

# Requisitos e padrões de segurança para o sistema web
assets:
  - name: web_server
    description: Servidor web que hospeda o aplicativo
    criticality: high
    security_level: 3
    security_controls:
      - encryption: TLS 1.3
      - authentication: Basic Auth
      - authorization: RBAC
      - auditing: Syslog
  - name: database
    description: Banco de dados que armazena os dados do aplicativo
    criticality: high
    security_level: 3
    security_controls:
      - encryption: AES 256
      - authentication: PostgreSQL Auth
      - authorization: SQL GRANT/REVOKE
      - auditing: PostgreSQL Audit Extension
roles:
  - name: developer
    description: Pessoa responsável pelo desenvolvimento do aplicativo
    permissions:
      - web_server: read/write/execute
      - database: read/write
  - name: operator
    description: Pessoa responsável pela operação do sistema
    permissions:
      - web_server: read/execute
      - database: read
  - name: security
    description: Pessoa responsável pela segurança do sistema
    permissions:
      - web_server: read
      - database: read

Realizar análisis estáticos y dinámicos del código

La segunda práctica para garantizar la seguridad en DevOps es realizar análisis estáticos y dinámicos del código, con el objetivo de identificar y corregir vulnerabilidades, errores y malas prácticas que puedan comprometer la seguridad del software. Los análisis estáticos y dinámicos deben realizarse de forma continua, integrados en el proceso de desarrollo y prueba.

Los análisis estáticos son aquellos que examinan el código fuente del software sin ejecutarlo, verificando aspectos como:

  • La conformidad con los estándares de codificación y seguridad;
  • La presencia de código malicioso, obsoleto o innecesario;
  • La existencia de fallas de lógica, diseño o implementación;
  • La calidad, complejidad y mantenibilidad del código.

Los análisis dinámicos son aquellos que prueban el comportamiento del software en ejecución, simulando escenarios reales y ataques potenciales, verificando aspectos como:

  • La robustez, el rendimiento y la escalabilidad del software;
  • La validación, saneamiento y codificación de los datos de entrada y salida;
  • La protección contra ataques comunes, como inyección de código, cross-site scripting, secuestro de sesión, etc.;
  • La detección y manejo de excepciones, errores y fallas.

Un ejemplo de código que se puede usar para realizar análisis estáticos y dinámicos del código es el uso de herramientas automatizadas que se integran con las plataformas de desarrollo y prueba. Por ejemplo, SonarQube es una herramienta que realiza análisis estáticos del código, verificando la calidad y seguridad del código en varios lenguajes. OWASP ZAPes una herramienta que realiza análisis dinámicos del código, probando la seguridad de las aplicaciones web contra ataques. Ambas herramientas se pueden integrar con Jenkins, una plataforma de integración y entrega continua. Por ejemplo, el siguiente archivo Jenkinsfile define un pipeline que realiza análisis estáticos y dinámicos del código de una aplicación web:

// Pipeline para realizar análises estáticas e dinâmicas do código
pipeline {
  agent any
  stages {
    stage('Checkout') {
      steps {
        // Obtém o código-fonte do repositório Git
        git 'https://github.com/example/web-app.git'
      }
    }
    stage('Build') {
      steps {
        // Compila o código-fonte usando Maven
        sh 'mvn clean package'
      }
    }
    stage('Static Analysis') {
      steps {
        // Realiza a análise estática do código usando SonarQube
        withSonarQubeEnv('SonarQube') {
          sh 'mvn sonar:sonar'
        }
      }
    }
    stage('Deploy') {
      steps {
        // Implanta o aplicativo web em um servidor Tomcat
        deploy adapters: [tomcat8(credentialsId: 'tomcat', path: '', url: 'http://localhost:8080/')], contextPath: 'web-app', war: '**/*.war'
      }
    }
    stage('Dynamic Analysis') {
      steps {
        // Realiza a análise dinâmica do código usando OWASP ZAP
        withZap() {
          zapCrawler(target: 'http://localhost:8080/web-app')
          zapScanner(failAllAlerts: true)
          zapAlerts()
          zapReport()
        }
      }
    }
  }
}

Utilizar contenedores y orquestadores seguros

La tercera práctica para garantizar la seguridad en DevOps es utilizar contenedores y orquestadores seguros para empaquetar, distribuir y ejecutar el software. Los contenedores son unidades aisladas que contienen el software y todas sus dependencias, facilitando la portabilidad, escalabilidad y actualización del software. Los orquestadores son sistemas que gestionan el ciclo de vida de los contenedores, automatizando tareas como aprovisionamiento, configuración, balanceo de carga y recuperación.

El uso de contenedores y orquestadores seguros es una práctica que busca garantizar la seguridad del software en entornos distribuidos y dinámicos, donde el software puede ejecutarse en diferentes plataformas, redes y nubes. Para utilizar contenedores y orquestadores seguros, es necesario considerar aspectos como:

  • La elección de imágenes de contenedores confiables y actualizadas, que contengan solo los componentes necesarios para el software y que no presenten vulnerabilidades conocidas;
  • La configuración de los contenedores con los parámetros de seguridad adecuados, como límites de recursos, privilegios mínimos, redes aisladas, montajes de solo lectura, etc.;
  • La verificación de la integridad y autenticidad de los contenedores, utilizando firmas digitales, hashes o sellos de tiempo;
  • La protección de los datos de los contenedores, utilizando cifrado, respaldos y políticas de retención;
  • El monitoreo del comportamiento de los contenedores, utilizando herramientas de observabilidad, detección de anomalías y respuesta a incidentes.

Un ejemplo de código que se puede usar para utilizar contenedores y orquestadores seguros es el uso de Docker y Kubernetes. Docker es una plataforma que permite crear, ejecutar y gestionar contenedores. Kubernetes es un sistema que permite orquestar contenedores en clústeres de servidores. Por ejemplo, el siguiente archivo Dockerfile define una imagen de contenedor para una aplicación web en Python:

# Imagem base do Python 3.9
FROM python:3.9

# Diretório de trabalho do contêiner
WORKDIR /app

# Copia os arquivos do aplicativo para o contêiner
COPY . .

# Instala as dependências do aplicativo
RUN pip install -r requirements.txt

# Expõe a porta 5000 do contêiner
EXPOSE 5000

# Executa o aplicativo quando o contêiner iniciar
CMD ["python", "app.py"]

El siguiente archivo YAML define un deployment de Kubernetes para ejecutar la aplicación web en tres réplicas de contenedores:

# Deployment do Kubernetes para o aplicativo web
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
spec:
  replicas: 3 # Número de réplicas do contêiner
  selector:
    matchLabels:
      app: web-app # Rótulo que identifica o contêiner
  template:
    metadata:
      labels:
        app: web-app # Rótulo que identifica o contêiner
    spec:
      containers:
      - name: web-app # Nome do contêiner
        image: web-app # Nome da imagem do contêiner
        ports:
        - containerPort: 5000 # Porta do contêiner
        resources:
          limits: # Limites de recursos do contêiner
            cpu: "1" # Limite de CPU
            memory: "512Mi" # Limite de memória
        securityContext: # Contexto de segurança do contêiner
          runAsUser: 1000 # Usuário com privilégios mínimos
          readOnlyRootFilesystem: true # Sistema de arquivos somente leitura

Implementar pipelines de integración y entrega continua con seguridad

La cuarta práctica para garantizar la seguridad en DevOps es implementar pipelines de integración y entrega continua con seguridad, es decir, procesos automatizados que permiten integrar, probar, desplegar y entregar el software con rapidez y calidad, incorporando la seguridad en cada etapa. Los pipelines de integración y entrega continua con seguridad deben considerar aspectos como:

  • El uso de herramientas y plataformas confiables y actualizadas para gestionar los pipelines, como Jenkins, GitLab CI/CD, GitHub Actions, etc.
  • La protección de los repositorios de código fuente, las imágenes de contenedores, los artefactos generados y los datos sensibles utilizados en los pipelines, mediante cifrado, control de acceso, monitoreo y auditoría.
  • La realización de pruebas automatizadas de unidad, integración, funcionalidad y seguridad en cada etapa de los pipelines, utilizando herramientas como JUnit, Selenium, SonarQube, OWASP ZAP, etc.;
  • El despliegue automatizado del software en entornos controlados y segregados, como desarrollo, pruebas, homologación y producción, usando herramientas como Ansible, Terraform, Helm, etc.;
  • La entrega automatizada del software a los usuarios finales, utilizando técnicas como despliegue continuo, despliegue azul-verde, despliegue canario, etc.

Un ejemplo de código que puede ser utilizado para implementar pipelines de integración y entrega continua con seguridad es el uso de Jenkins y Helm. Jenkins es una plataforma de integración y entrega continua que permite crear y ejecutar pipelines automatizados. Helm es una herramienta que permite gestionar aplicaciones Kubernetes usando charts, que son paquetes que contienen las configuraciones y los recursos necesarios para desplegar una aplicación. Por ejemplo, el siguiente archivo Jenkinsfile define un pipeline que realiza la integración y entrega continua de una aplicación web en Kubernetes:

// Pipeline para realizar a integração e a entrega contínua de um aplicativo web em Kubernetes
pipeline {
  agent any
  stages {
    stage('Checkout') {
      steps {
        // Obtém o código-fonte do repositório Git
        git 'https://github.com/example/web-app.git'
      }
    }
    stage('Build') {
      steps {
        // Compila o código-fonte usando Maven
        sh 'mvn clean package'
      }
    }
    stage('Static Analysis') {
      steps {
        // Realiza a análise estática do código usando SonarQube
        withSonarQubeEnv('SonarQube') {
          sh 'mvn sonar:sonar'
        }
      }
    }
    stage('Docker Build') {
      steps {
        // Constrói a imagem do contêiner usando Docker
        sh 'docker build -t web-app .'
      }
    }
    stage('Docker Push') {
      steps {
        // Envia a imagem do contêiner para o Docker Hub
        withCredentials([usernamePassword(credentialsId: 'dockerhub', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) {
          sh 'docker login -u $USERNAME -p $PASSWORD'
          sh 'docker push web-app'
        }
      }
    }
    stage('Helm Deploy') {
      steps {
        // Implanta o aplicativo web em Kubernetes usando Helm
        withKubeConfig([credentialsId: 'kubernetes']) {
          sh 'helm upgrade --install web-app ./helm-chart'
        }
      }
    }
    stage('Dynamic Analysis') {
      steps {
        // Realiza a análise dinâmica do código usando OWASP ZAP
        withZap() {
          zapCrawler(target: 'http://web-app')
          zapScanner(failAllAlerts: true)
          zapAlerts()
          zapReport()
        }
      }
    }
  }
}

Monitorear y responder a incidentes de seguridad

La quinta y última práctica para garantizar la seguridad en DevOps es monitorear y responder a incidentes de seguridad, es decir, recolectar, analizar y actuar sobre la información relacionada con la seguridad del software en operación, con el objetivo de prevenir, detectar y mitigar amenazas y ataques. El monitoreo y la respuesta a incidentes de seguridad deben considerar aspectos como:

  • La recolección de datos de seguridad provenientes de diversas fuentes, como logs, métricas, alertas, eventos, etc., utilizando herramientas como ELK Stack, Prometheus, Grafana, etc.;
  • El análisis de los datos de seguridad mediante técnicas de inteligencia artificial, aprendizaje automático y big data, para identificar patrones, tendencias y anomalías que indiquen posibles incidentes de seguridad;
  • La actuación sobre los incidentes de seguridad usando procedimientos estandarizados y automatizados, como notificación, escalamiento, contención, erradicación, recuperación y lecciones aprendidas.

El monitoreo y la respuesta a incidentes de seguridad son prácticas esenciales para garantizar la seguridad en DevOps, ya que permiten prevenir, detectar y mitigar amenazas y ataques que puedan comprometer el software en operación. Para monitorear y responder a incidentes de seguridad, es necesario recolectar, analizar y actuar sobre la información relacionada con la seguridad del software, utilizando herramientas y procedimientos adecuados.

Un ejemplo de código que puede ser utilizado para monitorear y responder a incidentes de seguridad es el uso de ELK Stack y TheHive. ELK Stack es una plataforma que permite recolectar, almacenar, buscar y visualizar datos de logs. TheHive es una plataforma que permite gestionar casos de incidentes de seguridad. Por ejemplo, el siguiente archivo Logstash.conf define una configuración para recolectar los logs de la aplicación web y enviarlos a Elasticsearch:

# Configuração do Logstash para coletar os logs do aplicativo web
input {
  # Coleta os logs do arquivo app.log
  file {
    path => "/var/log/app.log"
    start_position => "beginning"
    sincedb_path => "/dev/null"
  }
}
filter {
  # Filtra os logs usando expressões regulares
  grok {
    match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} %{DATA:class} - %{GREEDYDATA:message}" }
  }
  # Converte o campo timestamp para o formato ISO8601
  date {
    match => [ "timestamp", "ISO8601" ]
  }
}
output {
  # Envia os logs para o Elasticsearch
  elasticsearch {
    hosts => ["http://localhost:9200"]
    index => "web-app-%{+YYYY.MM.dd}"
  }
}

El siguiente archivo TheHive.conf define una configuración para integrar TheHive con Elasticsearch:

# Configuração do TheHive para integrar com o Elasticsearch
play.modules.enabled += org.thp.thehive.connector.elastic.ElasticModule

elastic.uri = "http://localhost:9200"

elastic.index = "the_hive_23"

elastic.audit.index = "the_hive_audit_23"

elastic.metrics.index = "the_hive_metrics_23"

elastic.alert.index = "the_hive_alert_23"

elastic.case.template.index = "the_hive_case_template_23"

elastic.attachment.index = "the_hive_attachment_23"

elastic.datastore.attachment.name = "the_hive_attachment_23"

elastic.datastore.attachment.hash = true

elastic.datastore.attachment.chunkSize = 1m

elastic.datastore.attachment.concurrentUpload = 5

elastic.datastore.attachment.endRetry = 3

elastic.datastore.attachment.retryDelay = 1s

elastic.search.scroll.keepalive = 1m

elastic.search.scroll.pageSize = 50

# Configuração para importar alertas do Elasticsearch
alerting.providers += local-elasticsearch

alerting.local-elasticsearch.name = "Local Elasticsearch"

alerting.local-elasticsearch.description = "Import alerts from local Elasticsearch index"

alerting.local-elasticsearch.endpoint = "http://localhost:9200/web-app-*"

alerting.local-elasticsearch.interval = 5 minutes

alerting.local-elasticsearch.filter.level = ERROR

alerting.local-elasticsearch.filter.class = SecurityException

alerting.local-elasticsearch.sourceRefPattern = %{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} %{DATA:class} - %{GREEDYDATA:message}

alerting.local-elasticsearch.titlePattern = Alert from web-app: %{message}

alerting.local-elasticsearch.descriptionPattern = An error occurred in the web-app at %{timestamp}: %{message}

alerting.local-elasticsearch.tags += web-app

alerting.local-elasticsearch.tags += elasticsearch

Con estas configuraciones, es posible monitorear los logs de la aplicación web en Elasticsearch utilizando Kibana, una herramienta de visualización de datos. Además, es posible importar alertas de seguridad de Elasticsearch a TheHive, una herramienta de gestión de casos. De este modo, es posible responder a los incidentes de seguridad utilizando procedimientos estandarizados y automatizados, como notificación, escalamiento, contención, erradicación, recuperación y lecciones aprendidas.

Conclusión

La seguridad en DevOps, o DevSecOps, es una forma de incorporar la seguridad en todo el ciclo de vida de DevOps, desde la planificación hasta la operación, pasando por el diseño, la codificación, las pruebas y el despliegue. DevSecOps busca crear una cultura de colaboración entre los equipos de desarrollo, operaciones y seguridad, así como aplicar herramientas y prácticas que garanticen la protección del software y los datos en todas las fases del proceso.

En este artículo, presentamos algunas de las mejores prácticas para implementar la seguridad en DevOps, así como ejemplos de código que ilustran cómo aplicarlas. Las prácticas son:

  • Definir requisitos y estándares de seguridad;
  • Realizar análisis estáticos y dinámicos del código;
  • Utilizar contenedores y orquestadores seguros;
  • Implementar pipelines de integración y entrega continua con seguridad;
  • Monitorear y responder a incidentes de seguridad.

Esperamos que este artículo haya sido útil e interesante para ti, y que puedas aplicar las prácticas presentadas en tus proyectos de DevOps. Recuerda que la seguridad no es un costo, sino una inversión que puede traer beneficios como confianza, calidad y competitividad.

Referencias Bibliográficas

BASS, L.; WEBER, I.; ZHU, L. DevOps: A Software Architect’s Perspective. Boston: Addison-Wesley Professional, 2015.

HUMBLE, J.; MOLESKY, J.; O’REILLY, B. Lean Enterprise: How High Performance Organizations Innovate at Scale. Sebastopol: O’Reilly Media, 2015.

KIM, G.; DEBOIS, P.; WILLIS, J.; HUMBLE, J. The DevOps Handbook: How to Create World-Class Agility, Reliability, and Security in Technology Organizations. Portland: IT Revolution Press, 2016.

OWASP. OWASP Top 10 - 2021: The Ten Most Critical Web Application Security Risks.

💡
Las opiniones y comentarios emitidos en este artículo son propiedad única de su autor y no necesariamente representan el punto de vista de Listopro.

Listopro Community da la bienvenida a todas las razas, etnias, nacionalidades, credos, géneros, orientaciones, puntos de vista e ideologías, siempre y cuando promuevan la diversidad, la equidad, la inclusión y el crecimiento profesional de los profesionales en tecnología.