Capítulo 1. Introducción a los microservicios en la nube

Este trabajo se ha traducido utilizando IA. Agradecemos tus opiniones y comentarios: translation-feedback@oreilly.com

La computación en nube y los microservicios se han convertido en un tema dominante en el mundo de la arquitectura de software. Los microservicios han añadido complejidad a una era en la que los ataques a la seguridad son demasiado frecuentes, y han aumentado la importancia de los profesionales de la seguridad en todas las organizaciones.

Esta es una historia (que escuché por primera vez en YouTube) que puede sonar familiar a muchos de vosotros. Una empresa de ritmo rápido está construyendo una aplicación basada en microservicios y tú estás en el equipo de seguridad. Es posible que tengas partes interesadas, como un director general o un director de producto, que quieren que tu producto se lance a tiempo para ganar cuota de mercado. Los desarrolladores de tu empresa están haciendo todo lo posible para cumplir los plazos y enviar el código más rápidamente. A ti te traen al final del proceso, y tu mandato es asegurarte de que el producto final es seguro. Esto debería alertarte inmediatamente. Si el producto se desarrolla independientemente de vosotros (el equipo de seguridad), seréis los únicos que os interpondréis en el camino de un producto que añada valor a la empresa. Según mi experiencia, en muchas empresas disfuncionales, los profesionales de la seguridad han sido vistos como detractores por los equipos de desarrollo, los jefes de producto y otras partes interesadas de las organizaciones.

El problema de las iniciativas de seguridad superficiales es que interfieren con las actividades que añaden valor. Las malas iniciativas de seguridad son famosas por causar frustración entre los desarrolladores. Esto suele deberse a un mal diseño y a malas implementaciones, ambas frecuentes en el sector. De ahí que las políticas de seguridad se asocien, a veces, con la "burocracia corporativa" y hayan dado lugar, según mi experiencia, a algunas conversaciones desagradables en las salas de reuniones. Esto ha obligado a muchos desarrolladores a eludir las medidas de seguridad para desarrollar más rápido. Y lo que es más importante, como muchas iniciativas de seguridad se elaboraron antes de la era de la computación en nube o los microservicios, no incorporan algunas de las ventajas que te proporcionan los nuevos diseños y tecnologías de software.

Está claro que tiene que haber una forma mejor. En este capítulo, pretendo mostrarte cómo incorporar la seguridad en la fase de arquitectura del diseño de microservicios y utilizar después algunas de las herramientas que proporciona AWS puede ayudar a crear sistemas que sean sencillos, seguros y rápidos de desarrollar al mismo tiempo. Empiezo hablando de algunos rasgos deseables en los sistemas seguros que se correlacionan con mejores resultados de seguridad. A continuación, explico cómo los microservicios pueden ayudarte a crear sistemas que tengan estos rasgos deseables. Y, por último, hablo de cómo AWS puede ayudarte a diseñar estos microservicios y a escalarlos para construir un sistema seguro.

Aspectos básicos de la seguridad de la información en la nube

Antes de entrar en los fundamentos de la seguridad en la nube, definamos algunos términos básicos de seguridad de la información, ya que muchos de ellos se utilizan indistintamente, lo que a veces provoca confusión:

Vulnerabilidad
Una vulnerabilidad es cualquier deficiencia del sistema que lo hace menos seguro. Una vulnerabilidad puede ser cualquier cosa en el software que pueda ser explotada. También puede deberse a que tu sistema utilice una versión antigua del sistema operativo o una biblioteca que pueda ser explotada.
Amenaza
Que exista una vulnerabilidad no significa que alguien vaya a explotarla. De hecho, las vulnerabilidades ocultas pueden seguir existiendo en todas las aplicaciones, a veces durante años, como en el caso del fallo Heartbleed. Pero en el momento en que la vulnerabilidad se convierte en explotable, puede considerarse una amenaza potencial. Si esta vulnerabilidad se explota, se dice que la amenaza se ha materializado. Por ejemplo, perder la llave de casa es una vulnerabilidad. Un hipotético ladrón que encuentre esta llave es una amenaza potencial. Que un ladrón la encuentre realmente es la materialización de esta amenaza. Una amenaza materializada tiene un impacto financiero, reputacional u operativo en tu organización.
Actor malicioso/actor de amenazas/agente de amenazas
El actor de la amenaza (o agente de la amenaza) es cualquiera que se aprovecha de una vulnerabilidad para causar la amenaza.
Responsabilidad
En el contexto de la seguridad, el parámetro de responsabilidad dicta quién es responsable de garantizar que una amenaza potencial nunca se convierta en realidad. Esta responsabilidad puede ser asumida por un empleado o un sistema automatizado, o puede descargarse en un producto de terceros o en un proveedor de servicios. Por ejemplo, en el caso de los bancos (sucursales), la responsabilidad de evitar el robo físico la asumen las empresas de seguridad.
Riesgo
El riesgo es la métrica que trata de evaluar la probabilidad de que se materialice una amenaza que provoque una pérdida de algún tipo. Esta pérdida puede ser financiera, de reputación u operativa. El riesgo agregado de una aplicación es la suma ponderada por la probabilidad de todas las amenazas a las que podría enfrentarse. El objetivo último de cualquier diseño seguro es reducir el riesgo agregado.
Control/contramedida
Un control o contramedida es cualquier actividad que pueda reducir el riesgo agregado (o el impacto negativo de la amenaza potencial especificada por un riesgo). Los controles suelen dirigirse a amenazas concretas y tienen alcances bien definidos. Los controles también pueden ser indirectos, cuando determinadas actividades reducen indirectamente el riesgo agregado de la organización (por ejemplo, cuando se fomenta la concienciación y la formación en ciberseguridad dentro de la organización, los incidentes tienden a disminuir).

Controles de riesgo y seguridad

El proceso de diseño de la seguridad incluye la identificación de los controles que pueden aplicarse para reducir el riesgo agregado en una organización. Por ejemplo, las organizaciones en las que los sistemas de red funcionan sin cortafuegos tienen un riesgo agregado mayor que las que tienen cortafuegos bien configurados, razón por la cual la mayoría de los profesionales de la seguridad recomiendan los cortafuegos. Más concretamente, los profesionales de la seguridad pueden añadir cortafuegos como contramedida contra la amenaza de acceso no autorizado a la red. En este caso, identificaron una amenaza potencial y aplicaron preventivamente una contramedida para reducir la probabilidad o el impacto de la amenaza (y así, por definición, reducir el riesgo de la aplicación). Este proceso se conoce como modelado de amenazas.

Consejo

Muchas empresas de seguridad han estudiado ampliamente y preparado marcos para identificar escenarios de amenazas comunes. Un ejemplo de un gran marco es la cadena de muerte cibernética de Lockheed Martin, que identifica lo que los adversarios deben completar para lograr su objetivo.

Se dice que los controles de seguridad son contundentes si bloquean unilateralmente todas las solicitudes sin intentar comprender su contexto o especificidades (por ejemplo, una valla alrededor de una casa que bloquea el paso a todo el mundo, independientemente de si es propietario de la casa o no). Se dice que los controles son precisos o afilados si identifican y bloquean solicitudes específicas (potencialmente no autorizadas) (por ejemplo, una cerradura en una puerta que permite abrirla a quienes tengan llave, con lo que no impide el paso a los usuarios legítimos, pero bloquea a cualquiera que no tenga acceso a una llave). Como regla general, los controles contundentes suelen ser fuertes y fáciles de implantar. Sin embargo, también pueden causar fricciones entre los usuarios legítimos e impedir que los empleados hagan su trabajo. Por otra parte, los controles contundentes pueden requerir mucho tiempo para afinarse adecuadamente, aunque sean eficaces. Dependiendo de la aplicación, ambos tipos de controles pueden ser necesarios para evitar distintos tipos de ataques. En el Capítulo 2, hablaré de los controles de autorización y autenticación, que son extremadamente afilados y pueden proporcionar una protección granular contra posibles amenazas a la organización. En el Capítulo 5, hablaré de la seguridad de la red, que actúa como un instrumento poderoso pero contundente.

