Saltar al contenido
Usuarios, grupos y directorios

Usuarios, grupos y directorios

De dónde proceden las personas (bloques user y group, SQL, LDAP, un proveedor de identidad) y qué les permite usar cada origen.

Un bloque user es todo el directorio de un hogar. Un sitio cuyas personas ya están en una base de datos o en LDAP no debería copiarlas a un segundo lugar que se quede desfasado, así que un bloque users las lee allí donde están.

users "sql" {
  driver   = "postgres"                 # or sqlite, or mysql
  dsn_file = "/etc/fileshare/dsn"       # a DSN holds a password: it lives in a file
  users    = "select login, null, nt_hash, ssh_keys from staff"
  groups   = "select team, member from team_members"
}

users "ldap" {
  url                = "ldaps://ldap.example.org"
  base_dn            = "ou=people,dc=example,dc=org"
  bind_dn            = "cn=reader,dc=example,dc=org"
  bind_password_file = "/etc/fileshare/bind.pw"
}

Las consultas son suyas, porque las personas de un sitio ya tienen la forma de ese sitio; un esquema inventado aquí obligaría a copiarlas a un segundo. Las columnas de la consulta de personas se leen por posición, no por nombre: un nombre y luego, cualquiera de estos, una contraseña, un hash NT, claves SSH (una por línea) y un secreto TOTP, en ese orden. Un NULL es una credencial que esa persona no tiene, por eso el ejemplo selecciona null para la contraseña. Una columna de contraseña se toma como la propia contraseña: aquí no hay ningún ajuste para una contraseña con hash.

El lado LDAP lee lo que ya publica un directorio adaptado a Samba: sambaNTPassword, sshPublicKey, memberUid. Dónde están las personas y los grupos, y qué atributos los nombran, es configurable: user_filter (por defecto (objectClass=posixAccount)), user_attribute (uid), group_base_dn (base_dn), group_filter ((objectClass=posixGroup)), group_attribute (cn), group_member_attribute (memberUid), y totp_attribute, que no tiene valor por defecto. sambaNTPassword y sshPublicKey se leen con esos nombres.

Ningún bind sin cifrar hacia otra máquina (desde la v0.19.0)

Un bloque users "ldap" rechaza ldap:// hacia otra máquina salvo que start_tls = true: cada contraseña que comprueba un bind cruzaría la red sin cifrar. Se acepta ldaps://, y también ldap:// hacia una dirección de loopback y ldapi://, donde no hay nadie en el camino. No existe ningún interruptor para desactivarlo (go-authn/directory v0.10.0).

El orden, y la única excepción

Los orígenes se consultan en el orden en que están escritos, y el primero que conoce un nombre se lo queda. Los bloques user y group van primero, así que una cuenta de servicio anotada localmente no queda sustituida por alguien con el mismo nombre en LDAP.

Los grupos son la excepción: los miembros de un grupo son la unión de todos los orígenes, porque un equipo puede tener personas en un archivo y en una base de datos.

share "photos" {
  allow   = ["@engineers", "alice"]
  writers = ["@owners"]
}

Expandido al arrancar, y de nuevo en cada recarga

Desde la v0.10.0, los bloques users —SQL, LDAP— se vuelven a leer cada reload = "5m", con SIGHUP, y con el ReloadDirectory de la API de administración; una pertenencia que cambia en LDAP ya no espera a un reinicio. Lo que una recarga aplica en caliente y lo que reinicia, y por qué un grupo que se vacía no abre su recurso compartido a todo el mundo, se explica en volver a leer el directorio. El directorio sigue sin consultarse en cada conexión: eso es otro diseño, y no es este.

Lo que un origen puede probar, y lo que necesita cada protocolo

Esta es la parte que, si no, un sitio descubre al montar, así que check la dice primero:

el origen tieneSMBS3WebDAVSFTP
una contraseña (archivo, o una columna en claro)sísísí—
un hash NT (sambaNTPassword, nt_hash)síno——
solo un bind (LDAP)nonosí—
claves públicas, o una CA de confianza———sí

NTLMv2 necesita la contraseña o su MD4, y nada más sirve

