36. Seguridad en PostgreSQL

PostgreSQL tiene un sistema de permisos rico y flexible, con la capacidad de asignar privilegios particulares a roles específicos, y otorgar a los usuarios los poderes de uno o más de esos roles.

Además, el servidor de PostgreSQL puede usar múltiples sistemas diferentes para autenticar usuarios. Esto significa que la base de datos puede utilizar la misma infraestructura de autenticación que otros componentes de la arquitectura, simplificando la gestión de contraseñas.

36.1. Usuarios y Roles

En este capítulo crearemos dos usuarios de producción útiles:

  • Un usuario de solo lectura para usar en una aplicación de publicación.

  • Un usuario de lectura/escritura para usar por un desarrollador en la construcción de un software o análisis de datos.

En lugar de crear usuarios y otorgarles los poderes necesarios, crearemos dos roles con los privilegios adecuados y luego crearemos dos usuarios y los agregaremos a los roles apropiados. De esa manera podremos reutilizar fácilmente los roles cuando creemos más usuarios.

36.1.1. Creación de Roles

Un rol es un usuario y un usuario es un rol. La única diferencia es que un «usuario» puede considerarse un rol con el privilegio de «login».

Así que, funcionalmente, las dos sentencias SQL siguientes son iguales: ambas crean un «rol con el privilegio de login», es decir, un «usuario».

CREATE ROLE mrbean LOGIN;
CREATE USER mrbean;

36.1.2. Usuarios de Solo Lectura

Nuestro usuario de solo lectura será para que una aplicación web consulte la tabla nyc_streets.

La aplicación tendrá acceso específico a la tabla nyc_streets, pero heredará el acceso necesario al sistema para operaciones PostGIS desde el rol postgis_reader.

-- A user account for the web app
CREATE USER app1;
-- Web app needs access to specific data tables
GRANT SELECT ON nyc_streets TO app1;

-- A generic role for access to PostGIS functionality
CREATE ROLE postgis_reader INHERIT;
-- Give that role to the web app
GRANT postgis_reader TO app1;

Ahora, cuando iniciamos sesión como app1, podemos seleccionar filas de la tabla nyc_streets. Sin embargo, ¡no podemos ejecutar una llamada a ST_Transform! ¿Por qué no?

-- This works!
SELECT * FROM nyc_streets LIMIT 1;

-- This doesn't work!
SELECT ST_AsText(ST_Transform(geom, 4326))
  FROM nyc_streets LIMIT 1;
ERROR:  permission denied for relation spatial_ref_sys
CONTEXT:  SQL statement "SELECT proj4text FROM spatial_ref_sys WHERE srid = 4326 LIMIT 1"

La respuesta está en la declaración de error. Aunque nuestro usuario app1 puede ver el contenido de la tabla nyc_streets sin problemas, no puede ver el contenido de spatial_ref_sys, por lo que la llamada a ST_Transform falla.

Por lo tanto, también necesitamos otorgar al rol postgis_reader acceso de lectura a todas las tablas de metadatos de PostGIS:

GRANT SELECT ON geometry_columns TO postgis_reader;
GRANT SELECT ON geography_columns TO postgis_reader;
GRANT SELECT ON spatial_ref_sys TO postgis_reader;

Ahora tenemos un rol genérico postgis_reader que podemos aplicar a cualquier usuario que necesite leer tablas PostGIS.

-- This works now!
SELECT ST_AsText(ST_Transform(geom, 4326))
  FROM nyc_streets LIMIT 1;

36.1.3. Usuarios de Lectura/Escritura

Existen dos tipos de escenarios de lectura/escritura que debemos considerar:

  • Aplicaciones web y otras que necesitan escribir en tablas de datos existentes.

  • Desarrolladores o analistas que necesitan crear nuevas tablas y columnas de geometría como parte de su trabajo.

Para aplicaciones web que requieren acceso de escritura a tablas de datos, solo necesitamos otorgar permisos adicionales a las propias tablas, y podemos seguir utilizando el rol postgis_reader.

-- Add insert/update/delete abilities to our web application
GRANT INSERT,UPDATE,DELETE ON nyc_streets TO app1;

Este tipo de permisos serían necesarios, por ejemplo, para un servicio WFS de lectura/escritura.

Para desarrolladores y analistas, se necesita un poco más de acceso a las tablas principales de metadatos de PostGIS. Necesitaremos un rol postgis_writer que pueda editar las tablas de metadatos de PostGIS!

-- Make a postgis writer role
CREATE ROLE postgis_writer;

-- Start by giving it the postgis_reader powers
GRANT postgis_reader TO postgis_writer;

-- Add insert/update/delete powers for the PostGIS tables
GRANT INSERT,UPDATE,DELETE ON spatial_ref_sys TO postgis_writer;

-- Make app1 a PostGIS writer to see if it works!
GRANT postgis_writer TO app1;

Ahora intenta la creación de tablas en SQL anterior con el usuario app1 y observa qué sucede!

36.2. Cifrado

PostgreSQL proporciona muchas facilidades de cifrado, muchas de ellas opcionales, algunas activadas de manera predeterminada.

  • De manera predeterminada, todas las contraseñas están cifradas con MD5. El intercambio cliente/servidor cifra doblemente la contraseña MD5 para evitar la reutilización del hash por cualquiera que intercepte la contraseña.

  • Las conexiones SSL están disponibles opcionalmente entre el cliente y el servidor, para cifrar todos los datos e información de inicio de sesión. La autenticación con certificados SSL también está disponible cuando se usan conexiones SSL.

  • Dentro de la base de datos, las columnas pueden cifrarse utilizando el módulo pgcrypto, que incluye algoritmos de hash, cifrados directos (blowfish, aes) y cifrado PGP tanto de clave pública como simétrica.