Algunos controles pueden no estar dirigidos específicamente a amenazas potenciales y, sin embargo, pueden reducir el riesgo agregado de la aplicación. Por ejemplo, implantar un sistema adecuado de monitoreo y alerta puede dar lugar a una rápida actuación del equipo de seguridad. Las organizaciones pueden optar por implantar fuertes sistemas de monitoreo, llamados controles detectivescos, para disuadir a los actores maliciosos de atacar dichos sistemas, reduciendo así el riesgo agregado.

Consejo

Puedes pensar en los controles como palancas que los profesionales de la seguridad pueden accionar en cualquier organización para ajustar la postura de seguridad y el riesgo agregado de cualquier aplicación.

Política de seguridad de la organización

Puede resultar tentador enfrentarse a todas las amenazas potenciales y aplicar controles estrictos contra todas las vulnerabilidades. Sin embargo, como ocurre con todos los aspectos de la ingeniería de software, esta idea tiene sus inconvenientes.

Muchas organizaciones adoptan un enfoque fragmentario hacia los controles de seguridad en lugar de uno holístico. Muy a menudo me encuentro en la siguiente situación:

  1. Un profesional de la seguridad identifica una vulnerabilidad muy concreta.

  2. La organización identifica un control o producto de mercado que aborda esa vulnerabilidad.

  3. La vulnerabilidad puede abordarse con la solución del Paso 2, pero puede seguir existiendo un conjunto más amplio de vulnerabilidades. Un control de este tipo puede proporcionar una solución sin tener en cuenta la implicación más amplia del cambio en la aplicación global.

  4. O bien el control puede ser demasiado preciso y, por tanto, con el tiempo pueden ser necesarios controles adicionales, o bien la solución puede ser demasiado amplia y, por tanto, puede interponerse en el camino de las actividades legítimas que pueden realizar los desarrolladores.

Dado que las soluciones puntuales (soluciones que tienen un objetivo estrecho y específico) suelen tener efectos secundarios, como la fricción de los desarrolladores, es casi imposible cuantificar el coste real de un control de seguridad en comparación con el impacto potencial del riesgo. Varios factores pueden limitar la capacidad de las organizaciones para mitigar vulnerabilidades individuales, como los costes, los plazos y los objetivos de ingresos.

Una política de seguridad es un plan abstracto que expone de forma más amplia la visión para identificar y aplicar los controles de seguridad. Las políticas de seguridad definen el papel que desempeñan la seguridad y los controles en una organización. El objetivo de una política de seguridad es cuantificar y comparar el coste de un posible incidente con el coste de aplicar una contramedida. El coste puede ser un coste monetario o un coste para la eficacia operativa de la organización (algo que se interpone en el camino de las actividades que añaden valor). La política de seguridad proporciona al equipo de seguridad una visión de alto nivel que le ayuda a elegir los controles adecuados para el trabajo y a decidir si los controles existentes son aceptables o necesitan afinarse para ser eficaces.

Consejo

Si los controles de seguridad son las palancas que se pueden utilizar para ajustar el riesgo potencial de una aplicación, una política de seguridad guía cuánto hay que tirar de cada una de esas palancas para encontrar el punto dulce que sea aceptable para la alta dirección. Una política de seguridad debe ser de alto nivel e identificar una amplia gama de amenazas contra las que se quiere proteger. Esto permitirá a sus ejecutores innovar y presentar un conjunto más amplio de herramientas que encajen bien en tu organización.

Al diseñar una política de seguridad, es importante pensar en los tres tipos de amenazas: posibles, plausibles y probables. Muchas amenazas son posibles. Un subconjunto significativamente menor de estas amenazas son plausibles. Y un subconjunto aún menor de amenazas son probables. Para las empresas en las que el impacto de los incidentes de seguridad no es significativo, puede no ser prudente establecer controles contra todas las amenazas posibles, pero sin duda puede ser una buena idea establecer controles contra todas las probables. Por otra parte, una empresa que opere en un sector sensible quizá no pueda permitirse ignorar algunas amenazas posibles, aunque no sean plausibles o probables.

Nota

El objetivo principal de este libro es ayudar a las organizaciones a enmarcar y aplicar controles basados en una política de seguridad bien enmarcada. Para determinar la eficacia de los controles dentro de las organizaciones, se pueden utilizar varias métricas, como el Center for Internet Security Benchmarks.

Incidentes de seguridad y la tríada de la CIA

Se dice que se produce un incidente de seguridad cuando se materializa una amenaza potencial, es decir, cuando se ha explotado una vulnerabilidad (posiblemente por un actor malicioso).

Cualquier incidente de seguridad puede comprometer uno de estos tres parámetros: confidencialidad, integridad y disponibilidad. Juntos, se denominan la tríada CIA de la seguridad de la información:

Confidencialidad
Se dice que afecta a la confidencialidad del sistema un incidente de seguridad en el que se exponen o filtran datos o información a cualquier persona no autorizada a acceder a dicha información. Ejemplos de este tipo de incidentes son la filtración de datos sensibles, la filtración de contraseñas, etc.
Integridad
Se dice que un incidente de seguridad en el que un cambio no autorizado se perpetúa en el sistema, dando lugar a un estado no deseado, afecta a la integridad del sistema. Ejemplos de este tipo de incidentes son la manipulación de datos, los virus, el ransomware, etc.
Disponibilidad
Se dice que afecta a la disponibilidad del sistema un incidente de seguridad en el que un actor malicioso sobrecarga el sistema impidiéndole realizar sus tareas habituales. Ejemplos de este tipo de incidentes son los ataques de fuerza bruta, los ataques de denegación de servicio (DoS), etc.

Cualquier incidente o ataque de seguridad puede tener un impacto negativo en uno o varios de estos parámetros. Como profesionales de la seguridad, nuestro trabajo consiste en cuantificar el impacto de ese riesgo y compararlo con el coste de las contramedidas que haya que poner en marcha para evitarlo.

Modelo de responsabilidad compartida de AWS

Ya he hablado de la responsabilidad en el contexto de la seguridad: como profesional de la seguridad, es fundamental identificar quién es responsable de la protección frente a amenazas específicas para las aplicaciones alojadas en AWS. Aquí es donde entra en escena el Modelo de Responsabilidad Compartida (SRM ) de AWS. Comprender el SRM te ayuda a identificar posibles amenazas y vulnerabilidades para las que necesitas proporcionar contramedidas en lugar de confiar en que AWS lo haga automáticamente.

Una forma sencilla de entender el reparto de responsabilidades entre AWS y el cliente es comprender que AWS es responsable de la seguridad de la nube. Esto significa que AWS es responsable de proteger la infraestructura que soporta todos los servicios prestados por AWS. Esto incluye la seguridad física de las máquinas que ejecutan la aplicación frente a robos. AWS asume la responsabilidad de asegurarse de que tu aplicación se ejecuta en un entorno virtualizado que está lógicamente separado de otros clientes.

Por otra parte, el cliente es responsable de la seguridad de la aplicación en la nube. La aplicación periódica de parches de seguridad en el software y la aplicación de requisitos adecuados de control de acceso, cifrado y autenticación forman parte de las responsabilidades que AWS espera que asuman los clientes.

Advertencia

Y lo que es más importante, también se espera que los clientes dispongan de las configuraciones adecuadas para permitir prácticas informáticas seguras, de acuerdo con su política de seguridad.

Una excepción a la regla general anterior es el caso de los servicios gestionados de AWS, en los que AWS asume una responsabilidad mayor que la simple protección de la infraestructura física de la nube. Profundizaré en ello más adelante en este capítulo.

Consejo

Si trabajas en un entorno que requiere conformidad normativa y tiene frecuentes auditorías de conformidad, AWS recopila toda su documentación relacionada con la conformidad en AWS Artifact. La documentación disponible en AWS Artifact incluye informes de conformidad y atestados normativos para los servicios gestionados de AWS. A través de AWS Artifact, puedes convencer a los auditores de la conformidad normativa de los servicios gestionados de AWS y, en efecto, de tu aplicación de software.

