◇ OpenCyber Academy
Técnico · Capítulo 3 · Español

Capítulo 3 — Sistemas operativos e identidades

Aprendizaje gratuito y abierto para quienes desean proteger a las personas y la tecnología. No se necesita una cuenta para estudiar ni consultar las respuestas.

Capítulo 3 — Sistemas operativos e identidades

Mapa de la lección

Lección 03 publicada. Mapa, ejemplo, EX009.

flowchart TD
  N0["Resultados de aprendizaje y conexión"]
  N1["3.1 Qué significa bastionar en el nivel técnico"]
  N2["3.2 Leer correctamente la configuración de sshd"]
  N3["3.3 Cuentas e identidades"]
  N4["3.5 Actividad práctica"]
  N5["Síntesis del capítulo"]
  N0 --> N1 --> N2 --> N3 --> N4 --> N5
  N5 --> EX["Ejemplo resuelto"]
  EX --> Q["Ejercicio EX009"]

Dibujo lógico

flowchart LR
  N0["Resultados de aprendizaje y conexión"]
  N1["3.1 Qué significa bastionar en el nivel técnico"]
  N2["3.2 Leer correctamente la configuración de sshd"]
  N3["3.3 Cuentas e identidades"]
  N4["3.5 Actividad práctica"]
  N5["Síntesis del capítulo"]
  N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> Q["EX009"]
[Resultados de aprendizaje y conexión]
    |
    v
[3.1 Qué significa bastionar en el nivel técnico]
    |
    v
[3.2 Leer correctamente la configuración de sshd]
    |
    v
[3.3 Cuentas e identidades]
    |
    v
[3.5 Actividad práctica]
    |
    v
[Síntesis del capítulo]
    |
    v
[Ejemplo resuelto] --> [Ejercicio EX009]

Resultados de aprendizaje y conexión

Al terminar este capítulo debería ser capaz de:

Los capítulos 1–2 describieron el servicio y su tráfico. Los servidores del centro de control (historiador, servidor SCADA, servidor de salto) ejecutan sistemas operativos corrientes; este capítulo convierte su configuración en algo que usted puede comprobar, no suponer.

3.1 Qué significa bastionar en el nivel técnico

Bastionar es eliminar lo que no se necesita y restringir lo que sí. Para un servidor de un entorno de control eso significa: servicios a la escucha solo en las interfaces que necesitan; acceso administrativo solo a través de la ruta de gestión; ninguna cuenta compartida ni huérfana; cuentas de servicio que no pueden iniciar sesión de forma interactiva; y una configuración registrada para poder detectar las derivas (capítulo 14). La guía general de servidores del NIST ofrece la lista de comprobación más amplia (SP 800-123); los Cross-Sector Cybersecurity Performance Goals de CISA resumen las prácticas de cuentas y credenciales que faltan con más frecuencia (CISA CPGs).

3.2 Leer correctamente la configuración de sshd

El demonio de OpenSSH lee sshd_config de arriba abajo y, para la mayoría de las palabras clave, se usa el primer valor obtenido; las líneas posteriores con la misma palabra clave se ignoran (sshd_config(5)). Los comentarios empiezan por #. Así, un archivo que tiene PasswordAuthentication yes cerca del principio y la corrección posterior de alguien, PasswordAuthentication no, al final, sigue permitiendo contraseñas. La comprobación fiable es la configuración efectiva: en un equipo real, sshd -T la imprime; en el Lab 3, el analizador conserva el primer valor, como hace el demonio.

Ajustes que importan en un equipo del centro de control: ListenAddress restringido a la interfaz de gestión; PermitRootLogin no; PasswordAuthentication no en cuanto funcionen las claves o los certificados; X11Forwarding no; un MaxAuthTries bajo; y AllowGroups con el nombre de un grupo cuya pertenencia también revise.

3.3 Cuentas e identidades

En Linux, el privilegio es un número: UID 0 es root, sea cual sea el nombre de la cuenta. Una cuenta adicional con UID 0 («backup2», «support») es una segunda contraseña de root que nadie rota. Las cuentas de servicio (por convención, UID inferiores a 1000 en muchas distribuciones) ejecutan demonios; deben tener un intérprete no interactivo como /usr/sbin/nologin, para que una credencial de servicio robada no pueda usarse para iniciar sesión. Las cuentas de persona deben corresponder a alguien de la lista actual de autorizaciones; una cuenta de proveedor que permanece de forma permanente en sudo es un privilegio permanente que debería estar limitado en el tiempo (capítulo 10). La pertenencia a grupos forma parte de la identidad: estar en sudo o en ops-admins suele importar más que la propia cuenta.

3.4 Ejemplo resuelto: auditoría de HIST-02 (sintético)

hist-02 almacena las series temporales de Kestrel Water. Política del KVROC: SSH solo en la dirección de gestión 10.90.0.21; sin inicio de sesión de root; solo claves; como máximo tres intentos; solo J. Tan y R. Kaur autorizados. Lab 3 (guárdelo como lab03.py y ejecútelo con python3 lab03.py):

