jueves, 30 de septiembre de 2010

Introducción al uso de ZFS en Solaris

Desde que hizo su aparición Solaris 10, se presentó con un gran número de avances con respecto a sus versiones anteriores, por ejemplo: el DTrace, la virtualización por medio de contenedores, la sustitución del rc por svc, etc. En esta ocasión vamos a mostrar como trabajar con una de estas nuevas características: el ZFS.

El ZFS es un nuevo tipo de filesystem, combina una serie de tecnologías de almacenamiento en una forma automatizada y simple, solo basta crear un pool de datos y crear en este filesystems, los cuales son montados en forma automática sin necesidad de darlos de alta en la tabla de montaje (/etc/vfstab).

Para este ejercicio, voy a utilizar un equipo con Solaris 10 x86 instalado y un disco duro nuevo sin utilizar.

Recordemos que en la plataforma x86 es necesario inicializar todos los discos duros nuevos:

fdisk /dev/rdsk/c1t1d0p0
No fdisk table exists. The default partition for the disk is:

  a 100% "SOLARIS System" partition

Type "y" to accept the default partition,  otherwise type "n" to edit the
partition table.
y

Ahora vamos a crear una partición nueva que ocupe todo el espacio disponible:

format
Searching for disks...done

AVAILABLE DISK SELECTIONS:
       0. c1t0d0 <DEFAULT cyl 2607 alt 2 hd 255 sec 63>
          /pci@0,0/pci15ad,1976@10/sd@0,0
       1. c1t1d0 <DEFAULT cyl 2607 alt 2 hd 255 sec 63>
          /pci@0,0/pci15ad,1976@10/sd@1,0
Specify disk (enter its number): 1
selecting c1t1d0
[disk formatted]

FORMAT MENU:
        disk       - select a disk
        type       - select (define) a disk type
        partition  - select (define) a partition table
        current    - describe the current disk
        format     - format and analyze the disk
        fdisk      - run the fdisk program
        repair     - repair a defective sector
        label      - write label to the disk
        analyze    - surface analysis
        defect     - defect list management
        backup     - search for backup labels
        verify     - read and display labels
        save       - save new disk/partition definitions
        inquiry    - show vendor, product and revision
        volname    - set 8-character volume name
        !<cmd>     - execute <cmd>, then return
        quit
format> p

PARTITION MENU:
        0      - change `0' partition
        1      - change `1' partition
        2      - change `2' partition
        3      - change `3' partition
        4      - change `4' partition
        5      - change `5' partition
        6      - change `6' partition
        7      - change `7' partition
        select - select a predefined table
        modify - modify a predefined partition table
        name   - name the current table
        print  - display the current table
        label  - write partition map and label to the disk
        !<cmd> - execute <cmd>, then return
        quit
partition>
p
Current partition table (original):
Total disk cylinders available: 2607 + 2 (reserved cylinders)

Part      Tag    Flag     Cylinders        Size            Blocks
  0 unassigned    wm       0               0         (0/0/0)           0
  1 unassigned    wm       0               0         (0/0/0)           0
  2     backup    wu       0 - 2606       19.97GB    (2607/0/0) 41881455
  3 unassigned    wm       0               0         (0/0/0)           0
  4 unassigned    wm       0               0         (0/0/0)           0
  5 unassigned    wm       0               0         (0/0/0)           0
  6 unassigned    wm       0               0         (0/0/0)           0
  7 unassigned    wm       0               0         (0/0/0)           0
  8       boot    wu       0 -    0        7.84MB    (1/0/0)       16065
  9 unassigned    wm       0               0         (0/0/0)           0

partition> 0
Part      Tag    Flag     Cylinders        Size            Blocks
  0 unassigned    wm       0               0         (0/0/0)           0

Enter partition id tag[unassigned]:
Enter partition permission flags[wm]:
Enter new starting cyl[0]: 1
Enter partition size[0b, 0c, 1e, 0.00mb, 0.00gb]: 2606e
partition>
p
Current partition table (unnamed):
Total disk cylinders available: 2607 + 2 (reserved cylinders)

Part      Tag    Flag     Cylinders        Size            Blocks
  0 unassigned    wm       1 - 2606       19.96GB    (2606/0/0) 41865390
  1 unassigned    wm       0               0         (0/0/0)           0
  2     backup    wu       0 - 2606       19.97GB    (2607/0/0) 41881455
  3 unassigned    wm       0               0         (0/0/0)           0
  4 unassigned    wm       0               0         (0/0/0)           0
  5 unassigned    wm       0               0         (0/0/0)           0
  6 unassigned    wm       0               0         (0/0/0)           0
  7 unassigned    wm       0               0         (0/0/0)           0
  8       boot    wu       0 -    0        7.84MB    (1/0/0)       16065
  9 unassigned    wm       0               0         (0/0/0)           0

partition> label
Ready to label disk, continue? y

partition>

Ahora que nuestro disco esta listo para trabajar, vamos a crear un pool de datos:

zpool create pool1 c1t1d0s0

Y ya estamos listos para crear filesystems, suponiendo que necesite uno que se monte en la ruta /tomcat, por ejemplo:

zfs create -o mountpoint=/tomcat pool1/tomcat

Con este comando estamos indicando que creé el nuevo filesystem “tomcat” utilizando el pool de datos llamado “pool1”, adicionalmente, le estamos indicando que utilice como punto de montaje la ruta /tomcat, si nosotros no indicamos un punto de montaje, en este caso lo hubiera montado por default en /pool1/tomcat. Ahora, vamos a utilizar el comando df para revisar como están nuestros filesystem:

df -h
Filesystem             size   used  avail capacity  Mounted on
/dev/dsk/c1t0d0s0      2.9G   464M   2.4G    16%    /
/devices                 0K     0K     0K     0%    /devices
ctfs                     0K     0K     0K     0%    /system/contract
proc                     0K     0K     0K     0%    /proc
mnttab                   0K     0K     0K     0%    /etc/mnttab
swap                   2.5G   940K   2.5G     1%    /etc/svc/volatile
objfs                    0K     0K     0K     0%    /system/object
sharefs                  0K     0K     0K     0%    /etc/dfs/sharetab
/dev/dsk/c1t0d0s4      5.8G   2.9G   2.8G    51%    /usr
/usr/lib/libc/libc_hwcap1.so.1
                       5.8G   2.9G   2.8G    51%    /lib/libc.so.1
fd                       0K     0K     0K     0%    /dev/fd
/dev/dsk/c1t0d0s3      2.9G    73M   2.8G     3%    /var
swap                   2.5G    40K   2.5G     1%    /tmp
swap                   2.5G    24K   2.5G     1%    /var/run
/dev/dsk/c1t0d0s6      2.9G   484M   2.4G    17%    /opt
/dev/dsk/c1t0d0s5      2.9G   3.0M   2.9G     1%    /export/home
pool1                   20G    21K    20G     1%    /pool1
pool1/tomcat            20G    21K    20G     1%    /tomcat

Observen que aparecen 2 nuevos filesystem pool1 y pool1/tomcat, pool1 representa al filesystem “raíz” del pool, sobre el se crean el resto de los ZFS.

Vamos a ver qué ocurre si creo otro filesystem:

zfs create -o mountpoint=/postgresql pool1/postgresql
df -h
Filesystem             size   used  avail capacity  Mounted on
/dev/dsk/c1t0d0s0      2.9G   464M   2.4G    16%    /
/devices                 0K     0K     0K     0%    /devices
ctfs                     0K     0K     0K     0%    /system/contract
proc                     0K     0K     0K     0%    /proc
mnttab                   0K     0K     0K     0%    /etc/mnttab
swap                   2.5G   940K   2.5G     1%    /etc/svc/volatile
objfs                    0K     0K     0K     0%    /system/object
sharefs                  0K     0K     0K     0%    /etc/dfs/sharetab
/dev/dsk/c1t0d0s4      5.8G   2.9G   2.8G    51%    /usr
/usr/lib/libc/libc_hwcap1.so.1
                       5.8G   2.9G   2.8G    51%    /lib/libc.so.1