Arquitectura y seguridad de la nube

Diseñar sistemas seguros implica examinar las aplicaciones de software adoptando una visión de sistemas de alto nivel. Por lo general, los arquitectos buscan el bosque en lugar de los árboles y enmarcan principios de diseño abstractos, dejando la implementación para los desarrolladores. Un diseño de arquitectura seguro actúa como facilitador de mejores controles de seguridad. Puedes mejorar la postura de seguridad de tu aplicación siguiendo algunos principios de seguridad fundamentales al diseñar la aplicación. Puedes aprender mucho sobre los principios de la arquitectura de seguridad en el libro Enterprise Security Architecture, de Nicholas Sherwood (CRC Press).

Aunque los principios de la arquitectura de seguridad de la información son anteriores a los microservicios y los sistemas en la nube, los investigadores han descubierto formas de aprovechar las ventajas de los sistemas de microservicios basados en la nube para reducir el riesgo agregado de tu aplicación. En esta sección repaso algunos de estos patrones arquitectónicos. Estos patrones no son mutuamente excluyentes. Con su ayuda, expondré los motivos por los que los microservicios basados en la nube reducen el riesgo de tus aplicaciones.

Seguridad mediante la modularidad

La mayoría de las aplicaciones actuales son complejas. Un enfoque sistémico del desarrollo de software considera que una aplicación de software está formada por módulos más pequeños y fáciles de gestionar. Una aplicación modular es aquella que puede descomponerse en piezas más pequeñas en las que se puede trabajar de forma independiente. Una aplicación modular es más fácil de parchear y, por tanto, de eliminar vulnerabilidades. La modularización es la ventaja clave que proporcionan los microservicios.

Desde el punto de vista de los profesionales de la seguridad, es fácil enmarcar una política de seguridad para aplicaciones modulares, ya que dicha política puede ser más flexible y adaptarse mejor a los contornos de tu aplicación.

Seguridad mediante la sencillez

Los sistemas sencillos son más fáciles de asegurar que los complejos. La complejidad del software puede ser desestabilizadora si no se gestiona bien. Las vulnerabilidades de las aplicaciones pequeñas y aisladas son más fáciles de detectar y parchear que las de los proyectos complejos más grandes. Si quieres una metáfora de construcción, los edificios pequeños con entradas limitadas son más fáciles de asegurar que los laberintos complicados. Así, si tus aplicaciones son pequeñas, puedes eliminar las vulnerabilidades antes de que se conviertan en amenazas, y reducir así el riesgo para tus aplicaciones.

Una gran aplicación modular compuesta de módulos más pequeños y sencillos acaba siendo más fácil de gestionar y segura. Por tanto, un principio rector a la hora de diseñar aplicaciones seguras es hacerlas lo más sencillas posible. Cualquier desviación de la simplicidad debe evaluarse, no sólo en términos de manejabilidad, sino también de seguridad, ya que es intrínsecamente más difícil asegurar aplicaciones complicadas.

Nota

En mi experiencia, los términos complejo y complicado se utilizan indistintamente para describir las arquitecturas de software. Sin embargo, en realidad no son lo mismo. Una arquitectura de software es compleja si está formada por un gran número de aplicaciones más pequeñas pero más sencillas. La complejidad es una consecuencia necesaria de la escala. El software complicado es un software que puede ser monolítico y puede implicar grandes componentes que pueden no ser fáciles de entender o seguros. El software complicado puede requerir habilidades especializadas para su mantenimiento. Las organizaciones deben evitar complicar sus aplicaciones.

Seguridad mediante servicios AWS totalmente administrados

Mencioné el SRM de AWS, donde hablé de cómo AWS es responsable de la "seguridad de la nube". Los servicios gestionados de AWS son una forma de descargar una responsabilidad adicional en AWS.

En un servicio gestionado, AWS asume una mayor parte de la responsabilidad de ejecutar una parte específica de la infraestructura para el usuario. En el caso de ejecutar MySQL, AWS ofrece el servicio AWS Relational Database Service (RDS), que ofrece múltiples opciones de MySQL a los usuarios finales. En AWS RDS, AWS asume la responsabilidad de ejecutar y parchear el motor de la base de datos, así como el sistema operativo subyacente. AWS mantiene actualizado el sistema operativo subyacente y elimina cualquier vulnerabilidad que pueda existir en él.

Advertencia

El hecho de que utilices un servicio administrado de AWS no significa automáticamente que tengas cero responsabilidades en materia de seguridad. Puede que sigas siendo responsable de controlar el acceso a los servicios y de configurar cortafuegos y otras medidas de seguridad básicas. Siempre que utilices un servicio gestionado, es importante averiguar qué parte de la responsabilidad de seguridad asume AWS y qué parte sigue recayendo sobre ti como cliente.

Con los servicios administrados de AWS, puedes reducir la responsabilidad de tu equipo de seguridad y escalar tu organización sin perder el foco. Si sustituyes un componente existente de tu infraestructura por un servicio administrado de AWS, puedes confiar en que AWS te proporcionará las contramedidas adecuadas para reducir el riesgo de tu aplicación.

Consejo

El uso de servicios gestionados también puede reducir la carga de cumplir los requisitos de conformidad, ya que la mayoría de los servicios gestionados cumplen la mayoría de los requisitos normativos (HIPAA, HITRUST, GDPR, SOC, NIST, ISO, PCI y FedRAMP). A lo largo del libro, recomendaré el uso de una flota de servicios gestionados de AWS que ayuden a aumentar la seguridad.

Radio de Explosión, Aislamiento y la Analogía de las Habitaciones Cerradas

Permíteme volver al proceso de modelado de amenazas. En este proceso, identificas vulnerabilidades en la aplicación y luego empiezas a pensar en posibles actores de amenazas que podrían explotarlas. Construyes escenarios hipotéticos en los que supones que el actor malicioso ha explotado efectivamente esta vulnerabilidad y ha causado problemas no autorizados a tu aplicación, afectando a cualquiera de las métricas de la CIA que has estado rastreando.

Las partes de tu aplicación sobre las que puede influir el hipotético actor de la amenaza en tu escenario de modelado de amenazas se denomina radio de explosión (también conocido como superficie de ataque) de tu aplicación.

En un sistema bien diseñado, quieres mantener este radio de explosión al mínimo. De ese modo, aunque un actor de la amenaza consiga acceder sin autorización, el resto de la aplicación podrá funcionar. Desde un punto de vista arquitectónico, es posible lograr este objetivo de reducir los radios de explosión utilizando el concepto de aislamiento. Puedes pensar en una gran aplicación modular como una serie de habitaciones cerradas en un edificio. El hecho de que una de las habitaciones haya sido violada por una persona no autorizada no significa que las demás también lo vayan a ser. Puedes tener una aplicación modular en la que los módulos individuales estén aislados entre sí y requieran una autenticación fuerte. De este modo, se puede aislar al actor de la amenaza sólo en el módulo que pudo violar, manteniendo el resto de la aplicación segura y funcional.

Defensa en profundidad y seguridad

¿Te has preguntado alguna vez por qué todos los aviones siguen teniendo ceniceros a pesar de que está prohibido fumar en todos los vuelos comerciales desde hace décadas? En la sesión informativa previa al despegue, se te recuerda que manipular el detector de humo del lavabo es un delito. También hay un cartel que te recuerda esta ley, pero justo debajo de ese cartel, encontrarás un cenicero. En 2009, un vuelo fue suspendido por no tener cenicero.

La Autoridad Federal de Aviación (FAA) explica que, aunque está prohibido fumar, algunas personas consiguen colar cigarrillos y fumar en los vuelos. Después de fumar, los pasajeros pueden tirar las colillas en los contenedores de basura, lo que puede suponer un riesgo de incendio. Desde el punto de vista de la seguridad, se trata de una amenaza que aumenta el riesgo de que se incendie un avión. Disponer de un cenicero garantiza que, si de algún modo la gente se las arregla para llevar cigarrillos en el vuelo, tengan un lugar donde apagarlos de forma segura. Los ceniceros son los controles que reducen el riesgo de incendio.

