DKIM en Postfix con GNU/Linux Debian

0

Introducción

DKIM (Domain Key Identified Email) es un mecanismo de seguridad que permite la autenticación de mensajes de correo electrónico, descrito en el RFC-5585 disponible en http://www.dkim.org/specs/rfc5585.html.

El mecanismo DKIM consiste en utilizar una infraestructura de claves públicas (certificados) y privadas para en principio firmar y posteriomente autenticar un mensaje de correo electrónico.

Los certificados están asociados a dominio (@example.com) o para direcciones de correo electrónico específicas (*@example.com, me@example.com).

Los mensajes salientes son firmados por el emisor, tomando un conjunto de encabezados (headers) aplicando un algoritmo hash con una clave privada para generar una encabezado (DKIM-Signature) que se añade al mensaje.

Los mensajes entrantes son verificados si contienen un encabezado de firma donde se especifica que clave pública consultar vía DNS para realizar la verificación.

Instalación y configuración de Debian para uso con Postfix

Para empezar suponemos que tenemos instalado y configurado en un servidor el servicio Postfix para el dominio “example.com”, en ese mismo servidor se configurará el servicio DKIM aunque esto no es obligatorio.

Instalar el paquete dkim-filter:

1
apt-get install dkim-filter

Si no se han generado las claves publicas y privadas, se debe generar una clave de prueba (test) que sirve para depurar y omitir error sin rechazar los correo electrónico, y una clave para producción (“default” en nuestro caso, aunque pueden generarse cuantas sean necesarias).

Primero creamos una carpeta que contendrá las claves públicas y privadas de nuestro dominio “example.com”:

1
2
mkdir -p /etc/dkim/keys/example.com
cd /etc/dkim/keys/example.com

Gereramos la clave de prueba y de producción respectivamente:

1
2
dkim-genkey -d example.com -r -s test -t
dkim-genkey -d example.com -r

El parametro -s indica que la clave de prueba será nominada con el selector “test” y la clave de producción como se especificó será nominada con el selector “default”.

Las claves públicas y privadas generadas en el directorio:

1
2
3
4
5
6
$ ls -l 
total 16
-rw------- 1 root root 887 Sep 21  2011 default.private
-rw------- 1 root root 308 Sep 21  2011 default.txt
-rw------- 1 root root 887 Sep 21  2011 test.private
-rw------- 1 root root 307 Sep 21  2011 test.txt

Se almacenan con la extensión “.private” mientras que los registros DNS en formato para bind9 se almacenan en los archivos “.txt” con el siguiente formato:

v=DKIM1; g=*; k=rsa; p=

Para publicar los certificados se deben crear dos (2) registros DNS tipo TXT para los nombres de servidores siguientes:

  1. El nombre “test._domainkey” del dominio “example.com” con el contenido del
    archivo “test.private”.
  2. El nombre “default._domainkey” del dominio “example.com” con el contenido
    del archivo “default.private”.

Una vez creado los registros DNS anteriores, la consulta DNS (usando el comando nslookup) para los nombres “default._domainkey” y “test._domainkey” del dominio “example.com” debe arrojar los siguientes resultados:

1
2
3
4
5
6
7
8
9
$ nslookup -type=txt test._domainkey.tsj-dem.gob.ve 200.44.32.12
Server:  200.44.32.12
Address: 200.44.32.12#53
test._domainkey.tsj-dem.gob.ve text = "v=DKIM1\; g=*\; k=rsa\; t=y\; p=<clave>"
 
$ nslookup -type=txt default._domainkey.tsj-dem.gob.ve 200.44.32.12
Server:  200.44.32.12
Address: 200.44.32.12#53
default._domainkey.tsj-dem.gob.ve text = "v=DKIM1\; g=*\; k=rsa\; p=<clave>"

Es importante indicar que la expresión es sensible a mayúsculas y minúsculas tanto en el archivo como en la consulta DNS el resultado debe ser el mismo.

Pero para garantizar que los selectores funcionen correctamente deben eliminarse la extensión “.private” o crear link simbólicos porque los nombres contentivos de la clave pública deben ser iguales a los nombres de los selectores:

1
2
3
4
5
6
7
8
$ ls -l 
total 16
lrwxrwxrwx 1 root root  15 Apr  9 16:32 default -> default.private
-rw------- 1 root root 887 Sep 21  2011 default.private
-rw------- 1 root root 308 Sep 21  2011 default.txt
lrwxrwxrwx 1 root root  12 Apr  9 16:32 test -> test.private
-rw------- 1 root root 887 Sep 21  2011 test.private
-rw------- 1 root root 307 Sep 21  2011 test.txt