36.2.1. Conexiones SSL

Para usar conexiones SSL, tanto el cliente como el servidor deben soportar SSL.

  • Primero, apaga PostgreSQL, ya que activar SSL requerirá un reinicio.

  • Luego, adquirimos o generamos un certificado y una clave SSL. El certificado no debe tener frase de paso, o el servidor de base de datos no podrá arrancar. Puedes generar una clave autofirmada de la siguiente forma:

    # Create a new certificate, filling out the certification info as prompted
    openssl req -new -text -out server.req
    
    # Strip the passphrase from the certificate
    openssl rsa -in privkey.pem -out server.key
    
    # Convert the certificate into a self-signed cert
    openssl req -x509 -in server.req -text -key server.key -out server.crt
    
    # Set the permission of the key to private read/write
    chmod og-rwx server.key
    
  • Copia los archivos server.crt y server.key en el directorio de datos de PostgreSQL.

  • Habilita el soporte SSL en el archivo postgresql.conf cambiando el parámetro «ssl» a «on».

  • Ahora reinicia PostgreSQL; el servidor está listo para operar con SSL.

Con el servidor habilitado para SSL, crear una conexión cifrada es fácil. En PgAdmin, crea una nueva conexión de servidor (File > Add Server…), y establece el parámetro SSL en “require”.

_images/ssl_create.jpg

Una vez que te conectes, podrás ver en sus propiedades que está usando una conexión SSL.

_images/ssl_props.jpg

Dado que el modo de conexión SSL predeterminado es «prefer», ni siquiera necesitas especificar una preferencia SSL al conectarte. Una conexión con la terminal de línea de comandos psql tomará la opción SSL y la usará de manera predeterminada:

psql (8.4.9)
SSL connection (cipher: DHE-RSA-AES256-SHA, bits: 256)
Type "help" for help.

postgres=#

Observa cómo la terminal informa el estado SSL de la conexión.

36.2.2. Cifrado de Datos

El módulo pgcrypto tiene una enorme variedad de opciones de cifrado, por lo que solo demostraremos el caso de uso más simple: cifrar una columna de datos usando un cifrado simétrico.

  • Primero, habilita pgcrypto cargando el archivo SQL de contrib, ya sea en PgAdmin o en psql.

    pgsql/8.4/share/postgresql/contrib/pgcrypto.sql
    
  • Luego, prueba la función de cifrado.

    -- encrypt a string using blowfish (bf)
    SELECT encrypt('this is a test phrase', 'mykey', 'bf');
    
  • Y asegúrate de que también sea reversible!

    -- round-trip a string using blowfish (bf)
    SELECT decrypt(encrypt('this is a test phrase', 'mykey', 'bf'), 'mykey', 'bf');
    

36.3. Identificación

PostgreSQL soporta muchos métodos de autenticación diferentes, para permitir una fácil integración en arquitecturas empresariales existentes. Para fines de producción, los siguientes métodos son comúnmente usados:

  • Password es el sistema básico donde las contraseñas son almacenadas por la base de datos, con cifrado MD5.

  • Kerberos es un método estándar de autenticación empresarial, utilizado tanto por los esquemas GSSAPI como SSPI en PostgreSQL. Usando SSPI, PostgreSQL puede autenticarse contra servidores Windows.

  • LDAP es otro método común de autenticación empresarial. El servidor OpenLDAP incluido en la mayoría de las distribuciones Linux proporciona una implementación de código abierto de LDAP.

  • La autenticación por certificado es una opción si esperas que todas las conexiones de cliente sean vía SSL y puedes gestionar la distribución de las claves.

  • La autenticación PAM es una opción si estás en Linux o Solaris y usas el esquema PAM para provisión de autenticación transparente.

Los métodos de autenticación se controlan con el archivo pg_hba.conf. El «HBA» en el nombre del archivo significa «host based access», porque además de permitir especificar el método de autenticación para cada base de datos, también permite limitar el acceso por host utilizando direcciones de red.

Aquí un ejemplo de archivo pg_hba.conf:

# TYPE  DATABASE    USER        CIDR-ADDRESS          METHOD

# "local" is for Unix domain socket connections only
local   all         all                               trust
# IPv4 local connections:
host    all         all         127.0.0.1/32          trust
# IPv6 local connections:
host    all         all         ::1/128               trust
# remote connections for nyc database only
host    nyc         all         192.168.1.0/2         ldap

El archivo consta de cinco columnas

  • TYPE determina el tipo de acceso, ya sea «local» para conexiones desde el mismo servidor o «host» para conexiones remotas.

  • DATABASE especifica a qué base de datos se refiere la línea de configuración o «all» para todas las bases de datos

  • USER especifica a qué usuarios se refiere la línea o «all» para todos los usuarios

  • CIDR-ADDRESS especifica las limitaciones de red para conexiones remotas, usando la sintaxis network/netmask

  • METHOD especifica el protocolo de autenticación a usar. «trust» omite completamente la autenticación y simplemente acepta cualquier nombre de usuario válido sin verificación.

Es común que se confíe de las conexiones locales, ya que el acceso al propio servidor suele ser privilegiado. Las conexiones remotas están deshabilitadas de manera predeterminada cuando se instala PostgreSQL: si deseas conectarte desde máquinas remotas, tendrás que añadir una entrada.

La línea para nyc en el ejemplo anterior es un ejemplo de entrada de acceso remoto. El ejemplo nyc permite acceso autenticado vía LDAP solo a máquinas en la red local (en este caso la red 192.168.1.) y solo a la base de datos nyc. Dependiendo de la seguridad de tu red, usarás versiones más o menos estrictas de estas reglas en tu configuración de producción.