Quizá te preguntes, viendo lo peligroso que es fumar en un vuelo, ¿por qué no se añaden mayores controles de seguridad en los aeropuertos para garantizar que los pasajeros no puedan llevar cigarrillos a bordo de los aviones? ¿Por qué se exige una costosa instalación de ceniceros redundantes en todos los vuelos, en todo el mundo?

La respuesta está en un concepto de seguridad llamado defensa en profundidad. En los sistemas seguros, se ha demostrado que los controles multicapa, a veces redundantes o incluso obsoletos, son más eficaces que una solución basada en un único punto. Se ha demostrado que tener varios controles dispersos en distintas capas, en lugar de un único control perfectamente fiable, supone un menor riesgo para la aplicación. Al diseñar cada control, asume que un control anterior falló al detener a un intruso. Esto garantiza que no haya un único punto de fallo. En el caso de las líneas aéreas, supones que la seguridad del aeropuerto no pudo atrapar los cigarrillos, por lo que se utiliza el cenicero para reducir aún más el riesgo de incendio.

En los sistemas seguros, a menudo se te pide que evalúes de forma independiente la eficacia de cada uno de tus controles. Muchas veces, la presencia de múltiples controles puede parecer redundante, pero con la defensa en profundidad, puedes justificar su presencia y uso. A lo largo de este libro, recomendaré la introducción de múltiples controles. Por ejemplo, en el Capítulo 5 recomendaré controles que funcionen en la capa de red, mientras que en el Capítulo 7 hablaré del cifrado en tránsito que opera principalmente en la capa de transporte.

Nota

Si miras a tu alrededor, puedes ver ejemplos de defensa en profundidad por todas partes, en muchos aspectos diferentes de la vida. Los edificios con rociadores siguen teniendo extintores. Los edificios con fuertes medidas de seguridad en las entradas siguen teniendo cerraduras en las puertas de las oficinas individuales. Los controles de seguridad superpuestos son los que nos protegen del fallo de los controles individuales, y abrazar esa realidad es lo que ayuda en la evolución de una estrategia de pensamiento seguro.

Seguridad mediante protección perimetral

Comienzo esta sección admitiendo que soy un cínico de este enfoque. En este enfoque, las organizaciones crean un fuerte cortafuegos contra cualquier solicitud que proceda de la Internet pública. Este cortafuegos se conoce como perímetro, que está asegurado para proteger tu aplicación contra amenazas externas. A continuación, se proporciona a los empleados remotos soluciones de red privada virtual (VPN) para que tengan una experiencia similar a la de sus homólogos presenciales. En el contexto de la seguridad, la confianza se refiere al acceso a los sistemas con poca o ninguna verificación de quién es alguien o por qué necesita este acceso. En esta arquitectura, los usuarios o servicios dentro de un límite de confianza (generalmente dentro del centro de datos de la organización o VPN) son de confianza, y por tanto no pasan por una capa adicional de autenticación. Aquí, la creencia es que la mayoría de los atacantes son externos a la organización, y se supone que los usuarios de confianza sólo tienen las mejores intenciones. De ahí que los controles de esta arquitectura se dirijan principalmente a las amenazas externas. Muchos profesionales de la seguridad afirman que una arquitectura de este tipo intenta defender el castillo contra los ataques externos. Muchos organismos reguladores siguen exigiendo la presencia de una protección perimetral de este tipo y, por tanto, si trabajas en un sector muy regulado, puede que no tengas elección en cuanto a la protección perimetral.

Seguridad mediante una arquitectura de confianza cero

En los últimos años, se ha hecho evidente que tanto los atacantes externos como los internos suponen graves amenazas para las organizaciones. La idea de que proteger sólidamente el perímetro es suficiente para lograr la seguridad está anticuada. Por ello, en muchas organizaciones modernas se emplea una arquitectura de confianza cero. Una arquitectura de confianza cero asume que las amenazas a tu aplicación son omnipresentes (internas y externas a la organización). Por tanto, no puedes confiar en los servicios internos y debes implantar controles, asumiendo que hay actores maliciosos trabajando bien dentro de tus límites de confianza. En otras palabras, este modelo supone que los atacantes ya están dentro de los muros de tu castillo y, en lugar de proteger tu castillo, debes pensar en proteger individualmente todos tus recursos. De hecho, muchos incidentes recientes de gran repercusión han sido causados por personas internas de confianza o por actores maliciosos que se hicieron pasar por personas internas, como se vio en la brecha de Capital One de 2019. De ahí que sea preferible una arquitectura de confianza cero.

El capítulo 8 te presentará algunas de las herramientas que ofrece AWS, que te ayudarán a implantar la arquitectura de confianza cero en tu organización, reduciendo al mismo tiempo las fricciones con tu equipo de desarrollo.

Nota

No soy el único que está a favor de una arquitectura de confianza cero. El 12 de mayo de 2021, el presidente de EEUU, Joe Biden, firmó una orden ejecutiva que pretende mejorar la arquitectura de seguridad de la información estadounidense. Como parte de esta orden, se ha encargado al gobierno federal, entre otras cosas, que "desarrolle un plan para implantar la arquitectura de confianza cero ".

Breve introducción a la arquitectura de software

Aunque es posible que ya conozcas los fundamentos de los microservicios y sus ventajas, quiero dedicar un poco de tiempo a refrescar los conceptos básicos del diseño de microservicios. La arquitectura de aplicaciones suele adoptar un enfoque de sistemas hacia el diseño de software. La mayoría del software empresarial consta de partes más pequeñas que se unen para crear el sistema deseado.

Arquitectura por niveles

Considera una aplicación típica de sitio web de comercio electrónico. Supongamos que esta aplicación admite cuatro acciones de usuario final:

  • Un usuario puede comprar un artículo.

  • Un usuario puede devolver un artículo.

  • Un usuario puede consultar su saldo.

  • Un usuario puede comprobar el suministro disponible de inventario.

El objetivo de una arquitectura escalonada (por capas) es que las funciones de presentación (interfaz de usuario), gestión de aplicaciones y gestión de datos estén separadas entre sí. Este estilo de arquitectura ha sido la norma de facto para la mayoría de las aplicaciones, principalmente por su sencillez, familiaridad y bajo coste. La Figura 1-1 muestra una típica aplicación por niveles.