En el archivo de configuración del servicio DKIM en la ruta /etc/dkim-keys.conf:

*@example.com:example.com:/etc/dkim/keys/example.com/test

En el archivo principal de configuración del servicio DKIM /etc/dkim-filter.conf:

Syslog yes
X-Header yes
LogWhy yes
#On-BadSignature accept
#On-DNSError accept
#On-InternalError accept
#On-NoSignature accept
#On-Security accept
On-Default accept

En Debian es modificar el archivo /etc/default/dkim-filter:

SOCKET=”inet:8891@localhost”

Finalmente, activamos el servicio DKIM:

1
/etc/init.d/dkim start

Verificar los registros:

1
/var/log/syslog | grep -i dkim

Para indicarle a Postfix que debe firmar los correos simplemente colocamos
en el archivo configuración /etc/postfix/main.cf:

# Firma Electrónica – DKIM
milter_default_action = accept
# Postfix ≥ 2.6
milter_protocol = 6
# 2.3 ≤ Postfix ≤ 2.5
#milter_protocol = 2
smtpd_milters = inet:localhost:8891
non_smtpd_milters = inet:localhost:8891

Ahora debemos reiniciar Postfix y realizar algunas pruebas:

  • Enviar un correo a GMAIL y verificar los encabezados DKIM-Signature y Authentication-Result.
  • Seguir las instrucciones del siguiente asisten de verificación de correo electrónico: http://www.brandonchecketts.com/emailtest.php

Para entender mejor el funcionamiento y procedimiento descritos sobre DKIM a continuación consulte y utilice los recursos siguientes:

- Página Principal del Proyecto DKIM (www.dkim.org)
- Fork del Proyecto DKIM (www.opendkim.org)
- http://www.dkim.org/specs/rfc5585.html
- http://www.debiantutorials.com/setup-domainkeys-identified-mail-dkim-in-postfix/
- http://staff.blog.ui.ac.id/jp/2009/04/07/creating-dkim-on-debian-50/
- http://www.brandonchecketts.com/emailtest.php

Enviar correo electrónico desde PostgreSQL con PERL

0

Para poder enviar correos desde PostgreSQL en GNU/Linux existe una forma sencilla de hacerlo, un script PERL disponible dentro del manejador de base de datos a través de una función.

Requerimientos

  • Todo esto ha sido probado en GNU/Linux Debian Squeeze 6.0
  • Instalar el módulo de PERL “Mail::Sender”: apt-get install libmail-sender-perl
  • Instalar “PLPERL” apt-get install postgresql-plperl-8.3. Para mayor información visite: http://www.postgresql.org/docs/8.3/static/plperl.html
  • Un servidor de correos local (opcional si tenemos otro servidor) instalado y configurado (por defecto): sendmail, exim4 o postfix.

Manos a la obra

Debemos cargar el contenido del archivo pgmail.sql y pgmailt.sql que se muestan debajo, para crear la función de envío de correo y hacer pruebas, respectivamente.

1
2
3
root# su - postgres
postgres$ psql < pgmail.sql 
postgres$ psql < pgmailt.sql

Creación de la función “pgmail”

El archivo pgmail.sql contiene lo siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
\c A;
-- CREATE LANGUAGE plperlu;
CREATE OR REPLACE FUNCTION pgmail(text, text, text, text) RETURNS INTEGER AS $$
 
$from_address = $_[0];
$to_address = $_[1];
$subject = $_[2];
$body = $_[3];
 
#$reply_to = 'no-reply@localhost.localdomain';
$server = 'localhost';
 
use Mail::Sender;
$sender = new Mail::Sender
	{
		smtp => $server, 
		from => $from_address
	};
$rc = $sender->MailMsg(
	{
	#	replyto => $reply_to,
		to => $to_address,
		subject => $subject,
		msg => $body
	}
);
 
if(ref($rc)){
        return 0;
}else{
	elog(ERROR, $sender->{'error_msg'});
	return $sender->{'error'};
}
 
$$ LANGUAGE plperlu VOLATILE STRICT;

Prueba de “pgmail”

El archivo pgmailt.sql contiene lo siguiente:

1
2
\c A;
select pgmail('me@localhost.localdomain', 'olafrv@gmail.com,olafrv@cantv.net','Mail desde postgres', 'Test!!!');

Recuperación de base de datos MySQL

0