fd                       0K     0K     0K     0%    /dev/fd
/dev/dsk/c1t0d0s3      2.9G    73M   2.8G     3%    /var
swap                   2.5G    40K   2.5G     1%    /tmp
swap                   2.5G    24K   2.5G     1%    /var/run
/dev/dsk/c1t0d0s6      2.9G   484M   2.4G    17%    /opt
/dev/dsk/c1t0d0s5      2.9G   3.0M   2.9G     1%    /export/home
pool1                   20G    21K    20G     1%    /pool1
pool1/tomcat            20G    21K    20G     1%    /tomcat
pool1/postgresql        20G    21K    20G     1%    /postgresql

Como podrán notar, todos los ZFS de este pool aparecen con el mismo número de espacio disponible (20Gb), esto es porque todos los ZFS de un mismo pool comparten el espacio disponible en el pool de datos, aunque cada uno de ellos mantiene su información independiente con respectos a los demás ZFS, es decir, los datos entre cada filesystem permanecen separados y conforme van aumentando del tamaño el pool les asigna más espacio.

Con esto se reduce la necesidad de reasignar espacios, lo cuál es un problema clásico en la administración de cualquier servidor: si mantengo la información en un solo filesystem se complica la administración del sistema operativo ya que una actualización implica modificar todo, si separo los filesystem, corro el riesgo de que alguno crezca mas allá de lo estimado y deba reorganizarlos.

Otro aspecto es que no tuve la necesidad de utilizar el mkfs para crear el filesystem, ni tampoco tuve que montarlo con el comando mount, todo esto se realizó de forma automática.

Si reiniciamos el servidor, podremos observar que los zfs se montan automáticamente y no tuvimos que darlos de “alta” en la tabla de montaje.

En siguientes entregas voy a explicar como migrar de un esquema de booteo UFS normal a uno ZFS y como hacer el mirroring.

miércoles, 29 de septiembre de 2010

Disk mirroring en Solaris

El disk mirroring o copia en espejo consiste en proteger la información contenida en un disco manteniendo una copia idéntica en otro disco. A esto también se le conoce como un arreglo RAID 1.

Una de las ventajas mas fuertes de Solaris es que, a partir de la versión 8, es posible crear diferentes tipos de arreglos sin necesidad de adquirir software adicional para esto, esto se logra mediante una aplicación anteriormente llamada Solstice DiskSuite y ahora Solaris Volume Manager (SVM).

El SVM permite crear volúmenes concatenados (concat) y distribuidos (data striping), también permite “espejearlos” (mirror) e incluso el fragmentarlos (soft partition).

Para este tutorial, voy a utilizar un equipo con 2 discos scsi de 20Gb iguales, al cual, le instalé Solaris 10 en el disco 0, dejando un slice libre y suficiente espacio para la metadatabase (esto es un espacio que requiere el SVM para operar), el tamaño del espacio es muy pequeño, yo he trabajado con slices de 50 Mb perfectamente. El disco 1 lo deje vacío.

Por medio de los comando df y swap reviso qué particiones se están utilizando como filesystem y como swap:

df -h
Filesystem             size   used  avail capacity  Mounted on
/dev/dsk/c1t0d0s0      2.9G   450M   2.4G    16%    /
/devices                 0K     0K     0K     0%    /devices
ctfs                     0K     0K     0K     0%    /system/contract
proc                     0K     0K     0K     0%    /proc
mnttab                   0K     0K     0K     0%    /etc/mnttab
swap                   2.4G   512K   2.4G     1%    /etc/svc/volatile
objfs                    0K     0K     0K     0%    /system/object
sharefs                  0K     0K     0K     0%    /etc/dfs/sharetab
/dev/dsk/c1t0d0s4      5.8G   2.9G   2.8G    51%    /usr
/usr/lib/libc/libc_hwcap1.so.1
                       5.8G   2.9G   2.8G    51%    /lib/libc.so.1
fd                       0K     0K     0K     0%    /dev/fd
/dev/dsk/c1t0d0s3      2.9G    73M   2.8G     3%    /var
swap                   2.4G   136K   2.4G     1%    /tmp
swap                   2.4G    28K   2.4G     1%    /var/run
/dev/dsk/c1t0d0s6      2.9G   484M   2.4G    17%    /opt
/dev/dsk/c1t0d0s5      2.9G   3.0M   2.9G     1%    /export/home

swap -l
swapfile             dev  swaplo blocks   free
/dev/dsk/c1t0d0s1   32,1       8 4209016 4209016

Podemos observar que estamos utilizando 6 slices del disco c1t0d0.

Para la metadatabase es muy recomendable tener por cada disco, un slice dedicado para este fin, de tal forma que si uno de los discos se daña, siempre podremos contar con otras copias en otros discos. Por lo que procedo a crear una partición nueva con el slice que dejé libre. Utilizo el comando format

format
Searching for disks...done

AVAILABLE DISK SELECTIONS:
       0. c1t0d0 <DEFAULT cyl 2607 alt 2 hd 255 sec 63>
          /pci@0,0/pci15ad,1976@10/sd@0,0
       1. c1t1d0 <DEFAULT cyl 2608 alt 2 hd 255 sec 63>
          /pci@0,0/pci15ad,1976@10/sd@1,0
Specify disk (enter its number):
0
selecting c1t0d0
[disk formatted]
Warning: Current Disk has mounted partitions.
/dev/dsk/c1t0d0s0 is currently mounted on /. Please see umount(1M).
/dev/dsk/c1t0d0s1 is currently used by swap. Please see swap(1M).
/dev/dsk/c1t0d0s3 is currently mounted on /var. Please see umount(1M).
/dev/dsk/c1t0d0s4 is currently mounted on /usr. Please see umount(1M).
/dev/dsk/c1t0d0s5 is currently mounted on /export/home. Please see umount(1M).
/dev/dsk/c1t0d0s6 is currently mounted on /opt. Please see umount(1M).

FORMAT MENU:
        disk       - select a disk
        type       - select (define) a disk type
        partition  - select (define) a partition table
        current    - describe the current disk
        format     - format and analyze the disk
        fdisk      - run the fdisk program
        repair     - repair a defective sector
        label      - write label to the disk
        analyze    - surface analysis
        defect     - defect list management
        backup     - search for backup labels
        verify     - read and display labels
        save       - save new disk/partition definitions
        inquiry    - show vendor, product and revision
        volname    - set 8-character volume name
        !<cmd>     - execute <cmd>, then return
        quit
format> p

PARTITION MENU:
        0      - change `0' partition
        1      - change `1' partition
        2      - change `2' partition
        3      - change `3' partition
        4      - change `4' partition
        5      - change `5' partition
        6      - change `6' partition
        7      - change `7' partition
        select - select a predefined table
        modify - modify a predefined partition table
        name   - name the current table
        print  - display the current table
        label  - write partition map and label to the disk
        !<cmd> - execute <cmd>, then return
        quit
partition>
p
Current partition table (original):
Total disk cylinders available: 2607 + 2 (reserved cylinders)

Part      Tag    Flag     Cylinders        Size            Blocks
  0       root    wm       1 -  390        2.99GB    (390/0/0)   6265350
  1       swap    wu     391 -  652        2.01GB    (262/0/0)   4209030
  2     backup    wm       0 - 2606       19.97GB    (2607/0/0) 41881455
  3        var    wm     653 - 1042        2.99GB    (390/0/0)   6265350
  4        usr    wm    1043 - 1807        5.86GB    (765/0/0)  12289725
  5       home    wm    1808 - 2197        2.99GB    (390/0/0)   6265350
  6 unassigned    wm    2198 - 2587        2.99GB    (390/0/0)   6265350
  7 unassigned    wm       0               0         (0/0/0)           0
  8       boot    wu       0 -    0        7.84MB    (1/0/0)       16065
  9 unassigned    wm       0               0         (0/0/0)           0

partition>