# Lab 3 - audit a host configuration and its local accounts (offline, standard library only)
# Synthetic files from historian host HIST-02 at the Kestrel Vale operations centre.
sshd_config = """
Port 22
ListenAddress 0.0.0.0
PermitRootLogin yes
PasswordAuthentication yes
# PasswordAuthentication no
PubkeyAuthentication yes
X11Forwarding yes
MaxAuthTries 6
AllowGroups ops-admins
"""
passwd = """root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
histsvc:x:998:998:historian service:/opt/hist:/bin/bash
jtan:x:1001:1001:J. Tan:/home/jtan:/bin/bash
rkaur:x:1002:1002:R. Kaur:/home/rkaur:/bin/bash
backup2:x:0:0:temp backup:/root:/bin/bash
vendor:x:1003:1003:vendor support:/home/vendor:/bin/bash"""
group = """ops-admins:x:1100:jtan,vendor
sudo:x:27:jtan,rkaur,vendor"""
policy = {"PermitRootLogin": "no", "PasswordAuthentication": "no", "X11Forwarding": "no",
          "ListenAddress": "10.90.0.21", "MaxAuthTries": "3"}
roster = {"jtan", "rkaur"}                     # people currently authorized on HIST-02
eff = {}
for line in sshd_config.splitlines():
    line = line.split("#", 1)[0].strip()
    if not line: continue
    key, val = line.split(None, 1)
    eff.setdefault(key, val)                   # sshd uses the FIRST value it reads for a keyword
findings = []
for k, want in policy.items():
    if eff.get(k) != want: findings.append(f"sshd {k} is {eff.get(k)!r}, policy {want!r}")
for line in passwd.splitlines():
    name, _, uid, gid, gecos, home, shell = line.split(":")
    if uid == "0" and name != "root": findings.append(f"account {name} has UID 0 (root equivalent)")
    if 0 < int(uid) < 1000 and shell.endswith("sh") and not shell.endswith("nologin"):
        findings.append(f"service account {name} has interactive shell {shell}")
    if int(uid) >= 1000 and name not in roster: findings.append(f"person account {name} not on roster")
for line in group.splitlines():
    g, _, _, members = line.split(":")
    for m in members.split(","):
        if m and m not in roster: findings.append(f"group {g} contains {m} (not on roster)")
for f in findings: print(f)
print("findings:", len(findings))

Salida esperada (Python 3.13.5):

sshd PermitRootLogin is 'yes', policy 'no'
sshd PasswordAuthentication is 'yes', policy 'no'
sshd X11Forwarding is 'yes', policy 'no'
sshd ListenAddress is '0.0.0.0', policy '10.90.0.21'
sshd MaxAuthTries is '6', policy '3'
service account histsvc has interactive shell /bin/bash
account backup2 has UID 0 (root equivalent)
person account vendor not on roster
group ops-admins contains vendor (not on roster)
group sudo contains vendor (not on roster)
findings: 10

Diez hallazgos. Fíjese en la línea de PasswordAuthentication: el archivo contiene un no comentado, que algunos revisores leen como «ya corregido». Es un comentario, y el valor efectivo es yes. Los hallazgos más peligrosos son backup2 con UID 0 (un segundo root sin gestionar) y vendor en sudo (acceso privilegiado permanente de un proveedor). La cuenta de servicio del historiador con /bin/bash importa porque las credenciales del servicio se guardan en disco para que el historiador las use.

Un orden de bastionado seguro: (1) confirmar que J. Tan y R. Kaur pueden iniciar sesión con clave desde jump-01; (2) restringir ListenAddress, PermitRootLogin y PasswordAuthentication en un único cambio, manteniendo abierta una sesión existente mientras prueba una nueva; (3) eliminar backup2 después de conservar su historial de inicios de sesión; (4) quitar a vendor de sudo y llevar el acceso del proveedor a un procedimiento limitado en el tiempo; (5) cambiar el intérprete de la cuenta de servicio a nologin después de comprobar que ningún script de mantenimiento inicia sesión con ella.

3.5 Actividad práctica

En una máquina virtual de su propiedad, ejecute sshd -T | sort y compare la salida con el archivo. Añada una palabra clave duplicada más abajo en el archivo, recargue y confirme que gana el primer valor. Anote la versión exacta de OpenSSH, porque el comportamiento de los bloques Include y Match varía según la versión. Anote la versión de OpenSSH y la ruta de cada archivo que sshd -T muestre como incluido. Después de recargar, abra una segunda sesión antes de cerrar la primera, para que un cambio erróneo de ListenAddress o de AllowGroups no le deje fuera. Compare los valores efectivos con la tabla de política del Lab 3 y anote cualquier palabra clave que aparezca dos veces en el archivo.

3.6 Errores comunes y límites

Ejercicios — capítulo 3