I.- MOTORES DE BASE DE DATOS

Los dos (2) motores de base de datos MySQL más usados para almacenar datos en tablas son MyISAM e InnoDB. El primero MyISAM, a diferencia de InnoDB no permite almacenamiento transaccional (conforme a ACID) con capacidades de commit (confirmación), rollback (cancelación) y recuperación de fallas, por eso más estable que InnoDB que es mucho más sensible a corrupciones de datos.

Los motores de base de datos activos pueden visualizarse con el comando:

1
mysql> show engines;

II.- ARCHIVOS BASES DE DATOS

En su mayoría los archivos de bases de datos se almacenan en archivos con el nombre de la tabla en una subcarpeta con el nombre de la base datos. Sin embargo, dependiendo del motor de base de datos esto varia como se describe a continuación:

Por cada tabla tipo MyISAM existe un archivo .frm con su estructura, un archivo de datos .MYD (MYData) y un archivo de índice .MYI (MYIndex).

El motor de almacenamiento InnoDB gestiona en cada instancia del servidor de MySQL archivos de datos de espacios de tablas (tablespaces) y archivos de registro (log). Para cada tabla tipo InnoDB existe un archivo .frm registrado en el diccionario de datos de InnoDB (no en el global de la instancia de MySQL), por esta razón no se pueden mover tablas entre bases de datos sencillamente moviendo los ficheros .frm.

Adicionalmente, a menos que la configuración por defecto de InnoDB sea modificada, MySQL crea un archivo de datos (autoextensible) llamado ibdata1 y dos archivos de registro (log) llamados ib_logfile0 y ib_logfile1 que son compartidos por todas las tablas InnoDB de una instancia MySQL. Es posible agregar la opción innodb_file_per_table en la configuración para indicar a MySQL que la información de las tablas InnoDB se almacenen en su propio archivo de datos .IBD.

III.- REPARACIÓN DE BASES DE DATOS

III.A.- SERVIDOR MYSQL EN LÍNEA

Antes de realizar cualquier labor de mantenimiento se deben detener los sistemas que se conectan al servidor de base de datos, o bien, reportar el servidor caído denegando las conexiones.

La manera más fácil de lograrlo es bloqueando las conexiones IP de la red local (Interfaz eth0) en el servidor MySQL utilizando iptables, dependiendo del número de instancias (3306, 3307, 3308) y del número de interfaces los comandos serían los siguientes:

1
2
3
iptables -I INPUT -i eth0 -p tcp -m multiport --dports 3306 -j REJECT
iptables -I INPUT -i eth0 -p tcp -m multiport --dports 3306,3307 -j REJECT
iptables -I INPUT -i eth0 -p tcp -m multiport --dports 3306:3308 -j REJECT

Para desactivar el bloqueo cambiamos “iptables -I INPUT” por “iptables -D INPUT” en los comandos anterior y para ver el listado de las reglas debloqueo activas ejecute “iptables -S”.

Es importante destacar que solo se pueden reparar bases de datos en una instancia de MySQL que se esté ejecutando (en línea).

Un servidor muestra en el log de error los siguientes mensajes cuando se detiene e inicia correctamente:

120301 16:37:11 [Note] /usr/sbin/mysqld: Normal shutdown
120301 16:37:11 [Note] Event Scheduler: Purging the queue. 0 events
120301 16:37:13 InnoDB: Starting shutdown…
120301 16:37:14 InnoDB: Shutdown completed; log sequence number 0 44233
120301 16:37:14 [Note] /usr/sbin/mysqld: Shutdown complete

120301 16:37:24 [Note] Plugin ‘FEDERATED’ is disabled.
120301 16:37:24 InnoDB: Started; log sequence number 0 44233
120301 16:37:24 [Note] Event Scheduler: Loaded 0 events
120301 16:37:24 [Note] /usr/sbin/mysqld: ready for connections.
Version: ’5.1.49-3′ socket: ‘/var/run/mysqld/mysqld002.sock’ port: 3307 (Debian)

Si el servidor MySQL no se está ejecutando entonces continúe en la sección “SERVIDOR DE MYSQL DETENIDO”.

El comando para realizar la reparación es “mysqlrepair” que tiene una sintaxis similar a “mysql”, algunos ejemplos son:

1
2
3
mysqlrepair -u root -p <base-de-datos>
mysqlrepair --socket=/var/run/mysqld/mysqld.sock -u root -p <base-de-datos>
mysqlrepair --protocol=tcp --port=3306 -h 127.0.0.1 -u root -p <base-de-datos>