Le indico que trabaje con el disco 0, me hace la advertencia de que tiene particiones que se encuentran montadas, le indico que trabajaremos con particiones y que muestre la tabla de partición, observamos que el slice 7 aparece sin espacio asignado y que el último ocupa hasta el cilindro 2587, por lo que tenemos desde el 2588 hasta el 2606 libres, procedemos entonces a crear la partición:

partition> 7
Part      Tag    Flag     Cylinders        Size            Blocks
  7 unassigned    wm       0               0         (0/0/0)           0

Enter partition id tag[unassigned]:
Enter partition permission flags[wm]:
Enter new starting cyl[0]:
2588
Enter partition size[0b, 0c, 2588e, 0.00mb, 0.00gb]: 2606e
partition>
p
Current partition table (unnamed):
Total disk cylinders available: 2607 + 2 (reserved cylinders)

Part      Tag    Flag     Cylinders        Size            Blocks
  0       root    wm       1 -  390        2.99GB    (390/0/0)   6265350
  1       swap    wu     391 -  652        2.01GB    (262/0/0)   4209030
  2     backup    wm       0 - 2606       19.97GB    (2607/0/0) 41881455
  3        var    wm     653 - 1042        2.99GB    (390/0/0)   6265350
  4        usr    wm    1043 - 1807        5.86GB    (765/0/0)  12289725
  5       home    wm    1808 - 2197        2.99GB    (390/0/0)   6265350
  6 unassigned    wm    2198 - 2587        2.99GB    (390/0/0)   6265350
  7 unassigned    wm    2588 - 2606      149.04MB    (19/0/0)     305235
  8       boot    wu       0 -    0        7.84MB    (1/0/0)       16065
  9 unassigned    wm       0               0         (0/0/0)           0

partition> label
Ready to label disk, continue? y

partition>

Con esto ya esta listo el disco 0, ahora vamos a preparar al disco 1, como en este caso estoy utilizando Solaris en x86, necesito inicializar el disco 1 con fdisk:

fdisk /dev/rdsk/c1t1d0p0
No fdisk table exists. The default partition for the disk is:

  a 100% "SOLARIS System" partition

Type "y" to accept the default partition,  otherwise type "n" to edit the
partition table.
y

Noten que el dispositivo que indique para que inicializara el disco c1t1d0 es el c1t1d0p0, esto es porque la plataforma x86 permite particionar los discos hasta en 4 particiones principales, a estas particiones Solaris las representa con p1 a p4 y p0 representa a todo el disco duro, por condición, la plataforma x86 requiere que exista por lo menos 1 partición en el disco duro, con el comando fdisk lo que hicimos fue crear esta partición (la p1) con el 100% del espacio disponible en el disco.

Una vez concluido esto vamos a copiar el VTOC del disco 0 en el disco 1, podemos hacerlo a mano con el format, pero en este caso los 2 discos son iguales, por lo que vamos a hacerlo con un atajo:

prtvtoc /dev/rdsk/c1t0d0s2 | fmthard -s - /dev/rdsk/c1t1d0s2
fmthard:  New volume table of contents now in place.

Este atajo también es válido en SPARC.

Cómo último paso para la preparación de este disco, necesitamos configurarlo como “booteable” ya que va a contener los archivos de sistema operativo, para Solaris10 x86 debemos hacer 2 pasos utilizando el comando fdisk y el installgrub:

fdisk -b /usr/lib/fs/ufs/mboot /dev/rdsk/c1t1d0p0

             Total disk size is 2610 cylinders
             Cylinder size is 16065 (512 byte) blocks

                                               Cylinders
      Partition   Status    Type          Start   End   Length    %
      =========   ======    ============  =====   ===   ======   ===
          1       Active    Solaris2          1  2609    2609    100

SELECT ONE OF THE FOLLOWING:
   1. Create a partition
   2. Specify the active partition
   3. Delete a partition
   4. Change between Solaris and Solaris2 Partition IDs
   5. Exit (update disk configuration and exit)
   6. Cancel (exit without updating disk configuration)
Enter Selection: 5

installgrub /boot/grub/stage1 /boot/grub/stage2 /dev/rdsk/c1t1d0s0
stage1 written to partition 0 sector 0 (abs 16065)
stage2 written to partition 0, 272 sectors starting at 50 (abs 16115)

En el caso de la plataforma SPARC se utiliza el comando installboot:

installboot /usr/platform/`uname -i`/lib/fs/ufs/bootblk /dev/rdsk/c1t0d0s0

Ya que nuestros discos están listos procedemos con el SVM, iniciamos creando la metadatabase:

metadb -a -f -c 4 c1t0d0s7 c1t1d0s7

Con esto estamos creando a la metadatabase en las particiones c1t0d0s7 y c1t1d0s7 con 4 copias en cada una, nótese que no requerimos indicar el path completo de los dispositivos.

Ahora vamos a crear un volumen para cada partición del disco 0 en las que tenemos filesystem y swap.

metainit -f d10 1 1 c1t0d0s0
d10: Concat/Stripe is setup
metainit -f d11 1 1 c1t0d0s1
d11: Concat/Stripe is setup
metainit -f d13 1 1 c1t0d0s3
d13: Concat/Stripe is setup
metainit -f d14 1 1 c1t0d0s4
d14: Concat/Stripe is setup
metainit -f d15 1 1 c1t0d0s5
d15: Concat/Stripe is setup
metainit -f d16 1 1 c1t0d0s6
d16: Concat/Stripe is setup

Después creamos los volúmenes espejo, para esto, debemos indicar para cada espejo cuál es el volumen primario, es decir, el que contiene la información que debemos duplicar:

metainit d0 -m d10
d0: Mirror is setup
metainit d1 -m d11
d1: Mirror is setup
metainit d3 -m d13
d3: Mirror is setup
metainit d4 -m d14
d4: Mirror is setup
metainit d5 -m d15
d5: Mirror is setup
metainit d6 -m d16
d6: Mirror is setup

Nota: Hasta aquí, podríamos indicarle que agregue los volúmenes secundarios a los espejos, sin embargo, yo no recomiendo hacerlo en este momento, debido a que debemos reiniciar el sistema operativo para que monte los filesystem utilizando los volúmenes en espejo en lugar de las particiones físicas, si por error reinicio sistema sin que los volúmenes estén sincronizados, nos va a dar un errores de consistencia, por lo que mi recomendación es dejar la sincronización como último paso.

Ahora, vamos a modificar el sistema para que inicie el sistema operativo montando los espejos, por lo que vamos a indicar primero que volumen contiene el filesystem raíz:

metaroot d0

Este comando modifica todos los archivos de configuración necesarios para que monte el volumen d0 como raíz (/), ahora debemos indicar en forma manual el resto de los volúmenes en el archivo /etc/vfstab, al editarlo, lo primero que vamos a observar es que ahora tiene indicado /dev/md/dsk/d0 como /, modificamos los demás sustituyendo a cada partición con el volumen que corresponda. Mi archivo antes de la modificación se encuentra así:

#device         device          mount           FS      fsck    mount   mount
#to mount       to fsck         point           type    pass    at boot options
#
fd      -       /dev/fd fd      -       no      -
/proc   -       /proc   proc    -       no      -
/dev/dsk/c1t0d0s1       -       -       swap    -       no      -
/dev/md/dsk/d0  /dev/md/rdsk/d0 /       ufs     1       no      -
/dev/dsk/c1t0d0s4       /dev/rdsk/c1t0d0s4      /usr    ufs     1       no      -
/dev/dsk/c1t0d0s3       /dev/rdsk/c1t0d0s3      /var    ufs     1       no      -
/dev/dsk/c1t0d0s5       /dev/rdsk/c1t0d0s5      /export/home    ufs     2       yes     -
/dev/dsk/c1t0d0s6       /dev/rdsk/c1t0d0s6      /opt    ufs     2       yes     -
/devices        -       /devices        devfs   -       no      -
sharefs -       /etc/dfs/sharetab       sharefs -       no      -
ctfs    -       /system/contract        ctfs    -       no      -
objfs   -       /system/object  objfs   -       no      -
swap    -       /tmp    tmpfs   -       yes     -