El estilo de arquitectura por capas, aunque tiene muchas ventajas, también presenta algunas desventajas claras. Una de ellas es la falta de agilidad y escalabilidad, que ha llevado al descubrimiento de otros estilos arquitectónicos. Los autores Neal Ford y Mark Richards, en su libro Fundamentals of Software Architecture (O'Reilly), tratan en detalle todos los inconvenientes de un diseño de este tipo.

Figura 1-1. En un enfoque por capas, la lógica de la aplicación puede dividirse en diferentes capas, dependiendo del nivel en el que se ejecute la aplicación.

Diseño basado en el dominio

Un contraste con el enfoque tradicional basado en niveles es el diseño dirigido por dominios (DDD). En el DDD, se supone que cada programa de software está relacionado con alguna actividad o interés de su usuario o de la función empresarial. Un arquitecto puede dividir la aplicación de forma que se alinee con sus unidades funcionales y de negocio, asociando la lógica de la aplicación a su dominio funcional (y, a veces, de forma más granular en subdominios).

Por ejemplo, si agruparas los servicios de la Figura 1-1 en función de sus dominios (y subdominios), verías que existen tres dominios funcionales:

Inventario o dominio del producto
Este dominio se ocupa de todos los servicios relacionados con la gestión de productos. Incluye el seguimiento del inventario de productos, precios y descripciones.
Dominio del cliente
Este dominio es responsable de aceptar las solicitudes de los clientes, como la salida de la aplicación o la devolución de cualquier artículo.
Ámbito financiero
Se encarga de cobrar al cliente y de controlar los saldos y todos los demás movimientos de dinero.

Si tienes que dividir los servicios de la Figura 1-1 en dominios funcionales, podría parecerse a la Figura 1-2.

Figura 1-2. La misma aplicación de la Figura 1-1, con los mismos componentes modulares, puede segregarse de forma diferente utilizando DDD. El DDD preserva los dominios empresariales al dividir las aplicaciones.

En un enfoque basado en dominios, es más probable que los servicios que satisfacen un dominio empresarial común tengan una fuerte relación entre sí y, por tanto, tiene sentido agruparlos. Además, el DDD facilita la gestión de proyectos empresariales de mayor envergadura, al alinear más estrechamente la arquitectura del software con los requisitos empresariales. Estos grupos suelen denominarse contextos delimitados, en los que los servicios de un contexto delimitado comparten una estrecha relación entre sí, mientras que cualquier interacción con una entidad externa puede considerarse un contrato definido formalmente. A la inversa, todos los servicios dentro de contextos delimitados sólo deberían tener relaciones poco estrechas con cualquier servicio que esté fuera de sus contextos delimitados.

Dentro de un contexto delimitado, las aplicaciones están diseñadas para la interoperabilidad. Hablan el mismo lenguaje proverbial. En un mundo ideal, un contexto delimitado y un subdominio deberían tener los mismos servicios constitutivos. En la práctica, sin embargo, especialmente cuando se trata de sistemas de software heredados, puede haber algunas diferencias.

Microservicios

Entonces, ¿qué hace que una arquitectura sea una arquitectura de microservicios? A diferencia de una aplicación monolítica, una aplicación basada en microservicios se compone de un gran número de servicios ligeros, que son:

Implementación independiente
Puedes actualizar, parchear o eliminar servicios individuales sin afectar al resto de la aplicación.
Escalable de forma independiente
Puedes ampliar o reducir servicios individuales si se produce una carga adicional en partes concretas de la aplicación, sin que ello afecte al resto de la aplicación.
Acoplamiento débil
La degradación o los cambios en los servicios individuales no deben afectar al resto de la aplicación.
Orientado al dominio
Los servicios se modularizan y agrupan en contextos según los dominios empresariales a los que pertenecen.
Responsable de una única tarea empresarial
Se supone que los microservicios siguen el principio de responsabilidad única (SRP).

Un paso clave en la definición de una arquitectura de microservicios es determinar el tamaño que debe tener un microservicio individual. Sin embargo, lo que diferencia a un microservicio de una aplicación normal es que un microservicio debe seguir el SRP.

El SRP propone que cada microservicio encapsule una única parte de la funcionalidad de una aplicación. Esto garantiza que cada microservicio sea ágil, ligero, agnóstico a la implementación y sencillo de entender.

Si buscas bibliografía en Internet sobre microservicios, a menudo los encontrarás generalmente compar ados con ladrillos de LEGO®. Un arquitecto de microservicios considera que cualquier aplicación grande está formada por varios microservicios que se unen entre sí, de forma similar a una construcción de LEGO. Dentro de estas aplicaciones, se espera que los microservicios individuales sigan el SRP. También se supone que estos servicios individuales son autónomos y deben tener una dependencia limitada o nula de otros servicios.

Consejo

A lo largo del libro, haré referencia al SRP con bastante frecuencia. Es el principio más importante que hay que recordar al diseñar arquitecturas de microservicios.

En "Arquitectura y seguridad en la nube", te prometí que las arquitecturas de microservicios en la nube ayudarán a realizar los patrones de diseño seguro que mencioné en la sección. Con la ayuda de la definición formal de microservicios, estoy seguro de que puedes ver por qué:

Seguridad gracias a la modularidad
Dado que, por definición, las aplicaciones de microservicios están formadas por pequeños servicios modulares, es posible implantar fácilmente controles de seguridad.
Seguridad mediante la sencillez
Como cada microservicio modular es pequeño y sigue el SRP, es mucho más fácil alcanzar el objetivo de simplicidad en una arquitectura de microservicios.
Seguridad mediante el aislamiento
Como los microservicios siguen el DDD, es más fácil crear un entorno aislado para ejecutar microservicios individuales.
Seguridad mediante una arquitectura de confianza cero
Utilizando mejor el SRM de AWS, y aprovechando los controles granulares que permiten las arquitecturas de microservicios, es posible implementar fácilmente una arquitectura de confianza cero .

En resumen, los microservicios son funciones empresariales atómicas y discretas, cada una con una función. Los desarrolladores de microservicios deben tener libertad para elegir la herramienta que les proporcione el mejor rendimiento mientras diseñan su microservicio específico para realizar la única tarea que se supone que debe realizar. Como arquitecto responsable de integrar estos microservicios individuales en una aplicación más grande y cohesionada, lo más importante que debe importarte es la función empresarial del microservicio. Todo lo demás es ruido de fondo y no debe orientar las decisiones políticas.

Implementación de Microservicios en AWS

No hay ninguna regla sobre cómo debe implementarse realmente un microservicio. Sin embargo, es importante modularizar la aplicación y acoplar libremente estos módulos para que estos servicios puedan intercambiarse, actualizarse, sustituirse o escalarse por sí solos.

En los últimos años, debido a diversas razones, se ha producido una consolidación en el sector en la que muchas organizaciones han decidido adoptar una de estas dos vías:

Enfoque basado en contenedores
En este enfoque, los microservicios se encapsulan en contenedores ligeros y autónomos (como los contenedores Docker), que se envían para ejecutarse sobre un motor de contenedores como el motor Docker. Mientras exista un motor Docker que pueda ejecutar estos contenedores, los desarrolladores pueden utilizar la herramienta, el lenguaje o el tiempo de ejecución que deseen para escribir estos servicios. Cada servidor físico (llamado nodo) ejecuta el motor Docker, y en ellos pueden desplegarse múltiples contenedores.
Enfoque basado en FaaS
En este enfoque, la función empresarial se ejecuta directamente en una plataforma de Función como Servicio (FaaS). En lugar de empaquetar tu aplicación en un contenedor, escribes tu función empresarial de forma estandarizada para que pueda ejecutarse directamente en una plataforma en la nube, que entrega la responsabilidad de ejecutarla de forma segura al proveedor de la nube.

Ambas opciones tienen ventajas y limitaciones desde el punto de vista de la seguridad y la escalabilidad. Hay mucha literatura en Internet sobre ambos enfoques y sus ventajas y desventajas. (Un gran artículo que leí sobre los microservicios basados en contenedores fue en un blog de Severless). A lo largo de este libro, me centraré en las formas de aumentar la seguridad en torno a ambos enfoques aprovechando las herramientas que nos proporciona AWS.

Arquitectura de microservicios basada en contenedores

Volviendo al SRP, puesto que todo lo demás fuera de la función empresarial del microservicio es ruido de fondo, ¿no sería genial si pudiéramos empaquetar la función empresarial y todas sus dependencias en un entorno virtual dedicado y aislado, y desplegarlo en todas partes? Este es el enfoque de los microservicios basado en contenedores.

En este enfoque, toda la lógica empresarial, junto con cualquier dependencia, se empaqueta en un contenedor ligero, portátil y desplegable. Este contenedor contiene la función empresarial que se supone que debe realizar el microservicio, junto con las instrucciones exactas que se necesitan para ejecutar este código de aplicación en cualquier lugar, en cualquier entorno que admita la ejecución de un contenedor de este tipo. El mismo contenedor (junto con su lógica de aplicación) se prueba en distintos entornos de desarrollo y se despliega en el entorno de tu aplicación. Este contenedor puede ampliarse, actualizarse o intercambiarse en función de las necesidades de la aplicación. Docker ha demostrado ser una tecnología de contenedores popular en la industria, por lo que, a efectos de este libro, utilizaré Docker para mis ejemplos.

Toda tu aplicación es ahora una malla de tales contenedores que proporcionan la funcionalidad empresarial necesaria para ejecutar la aplicación. Al implantar un enfoque basado en contenedores, el arquitecto suele crear un documento (llamado especificación), que especifica qué contenedores deben ejecutarse en producción, creando el plano de toda tu aplicación. Mientras todos los servicios definidos en la especificación estén disponibles, se considera que la aplicación funciona correctamente.

La Figura 1-3 muestra una aplicación de este tipo en la que se despliegan microservicios en contenedores para ofrecer un producto unificado.

Figura 1-3. Los contenedores Docker pueden enviarse y desplegarse para componer y crear una oferta de productos unificada hecha enteramente de microservicios modularizados y en contenedores.

Desde el punto de vista de la seguridad, confías en Docker para aislar y contenerizar la lógica empresarial. Varios contenedores pueden ejecutarse en el mismo servidor físico, por lo que dependes en gran medida de la capacidad del motor Docker para aislar cada contenedor e impedir que interfiera con el código que se ejecuta en otro contenedor. Cualquier vulnerabilidad que permita que los servicios de un contenedor interfieran con el sistema operativo anfitrión o con otro contenedor se denomina vulnerabilidad de fuga. Así que, en términos técnicos, confías en que Docker asuma la responsabilidad de evitar las fugas. Esto significa que es fundamental que te asegures de que ejecutas las últimas versiones tanto del contenedor Docker como del motor que ejecuta estos contenedores.

Estos contenedores suelen almacenarse en un registro de contenedores, un sistema de almacenamiento especializado para contenedores Docker. En AWS, estos contenedores pueden almacenarse de forma segura dentro de Amazon Elastic Container Registry (ECR).

Consejo

Para una visión detallada de Docker, te recomiendo el libro Docker: Up and Running de Sean Kane y Karl Matthias (O'Reilly).

Brevísima introducción a Kubernetes

Aunque cada contenedor Docker es una unidad de implementación, en la mayoría de los entornos de producción, querrás unirlos para que funcionen como una unidad cohesionada. Los orquestadores de contenedores como Kubernetes son los que te permiten ejecutar múltiples microservicios basados en contenedores Docker. Puedes ordenar a un clúster de Kubernetes que ejecute un determinado número de instancias de cada uno de los contenedores Docker, y Kubernetes puede ejecutarlos por ti.

La configuración de un clúster Kubernetes es el tema exclusivo de muchos otros libros, por lo que no entraré en detalles. Pero te daré lo esencial de lo que un clúster Kubernetes hace por ti. Si te interesa más el proceso de configuración, te recomiendo Kubernetes en acción, de Marko Luksa (Manning Publications). La documentación oficial de Kubernetes también contiene material excelente que puede ayudarte a ejecutar tus clusters. Kubernetes, como ya sabrás, es un orquestador que puedes utilizar para ejecutar cualquier número de servicios en cualquier momento. Si proporcionas a Kubernetes una especificación del número de instancias de cada servicio que deseas mantener en ejecución, hará girar nuevos contenedores basándose en la configuración que definas en la especificación.

La unidad de microservicio más básica de un clúster de Kubernetes se llama pod. Un pod es un grupo de uno o más contenedores, con almacenamiento y recursos de red compartidos. Un nodo es una máquina de trabajo en Kubernetes y puede ser una máquina virtual o física. Kubernetes ejecuta tus microservicios colocando contenedores en pods para que se ejecuten en nodos. Como puedes imaginar, puedes escalar microservicios individuales añadiendo nuevos pods a tu clúster. Los pods virtualizan el tiempo de ejecución de tu microservicio. Los pods se ejecutan en un hardware subyacente que puede escalarse añadiendo nuevos nodos al clúster. La parte del clúster Kubernetes que administra y facilita la orquestación de los pods se denomina plano de control. La Figura 1-4 ilustra esta configuración.

Figura 1-4. Visión general concisa de alto nivel de una configuración típica de Kubernetes.

En resumen, en una configuración de Kubernetes, el objetivo principal es ejecutar la lógica de la aplicación, que luego se pone en contenedores y se almacena en un registro de contenedores. Basándose en las especificaciones que proporcionas a este clúster, los contenedores ejecutan esta lógica empresarial en los nodos. Los actores maliciosos podrían dirigirse al plano de control, al almacenamiento de contenedores o al entorno de ejecución de la aplicación (nodos) para causar problemas no deseados en la aplicación.

Consejo

Considero la especificación como la receta que proporciono a mi clúster de Kubernetes. Basándose en esta receta, Kubernetes elabora una lista de todos los servicios (contenedores) que necesita ejecutar, obtiene todos los contenedores del registro de contenedores y ejecuta estos servicios en mis nodos por mí. Así, pone en marcha toda una aplicación de microservicios basándose simplemente en mis especificaciones. Puedes configurar dónde se ejecutan estos microservicios, especificados en tu especificación, configurando los nodos de tu clúster.

AWS te proporciona dos opciones administradas para ejecutar tu clúster de Kubernetes:

  • Servicio Elástico de Kubernetes de AWS (Amazon EKS)

  • Servicio AWS Elastic Kubernetes, modo Fargate (Amazon EKS Fargate)

Dado que AWS asume la responsabilidad de ejecutar, escalar e implementar tus funciones en AWS Lambda, no necesitas un orquestador independiente.

Entonces, ¿cómo decides cómo ejecutar tus microservicios? Como lo que preocupa es la seguridad, he creado un práctico diagrama de flujo que puedes seguir para tomar esa decisión, que se muestra en la Figura 1-5.

Figura 1-5. Un diagrama de flujo para ayudar a los arquitectos a decidir cómo ejecutar sus microservicios.

La siguiente sección entra en los detalles de estos métodos de aplicación.

Nota

AWS Elastic Container Service (AWS ECS) también es una opción si quieres orquestar contenedores en AWS. Aunque ECS difiere ligeramente de EKS en su oferta, existe un solapamiento bastante grande entre EKS y ECS desde el punto de vista de la seguridad. Por ello, para evitar repeticiones, centraré mi atención en Amazon EKS y AWS Lambda. Si te interesa una visión general en profundidad de ECS, aparte de la documentación de AWS, Docker on Amazon Web Services de Justin Menga (Packt Publishing) entra en los detalles.

Función como servicio: FaaS con AWS Lambda

FaaS es una forma diferente de enfocar los microservicios. AWS se dio cuenta de que la lógica empresarial es la característica principal de cualquier microservicio. En consecuencia, AWS proporciona un entorno en el que los usuarios pueden ejecutar esta lógica sin tener que utilizar la contenedorización o el empaquetado. Basta con conectar tu función empresarial, escrita en un lenguaje de programación compatible, al entorno de la nube para que se ejecute directamente. AWS Lambda proporciona esta capacidad de tiempo de ejecución. La Figura 1-6 muestra una aplicación de microservicios en la que se implementan AWS Lambdas para proporcionar una oferta de productos unificada.

Figura 1-6. Las funciones que proporcionan lógica empresarial pueden implementarse en AWS Lambda para ejecutarse juntas y ofrecer un producto unificado.

Lo bueno de AWS Lambda es que AWS asume la responsabilidad de ejecutar la función, lo que te quita parte de las responsabilidades de seguridad como parte de la SRM. En esta configuración, no tienes que preocuparte por la seguridad de los contenedores, la ejecución de los nodos o la seguridad de la configuración de la orquestación.

Visión general de la implementación de microservicios en la nube

Desde el punto de vista de la seguridad, hay muchos lugares en los que los profesionales de la seguridad pueden prever incidentes de seguridad en un entorno de microservicios. En la Figura 1-7 se ilustra un microservicio típico. Esta sección cubre brevemente lo que significa cada una de estas capas y cómo un atacante podría explotar tu aplicación en cada una de ellas para obtener un control no autorizado:

Lógica empresarial

También llamado a veces función o lógica de aplicación, es el código de aplicación que ejecuta la función empresarial central que tu microservicio pretende abordar. Este código es muy específico del dominio y debe ceñirse al SRP. También puede estar escrito en el lenguaje de programación que elija el usuario. Dado que este código es específico del dominio, es posible que los actores maliciosos lo secuestren para realizar actividades no autorizadas.

Entorno de ejecución (entorno contenedor)

El entorno del contenedor debe contener el entorno de ejecución del lenguaje necesario para ejecutar la lógica de la aplicación del componente 1. Este es el entorno en el que la lógica de la aplicación se ejecuta en un entorno aislado (sandboxed), aislando así el tiempo de ejecución y conteniendo el radio de explosión del microservicio (hasta cierto punto). Sin embargo, como con cualquier tiempo de ejecución de la aplicación, mantener actualizada la versión del contenedor y parchear las vulnerabilidades más antiguas de los contenedores y su tiempo de ejecución es importante para garantizar la seguridad de tu aplicación.

Tiempo de ejecución del contenedor (motor del contenedor)

Es el software capaz de ejecutar contenedores del componente dos. Dado que los microservicios que se ejecutan en contenedores se ejecutan en un entorno aislado y aislado, es importante asegurarse de que las vulnerabilidades de seguridad en la capa de virtualización del tiempo de ejecución del contenedor no afecten al sistema operativo anfitrión ni a otros contenedores que se ejecuten en la misma máquina. Este aislamiento es responsabilidad del tiempo de ejecución del contenedor. Estas vulnerabilidades de ruptura pueden ser identificadas de vez en cuando y parcheadas inmediatamente por Docker. Por eso es importante actualizar continuamente el tiempo de ejecución del contenedor para asegurarte de que estás ejecutando el último motor Docker.

Máquina virtual

Esta es la máquina virtual (VM) donde ejecutarás el motor de contenedores. Cada VM puede contener varios contenedores ejecutando contenedores; puedes alojar varios microservicios en cada VM. Dado que una VM es similar a cualquier otro sistema operativo, los atacantes pueden ser capaces de explotar vulnerabilidades a nivel de sistema operativo, especialmente con VMs que no ejecuten la última versión del sistema operativo.

Hardware físico

Esta es la capa más básica dentro de la infraestructura de microservicios y se refiere al hardware físico que puede estar proporcionando la potencia de cálculo necesaria para ejecutar los microservicios. Como cualquier otro elemento físico, estos servidores pueden ser vulnerables al robo, al vandalismo o a la piratería informática mediante unidades flash u otros dispositivos físicos.

Almacenamiento en contenedores

Es habitual almacenar contenedores preconstruidos como parte del proceso de desarrollo en sistemas de almacenamiento dedicados. Si los contenedores preconstruidos no se almacenan de forma segura, un atacante podría manipular las imágenes construidas inyectando código malicioso en ellas o intercambiando imágenes y sustituyéndolas por código malicioso.

Orquestación de contenedores

Un orquestador toma decisiones sobre cuántas instancias de un servicio concreto deben mantenerse en ejecución para lograr la salud de la aplicación. La orquestación te permite crear servicios de aplicación que abarquen varios contenedores, programar contenedores en un clúster, escalar esos contenedores y gestionar su estado a lo largo del tiempo. Un orquestador es responsable de garantizar que los servicios se mantienen en funcionamiento o se reinician cuando se caen. También puede tomar decisiones sobre la ampliación o reducción de los servicios para adaptarlos al tráfico.

Figura 1-7. Representación por capas de un microservicio que se ejecuta en un entorno de nube.

Las siguientes secciones repasan las distintas opciones de tiempo de ejecución de microservicios y, desde el punto de vista de la seguridad, analizan tus responsabilidades frente a las responsabilidades asumidas por AWS. Empiezo con la opción que te asigna la mayor cantidad de responsabilidad dentro de las tres opciones y termino con la opción en la que AWS asume la mayor parte de la responsabilidad.

Amazon EKS

Los planos de control desempeñan un papel crucial en una configuración de Kubernetes, ya que controlan constantemente la disponibilidad de la aplicación garantizando que los servicios en tiempo de ejecución actúen de acuerdo con las especificaciones. Dada su importancia, AWS proporciona a los usuarios un plano de control totalmente gestionado en forma de Amazon EKS. Amazon EKS es un servicio gestionado que te permite configurar el plano de control de Kubernetes en AWS. Al hacerlo, AWS asume la responsabilidad de la infraestructura que ejecuta el plano de control que ejecuta tu clúster como parte del SRM. Dicho esto, sigues siendo responsable de configurar y asegurar los ajustes que hacen que este plano de control sea seguro.

La Figura 1-8 ilustra la configuración mediante Amazon EKS. AWS garantiza que el riesgo de que un actor malicioso se apodere de tu plano de control está mitigado como parte del SRM. Sin embargo, en Amazon EKS sigues siendo responsable del funcionamiento de los nodos, por lo que sigue existiendo el riesgo de que un actor malicioso se apodere de tus nodos.

Figura 1-8. Amazon EKS es un plano de control de Kubernetes totalmente gestionado que puede orquestar los microservicios que ejecutas en los servidores que tienes que administrar.

La Figura 1-9 muestra la división de responsabilidades y cómo EKS aprovecha el SRM de AWS para liberarte de algunas de las responsabilidades de seguridad de ejecutar contenedores, comparándolo con el modelo descrito en la Figura 1-7.

Figura 1-9. La orquestación de contenedores, el almacenamiento de contenedores y la seguridad del hardware físico pueden ser asumidos por AWS en este modelo.

Modo Fargate de Amazon EKS

Una deficiencia del modo EKS normal, como se ha descrito en el apartado anterior, es que tienes que cargar con la responsabilidad de hacer funcionar los nodos. Para muchos administradores, esto añade un conjunto extra de responsabilidades que es, a veces, innecesario. Si el único aspecto de la arquitectura de microservicios que te importa es la única función empresarial que proporciona, tal vez quieras delegar la responsabilidad de ejecutar los nodos en AWS.

Aquí es donde entra en escena el modo Fargate. En el modo Fargate, puedes crear los contenedores Docker que deseas ejecutar en producción, configurar EKS para crear un clúster de estos contenedores y, a continuación, entregar estos contenedores a AWS para que los ejecute en sus servidores. De este modo, AWS se encarga de proteger los servidores, los sistemas operativos que contienen (manteniendo el SO actualizado) y de mantener la seguridad física y de red del hardware que soporta estos servidores, mientras tú te centras en los microservicios en sí, en lugar de en la infraestructura de backend.

La Figura 1-10 muestra la misma arquitectura descrita en la Figura 1-8, en la que se ejecutaba en el modo EKS normal. Pero esta vez, se ejecuta en el modo Fargate.

Figura 1-10. En el modo AWS Fargate, AWS asume la responsabilidad de ejecutar los nodos, reduciendo así tu responsabilidad.

Puedes ver cómo la responsabilidad de los nodos que ejecutaban el motor Docker la asume ahora AWS en la nube, reduciendo así tu responsabilidad de seguridad. Sin embargo, sigues siendo responsable de los propios contenedores, así como de la lógica empresarial que se ejecuta en ellos. También puedes redibujar la pila de tiempo de ejecución de la aplicación, como se muestra en la Figura 1-11. Como ya se ha dicho, el motor Docker se ejecuta en los nodos; por tanto, su responsabilidad la asume AWS. Tú sólo eres responsable de utilizar el contenedor Docker adecuado y la lógica empresarial que se ejecuta en él.

Figura 1-11. En este modelo, AWS asume la seguridad de la orquestación de contenedores, el almacenamiento de contenedores, el hardware físico, la máquina virtual y el tiempo de ejecución de los contenedores.

Función como servicio con AWS Lambda

El servicio basado en FaaS es el último tipo de microservicio que ayuda a los desarrolladores a dar el pistoletazo de salida asumiendo la responsabilidad de todo tipo de seguridad en torno a la ejecución del servicio; por tanto, los desarrolladores pueden centrarse en la lógica empresarial en lugar de en cualquier otra cosa. En AWS, AWS Lambda permite a los desarrolladores ejecutar su función en un entorno FaaS.

En AWS Lambda, la responsabilidad de implementar la mayoría de los controles la asume AWS. Sin embargo, sigues teniendo que configurar el acceso y establecer controles de red y otras configuraciones para garantizar que AWS pueda habilitar la seguridad en tu nombre. AWS asume la responsabilidad de aprovisionar un servidor y ejecutar tu código en un entorno sandboxed, siempre que esté escrito según las especificaciones de AWS Lambda. Las AWS Lambdas son una forma potente, escalable y, lo que es más importante, segura de ejecutar microservicios en AWS.

La pila de arquitectura en tiempo de ejecución de microservicios que se ejecutan en AWS Lambda puede verse en la Figura 1-12. Como se ha mencionado, el cliente sólo es responsable de la lógica empresarial, mientras que todo lo demás lo gestiona AWS. En una arquitectura basada en Lambda, no tienes que preocuparte de parchear el sistema operativo, las versiones de Docker ni nada relacionado con la infraestructura.

Figura 1-12. La responsabilidad de todo, excepto de la lógica empresarial y su configuración, la asume AWS.
Nota

En el momento de escribir este libro, AWS también te permite ejecutar contenedores Docker en AWS Lambda. Sin embargo, a efectos de este libro, estoy restringiendo el alcance únicamente a la ejecución de funciones (FaaS).

Resumen de la implementación de microservicios

La Figura 1-13 ilustra cómo cambian tus responsabilidades de seguridad en función de la implementación de microservicios que elijas.

Figura 1-13. AWS proporciona diferentes formas de ejecutar la misma función. Dependiendo de tu elección, puedes compensar el coste, la flexibilidad y la configurabilidad con la responsabilidad de la seguridad.

Como arquitecto, debes decidir cuánta responsabilidad quieres asumir, a cambio de la flexibilidad que obtienes al dirigir la aplicación en tus propios términos.

Ejemplos de patrones de comunicación de microservicios

Volvamos a la analogía LEGO de los microservicios. ¿Qué puedes hacer con un solo ladrillo de LEGO? Quizá no mucho. ¿Qué tal 10 de ellos? Ahora puedes hacer unas cuantas formas diferentes. Cien ladrillos de LEGO te ofrecen muchas posibilidades. La mayoría de las grandes aplicaciones se crearán componiendo cientos de microservicios más pequeños, todos ellos trabajando entre sí y, lo que es más importante, comunicándose entre sí. Dado que los enlaces de comunicación son los eslabones más débiles de cualquier aplicación, esta comunicación entre servicios aumenta el riesgo agregado de la aplicación. Tienes que asegurar nuevos canales de comunicación externa en lugar de las conocidas llamadas en memoria, como puede ocurrir con los monolitos. Por ello, gran parte de este libro se dedica a asegurar la comunicación interservicio. Para ilustrar cómo se aplicarán los conceptos de seguridad a lo largo de este libro, me gustaría comentar brevemente algunos de los muchos patrones que los arquitectos utilizan en la comunicación entre microservicios. Estos ejemplos no constituyen una lista exhaustiva, y en la industria se siguen muchos otros patrones de comunicación. El blog Microservices.io o el ebook de arquitectura de Microsoft son excelentes recursos si te interesan otros patrones de comunicación de microservicios.

Ejemplo 1: Paso simple de mensajes entre contextos

La forma más sencilla de comunicarse entre contextos es enviarse directamente mensajes (generalmente mediante solicitudes HTTP). En este ejemplo, cada vez que un cliente retire un artículo, el servicio de caja enviará dos mensajes. El primero sería al dominio productos, informándole de que reduzca las existencias de inventario para reflejar esta compra. El segundo sería para el servicio financiero, informándole de que cargue el importe en la tarjeta de crédito registrada del cliente.

La Figura 1-14 muestra un ejemplo de comunicación directa.

Figura 1-14. Hay muchas formas de pasar estos mensajes.

La forma tradicional de pasar mensajes es utilizando puntos finales REST síncronos. Aunque no se ajusta a mi definición de comunicación basada en microservicios, empresas de todo el mundo la utilizan. Cada vez que se realiza una compra, el servicio de caja llamará a un punto final POST en el servicio de recogida de efectivo y, en consecuencia, llamará a un punto final POST en el dominio de inventario. Sin embargo, la comunicación síncrona mediante REST significará que el servicio de caja esperará a que finalicen las dos operaciones síncronas para poder completar su trabajo. Esto añade una fuerte dependencia y aumenta el acoplamiento entre los dominios de finanzas, inventario y cliente.

En tales situaciones, el trabajo de los profesionales de la seguridad consiste en asegurar los puntos finales REST y la infraestructura HTTP de la aplicación. El Capítulo 7 habla de los fundamentos de la configuración de la seguridad en tránsito.

Advertencia

En mi opinión, la comunicación síncrona de este modo va en contra de la esencia misma de los microservicios, ya que los microservicios resultantes ya no son independientes y seguirán manteniendo una fuerte relación. Aunque algunas arquitecturas de microservicios siguen utilizando la comunicación síncrona REST, la mayoría de los modelos arquitectónicos para microservicios disuaden a los servicios de microservicios de utilizar la comunicación síncrona.

Ejemplo 2: Colas de mensajes

Los corredores de mensajes o sistemas de colas se utilizan habitualmente para la comunicación entre dominios en microservicios. Un servicio que quiera enviar un mensaje lo pondrá en un medio persistente. En cambio, el destinatario del mensaje lo leerá del medio persistente. La comunicación a través de colas de mensajes se produce de forma asíncrona, lo que significa que los extremos que publican y consumen mensajes interactúan con la cola, en lugar de entre sí. Los productores pueden añadir mensajes a la cola una vez que estén listos, y los consumidores sólo pueden manejar mensajes si tienen capacidad suficiente. Ningún productor del sistema se queda nunca estancado a la espera de un consumidor descendente ni se ve afectado por su fiabilidad. La Figura 1-15 ilustra una comunicación basada en colas.

Figura 1-15. Utilizar colas de mensajes para la comunicación entre microservicios

Puedes ver cómo el papel de un profesional de la seguridad aumenta ligeramente en este ejemplo. Como las colas utilizan una capa de persistencia, los profesionales de la seguridad deben asegurar tanto las colas como los puntos finales que el servicio A y el servicio B utilizan para conectarse a la cola.

Ejemplo 3: Microservicios basados en eventos

El paradigma de la comunicación basada en eventos es otra forma popular de diseñar la comunicación entre microservicios. Un sistema basado en eventos funciona sobre la premisa de que cada comando que cambia de estado da lugar a un evento que luego se difunde (generalmente utilizando una entidad conocida como corredor de eventos) a otras partes de la aplicación. Otros servicios dentro de otros contextos se suscriben a estos eventos. Cuando reciben un evento, pueden actualizar su propio estado para reflejar este cambio, lo que podría dar lugar a la publicación de más eventos. La Figura 1-16 ilustra un ejemplo de aplicación de microservicios basada en eventos. Para saber más, consulta Building Event-Driven Microservices, de Adam Bellemare (O'Reilly), un libro entero dedicado a este tipo de arquitectura.

Figura 1-16. Los microservicios basados en eventos ofrecen un enfoque coreografiado de los microservicios.

En este ejemplo, los profesionales de la seguridad deben asegurar el corredor de eventos, junto con toda la infraestructura necesaria para almacenar, difundir y alojar los eventos.

Resumen

En este capítulo se han introducido los conceptos básicos de amenazas y riesgo, y después se ha explicado el concepto de control y contramedidas. En un entorno en la nube, la responsabilidad de aplicar los controles se reparte entre el cliente y AWS. Entender en qué consiste esta división es la idea principal de la seguridad en la nube. Aunque AWS asuma la responsabilidad de ciertos controles, puede seguir siendo responsabilidad del cliente configurar los controles de forma que AWS pueda protegerse contra posibles ataques. El capítulo también ha presentado algunos de los patrones comunes de arquitectura de microservicios y su implementación en AWS. El siguiente capítulo profundiza en la autenticación y la autorización, dos de los controles más básicos disponibles que reducen el riesgo de tu aplicación frente a posibles amenazas.

Get Seguridad y arquitectura de microservicios en AWS now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.