sepgsql es un módulo cargable que admite el control de acceso
obligatorio (MAC) basado en etiquetas y según la política de seguridad de
SELinux.
La implementación actual tiene limitaciones significativas y no aplica el control de acceso obligatorio para todas las acciones. Consulta Section F.40.7.
Este módulo se integra con SELinux para proporcionar una capa adicional de comprobación de seguridad más allá de lo que normalmente ofrece PostgreSQL. Desde la perspectiva de SELinux, este módulo permite que PostgreSQL funcione como un gestor de objetos en el espacio de usuario. Cada acceso a una tabla o función iniciado por una consulta DML se comprobará contra la política de seguridad del sistema. Esta comprobación es adicional a la habitual comprobación de permisos SQL que realiza PostgreSQL.
Las decisiones de control de acceso de SELinux se toman utilizando
etiquetas de seguridad, representadas por cadenas como
system_u:object_r:sepgsql_table_t:s0. Cada decisión de control de acceso
implica dos etiquetas: la etiqueta del sujeto que intenta realizar la acción y la etiqueta
del objeto sobre el cual se va a realizar la operación. Dado que estas etiquetas se pueden aplicar
a cualquier tipo de objeto, las decisiones de control de acceso para los objetos almacenados
dentro de la base de datos se pueden someter (y, con este módulo, se someten) a los mismos criterios
generales que se utilizan para objetos de cualquier otro tipo, como los archivos. Este diseño está
pensado para permitir que una política de seguridad centralizada proteja los activos de información
independientemente de las particularidades de cómo se almacenan dichos activos.
La sentencia SECURITY LABEL permite asignar
una etiqueta de seguridad a un objeto de la base de datos.
sepgsql solo se puede utilizar en Linux
2.6.28 o superior con SELinux habilitado.
No está disponible en ninguna otra plataforma. También necesitarás
libselinux 2.1.10 o superior y
selinux-policy 3.9.13 o superior (aunque algunas
distribuciones pueden portar las reglas necesarias a versiones de política más antiguas).
El comando sestatus te permite comprobar el estado de
SELinux. Una visualización típica es:
$ sestatus SELinux status: enabled SELinuxfs mount: /selinux Current mode: enforcing Mode from config file: enforcing Policy version: 24 Policy from config file: targeted
Si SELinux está deshabilitado o no está instalado, debes configurar ese producto primero antes de instalar este módulo.
Para compilar este módulo, especifica --with-selinux
(cuando utilices make y autoconf) o
-Dselinux={ auto | enabled | disabled } (cuando utilices meson).
Asegúrate de que el RPM libselinux-devel esté instalado en el momento
de la compilación.
Para usar este módulo, debes incluir sepgsql en el parámetro
shared_preload_libraries en postgresql.conf. El módulo
no funcionará correctamente si se carga de cualquier otra manera. Una vez cargado el módulo,
debes ejecutar sepgsql.sql en cada base de datos. Esto instalará las funciones
necesarias para la gestión de etiquetas de seguridad y asignará las etiquetas de seguridad iniciales.
Aquí tienes un ejemplo que muestra cómo inicializar un clúster de bases de datos nuevo con las
funciones de sepgsql y las etiquetas de seguridad instaladas. Ajusta las
rutas que se muestran según corresponda para tu instalación:
$ export PGDATA=/ruta/al/directorio/de/datos
$ initdb
$ vi $PGDATA/postgresql.conf
cambia
#shared_preload_libraries = '' # (el cambio requiere reiniciar)
a
shared_preload_libraries = 'sepgsql' # (el cambio requiere reiniciar)
$ for DBNAME in template0 template1 postgres; do
postgres --single -F -c exit_on_error=true $DBNAME \
< /usr/local/pgsql/share/contrib/sepgsql.sql >/dev/null
done
Ten en cuenta que puedes ver algunas o todas las siguientes notificaciones dependiendo de las versiones particulares que tengas de libselinux y selinux-policy:
/etc/selinux/targeted/contexts/sepgsql_contexts: line 33 has invalid object type db_blobs /etc/selinux/targeted/contexts/sepgsql_contexts: line 36 has invalid object type db_language /etc/selinux/targeted/contexts/sepgsql_contexts: line 37 has invalid object type db_language /etc/selinux/targeted/contexts/sepgsql_contexts: line 38 has invalid object type db_language /etc/selinux/targeted/contexts/sepgsql_contexts: line 39 has invalid object type db_language /etc/selinux/targeted/contexts/sepgsql_contexts: line 40 has invalid object type db_language
Estos mensajes son inofensivos y deben ignorarse.
Si el proceso de instalación se completa sin errores, ahora puedes iniciar el servidor normalmente.
El conjunto de pruebas de sepgsql se ejecuta si
PG_TEST_EXTRA contiene sepgsql (consulta
Section 31.1.3). Este método es adecuado durante el desarrollo
de PostgreSQL. Alternativamente, existe una forma de ejecutar
las pruebas para comprobar si una instancia de base de datos se ha configurado correctamente
para sepgsql.
Debido a la naturaleza de SELinux, la ejecución de las pruebas de
regresión para sepgsql requiere varios pasos de configuración adicionales,
algunos de los cuales deben realizarse como root.
Las pruebas manuales deben ejecutarse en el directorio contrib/sepgsql de
un árbol de compilación configurado de PostgreSQL. Aunque requieren un árbol de compilación, las
pruebas están diseñadas para ejecutarse contra un servidor instalado, es decir, son comparables a
make installcheck, no a make check.
Primero, configura sepgsql en una base de datos en funcionamiento de acuerdo
con las instrucciones en Section F.40.2. Ten en cuenta que el usuario
actual del sistema operativo debe poder conectarse a la base de datos como superusuario sin
autenticación de contraseña.
Segundo, compila e instala el paquete de políticas para la prueba de regresión. La política
sepgsql-regtest es un paquete de políticas de propósito especial que proporciona
un conjunto de reglas que se permitirán durante las pruebas de regresión. Debe compilarse a partir del
archivo de origen de políticas sepgsql-regtest.te, lo cual se hace utilizando
make con un Makefile proporcionado por SELinux. Necesitarás localizar el Makefile
adecuado en tu sistema; la ruta que se muestra a continuación es solo un ejemplo. (Este Makefile suele
ser suministrado por el RPM selinux-policy-devel o
selinux-policy). Una vez compilado, instala este paquete de políticas utilizando
el comando semodule, el cual carga los paquetes de políticas suministrados en el núcleo.
Si el paquete se instala correctamente, debería listar
semodule -lsepgsql-regtest como un paquete de políticas disponible:
$ cd .../contrib/sepgsql $ make -f /usr/share/selinux/devel/Makefile $ sudo semodule -u sepgsql-regtest.pp $ sudo semodule -l | grep sepgsql sepgsql-regtest 1.07
Tercero, activa sepgsql_regression_test_mode. Por razones de seguridad, las reglas en
sepgsql-regtest no están habilitadas por defecto; el parámetro
sepgsql_regression_test_mode habilita las reglas necesarias para lanzar las pruebas
de regresión. Se puede activar mediante el comando setsebool:
$ sudo setsebool sepgsql_regression_test_mode on $ getsebool sepgsql_regression_test_mode sepgsql_regression_test_mode --> on
Cuarto, verifica que tu shell esté funcionando en el dominio unconfined_t:
$ id -Z unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
Consulta Section F.40.8 para obtener detalles sobre cómo ajustar tu dominio de trabajo, si es necesario.
Finalmente, ejecuta el script de pruebas de regresión:
$ ./test_sepgsql
Este script intentará verificar que has realizado todos los pasos de configuración correctamente y,
a continuación, ejecutará las pruebas de regresión para el módulo sepgsql.
Después de completar las pruebas, se recomienda desactivar el parámetro
sepgsql_regression_test_mode:
$ sudo setsebool sepgsql_regression_test_mode off
Es posible que prefieras eliminar por completo la política sepgsql-regtest:
$ sudo semodule -r sepgsql-regtest
sepgsql.permissive (boolean)
#
Este parámetro permite que sepgsql funcione en modo permisivo,
independientemente de la configuración del sistema. El valor predeterminado es off.
Este parámetro solo se puede establecer en el archivo postgresql.conf
o en la línea de comandos del servidor.
Cuando este parámetro está activado, sepgsql funciona en modo
permisivo, incluso si SELinux en general está funcionando en modo enforcing. Este parámetro
es útil principalmente para fines de prueba.
sepgsql.debug_audit (boolean)
#Este parámetro permite la impresión de mensajes de auditoría independientemente de la configuración de la política del sistema. El valor predeterminado es off, lo que significa que los mensajes se imprimirán de acuerdo con la configuración del sistema.
La política de seguridad de SELinux también tiene reglas para controlar si se registran o no accesos particulares. Por defecto, las violaciones de acceso se registran, pero los accesos permitidos no.
Este parámetro fuerza la activación de todos los registros posibles, independientemente de la política del sistema.
El modelo de seguridad de SELinux describe todas las reglas de control de
acceso como relaciones entre una entidad sujeto (normalmente, un cliente de la base de datos) y una
entidad objeto (como un objeto de la base de datos), cada una de las cuales se identifica mediante una
etiqueta de seguridad. Si se intenta acceder a un objeto no etiquetado, el objeto se trata como si tuviera
asignada la etiqueta unlabeled_t.
Actualmente, sepgsql permite asignar etiquetas de seguridad a esquemas, tablas,
columnas, secuencias, vistas y funciones. Cuando sepgsql está en uso, las etiquetas
de seguridad se asignan automáticamente a los objetos de base de datos admitidos en el momento de su creación.
Esta etiqueta se denomina etiqueta de seguridad predeterminada y se decide de acuerdo con la política de
seguridad del sistema, la cual toma como entrada la etiqueta del creador, la etiqueta asignada al objeto
padre del nuevo objeto y, opcionalmente, el nombre del objeto construido.
Un nuevo objeto de base de datos básicamente hereda la etiqueta de seguridad del objeto padre, excepto cuando la política de seguridad tiene reglas especiales conocidas como reglas de transición de tipo (type-transition), en cuyo caso se puede aplicar una etiqueta diferente. Para los esquemas, el objeto padre es la base de datos actual; para las tablas, secuencias, vistas y funciones, es el esquema contenedor; para las columnas, es la tabla contenedora.
Para las tablas, se comprueba db_table:select, db_table:insert,
db_table:update o db_table:delete para todas las tablas de destino
referenciadas, según el tipo de sentencia; además, también se comprueba db_table:select
para todas las tablas que contienen columnas referenciadas en la cláusula WHERE o
RETURNING, como origen de datos para UPDATE, etc.
También se comprobarán los permisos a nivel de columna para cada columna referenciada.
db_column:select se comprueba no solo en las columnas que se están leyendo mediante
SELECT, sino en aquellas que se referencian en otras sentencias DML; también se comprobará
db_column:update o db_column:insert para las columnas que están siendo
modificadas por UPDATE o INSERT.
Por ejemplo, considera:
UPDATE t1 SET x = 2, y = func1(y) WHERE z = 100;
Aquí, se comprobará db_column:update para t1.x porque se está actualizando,
se comprobará db_column:{select update} para t1.y porque se actualiza y se
referencia a la vez, y se comprobará db_column:select para t1.z porque solo
se referencia. También se comprobará db_table:{select update} a nivel de tabla.
Para las secuencias, se comprueba db_sequence:get_value cuando hacemos referencia a un objeto
de secuencia mediante SELECT; sin embargo, ten en cuenta que actualmente no comprobamos los
permisos en la ejecución de las funciones correspondientes como lastval().
Para las vistas, se comprobará db_view:expand, y luego se comprobarán otros permisos necesarios en
los objetos que se expanden a partir de la vista, individualmente.
Para las funciones, se comprobará db_procedure:{execute} cuando el usuario intente ejecutar una
función como parte de una consulta o mediante una invocación de acceso rápido (fast-path). Si esta función es un
procedimiento de confianza, también se comprueba el permiso db_procedure:{entrypoint} para
verificar si puede actuar como punto de entrada del procedimiento de confianza.
Para acceder a cualquier objeto de esquema, se requiere el permiso db_schema:search en el esquema
contenedor. Cuando se hace referencia a un objeto sin calificación de esquema, no se buscará en los esquemas en los
que este permiso no esté presente (al igual que si el usuario no tuviera el privilegio USAGE en el
esquema). Si hay una calificación de esquema explícita, se producirá un error si el usuario no tiene el permiso necesario
en el esquema especificado.
El cliente debe tener permiso para acceder a todas las tablas y columnas referenciadas, incluso si proceden de vistas que luego se expandieron, de modo que apliquemos reglas de control de acceso coherentes independientemente de la forma en que se haga referencia a los contenidos de la tabla.
El sistema de privilegios de base de datos predeterminado permite a los superusuarios de la base de datos modificar
los catálogos del sistema mediante comandos DML y referenciar o modificar tablas toast. Estas operaciones están
prohibidas cuando sepgsql está habilitado.
SELinux define varios permisos para controlar las operaciones comunes de cada tipo de objeto, como la creación, alteración, eliminación y reetiquetado de la etiqueta de seguridad. Además, varios tipos de objetos tienen permisos especiales para controlar sus operaciones características, como la adición o eliminación de entradas de nombre dentro de un esquema particular.
La creación de un nuevo objeto de base de datos requiere el permiso create.
SELinux concederá o denegará este permiso basándose en la etiqueta de seguridad del cliente y
en la etiqueta de seguridad propuesta para el nuevo objeto. En algunos casos, se requieren privilegios adicionales:
CREATE DATABASE requiere adicionalmente el permiso
getattr para la base de datos de origen o plantilla.
La creación de un objeto de esquema requiere adicionalmente el permiso add_name en el esquema padre.
La creación de una tabla requiere adicionalmente permiso para crear cada columna de tabla individual, de la misma manera que si cada columna de tabla fuera un objeto independiente de nivel superior.
La creación de una función marcada como LEAKPROOF requiere adicionalmente el permiso
install. (Este permiso también se comprueba cuando se establece LEAKPROOF para
una función existente).
Cuando se ejecuta el comando DROP, se comprobará drop en el objeto que se está eliminando.
También se comprobarán los permisos para los objetos eliminados indirectamente a través de CASCADE. La
eliminación de objetos contenidos dentro de un esquema particular (tablas, vistas, secuencias y procedimientos) requiere
adicionalmente el permiso remove_name en el esquema.
Cuando se ejecuta el comando ALTER, se comprobará setattr en el objeto que se está
modificando para cada tipo de objeto, excepto para los objetos subsidiarios como los índices o disparadores (triggers)
de una tabla, donde los permisos se comprueban en su lugar en el objeto padre. En algunos casos, se requieren permisos adicionales:
Mover un objeto a un nuevo esquema requiere adicionalmente el permiso remove_name en el esquema antiguo
y el permiso add_name en el nuevo.
Establecer el atributo LEAKPROOF en una función requiere el permiso install.
El uso de SECURITY LABEL en un objeto requiere adicionalmente
el permiso relabelfrom para el objeto en conjunción con su antigua etiqueta de seguridad y el permiso
relabelto para el objeto en conjunción con su nueva etiqueta de seguridad. (En los casos en que se instalan
múltiples proveedores de etiquetas y el usuario intenta establecer una etiqueta de seguridad pero esta no es gestionada por
SELinux, solo debería comprobarse setattr aquí. Esto no se hace actualmente debido a
restricciones de la implementación).
Los procedimientos de confianza son similares a las funciones definidoras de seguridad (security definer) o a los comandos setuid. SELinux proporciona una característica que permite que el código de confianza se ejecute utilizando una etiqueta de seguridad diferente a la del cliente, generalmente con el fin de proporcionar un acceso altamente controlado a datos sensibles (por ejemplo, se pueden omitir filas o se puede reducir la precisión de los valores almacenados). El hecho de que una función actúe o no como un procedimiento de confianza está controlado por su etiqueta de seguridad y por la política de seguridad del sistema operativo. Por ejemplo:
postgres=# CREATE TABLE customer (
cid int primary key,
cname text,
credit text
);
CREATE TABLE
postgres=# SECURITY LABEL ON COLUMN customer.credit
IS 'system_u:object_r:sepgsql_secret_table_t:s0';
SECURITY LABEL
postgres=# CREATE FUNCTION show_credit(int) RETURNS text
AS 'SELECT regexp_replace(credit, ''-[0-9]+$'', ''-xxxx'', ''g'')
FROM customer WHERE cid = $1'
LANGUAGE sql;
CREATE FUNCTION
postgres=# SECURITY LABEL ON FUNCTION show_credit(int)
IS 'system_u:object_r:sepgsql_trusted_proc_exec_t:s0';
SECURITY LABEL
Las operaciones anteriores deben ser realizadas por un usuario administrador.
postgres=# SELECT * FROM customer; ERROR: SELinux: security policy violation postgres=# SELECT cid, cname, show_credit(cid) FROM customer; cid | cname | show_credit -----+--------+--------------------- 1 | taro | 1111-2222-3333-xxxx 2 | hanako | 5555-6666-7777-xxxx (2 rows)
En este caso, un usuario normal no puede hacer referencia a customer.credit directamente, pero un
procedimiento de confianza show_credit le permite imprimir los números de tarjeta de crédito de los
clientes con algunos de los dígitos enmascarados.
Es posible utilizar la característica de transición dinámica de dominio de SELinux para cambiar la etiqueta de seguridad
del proceso del cliente (el dominio del cliente) a un nuevo contexto, si la política de seguridad lo permite. El dominio
del cliente necesita el permiso setcurrent y también dyntransition del dominio antiguo
al nuevo.
Las transiciones dinámicas de dominio deben considerarse con cuidado, porque permiten a los usuarios cambiar su etiqueta,
y por tanto sus privilegios, a su elección, en lugar de hacerlo según lo dispuesto por el sistema (como en el caso de un
procedimiento de confianza). Por lo tanto, el permiso dyntransition solo se considera seguro cuando se
utiliza para cambiar a un dominio con un conjunto de privilegios menor que el original. Por ejemplo:
regression=# select sepgsql_getcon();
sepgsql_getcon
-------------------------------------------------------
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
(1 row)
regression=# SELECT sepgsql_setcon('unconfined_u:unconfined_r:unconfined_t:s0-s0:c1.c4');
sepgsql_setcon
----------------
t
(1 row)
regression=# SELECT sepgsql_setcon('unconfined_u:unconfined_r:unconfined_t:s0-s0:c1.c1023');
ERROR: SELinux: security policy violation
En este ejemplo anterior, se nos permitió cambiar del rango MCS más grande c1.c1023 al rango más
pequeño c1.c4, pero se denegó el cambio de regreso.
Una combinación de transición dinámica de dominio y procedimiento de confianza permite un caso de uso interesante que
se adapta al ciclo de vida típico de los procesos del software de pool de conexiones (connection pooling). Aunque su
software de pool de conexiones no tenga permiso para ejecutar la mayoría de los comandos SQL, puede permitirle cambiar
la etiqueta de seguridad del cliente mediante la función sepgsql_setcon() desde dentro de un procedimiento
de confianza; eso debería requerir alguna credencial para autorizar la solicitud de cambio de la etiqueta del cliente.
Después de eso, esta sesión tendrá los privilegios del usuario de destino, en lugar del gestor del pool de conexiones. El
gestor del pool de conexiones puede revertir más tarde el cambio de etiqueta de seguridad utilizando de nuevo
sepgsql_setcon() con un argumento NULL, invocado de nuevo desde un procedimiento de
confianza con las comprobaciones de permisos adecuadas. El punto clave aquí es que solo el procedimiento de confianza tiene
realmente permiso para cambiar la etiqueta de seguridad efectiva, y solo lo hace cuando se le proporcionan las credenciales
adecuadas. Por supuesto, para un funcionamiento seguro, el almacén de credenciales (tabla, definición de procedimiento, o
lo que sea) debe protegerse contra accesos no autorizados.
El Table F.32 muestra las funciones disponibles.
Table F.32. Funciones de Sepgsql
Función Descripción |
|---|
Devuelve el dominio del cliente, que es la etiqueta de seguridad actual del cliente. |
Cambia el dominio del cliente de la sesión actual al nuevo dominio, si la política de seguridad lo permite. También
acepta una entrada |
Traduce el rango MLS/MCS calificado dado al formato bruto (raw) si el demonio mcstrans se está ejecutando. |
Traduce el rango MLS/MCS bruto dado al formato calificado si el demonio mcstrans se está ejecutando. |
Configura las etiquetas de seguridad iniciales para todos los objetos dentro de la base de datos actual. El argumento
puede ser |
Debido a restricciones de la implementación, algunas operaciones DDL no comprueban los permisos.
Debido a restricciones de la implementación, las operaciones DCL no comprueban los permisos.
PostgreSQL admite el acceso a nivel de fila, pero sepgsql no lo hace.
sepgsql no intenta ocultar la existencia de un determinado objeto, incluso si el usuario no tiene
permitido referenciarlo. Por ejemplo, podemos inferir la existencia de un objeto invisible como resultado de conflictos de
claves primarias, violaciones de claves extranjeras, etc., incluso si no podemos obtener los contenidos del objeto. La
existencia de una tabla de alto secreto no se puede ocultar; solo esperamos ocultar su contenido.
Esta página de la wiki ofrece una breve descripción general, el diseño de seguridad, la arquitectura, la administración y las próximas características.
Este documento proporciona un amplio espectro de conocimientos para administrar SELinux en tus sistemas. Se centra principalmente en los sistemas operativos Red Hat, pero no se limita a ellos.
Este documento responde a las preguntas más frecuentes sobre SELinux. Se centra principalmente en Fedora, pero no se limita a Fedora.
KaiGai Kohei <[email protected]>