Después de modificar queda así:

#device         device          mount           FS      fsck    mount   mount
#to mount       to fsck         point           type    pass    at boot options
#
fd      -       /dev/fd fd      -       no      -
/proc   -       /proc   proc    -       no      -
/dev/md/dsk/d1  -       -       swap    -       no      -
/dev/md/dsk/d0  /dev/md/rdsk/d0 /       ufs     1       no      -
/dev/md/dsk/d4  /dev/md/rdsk/d4 /usr    ufs     1       no      -
/dev/md/dsk/d3  /dev/md/rdsk/d3 /var    ufs     1       no      -
/dev/md/dsk/d5  /dev/md/rdsk/d5 /export/home    ufs     2       yes     -
/dev/md/dsk/d6  /dev/md/rdsk/d6 /opt    ufs     2       yes     -
/devices        -       /devices        devfs   -       no      -
sharefs -       /etc/dfs/sharetab       sharefs -       no      -
ctfs    -       /system/contract        ctfs    -       no      -
objfs   -       /system/object  objfs   -       no      -
swap    -       /tmp    tmpfs   -       yes     -

Reiniciamos sistema operativo y ahora podemos ver que están montados los espejos en lugar de las particiones físicas:

df -h
Filesystem             size   used  avail capacity  Mounted on
/dev/md/dsk/d0         2.9G   453M   2.4G    16%    /
/devices                 0K     0K     0K     0%    /devices
ctfs                     0K     0K     0K     0%    /system/contract
proc                     0K     0K     0K     0%    /proc
mnttab                   0K     0K     0K     0%    /etc/mnttab
swap                   2.5G   948K   2.5G     1%    /etc/svc/volatile
objfs                    0K     0K     0K     0%    /system/object
sharefs                  0K     0K     0K     0%    /etc/dfs/sharetab
/dev/md/dsk/d4         5.8G   2.9G   2.8G    51%    /usr
/usr/lib/libc/libc_hwcap1.so.1
                       5.8G   2.9G   2.8G    51%    /lib/libc.so.1
fd                       0K     0K     0K     0%    /dev/fd
/dev/md/dsk/d3         2.9G    73M   2.8G     3%    /var
swap                   2.5G    40K   2.5G     1%    /tmp
swap                   2.5G    24K   2.5G     1%    /var/run
/dev/md/dsk/d6         2.9G   484M   2.4G    17%    /opt
/dev/md/dsk/d5         2.9G   3.0M   2.9G     1%    /export/home

swap -l
swapfile             dev  swaplo blocks   free
/dev/md/dsk/d1      85,1       8 4209016 4209016

Solo nos resta crear los volúmenes secundarios e iniciar la sincronización, los volúmenes secundarios se crean en la misma forma que los primarios:

metainit d20 1 1 c1t1d0s0
d20: Concat/Stripe is setup
metainit d21 1 1 c1t1d0s1
d21: Concat/Stripe is setup
metainit d23 1 1 c1t1d0s3
d23: Concat/Stripe is setup
metainit d24 1 1 c1t1d0s4
d24: Concat/Stripe is setup
metainit d25 1 1 c1t1d0s5
d25: Concat/Stripe is setup
metainit d26 1 1 c1t1d0s6
d26: Concat/Stripe is setup

Y agregamos cada volumen secundario a cada espejo que corresponde con lo que da inicio la sincronización:

metattach d0 d20
d0: submirror d20 is attached
metattach d1 d21
d1: submirror d21 is attached
metattach d3 d23
d3: submirror d23 is attached
metattach d4 d24
d4: submirror d24 is attached
metattach d5 d25
d5: submirror d25 is attached
metattach d6 d26
d6: submirror d26 is attached

Una vez que concluya la sincronización nuestro servidor se encuentra ya respaldado, el comando para monitorear el progreso es metastat:

metastat
d6: Mirror
    Submirror 0: d16
      State: Okay
    Submirror 1: d26
      State: Resyncing
    Resync in progress: 13 % done
    Pass: 1
    Read option: roundrobin (default)
    Write option: parallel (default)
    Size: 6265350 blocks (3.0 GB)

d16: Submirror of d6
    State: Okay
    Size: 6265350 blocks (3.0 GB)
    Stripe 0:
        Device     Start Block  Dbase        State Reloc Hot Spare
        c1t0d0s6          0     No            Okay   Yes

d26: Submirror of d6
    State: Resyncing
    Size: 6265350 blocks (3.0 GB)
    Stripe 0:
        Device     Start Block  Dbase        State Reloc Hot Spare
        c1t1d0s6          0     No            Okay   Yes

d5: Mirror
    Submirror 0: d15
      State: Okay
    Submirror 1: d25
      State: Resyncing
    Resync in progress: 71 % done
    Pass: 1
    Read option: roundrobin (default)
    Write option: parallel (default)
    Size: 6265350 blocks (3.0 GB)

d15: Submirror of d5
    State: Okay
    Size: 6265350 blocks (3.0 GB)
    Stripe 0:
        Device     Start Block  Dbase        State Reloc Hot Spare
        c1t0d0s5          0     No            Okay   Yes

d25: Submirror of d5
    State: Resyncing
    Size: 6265350 blocks (3.0 GB)
    Stripe 0:
        Device     Start Block  Dbase        State Reloc Hot Spare
        c1t1d0s5          0     No            Okay   Yes

d4: Mirror
    Submirror 0: d14
      State: Okay
    Submirror 1: d24
      State: Resyncing
    Resync in progress: 3 % done
    Pass: 1
    Read option: roundrobin (default)
    Write option: parallel (default)
    Size: 12289725 blocks (5.9 GB)

d14: Submirror of d4
    State: Okay
    Size: 12289725 blocks (5.9 GB)
    Stripe 0:
        Device     Start Block  Dbase        State Reloc Hot Spare
        c1t0d0s4          0     No            Okay   Yes

d24: Submirror of d4
    State: Resyncing
    Size: 12289725 blocks (5.9 GB)
    Stripe 0:
        Device     Start Block  Dbase        State Reloc Hot Spare
        c1t1d0s4          0     No            Okay   Yes

d3: Mirror
    Submirror 0: d13
      State: Okay
    Submirror 1: d23
      State: Resyncing
    Resync in progress: 38 % done
    Pass: 1
    Read option: roundrobin (default)
    Write option: parallel (default)
    Size: 6265350 blocks (3.0 GB)

d13: Submirror of d3
    State: Okay
    Size: 6265350 blocks (3.0 GB)
    Stripe 0:
        Device     Start Block  Dbase        State Reloc Hot Spare
        c1t0d0s3          0     No            Okay   Yes

d23: Submirror of d3
    State: Resyncing
    Size: 6265350 blocks (3.0 GB)
    Stripe 0:
        Device     Start Block  Dbase        State Reloc Hot Spare
        c1t1d0s3          0     No            Okay   Yes

d1: Mirror
    Submirror 0: d11
      State: Okay
    Submirror 1: d21
      State: Okay
    Pass: 1
    Read option: roundrobin (default)
    Write option: parallel (default)
    Size: 4209030 blocks (2.0 GB)

d11: Submirror of d1
    State: Okay
    Size: 4209030 blocks (2.0 GB)
    Stripe 0:
        Device     Start Block  Dbase        State Reloc Hot Spare
        c1t0d0s1          0     No            Okay   Yes

d21: Submirror of d1
    State: Okay
    Size: 4209030 blocks (2.0 GB)
    Stripe 0:
        Device     Start Block  Dbase        State Reloc Hot Spare
        c1t1d0s1          0     No            Okay   Yes

d0: Mirror
    Submirror 0: d10
      State: Okay
    Submirror 1: d20
      State: Resyncing
    Resync in progress: 18 % done
    Pass: 1
    Read option: roundrobin (default)
    Write option: parallel (default)
    Size: 6265350 blocks (3.0 GB)