EX009 — Gana el primer valor. Objetivo: razonar sobre la configuración efectiva. Entradas: el sshd_config del Lab 3. Pasos: (1) prediga el PasswordAuthentication efectivo si la línea comentada se descomenta y se deja donde está; (2) indique dónde debe ir la corrección. Evidencia esperada: predicción y ubicación. Rúbrica: 3 = sigue siendo yes porque gana la línea anterior; la corrección sustituye la primera aparición (o se borra la línea anterior), verificado con sshd -T; 2 = respuesta correcta, sin verificación; 1 = predice no; 0 = nada.

EX010 — Priorice los hallazgos de HIST-02. Objetivo: ordenar los cambios por riesgo y seguridad. Entradas: la salida del Lab 3. Pasos: agrupe los diez hallazgos en hoy / esta semana / próxima ventana de mantenimiento, con razones de una línea y un paso de conservación donde haga falta. Evidencia esperada: una lista en tres grupos. Rúbrica: 3 = backup2 con UID 0 y vendor en sudo hoy, conservando antes el historial de inicios de sesión; el enlace de SSH y los ajustes de root/contraseña como un único cambio probado; el intérprete del servicio tras comprobar los scripts; 2 = sensato pero sin conservación; 1 = sin orden; 0 = nada.

EX011 — Amplíe la auditoría. Objetivo: añadir una comprobación. Entradas: el Lab 3. Pasos: añada una comprobación que marque cualquier cuenta distinta de root cuyo intérprete sea interactivo y cuyo directorio personal sea /root o /. Informe de la nueva salida. Evidencia esperada: código y salida. Rúbrica: 3 = marca backup2 (directorio personal /root) y solo esa; explica por qué los directorios personales compartidos ocultan la rendición de cuentas; 2 = funciona sin explicación; 1 = intentado; 0 = nada.

EX012 — Diseño de una cuenta de servicio. Objetivo: diseñar una identidad no interactiva. Entradas: el servicio del historiador necesita leer archivos de /opt/hist y escribir en su base de datos. Pasos: especifique el rango de UID, el intérprete, el directorio personal, el grupo, los permisos de archivo y cómo se guarda y se rota su credencial. Evidencia esperada: una especificación breve. Rúbrica: 3 = UID de sistema, intérprete nologin, grupo dedicado, modos de archivo de mínimo privilegio, credencial legible solo por el servicio, responsable e intervalo de rotación; 2 = una carencia; 1 = genérico; 0 = nada.

Síntesis del capítulo

El bastionado del sistema operativo se puede comprobar: los ajustes efectivos, los UID, los intérpretes y la pertenencia a grupos pueden leerse y compararse con una política escrita. Sepa cómo lee realmente el demonio su archivo, mire los números en lugar de los nombres y ordene los cambios de modo que nunca deje fuera a las personas que operan el servicio.

Siga estudiando — capítulo 03 de 18

← Capítulo 02 · Índice de capítulos del curso · Capítulo 04 →

Continúe con la siguiente lección escrita.

Respuestas desarrolladas

EX009 — Gana el primer valor. Si la línea comentada se descomenta donde está (después de PasswordAuthentication yes), el valor efectivo sigue siendo yes, porque sshd usa el primer valor que lee. La corrección debe sustituir la primera aparición (o borrarla) y confirmarse después con sshd -T | grep -i passwordauthentication.

EX010 — Priorice los hallazgos de HIST-02. Hoy: conservar last/lastlog/los registros de autenticación de backup2 y vendor; eliminar backup2 (UID 0) y quitar a vendor de sudo y de ops-admins. Esta semana, como un único cambio probado desde una sesión abierta: ListenAddress 10.90.0.21, PermitRootLogin no, PasswordAuthentication no (tras confirmar los inicios de sesión con clave de las dos personas autorizadas), X11Forwarding no, MaxAuthTries 3. Próxima ventana: cambiar el intérprete de histsvc a /usr/sbin/nologin tras comprobar las tareas programadas y los scripts. El acceso del proveedor pasa al proceso limitado en el tiempo del capítulo 10.

EX011 — Amplíe la auditoría. Añada dentro del bucle de passwd: if name != "root" and home in ("/root", "/") and not shell.endswith("nologin"): findings.append(f"account {name} has interactive shell and home {home}"). La salida añade account backup2 has interactive shell and home /root, findings 11. Un directorio personal compartido mezcla el historial del intérprete y las claves entre identidades, de modo que las acciones no pueden atribuirse.

EX012 — Diseño de una cuenta de servicio. UID de sistema (por ejemplo, 998), intérprete /usr/sbin/nologin, directorio personal /opt/hist propiedad de root y legible por el grupo histsvc; directorio de datos con escritura solo para histsvc; credencial de la base de datos en un archivo con modo 0400 propiedad de histsvc, o en el almacén de secretos de la plataforma; rotada anualmente y tras cualquier cambio de personal con acceso, con el equipo de plataforma del KVROC como responsable; la cuenta nunca la usan personas.