Saltar al contenido
Personas

De dónde proceden las personas

Bloques user y group, una base de datos SQL, otro directorio LDAP: cómo se escribe cada uno, en qué orden se consultan y qué permite hacer cada uno a una persona.

Un bloque user es el directorio entero de un sitio pequeño, o las cuentas de servicio que uno grande mantiene fuera de su base de datos. 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 donde están. El bloque users es el hcldir de go-authn/directory, el mismo que lee go-fileshare: un mismo directorio se describe igual para ambos.

Escritas en la configuración

user "alice" { password_file = "/etc/authnd/passwords/alice.pw" }

user "carol" {
  nt_hash         = "…"                                   # MD4(UTF16LE(password)), 32 hex
  authorized_keys = ["ssh-ed25519 AAAA… carol@laptop"]    # published as sshPublicKey
}

group "staff" { members = ["alice", "carol"] }
campoqué es
passwordla contraseña, en línea
password_filelo mismo, leído de un archivo (sin los espacios en blanco del principio y del final)
nt_hashMD4(UTF16LE(password)), 32 caracteres hexadecimales, para un sitio que guarda eso y no la contraseña
totp_secretun secreto de código de un solo uso en base32, de al menos 128 bits; consulte un segundo factor
authorized_keyslíneas de authorized_keys, publicadas como sshPublicKey
authorized_keys_filelo mismo, a partir de un archivo
attributesdesde la v0.11.0, lo que describe a la persona y no prueba nada —sn, uidNumber, gidNumber, homeDirectory, mail…—, como un mapa de cadenas o de listas de cadenas; un bloque group también lo admite. Deciden como qué se publica la entrada: consulte las entradas

Se rechaza al arrancar, nombrando a la persona:

  • password y password_file juntos: indique cuál;
  • password y nt_hash juntos: el hash se deriva de la contraseña, así que los dos pueden no coincidir;
  • authorized_keys y authorized_keys_file juntos;
  • un nt_hash que no tiene 32 caracteres hexadecimales, una línea de authorized_keys que no se puede analizar, un totp_secret de menos de 128 bits;
  • el mismo user o group dos veces, y un group sin miembros.

Un miembro de grupo que ningún origen conoce también se rechaza, lo que detecta una errata antes de que, sin decir nada, no conceda nada:

$ authnd check cases/typo.hcl
authnd: group "staff" has "alise" in it, who is not in the configuration file

Un nt_hash solo no puede hacer un bind

Una persona escrita solo con nt_hash se publica, puede entregarse a un servidor SMB mediante sambaNTPassword, y no puede hacer un bind con el propio authnd: un bind simple de LDAP envía la contraseña, y un hash NT no es aquí una forma de comprobarla. bob, más abajo, solo tiene un hash NT, y el hash es el de la contraseña enviada:

$ ldapwhoami -x -H ldap://127.0.0.1:3893 -D uid=bob,ou=people,dc=example,dc=org -y bob.pwin
ldap_bind: Invalid credentials (49)

check lo dice, después de las tablas:

bob and eli cannot bind with a password: their sources hold only what an SMB server needs (an NT hash), which a bind cannot be checked against

En una base de datos SQL

users "sql" {
  driver   = "postgres"                      # or mysql (mariadb), or sqlite
  dsn_file = "/etc/authnd/pg.dsn"            # required: a DSN may hold a password
  users    = "select login, secret, nt_hash from staff"   # required
  groups   = "select team, member from team_members"      # optional
}

Las consultas las escribe usted, porque las personas de un sitio ya tienen la forma de ese sitio. Las columnas de la consulta users se leen por posición: un nombre y, después, cualquiera de una contraseña, un hash NT, claves SSH (una por línea) y un secreto de código de un solo uso, en ese orden, hasta cinco columnas. Un NULL es una credencial que esa persona no tiene. Una columna de contraseña se compara tal como está guardada: authnd no tiene ningún ajuste para una columna con hash. La consulta groups devuelve un nombre de grupo y un miembro, una fila por pertenencia.