d10: Submirror of d0
    State: Okay
    Size: 6265350 blocks (3.0 GB)
    Stripe 0:
        Device     Start Block  Dbase        State Reloc Hot Spare
        c1t0d0s0          0     No            Okay   Yes

d20: Submirror of d0
    State: Resyncing
    Size: 6265350 blocks (3.0 GB)
    Stripe 0:
        Device     Start Block  Dbase        State Reloc Hot Spare
        c1t1d0s0          0     No            Okay   Yes

Device Relocation Information:
Device   Reloc  Device ID
c1t1d0   Yes    id1,sd@n6000c29bb05a74f0966940ff84e13c6a
c1t0d0   Yes    id1,sd@n6000c298a7553d9bfab466ad901ff8d3

Obsérvese que en cada espejo indica sus volúmenes miembro y en que estado se encuentra cada uno, en este caso en casi todo aparece el submirror 1 como resincronizando, esta herramienta debo ejecutarla periódicamente para revisar el estado en el que se encuentra los volúmenes SVM del servidor.

Debemos evitar reiniciar este equipo mientras este sincronizando, también es recomendable no ponerlo en “producción” hasta que termine, debido a que una sincronización de este nivel afecta el desempeño del equipo.

martes, 28 de septiembre de 2010

Instalación de un servidor de correo (parte 4)

Hasta ahora, hemos completado la instalación de un servidor de correo que nos permite enviar y recibir mensajes de Internet utilizando un lector de correo desde nuestra estación de trabajo, este sirve muy bien si solo requerimos conectarnos a él desde una red local privada, pero si además de eso requerimos conectarnos desde cualquier nodo en Internet representa un riesgo de seguridad el iniciar sesión en el servidor desde cualquier sitio ya que es posible rastrear los datos y descubrir sin mucho esfuerzo cuentas y contraseñas, además de eso, si damos de alta IP’s externas para el relay, nada nos garantiza que estas mismas direcciones no puedan ser utilizadas con fines nocivos.

Es por todo esto que al extender del uso de nuestro servidor a direcciones fuera de nuestra organización, debemos adoptar un esquema de seguridad basado en la encriptación de datos y en la autentificación del usuario. Vamos a ver una forma muy sencilla para lograr esto que, aunque es sencilla, es suficientemente robusta para mantener un nivel de seguridad muy aceptable.

La forma en la que este esquema de seguridad trabaja consiste en dos partes:

  • La transmisión de datos entre el software cliente y el servidor será encriptada empleando el protocolo TLS/SSL.
  • Tanto para el servicio de envío como de recepción el cliente proporcionará un usuario y una contraseña.

El tipo de autentificación que utilizaremos será el llamado “plano” (plaintext), en algunos sitios mencionan que esto no es seguro, lo cual, no es del todo cierto, al estar cifrada la comunicación entre cliente y servidor, los datos de usuario y contraseña permanecen cifrados también, por lo que no presenta riesgo, siempre y cuando nuestros usuarios configuren correctamente su servicio de correo en su lector de mensajes.

Para poder activar estas funcionalidades es necesario tener instalado en nuestro servidor el OpenSSL y el Cyrus-SASL

En mi caso, en que estoy utilizando Ubuntu, por medio del apt, instalé los siguientes paquetes: libssl-dev, libssl0.9.8, openssl, libsasl2-2, libsasl2-dev, libsasl2-modules y sasl2-bin.

sudo aptitude install libssl-dev libssl0.9.8 openssl libsasl2-2 libsasl2-dev libsasl2-modules sasl2-bin

Nota: Para este tutorial me estoy basando por completo en SASL versión 2

Lo primero que vamos a hacer es activar el SSL en dovecot así que revisamos si fue compilado con el soporte a SSL por medio del parámetro –build-options

/usr/local/sbin/dovecot --build-options
Build options: ioloop=epoll notify=inotify ipv6 openssl io_block_size=8192
Mail storages: cydir maildir mbox mdbox raw sdbox shared
SQL drivers:
Passdb: checkpassword pam passwd passwd-file shadow
Userdb: checkpassword nss passwd prefetch passwd-file

En caso de que no presente openssl dentro de las opciones de compilación, vamos a recompilarlo, esta vez, asegurándonos que utilice el OpenSSL, desde el directorio con los archivos de instalación:

make clean
./configure --sysconfdir=/etc --with-ssl
make
sudo make install

Nota: Generalmente, la compilación la hago con un usuario sin privilegios y la instalación, al requerir la cuenta root, la hago con el comando sudo. Sin embargo es posible hacerlo todo con root.

Una vez instalado el dovecot con soporte para SSL, vamos a crear 2 certificados que vamos a necesitar para la encriptación.

Voy a explicar de forma muy breve cómo hacer certificados, en una entrada posterior, en la que explique como activar el SSL en Apache, explicaré de una forma más amplia como crear estos certificados.

Vamos crear un directorio de trabajo, podemos llamarle como nos guste, en mi caso, lo llamaré certs

mkdir certs
cd certs

Dentro de este directorio, vamos a crear los siguientes subdirectorios y archivos:

mkdir demoCA
mkdir demoCA/newcerts
mkdir demoCA/private
demoCA/index.txt
echo 01 > demoCA/serial

Creamos una llave RSA:

openssl genrsa -out demoCA/private/cakey.pem 1024
Generating RSA private key, 1024 bit long modulus
.++++++
................................++++++
e is 65537 (0x10001)

Generamos un certificado x509 para firmar certificados como CA.

openssl req -new -key demoCA/private/cakey.pem -x509 -out demoCA/cacert.pem
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:
MX
State or Province Name (full name) [Some-State]:
Queretaro
Locality Name (eg, city) []:Queretaro
Organization Name (eg, company) [Internet Widgits Pty Ltd]:unixymas.com.mx
Organizational Unit Name (eg, section) []:
Common Name (eg, YOUR name) []:
unixymas.com.mx
Email Address []:webmaster@unixymas.com.mx

Generamos otra llave para el certificado para nuestro servidor:

openssl genrsa -out key.pem 1024
Generating RSA private key, 1024 bit long modulus
...++++++
......................................++++++
e is 65537 (0x10001)

Creamos una solicitud de certificado:

openssl req -new -key key.pem -out req.pem
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:MX
State or Province Name (full name) [Some-State]:Queretaro
Locality Name (eg, city) []:Queretaro
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
unixymas.com.mx
Organizational Unit Name (eg, section) []:
Common Name (eg, YOUR name) []:unixymas.com.mx
Email Address []:webmaster@unixymas.com.mx

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

Y la firmamos:

openssl ca -in req.pem -key key.pem -out cert.pem
Using configuration from /usr/lib/ssl/openssl.cnf
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 1 (0x1)
        Validity
            Not Before: Sep 28 23:13:33 2010 GMT
            Not After : Sep 28 23:13:33 2011 GMT
        Subject:
            countryName               = MX
            stateOrProvinceName       = Queretaro
            organizationName          = unixymas.com.mx
            commonName                = unixymas.com.mx
            emailAddress              = webmaster@unixymas.com.mx
        X509v3 extensions:
            X509v3 Basic Constraints:
                CA:FALSE
            Netscape Comment:
                OpenSSL Generated Certificate
            X509v3 Subject Key Identifier:
                D3:EF:80:66:10:6C:37:61:0A:54:5B:17:47:15:CF:75:05:52:C0:9A
            X509v3 Authority Key Identifier:
                keyid:32:84:3B:C2:B8:44:2C:06:5D:40:10:7D:F4:CC:13:8E:2D:79:E7:6B

Certificate is to be certified until Sep 28 23:13:33 2011 GMT (365 days)
Sign the certificate? [y/n]:y

1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated

Ahora con root copiamos los siguientes archivos:

cp cert.pem /etc/ssl/certs/dovecot.pem
cp key.pem /etc/ssl/private/dovecot.pem
cp demoCA/cacert.pem /etc/ssl/certs/cacert.pem

Y cambiamos los siguientes permisos:

chmod 600 /etc/ssl/private/dovecot.pem