NOTA: La ruta del socket, la dirección ip, el puerto o el protocolo pueden varias dependiendo del número y ubicación de las instancias del servidor MySQL.

Si una base de datos no pudo ser reparada se debe eliminar y restaurar partiendo un respaldo (dump) previamente hecho con el comando mysqldump, ejecutando el siguiente comando:

1
mysql --protocol=tcp --port=3306 -u root -p mibasededatos < midump.sql

Si no tiene un respaldo entonces la información se habrá perdido definitivamente.

III.B.- SERVIDOR DE MYSQL DETENIDO

Si el servidor MySQL no se está ejecutando debemos determinar la causa inspeccionando el log de error del servidor.

Si no está configurado debe activarlo colocando en el archivo de configuración my.cf:

[mysqld]
log-error = /var/log/mysql/mysql.err.log

Si se determina que el servidor no inicia debido a problemas con InnoDB (90% de las veces) entonces se debe proceder como describe a continuación, por el contrario, si el problema es con otro motor de almacenamiento lo más recomendable es restaurar la tabla o base de datos afectada desde cero.

Algunos mensajes que indican problemas con InnoDB son los siguientes:

InnoDB: Page directory corruption: infimum not pointed to

InnoDB: Page directory corruption: supremum not pointed to

InnoDB: Probable reason is database corruption or memory
InnoDB: corruption. If this happens in an InnoDB database recovery, see
InnoDB: http://dev.mysql.com/doc/refman/5.1/en/forcing-recovery.html
InnoDB: how to force recovery.

InnoDB: We intentionally generate a memory trap.
InnoDB: Submit a detailed bug report to http://bugs.mysql.com.
InnoDB: If you get repeated assertion failures or crashes, even
InnoDB: immediately after the mysqld startup, there may be
InnoDB: corruption in the InnoDB tablespace. Please refer to
InnoDB: http://dev.mysql.com/doc/refman/5.1/en/forcing-recovery.html
InnoDB: about forcing recovery.

Una vez confirmada que la causa está relacionada con InnoDB, debemos intentar que MySQL aplique sus propios mecanismos de recuperación, probando cada uno hasta que logremos iniciar el servidor e intentar rescatar los datos existentes o iniciar la reparación de de las bases de datos. En estos modos de recuperación sólo se pueden ejecutar instrucciones SELECT en caso de que el servidor inicie.

Los mecanismos de recuperación se establecen colocando en el archivo de configuración my.cf lo siguiente:

[mysqld]
# 1 (SRV_FORCE_IGNORE_CORRUPT)
# 2 (SRV_FORCE_NO_BACKGROUND)
# 3 (SRV_FORCE_NO_TRX_UNDO)
# 4 (SRV_FORCE_NO_IBUF_MERGE)
# 5 (SRV_FORCE_NO_UNDO_LOG_SCAN)
# 6 (SRV_FORCE_NO_LOG_REDO)
innodb_force_recovery = 1

Cada vez que intentemos iniciar el servidor al principio del log general o de error aparecerá un mensaje similar al siguiente:

InnoDB: The user has set SRV_FORCE_NO_LOG_REDO on
InnoDB: Skipping log redo

NOTA: Para mayor información sobre los valores innodb_force_recovery de visite 15.8.1. Forzar una recuperación.

El servidor iniciará pero deberá verificarse que inicie de forma limpia (sin errores) como se describe en la sección “SERVIDOR MYSQL EN LÍNEA”.

Si el servidor no inicia entonces debemos deshabilitar el motor de almacenamiento InnoDB colocando en el archivo de configuración my.cf:

[mysqld]
skip-innodb

Si el servidor tampoco inicia entonces debemos descartar el uso del parámetro “skip-innodb”.

No hay otra opción sino dar por perdidos los datos InnoDB de una o varias base de datos y debemos proceder como sigue:

- Detener el servidor MySQL y desactivar “skip-innodb”.
- Hacer un respaldo de los archivos ibdata* a ibdata*.bak
- Hacer un respaldo de los archivos ib_logfile* a ib_logfile*.bak
- Iniciar el servidor.

Si el servidor inicia correctamente entonces tratamos de reparar las bases de datos, de lo contrario hemos llegado al peor caso debemos restaurar todas las bases de datos desde, o bien, reinstalar la(s) instancia(s) afectada(s) del servidor de MySQL.

IV.- REFERENCIAS

Tomadas del Manual de Referencia de MySQL:

Go to Top
?>