Otras dos consultas, opcionales, leen atributos por alias de columna en lugar de por posición: users_attributes (un nombre y después una columna por atributo) y groups_attributes (un grupo y después lo mismo). PostgreSQL pasa a minúsculas un alias sin comillas. Consulte las entradas.

driver acepta postgres (o postgresql, pgx), mysql (o mariadb) y sqlite (o sqlite3). La base de datos se contacta al arrancar, antes de que nada escuche, así que una que no responde detiene el servidor allí donde alguien está mirando:

$ authnd check cases/nodb
authnd: users "sql": the postgres database is not answering: failed to connect to `user=authnd database=authnd`:
	127.0.0.1:1 (127.0.0.1): dial error: dial tcp 127.0.0.1:1: connect: connection refused
	127.0.0.1:1 (127.0.0.1): dial error: dial tcp 127.0.0.1:1: connect: connection refused

PostgreSQL en la misma máquina, a través de su socket y de la autenticación peer, no necesita ninguna contraseña en el DSN: host=/run/postgresql dbname=authnd user=authnd. SQLite en el directorio de estado: file:/var/lib/authnd/people.db.

Una clave que pertenece a la otra clase de bloque se rechaza en lugar de ignorarse:

$ authnd check cases/sqlwrongkey.hcl
authnd: users "sql" has base_dn in it, which belongs to an ldap block

En otro directorio LDAP

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/authnd/upstream.pw"
}

url y base_dn son obligatorios. Dónde están las personas y los grupos, y qué atributos los nombran:

clavepor defecto
user_filter(|(objectClass=posixAccount)(objectClass=account)(objectClass=uidObject))
user_attributeuid
group_base_dnbase_dn
group_filter(|(objectClass=posixGroup)(objectClass=groupOfNames))
group_attributecn
group_member_attributeninguno: memberUid (nombres) y member (DN); si se define, es el único atributo que se lee
totp_attributeninguno: no hay ningún atributo estándar, y uno adivinado no leería nada aparentando haber buscado
attributes, group_attributesninguno: los atributos que se copian de la entrada de cada persona y de la de cada grupo, como ["mail", "uidNumber", "homeDirectory"] y ["gidNumber"] (las entradas)
start_tlsfalse

Un DN en member solo cuenta cuando es el DN de una entrada que devolvió la búsqueda de personas: un DN fuera de ellas, o que no nombra a nadie, no corresponde a nadie, y el nombre nunca se extrae del DN. sambaNTPassword y sshPublicKey se leen con esos nombres.

Desde la v0.11.0, los valores por defecto leen más del directorio de una institución

El bloque es el de go-authn/directory, y directory v0.14.0, que incorpora authnd v0.11.0, amplió sus valores por defecto: hasta la v0.10.2, user_filter era (objectClass=posixAccount), group_filter (objectClass=posixGroup) y group_member_attribute memberUid. Un directorio con entradas account o uidObject que no son posixAccount —cuentas de servicio, máquinas nombradas por uid, personas importadas de otro lugar— se las entrega ahora a authnd, y cada una puede comprobarse con un bind; sus grupos groupOfNames pasan a ser grupos aquí. Para conservar exactamente el conjunto anterior, escriba los valores anteriores:

users "ldap" {
  # ...
  user_filter            = "(objectClass=posixAccount)"
  group_filter           = "(objectClass=posixGroup)"
  group_member_attribute = "memberUid"
}

Dos cosas se rechazan antes de abrir nada:

$ authnd check cases/ldap-clear.hcl
authnd: users "ldap" would send every password to "ldap.example.org" in the clear: use ldaps://, or start_tls = true (RFC 4513 §5.1.3)

$ authnd check cases/ldap-cred.hcl
authnd: users "ldap" has credentials in its url, and a url is printed: use bind_dn with bind_password_file

ldap:// hacia una dirección de loopback y ldapi:// se aceptan: no hay nadie en medio.

Un directorio detrás de este comprueba las contraseñas haciendo un bind contra él; no las entrega. Aquí un authnd hace de fachada de otro, bajo una base distinta; el que está detrás es el ejemplo de check, servido en el 3893:

listen  = "127.0.0.1:3894"
base_dn = "dc=example,dc=net"