En el directorio /etc/dovecot/conf.d creamos o modificamos el archivo 10-ssl.conf

##
## SSL settings
##

# SSL/TLS support: yes, no, required. <doc/wiki/SSL.txt>
ssl = yes

# PEM encoded X.509 SSL/TLS certificate and private key. They're opened before
# dropping root privileges, so keep the key file unreadable by anyone but
# root. Included doc/mkcert.sh can be used to easily generate self-signed
# certificate, just make sure to update the domains in dovecot-openssl.cnf
ssl_cert = </etc/ssl/certs/dovecot.pem
ssl_key = </etc/ssl/private/dovecot.pem

# If key file is password protected, give the password here. Alternatively
# give it when starting dovecot with -p parameter. Since this file is often
# world-readable, you may want to place this setting instead to a different
# root owned 0600 file by using ssl_key_password = <path.
#ssl_key_password =

# PEM encoded trusted certificate authority. Set this only if you intend to use
# ssl_verify_client_cert=yes. The file should contain the CA certificate(s)
# followed by the matching CRL(s). (e.g. ssl_ca = </etc/ssl/certs/ca.pem)
ssl_ca = </etc/ssl/certs/cacert.pem

# Request client to send a certificate. If you also want to require it, set
# auth_ssl_require_client_cert=yes in auth section.
ssl_verify_client_cert = yes

# Which field from certificate to use for username. commonName and
# x500UniqueIdentifier are the usual choices. You'll also need to set
# auth_ssl_username_from_cert=yes.
#ssl_cert_username_field = commonName

# How often to regenerate the SSL parameters file. Generation is quite CPU
# intensive operation. The value is in hours, 0 disables regeneration
# entirely.
#ssl_parameters_regenerate = 168

# SSL ciphers to use
#ssl_cipher_list = ALL:!LOW:!SSLv2:!EXP:!aNULL

En el archivo /etc/dovecot/dovecot.conf eliminamos la línea ssl = no y, por último, iniciamos el dovecot

/usr/local/sbin/dovecot

Ahora vamos a trabajar con el sendmail, verificamos si ya tiene activas las opciones STARTTLS y SASL

/usr/sbin/sendmail -d0 < /dev/null
Version 8.14.4
Compiled with: DNSMAP LOG MATCHGECOS MILTER MIME7TO8 MIME8TO7
                NAMED_BIND NETINET NETUNIX NEWDB PIPELINING SASLv2 SCANF
                STARTTLS USERDB XDEBUG

============ SYSTEM IDENTITY (after readcf) ============
      (short domain name) $w = ubuntu
  (canonical domain name) $j = ubuntu.unixymas.com.mx
         (subdomain name) $m = unixymas.com.mx
              (node name) $k = ubuntu
========================================================

Recipient names must be specified

En caso de que no, que es lo mas probable, vamos a activarlas y recompilar.

Nuevamente en nuestros archivos de instalación vamos a crear el archivo devtools/Site/site.config.m4 con el siguiente contenido:

APPENDDEF(`confENVDEF', `-DSASL=2')
APPENDDEF(`confLIBS', `-lsasl2')
APPENDDEF(`confENVDEF',`-DSTARTTLS')
APPENDDEF(`confLIBS', `-lssl -lcrypto')
APPENDDEF(`confLIBDIRS', `-L/usr/local/lib -L/usr/lib/sasl2')dnl
APPENDDEF(`confINCDIRS', `-I/usr/local/include')dnl

Recompilamos e instalamos:

sh ./Build clean
sh ./Build -c
sudo sh ./Build install

Nota: La opción –c en Build indica que hubo cambio en la configuración, si olvidamos incluirla compilará nuevamente con la configuración anterior.

En el subdirectorio cf/cf dejamos el archivo sendmail.mc con el siguiente contenido:

divert(-1)
#
# Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
#       All rights reserved.
# Copyright (c) 1983 Eric P. Allman.  All rights reserved.
# Copyright (c) 1988, 1993
#       The Regents of the University of California.  All rights reserved.
#
# By using this file, you agree to the terms and conditions set
# forth in the LICENSE file which can be found at the top level of
# the sendmail distribution.
#
#

#
#  This is a generic configuration file for Linux.
#  It has support for local and SMTP mail only.  If you want to
#  customize it, copy it to a name appropriate for your environment
#  and do the modifications there.
#

divert(0)dnl
VERSIONID(`$Id: generic-linux.mc,v 8.1 1999/09/24 22:48:05 gshapiro Exp $')
OSTYPE(linux)dnl
DOMAIN(generic)dnl
MASQUERADE_AS(`unixymas.com.mx')dnl
FEATURE(`allmasquerade')dnl
FEATURE(`masquerade_envelope')dnl
FEATURE(`access_db')dnl
define(`confCACERT_PATH', `/etc/mail/certs')dnl
define(`confCACERT', `/etc/mail/certs/cacert.pem')dnl
define(`confSERVER_CERT', `/etc/mail/certs/cert.pem')dnl
define(`confSERVER_KEY', `/etc/mail/certs/key.pem')dnl
define(`confCLIENT_CERT', `/etc/mail/certs/cert.pem')dnl
define(`confCLIENT_KEY', `/etc/mail/certs/key.pem')dnl
define(`confAUTH_OPTIONS', `A')dnl
define(`confAUTH_MECHANISMS', `PLAIN LOGIN')dnl
TRUST_AUTH_MECH(`PLAIN LOGIN')dnl
MAILER(local)dnl
MAILER(smtp)dnl

Nota: La característica (feature) confAUTH_OPTIONS es muy importante y curiosamente en pocos sitios en Internet se menciona, sin esta característica, el sendmail, simplemente no hace la validación de la cuenta para permitir el relay.

Compilamos el archivo y lo copiamos a /etc/mail

cd cf/cf
sh ./Build sendmail.cf
sudo cp sendmail.cf /etc/mail/sendmail.cf

Con root, creamos el subdirectorio /etc/mail/certs y copiamos los certificados cacert.pem y cert.pem y la llave key.pem con permisos solo para root, podemos usar los mismos certificados para el dovecot u otros.

cp cert.pem /etc/mail/certs/cert.pem
cp key.pem /etc/mail/certs/key.pem
cp demoCA/cacert.pem /etc/mail/certs/cacert.pem
chmod 600 /etc/mail/certs/key.pem

Antes de iniciar el sendmail, necesitamos configurar el SASL, el archivo /etc/default/saslauthd principalmente modificaremos a START=yes y nos aseguraremos que MECHANISM sea igual a “pam”, quedará así:

#
# Settings for saslauthd daemon
# Please read /usr/share/doc/sasl2-bin/README.Debian for details.
#

# Should saslauthd run automatically on startup? (default: no)
START=yes

# Description of this saslauthd instance. Recommended.
# (suggestion: SASL Authentication Daemon)
DESC="SASL Authentication Daemon"

# Short name of this saslauthd instance. Strongly recommended.
# (suggestion: saslauthd)
NAME="saslauthd"

# Which authentication mechanisms should saslauthd use? (default: pam)
#
# Available options in this Debian package:
# getpwent  -- use the getpwent() library function
# kerberos5 -- use Kerberos 5
# pam       -- use PAM
# rimap     -- use a remote IMAP server
# shadow    -- use the local shadow password file
# sasldb    -- use the local sasldb database file
# ldap      -- use LDAP (configuration is in /etc/saslauthd.conf)
#
# Only one option may be used at a time. See the saslauthd man page
# for more information.
#
# Example: MECHANISMS="pam"
MECHANISMS="pam"

# Additional options for this mechanism. (default: none)
# See the saslauthd man page for information about mech-specific options.
MECH_OPTIONS=""

# How many saslauthd processes should we run? (default: 5)
# A value of 0 will fork a new process for each connection.
THREADS=5

# Other options (default: -c -m /var/run/saslauthd)
# Note: You MUST specify the -m option or saslauthd won't run!
#
# WARNING: DO NOT SPECIFY THE -d OPTION.
# The -d option will cause saslauthd to run in the foreground instead of as
# a daemon. This will PREVENT YOUR SYSTEM FROM BOOTING PROPERLY. If you wish
# to run saslauthd in debug mode, please run it by hand to be safe.
#
# See /usr/share/doc/sasl2-bin/README.Debian for Debian-specific information.
# See the saslauthd man page and the output of 'saslauthd -h' for general
# information about these options.
#
# Example for postfix users: "-c -m /var/spool/postfix/var/run/saslauthd"
OPTIONS="-c -m /var/run/saslauthd"

Creamos el archivo /usr/lib/sasl2/Sendmail.conf (nótese la “S” mayúscula) con el siguiente contenido:

pwcheck_method: saslauthd
mech_list: login plain

Iniciamos al saslauthd:

/etc/init.d/saslauthd start

Y por último el sendmail:

/usr/sbin/sendmail –bd –q15m

Finalmente probamos, dándole un telnet al puerto 25, darle un EHLO y esperar que en su respuesta aparezca una línea que indique la capacidad STARTTLS y otra para la autentificación por contraseña plana (AUTH PLAIN LOGIN).

telnet localhost 25
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 ubuntu.unixymas.com.mx ESMTP Sendmail 8.14.4/8.14.4; Tue, 28 Sep 2010 19:51:09 -0500
ehlo unixymas.com.mx
250-ubuntu.unixymas.com.mx Hello localhost [127.0.0.1], pleased to meet you
250-ENHANCEDSTATUSCODES
250-PIPELINING
250-EXPN
250-VERB
250-8BITMIME
250-SIZE
250-DSN
250-ETRN
250-AUTH PLAIN LOGIN
250-STARTTLS
250-DELIVERBY
250 HELP

Para la configuración del lector de correo, deben activarse las características de seguridad, para el POP3 y el IMAP conexión TLS/SSL autentificación con usuario y contraseña normal y para el SMTP conexión STARTTLS y autentificación por usuario y contraseña.

lunes, 27 de septiembre de 2010

Instalación de un servidor de correo (parte 3)

Ya hemos visto cómo instalar un servidor sendmail que nos permita enviar y recibir mensajes a Internet, en esta ocasión vamos a habilitarlo para que nos permita el uso de un cliente de correo electrónico instalado en nuestra estación de trabajo. Este cliente puede ser cualquiera que soporte el SMTP para el envío y el POP3 o el IMAP para recibir mensajes.

El servicio de correo que requerimos, básicamente, funciona de esta forma:

El servidor de correo utiliza el protocolo SMTP para recibir mensajes dirigidos a cuentas del mismo y los agrega a un archivo "buzón" (inbox) para cada usuario, en estos archivos, los mensajes se van acumulando, su formato es de texto y si en ellos hay archivos adjuntos, estos están codificados en un formato de texto llamado MIME.

Los mensajes de cada inbox pueden recibirse en un lector de mensajes empleando un protocolo, actualmente existen el POP3 y el IMAP, es importante resaltar que estos protocolos solo permiten recibir correo.

Para el envío de mensaje también se utiliza el protocolo SMTP de tal forma que el servidor recibe los mensajes desde el lector de mensajes del usuario y los reenvía a los destinatarios que corresponda, locales o remotos. A este reenvío se le conoce como relay.

Para esto va a ser necesario instalar un software que nos proporcione el protocolo POP3 o el IMAP, actualmente hay varias opciones, el software con el que vamos a trabajar es el dovecot.

También va a ser necesario configurar al sendmail para que haga relay solo de nuestros usuarios o de lo contrario, cualquier persona desde cualquier lugar del mundo podría utilizar nuestro servidor para hacer el envío de mensajes no deseados (spam), si ocurriera esto, nuestro servidor sería puesto en "lista negra" y no podríamos enviar mensajes a ningún lugar (y créanme que esto ocurre con mucha frecuencia) por lo que debemos mantener reglas para el reenvío.

Para instalar el dovecot, ya como es costumbre, vamos a bajar el archivo fuente (recomiendo la versión 2.0.4), la descomprimimos, la configuramos, compilamos e instalamos:

./configure --sysconfdir=/etc

make

sudo make install

Creamos los usuarios sin privilegios dovecot y dovenull.

useradd dovecot

useradd dovenull

En el directorio /etc/pam.d creamos el archivo dovecot con el siguiente contenido:

auth    required        pam_unix.so
account required        pam_unix.so

Copiamos el contenido del directorio /usr/local/share/doc/dovecot/example-config en /etc/dovecot

cp –r /usr/local/share/doc/dovecot/example-config/* /etc/dovecot

Ahora vamos a configurar el dovecot, para esto vamos a editar varios archives en /etc/dovecot

dovecot.conf.- Agregamos al final la línea:

ssl = no

conf.d/10-auth.conf.- Quitamos el signo de comentario a la línea disable_plaintext_auth y la dejamos asi:

disable_plaintext_auth = no

conf.d/10-master.conf.- La línea mail_location queda asi:

mail_location = mbox:~/mail:INBOX=/var/mail/%u

conf.d/10-ssl.conf.- Borramos el archivo o lo renombramos modificando el .conf, por ejemplo, yo lo renombre como 10-ssl.no

Una vez que lo configuramos estamos listos para ejecutarlo:

/usr/local/sbin/dovecot

Es normal que la primera vez que se ejecute aparezcan advertencias en los permisos de algunos directorios, ya en la segunda vez no deben de aparecer.

Para probarlo vamos a ejecutar lo siguiente:

telnet localhost 110
Trying ::1...
Connected to localhost.
Escape character is '^]'.
+OK Dovecot ready.
user cuenta
+OK
pass contraseña
+OK Logged in.
list
+OK 5 messages:
1 461
2 1358
3 2045
4 2497
5 1181
.
quit
+OK Logging out.

Lo siguiente es configurar al sendmail para que permita el relay solo a ciertas IP's, para esto vamos a ir a los archivos de instalación del sendmail (cómo podrán ver, vale la pena mantener estos archivos ya que se utilizan con mucha frecuencia), nos cambiamos al subdirectorio cf/cf y modificamos el archivo sendmail.mc agregando 2 nuevas características: el access_db y el relay_hosts_only

divert(-1)
#
# Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
#       All rights reserved.
# Copyright (c) 1983 Eric P. Allman.  All rights reserved.
# Copyright (c) 1988, 1993
#       The Regents of the University of California.  All rights reserved.
#
# By using this file, you agree to the terms and conditions set
# forth in the LICENSE file which can be found at the top level of
# the sendmail distribution.
#
#

#
#  This is a generic configuration file for Linux.
#  It has support for local and SMTP mail only.  If you want to
#  customize it, copy it to a name appropriate for your environment
#  and do the modifications there.
#

divert(0)dnl
VERSIONID(`$Id: generic-linux.mc,v 8.1 1999/09/24 22:48:05 gshapiro Exp $')
OSTYPE(linux)dnl
DOMAIN(generic)dnl
MASQUERADE_AS(`unixymas.com.mx')dnl
FEATURE(`allmasquerade')dnl
FEATURE(`masquerade_envelope')dnl
FEATURE(`access_db')dnl
FEATURE(`relay_hosts_only')dnl
MAILER(local)dnl
MAILER(smtp)dnl

Lo compilamos y copiamos a /etc/mail el sendmail.cf

Creamos el archivo de texto access y por cada dirección de usuario agregamos una línea con la IP un tabulador y la palabra RELAY

localhost       RELAY
ubuntu.unixymas.com.mx  RELAY
192.168.188.1      RELAY

También podemos utilizar nombres en lugar de las IP, pero debemos configurar el DNS para que la IP que resuelva cada nombre, también resuelva en reversa.

Ya que terminemos de crear el archivo, vamos a generar la base de datos con este "mapa" utilizando el comando makemap:

makemap hash access < access

Reiniciamos el sendmail y ya está listo para recibir peticiones de nuestro software cliente.

Configuramos al cliente de correo indicando la dirección de nuestro servidor SMTP, sin ningún tipo de autentificación, además de configurar el recibo de correo por medio del protocolo POP3 o el IMAP, indicando que la autentificación es normal, además de indicarle nuestra cuenta y contraseña del servidor.

Con esto damos por finalizada esta parte, tenemos como resultado un servidor de correo electrónico corporativo con un esquema de seguridad muy básico pero lo suficientemente robusto para mantener nuestras cuentas de correo seguras y que nuestro servidor no sea empleado cómo difusor de spam.

En la siguiente entrada vamos a ver una forma simple para brindarle a nuestro servidor un esquema de encriptación y autentificación que nos permita hacer el envío de correo desde cualquier dirección local y remota sin comprometer la seguridad de éste.

jueves, 23 de septiembre de 2010

Instalación de un servidor de correo (parte2)

En la entrada anterior, vimos cómo activar en un servidor el envío y recepción de correo por medio del sendmail, en esta ocasión, vamos a habilitar este servidor para que reciba el correo de nuestra organización. En mi ejemplo, voy recibir el correo del dominio unixymas.com.mx con el servidor ubuntu.unixymas.com.mx.

Para dar de alta este servicio, es indispensable anunciarlo en Internet por medio del servidor DNS de mi dominio, por lo que vamos a utilizar el que instalamos en una entrada anterior, con este mismo servidor (solaris10.unixymas.com.mx), vamos a realizar pruebas, así que, previamente le instalé el sendmail.

Para anunciar en Internet el servidor de correo para el dominio, agregamos en el archivo de la zona que corresponde a nuestro dominio un registro MX de esta forma:

unixymas.com.mx.        IN MX 10 ubuntu.unixymas.com.mx.

Con este registro, estoy definiendo para el dominio unixymas.com.mx un servidor de correo (Mail eXchanger) con un número de prioridad 10 y por nombre ubuntu.unixymas.com.mx. El número de prioridad es completamente libre a nuestro criterio, en el caso de que existiera más de un servidor de correo, el número define qué servidor debe anunciar con más frecuencia, si para todos los servidores el número de prioridad es igual, los anuncia con la misma frecuencia. El nombre del servidor puede ser parte de nuestro dominio o ser un servidor que pertenezca a un dominio diferente, las 2 condiciones que debe tener es que su nombre pueda ser resuelto por algún servidor y que éste tenga una respuesta autoritativa. Para este ejemplo, el servidor es parte de mi dominio, por lo que en la misma zona tengo definido un registro A para este servidor:

ubuntu  IN A 192.168.188.132

Una vez finalizada la edición de mi archivo de zona, reinicio el servidor BIND, este reinicio puede ser simplemente dando de baja el servidor y dándolo de alta nuevamente. La otra forma es por medio del comando rndc desde el mismo servidor:

rndc reload

Ahora, volviendo al servidor de correo, vamos a cambiarnos al directorio cf/cf dentro de los archivos de instalación, aquí recordaran que se encuentran los archivos de configuración, los .mc, vamos a realizar algunas modificaciones al archivo sendmail.mc para "enmascarar" nuestros mensajes, es decir, que los mensajes generados en el servidor, aparezcan solo con el dominio en su remitente en lugar de agregar el nombre completo del servidor, para esto vamos a agregar las siguientes líneas:

MASQUERADE_AS(`dominio'): Define la máscara, es decir, dominio con el que se van a enmascarar los mensajes.

FEATURE(`allmasquerade'): Indica que debe agregar la máscara al nombre de los usuarios que envíen mensajes.

FEATURE(`masquerade_envelope'): Indica que en los encabezados, la dirección de remitente debe estar enmascarada.

Para mi servidor el archivo sendmail.mc quedo de la siguiente forma:

divert(-1)
#
# Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
#       All rights reserved.
# Copyright (c) 1983 Eric P. Allman.  All rights reserved.
# Copyright (c) 1988, 1993
#       The Regents of the University of California.  All rights reserved.
#
# By using this file, you agree to the terms and conditions set
# forth in the LICENSE file which can be found at the top level of
# the sendmail distribution.
#
#

#
#  This is a generic configuration file for Linux.
#  It has support for local and SMTP mail only.  If you want to
#  customize it, copy it to a name appropriate for your environment
#  and do the modifications there.
#

divert(0)dnl
VERSIONID(`$Id: generic-linux.mc,v 8.1 1999/09/24 22:48:05 gshapiro Exp $')
OSTYPE(linux)dnl
DOMAIN(generic)dnl
MASQUERADE_AS(`unixymas.com.mx')dnl
FEATURE(`allmasquerade')dnl
FEATURE(`masquerade_envelope')dnl
MAILER(local)dnl
MAILER(smtp)dnl

Noten que las cadenas de caracteres se delimitan con un acento grave al inicio y un apóstrofe al final, además de que todas las sentencias se delimitan al final con la cadena dnl, esta cadena sería un equivalente al punto y coma de algunos lenguajes de programación.

Terminada la edición del archivo "compilamos" el archivo por medio del m4, de esta forma:

m4 ../m4/cf.m4 sendmail.mc > sendmail.cf

Si llegara a aparecer un mensaje de error relacionado con permisos sobre el archive sendmail.cf, simplemente le cambiamos los permisos o lo borramos. El archivo sendmail.cf lo copiamos a /etc/mail.

Por último modificamos el archivo /etc/mail/local-host-names agregando el nombre de nuestro dominio (en este caso unixymas.com.mx), reiniciamos el sendmail y ya tenemos listo nuestro servidor para enviar y recibir mensajes con el nombre de nuestro dominio.

En mi caso voy a probar utilizando el comando mail:

mail hajarami@solaris10.unixymas.com.mx
Subject: Prueba
Mensaje de prueba
.

Este es el mensaje que se recibió incluyendo encabezados:

From hajarami@unixymas.com.mx Thu Sep 23 17:55:18 2010
Return-Path: <hajarami@unixymas.com.mx>
Received: from ubuntu.unixymas.com.mx (ubuntu.unixymas.com.mx [192.168.188.132])
        by solaris10.unixymas.com.mx (8.14.4+Sun/8.14.4) with ESMTP id o8NMtGpG000876
        for <hajarami@solaris10.unixymas.com.mx>; Thu, 23 Sep 2010 17:55:17 -0500 (CDT)
Received: from ubuntu.unixymas.com.mx (localhost [127.0.0.1])
        by ubuntu.unixymas.com.mx (8.14.4/8.14.4) with ESMTP id o8NMt1Dn001306
        for <hajarami@solaris10.unixymas.com.mx>; Thu, 23 Sep 2010 17:55:01 -0500
Received: (from hajarami@localhost)
        by ubuntu.unixymas.com.mx (8.14.4/8.14.4/Submit) id o8NMt1vK001304
        for hajarami@solaris10.unixymas.com.mx; Thu, 23 Sep 2010 17:55:01 -0500
Date: Thu, 23 Sep 2010 17:55:01 -0500
From: Hector Alejandro Jaramillo Zavala <hajarami@unixymas.com.mx>
Message-Id: <201009232255.o8NMt1vK001304@ubuntu.unixymas.com.mx>
To: hajarami@solaris10.unixymas.com.mx
Subject: Prueba
Content-Length: 18

Mensaje de prueba

Como podrán observar, en el mensaje aparece la dirección del remitente sólo con el dominio unixymas.com.mx, si yo envió un mensaje a esta dirección lo voy a recibir en mi servidor ubuntu.

Si tengo conectados mis servidores de correo y DNS en Internet, y en el NIC tengo contratado mi dominio y tengo registrado mi servidor DNS como servidor primario, voy a poder enviar mensajes de esta misma forma a cualquier dirección válida en Internet, además de que también voy a poder recibir mensajes.

Con esto ya tengo un servidor capaz de enviar y recibir mensajes de correo electrónico en Internet, en la siguiente entrega, vamos a ver cómo darle a nuestro servidor la capacidad de enviar y recibir mensajes por medio de una aplicación cliente que corra desde nuestra estación de trabajo.