Un cliente nunca envía una contraseña a un servidor SMB —envía una prueba calculada a partir de ella—, así que un directorio que solo comprueba contraseñas no puede responder a SMB, por buena que sea la comprobación. Es una propiedad del protocolo, no una limitación de este programa, y ninguna configuración la cambia. WebDAV solo pregunta «¿es esta la contraseña correcta?», y eso lo responde un bind.

Una persona que un directorio nombra pero para la que no prueba nada es legítima —un listado con los secretos en otro lugar—, y check lo indica en una línea en lugar de dejar que lo descubra.

Las personas que nombra el proveedor de identidad, no este archivo

Una federación —RENATER a través de go-authn/bridge, por ejemplo— sabe quién forma parte de un proyecto, y un recurso compartido puede preguntárselo a ella en lugar de copiar la lista. Con un bloque oidc:

share "photos" {
  image   = "/srv/photos.img"
  allow   = ["oidc:groups:urn:mace:univ-example.fr:photos", "oidc:user:bob@univ-example.fr", "alice"]
  writers = ["oidc:groups:urn:mace:univ-example.fr:photos"]
}

oidc:groups:<value> es alguien cuyo claim de grupos del token contiene el valor; oidc:user:<name> es alguien a quien nombra el token. La grafía es la de opkssh, para que un mismo vocabulario diga quién llega a una shell y quién llega a un recurso compartido. Alguien a quien nombra una regla es conocido por este servidor en la medida en que lo es por el proveedor —también para los recursos compartidos abiertos—, y alguien a quien no nombra ninguna regla sigue siendo un desconocido. Las mismas reglas se aplican por SFTP, donde los grupos viajan en el certificado en lugar del token.

Una regla se refiere solo a las personas del proveedor

oidc:user:bob es el bob que avala el proveedor; una cuenta local llamada bob, con contraseña, es otra persona y no coincide con ninguna regla. Una regla sin bloque oidc, una mal formada, o una que puede escribir sin tener permiso para conectarse se rechaza al arrancar.

El alice del proveedor no es el alice local salvo que usted lo diga (desde la v0.20.0)

Un nombre a secas en allow o writers es una cuenta local; a un token o a un certificado del proveedor solo se llega mediante las reglas oidc: de un recurso compartido. Un sitio cuyos nombres en el proveedor SON sus nombres locales escribe local_names = true en el bloque oidc, y debería establecer domains junto con ello, o tomar el nombre de un claim que el proveedor controle: un proveedor en el que las personas eligen su propio preferred_username entregaría si no a cualquiera que se registre los recursos compartidos de una cuenta local, escritura incluida. Ese era el comportamiento por defecto antes de la v0.20.0 (auditoría de seguridad F4). Un nombre federado rechazado por falta de local_names se registra con la línea que hay que añadir, y fileshare check indica qué regla está en vigor.

Los certificados de cliente NFS (identity = "certificate") son la excepción: su CA es la que client_ca_file fija precisamente para eso, y los nombres a secas son la única forma en que un recurso compartido NFS puede nombrar a alguien, así que sus nombres son nombres locales diga lo que diga local_names.

Qué instituciones

oidc {
  issuer   = "https://login.example.org"
  audience = "fileshare"
  domains  = ["univ-a.fr", "univ-b.fr"]   # nobody else from the federation gets in
}

share "projet-x" {
  image   = "/srv/projet-x.img"
  allow   = ["oidc:groups:urn:mace:univ-a.fr:projet-x", "oidc:domain:univ-b.fr"]
  writers = ["oidc:groups:urn:mace:univ-a.fr:projet-x"]
}

domains se comprueba en la autenticación, tanto por SFTP como por WebDAV, y para los certificados de cliente NFS: un nombre debe ser <algo>@<uno de ellos>, comparado entero (evilunivb.fr no es univb.fr). oidc:domain: es la misma prueba para un solo recurso compartido. Se puede confiar en el dominio tanto como en el proveedor: go-authn/bridge descarta un eppn o un subject-id cuyo ámbito no le conceden los metadatos de federación del IdP.

Los grupos son lo que publica el IdP de la institución, convertido en el claim groups por el claims { groups = [...] } de go-authn/bridge: eduPersonEntitlement por defecto (los grupos de un laboratorio o de una VO), o eduPersonScopedAffiliation (staff@univ-a.fr, student@univ-b.fr).

Creada el por tannevaled

Modificada el por tannevaled