users "ldap" {
  url                = "ldap://127.0.0.1:3893"
  base_dn            = "ou=people,dc=example,dc=org"
  group_base_dn      = "ou=groups,dc=example,dc=org"
  bind_dn            = "cn=reader,dc=example,dc=org"
  bind_password_file = "etc/authnd/reader.pw"
}

user "svc-backup" { password_file = "etc/authnd/svc-backup.pw" }
$ authnd check front2
ldap://127.0.0.1:3894, base dc=example,dc=net

USER        FROM                    CAN PROVE         PUBLISHED AS        WITH
alice       ldap://127.0.0.1:3893   a password check  account, uidObject  uid
bob         ldap://127.0.0.1:3893   a password check  account, uidObject  uid
dora        ldap://127.0.0.1:3893   a password check  account, uidObject  uid
eli         ldap://127.0.0.1:3893   a password check  account, uidObject  uid
svc-backup  the configuration file  a password        account, uidObject  uid

GROUP      MEMBERS              PUBLISHED AS
engineers  dora and eli         groupOfNames
staff      alice, bob and dora  groupOfNames

alice has no uidNumber, gidNumber or homeDirectory: not a posixAccount, published as account, uidObject
bob has no uidNumber, gidNumber or homeDirectory: not a posixAccount, published as account, uidObject
dora has no uidNumber, gidNumber or homeDirectory: not a posixAccount, published as account, uidObject
eli has no uidNumber, gidNumber or homeDirectory: not a posixAccount, published as account, uidObject
svc-backup has no uidNumber, gidNumber or homeDirectory: not a posixAccount, published as account, uidObject
group engineers has no gidNumber: not a posixGroup, published as a groupOfNames (member DNs, no memberUid)
group staff has no gidNumber: not a posixGroup, published as a groupOfNames (member DNs, no memberUid)

a bind carries a password
no reader is declared: nothing may search, and binds are not affected
sambaNTPassword is not published, so nothing here can authenticate an SMB session (NTLMv2 needs the password or its MD4, and a bind cannot answer it)

this configuration can be served

Cada persona que publica el directorio de detrás es un account y cada grupo un groupOfNames, ya que ninguno tiene atributos POSIX: los valores por defecto los leen, y los DN en member de los grupos corresponden a las personas importadas. Con los valores por defecto de hasta la v0.10.2, (objectClass=posixAccount) no habría encontrado a ninguna de ellas.

A password check basta para un bind, y nunca basta para un ticket Kerberos ni para SMB.

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 queda con él. Los bloques user siempre van primero, de modo que una cuenta de servicio escrita localmente no la anula alguien con el mismo nombre en la base de datos. La pertenencia a grupos es la unión de todos los orígenes: un grupo que nombran a la vez un bloque group y la consulta groups de una base de datos tiene los miembros de ambos.

Dos nombres que solo difieren en mayúsculas y minúsculas se rechazan

Un uid se compara sin distinguir mayúsculas de minúsculas (RFC 4519 §2.39), y lo mismo ocurre con cada DN, así que Dora en el archivo y dora en una base de datos son un solo nombre para LDAP y dos personas para todo lo que compara bytes: un cambio de contraseña de una acabaría en la otra. Una configuración así no arranca:

$ authnd check cases/case.hcl
authnd: "Dora" (from the configuration file) and "dora" (from a sqlite database) differ only by case, and an LDAP name does not tell them apart: a uid is compared ignoring case. Rename one of them

Se leen una vez

Cada origen se lee una vez, al arrancar. Una persona añadida a la base de datos, o una pertenencia modificada en el directorio que hay detrás de este, se sirve tras un reinicio, no antes. Eso incluye una columna de contraseña en una base de datos: se lee con el resto de la fila. Un directorio detrás de este solo se diferencia en que un bind se comprueba haciendo un bind contra él, así que la contraseña que funciona es la cambiada allí. La otra excepción es una contraseña que una persona cambia a través del propio authnd, que se aplica al instante. No hay recarga; consulte ejecutarlo.

Creada el por tannevaled

Modificada el por tannevaled