Cifrando discos, particiones o ficheros con LUKS

Uno de los mecanismos más eficaces para proteger nuestra información es el cifrado. Hoy no se me pasa por la cabeza tener un portátil sin el disco cifrado. Lo grave no sería la pérdida física del mismo, sino la de la información que lleve y en las manos que pueda acabar. Pero esto no es sólo aplicable a portátiles, discos USB o pendrives con información sensible también deberían estar cifrados para evitar que dicha información sea accesible por terceros no autorizados.

En GNU/Linux tenemos múltiples opciones a la hora de cifrar nuestra información. GPG sobre ficheros, eCryptfsEncFS sobre directorios, TrueCrypt o dm-crypt sobre dispositivos,  loop-AES para ficheros loop, etc. De todas las opciones mi preferida es LUKS (Linux Unified Key Setup), que podemos usar sobre discos, particiones, volúmenes lógicos (LVs) o ficheros loop. Entre sus ventajas están: su sencillez de uso, incluido en el propio kernel y la capacidad de asignar, cambiar y revocar varias claves para un mismo dispositivo.

La instalación de muchas distribuciones actuales hace muy sencillo incorporar el cifrado del sistema completo desde el principio. Mi recomendación en un portátil es: crear una pequeña partición para /boot (que no irá cifrada) y dejar el resto del disco para ser cifrado con LUKS. Sobre dicho cifrado crear un PV para LVM y  todo lo que vaya sobre el LVM ya estará cifrado.

Pero en la entrada de hoy veremos como usar LUKS en un sistema que ya está corriendo, por ejemplo para cifrar un nuevo volumen lógico, un fichero loop donde guardar información sensible, o un dispositivo USB donde realizar backups.

Ingredientes

Tener instalado el paquete cryptsetup (también llamado cryptsetup-luks en algunas distribuciones). Tener un dispositivo sin usar (su información será reescrita al cifrarlo inicialmente), por ejemplo /dev/sdc, /dev/vgpruebas/cifrado, /dev/sdb2,… En el caso de querer user un fichero (loop) podemos crearlo con este comando:

## En este ejemplo 50 bloques de 1MB ~ 50MB
## Aunque es posible crecer el fichero posteriormente es
## algo enrevesado, mejor afinar con el tamaño que necesitemos
## Podemos usar /dev/zero como origen de datos en la creación
## del fichero también, pero facilitaría un posible criptoanálisis
$ dd if=/dev/urandom of=fichero_cifrado bs=1M count=50

Inicialización del cifrado

El primer paso será dar el formato LUKS al dispositivo. Para ello usaremos el comando cryptsetup con argumento luksFormat. Entre las diversas opciones que podemos especificar está el algoritmo de cifrado, el tamaño de la clave o la función hash (resumen) o el fichero clave.

Veamos algunos ejemplos:

## Cifrar el fichero creado en el ejemplo anterior con una
## contraseña, pidiéndola dos veces (para confirmar que
## se tecleó correctamente). Usando valores por defecto
## para el cifrado:
$ cryptsetup --verify-passphrase luksFormat fichero_cifrado

## Podemos averiguar el algoritmo, tamaño de clave y función
## hash que se usan por defecto con este comando:
$ cryptsetup --help | grep LUKS.*Key
 LUKS1: aes-xts-plain64, 
 Key: 256 bits, 
 LUKS header hashing: sha1, 
 RNG: /dev/urandom

## Si los valores por defecto no nos convencen, podemos
## especificar otros, por ejemplo un tamaño de clave de
## cifrado mayor (de 256 bits) y una función hash que no
## haya sido declarada insegura (como es el caso de SHA1):
cryptsetup --hash=sha256 --key-size=512 --verify-passphrase \
 luksFormat fichero_cifrado

## Cifrar un dispositivo (p.e. un disco USB) usando un fichero
## como contraseña.
## Primero creamos el fichero de contraseña (podemos hacerlo
## a mano, o usar /dev/random o /dev/urandom para rellenarlo)
$ dd if=/dev/urandom of=mi_secreto bs=1M count=1

## Un megabyte de contraseña!
## ¿Qué tamaño máximo de contraseña (tecleada o en fichero)
## podemos usar? El siguiente comando lo aclara:
$ cryptsetup --help | grep Maximum
   Maximum keyfile size: 8192kB,
   Maximum interactive passphrase length 512 (characters)
 
## Una vez tenemos el fichero de contraseña, podemos dar el
## formato LUKS usando éste, en vez de tecleando una contraseña
## de forma interactiva
## El siguiente comando lo ejecutamos como root, al tratarse
## de un dispositivo (/dev/sdc) y no un fichero de usuario:
# cryptsetup luksFormat /dev/sdc /path/al/fichero/mi_secreto
## o
# cryptsetup --key-file=/path/al/fichero/mi_secreto luksFormat /dev/sdc

## Por supuesto también podríamos modificar el tamaño de clave
## de cifrado o la función hash.

Clave de cifrado, contraseña y cabecera LUKS

Llegados a este punto debo (intentar) esclarecer algún término. Cuando damos formato LUKS a un dispositivo/fichero hablamos de dos términos similares, pero diferentes:

  • Contraseña. Ya sea una tecleada en el momento, o un fichero usado como tal, es la que nos permite acceder al dispositivo LUKS. Esta contraseña no es usada para cifrar los datos. De hecho, una de las ventajas de usar LUKS es que podemos usar varias contraseñas/ficheros contraseña para un mismo dispositivo. Más adelante daré un ejemplo.
  • Clave de cifrado. Esta clave se genera automáticamente cuando damos el formato LUKS al dispositivo. Se genera de forma aleatoria (por defecto usando /dev/urandom) y con el tamaño por defecto (256 bits) o el que se especifique con la opción –key-size. Si bien es posible especificar una clave de cifrado de forma manual (–master-key-file) no es recomendable hacerlo salvo que sepas exactamente que estás haciendo.

El formato LUKS se caracteriza por una cabecera que incluye la información del algoritmo de cifrado, tamaño de clave, contraseñas en uso, etc. Podemos consultar dicha cabecera (que no las contraseñas!) con el siguiente comando:

$ cryptsetup luksDump fichero_cifrado 
LUKS header information for fichero_cifrado

Version: 1
Cipher name: aes
Cipher mode: xts-plain64
Hash spec: sha256
Payload offset: 4096
MK bits: 512
MK digest: ca cb 7e f6 20 fa 42 8a 7e 0a 92 66 86 bd 20 46 77 28 a5 25 
MK salt: a1 e5 54 8d c2 4d db af 3d 72 73 4d f6 0b 9f b7 
 41 d7 46 31 ce dc f8 11 21 86 8c 22 d9 cf e5 ca 
MK iterations: 95125
UUID: d58132bd-ea6b-4879-aa73-c8d444300545

Key Slot 0: ENABLED
 Iterations: 378697
 Salt: 1a 54 1a cd 92 74 13 78 5d 72 f4 00 60 b4 69 85 
 c7 8a a9 fa 50 65 6b 32 f4 13 a4 e2 b6 3b c3 69 
 Key material offset: 8
 AF stripes: 4000
Key Slot 1: DISABLED
Key Slot 2: DISABLED
Key Slot 3: DISABLED
Key Slot 4: DISABLED
Key Slot 5: DISABLED
Key Slot 6: DISABLED
Key Slot 7: DISABLED

En este ejemplo vemos que se está usando AES como algoritmo de cifrado, que el tamaño de clave es de 512 bits, la función hash es SHA256 y que hay una contraseña (de las 8 posibles) en uno (Key Slot 0: ENABLED). El resto de posibles contraseñas no están establecidas (DISABLED).

Usando el dispositivo cifrado

Una vez tenemos el formato LUKS en el dispositivo, para acceder a los datos en claro habrá que «abrir el contenedor cifrado». Es decir, antes de poder usarlo (montarlo o formatearlo) hay que descifrarlo:

## Si vamos a abrir un fichero protegido con
## contraseña "tecleada":
# cryptsetup luksOpen fichero_cifrado dispositivo_descifrado

## Si el fichero o dispositivo está protegido con un fichero
## contraseña, se lo indicamos como opción:
#  cryptsetup --key-file=mi_secreto luksOpen /dev/sdc dispositivo_descifrado

## Unos comentarios sobre estos ejemplos:
## 1.- "dispositivo_descifrado" es el nombre que queremos para el
##     dispositivo que se creará trás ejecutar este comando
##     y que será el que ya usemos para formatear o montar de forma
##     normal
## 2.- Si la contraseña es válida, desde este momento podremos acceder
##     al dispositivo "en claro" como /dev/mapper/dispositivo_descifrado
## 3.- Estos comandos se ejecutan con el usuario "root" ya que crean
##     un dispositivo nuevo. (Sí, seguro que hay interfaces de usuario
##     que permiten estas tareas a un usuario corriente)

Por supuesto, la primera vez que lo abrimos lo más frecuente será formatearlo, como con cualquier dispositivo nuevo:

mkfs.ext4 /dev/mapper/dispositivo_descifrado

Desde ese momento, y después de abrirlo con «luksOpen«, simplemente lo montaremos como el resto de dispositivos de almacenamiento:

mount /dev/mapper/dispositivo_descifrado /media/mis_datos_secretos

Cerrar después de usar

Cuando ya no necesitemos acceso a los datos, y después de desmontar como con cualquier otro dispositivo de almacenamiento, debemos «cerrar» el acceso al dispositivo sin cifrar. O como decía Mamá – deja las cosas como las encontraste:

## Desmontar antes de cerrar el acceso
# umount /media/mis_datos_secretos
## Eliminar el acceso al dispositivo descifrado
# cryptsetup luksClose dispositivo_descifrado

¿Varias contraseñas?

Para terminar comentaré una de las características que más me gustan de LUKS y que en un principio puede sonar extraña: la capacidad de tener varias contraseñas/ficheros contraseña.

Insistir en que las contraseñas no son las que se usan para cifrar, eso se hace con la clave de cifrado, sino para dar acceso a ésta y poder abrir el dispositivo. Poder usar más de una (y ser capaces de revocarlas, cambiarlas o añadirlas) permite:

  • Tener una contraseña por usuario para un mismo dispositivo. De forma que cada uno sabe la suya y si un día se decide evitar el acceso de uno de ellos basta con eliminar su contraseña, lo que no afecta al resto de usuarios.
  • Tener una contraseña para nosotros (que tecleamos cuando queremos acceso al dispositivo) y tener un fichero contraseña para tareas automatizadas (por ejemplo backups). Yo tengo un disco USB donde se hacen backups de mi portátil de forma automática. Para no tener que teclear la contraseña (y estar delante del ordenador) cuando se realiza el backup, en el disco del portátil tengo un fichero contraseña que le permite descifrar el USB y realizar el backup. Por supuesto este fichero contraseña sólo puede leerlo el usuario root y el disco de mi portátil está cifrado. Pero ¿qué pasaría si el disco de mi portátil muere? Ya no tendría el fichero contraseña para descifrar el disco USB de backup. Estúpida situación ésta… Salvo que el USB con LUKS tiene una segunda contraseña (que puedo teclear) y que me permitiría acceder a él aunque el disco de mi portátil muriera.

Sobra decir que hay que tener sumo cuidado con los ficheros usados como contraseña, su acceso debería estar extremadamente limitado (permisos, acceso al dispositivo donde se almacenan, etc..).

¿Cómo gestionamos las contraseñas de un dispositivo con LUKS?

Como vimos anteriormente, podemos ver la información de la cabecera LUKS con el comando «cryptsetup luksDump DISPOSITIVO«. En el veremos los «slots» («contraseñas») que están en uso. Normalmente el slot-0 siempre lo está, porque es donde se guarda la contraseña inicial. Podemos añadir una nueva contraseña con el siguiente comando:

## Si queremos una contraseña "tecleada"
# cryptsetup luksAddKey /dev/sdc

## Primero nos pedirá una contraseña ya existente
## en alguno de los slots, si no hay contraseña
## sino "fichero contraseña" deberemos usar la
## opción --key-file:
# cryptsetup --key-file=/etc/mi_secreto luksAddKey /dev/sdc

## Si queremos añadir un "fichero contraseña"
# cryptsetup luksAddKey /dev/sdc /etc/mi_nuevo_secreto

## Al igual que antes, si no hay una contraseña en
## algún slot, sino que son todo ficheros contraseña
## le indicamos alguno de los actuales con --key-file
# cryptsetup --key-file=/etc/mi_secreto \
    luksAddKey /dev/sdc /etc/mi_nuevo_secreto

También podemos borrar o cambiar contraseñas (o ficheros contraseña) existentes:

## Para borrar un "slot" tenemos dos opciones:
## Teclear (o especificar el fichero contraseña
## después del nombre de dispositivo)
$ cryptsetup luksRemoveKey /dev/sdc
$ cryptsetup luksRemoveKey /dev/sdc /etc/secreto_a_eliminar

## O si no tenemos/recordamos la contraseña, especificar
## el slot que queremos eliminar (nos pedirá alguna de las
## contraseñas (o ficheros contraseña con --key-file)
## restantes en otro slot
$ cryptsetup luksKillSlot /dev/sdc 2
$ cryptsetup --key-file /etc/secreto_valido /dev/sdc 2

Copia de seguridad

El punto más débil de nuestro dispositivo cifrado es la cabecera LUKS. Sin ésta sería imposible acceder a los datos que contiene. Es recomendable por tanto, realizar una copia de seguridad de ella que nos permita acceder a los datos cifrados en el caso de que la cabecera LUKS quede dañada (por error en su gestión, o daño físico en el dispositivo de almacenamiento).

## Podemos sacar una copia de la cabecera con el siguiente comando
$ cryptsetup luksHeaderBackup /dev/sdc --header-backup-file cabecera_backup
## O restaurar una cabecera dañada desde un backup
$ cryptsetup luksHeaderRestore /dev/sdc --header-backup-file cabecera_backup

No metas cosas en criptas, cogen humedad

Cada vez que alguien dice «encriptar» o «encriptado» Dios mata un gatito. FYI.

$ exit

LVM para torpes (III). Ampliando espacio.

¿Así que ya tienes LVM funcionando? ¿Y seguiste mi recomendación de dejar todo el espacio posible en el VG y tus LVs están justitos de espacio? ¿O te has quedado sin espacio en el VG? En este post veremos como ampliar el espacio disponible en los diferentes componentes del LVM.

Ampliar un PV

Aunque no es corriente que un dispositivo «físico» de almacenamiento pueda crecer, este caso se puede dar cuando se trata de una máquina virtualizada, en la que podríamos aumentar el tamaño su disco, o en una máquina en la que ampliemos una partición tradicional, o un RAID, usada como PV. Esta operación (la ampliación del PV), como las que siguen, se puede realizar sin problemas con todo el sistema corriendo, sin tener que parar ningún servicio o desmontar sistema de ficheros. Lo que se denomina «en caliente». Simplemente hay que indicarle al LVM que «estire» el tamaño del PV, hasta su nuevo tamaño completo, con el comando «pvresize DISPOSITIVO«. Veamos un ejemplo:

## Originalmente el PV tenía 400MB
# pvs
 PV VG Fmt Attr PSize PFree 
 /dev/vda3 multimedia lvm2 a-- 396.00m 356.00m
## Se amplia la partición a 500MB y se ejecuta pvresize
# pvresize /dev/vda3
 Physical volume "/dev/vda3" changed
 1 physical volume(s) resized / 0 physical volume(s) not resized
# pvs
 PV VG Fmt Attr PSize PFree 
 /dev/vda3 multimedia lvm2 a-- 496.00m 456.00m
## Ya tenemos 100MB más en el PV y por tanto en el VG

Ampliar un VG

Cuando nuestros LVs han consumido todo el espacio del VG no podremos seguir creciendo éstos cuando lo necesitemos. Para solventar esta situación podemos ampliar el VG añadiendo un PV nuevo. El comando vgextend es muy similar al de creación (vgcreate), simplemente hay que indicar el nombre del VG a ampliar y el (o los) PV(s) nuevo(s) a añadir:

## Inicialmente el VG multimedia tiene 50MB libres y 1 PV
# vgs
 VG #PV #LV #SN Attr VSize VFree 
 multimedia 1 1 0 wz--n- 496.00m 50.00m
## Recuerda "marcar" el dispositivo como PV primero
# pvcreate /dev/vda5
 Writing physical volume data to disk "/dev/vda5"
 Physical volume "/dev/vda5" successfully created
## Añadimos el nuevo PV al VG
# vgextend multimedia /dev/vda5
 Volume group "multimedia" successfully extended
## Ahora nuestro VG tiene 150MB libres y 2 PVs
# vgs
 VG #PV #LV #SN Attr VSize VFree 
 multimedia 2 1 0 wz--n- 592.00m 150.00m

Comentar que lo ideal es que los PVs que pertenezcan al VG tengan características de redundancia y velocidad similares. Si bien es verdad que a la hora de crear LVs podemos elegir de que PV podemos sacar su espacio, si no prestamos atención a esta posibilidad el LVM irá asignando espacio de los PVs según crea conveniente y podríamos acabar con parte de un LV sobre un PV con RAID y otra parte en otro PV sin él. No tendría mucho sentido. Lo mismo que si un PV es muy rápido y otro es lento. Esto no quiere decir que no podamos tener PVs completamente diferentes en un VG, y que podamos usarlos de forma selectiva. Por ejemplo un PV puede ser un RAID y sobre él tener un LV importante, y otro PV puede ser un disco simple que nos permita crear un snapshot del LV principal, quitando esta «carga» temporal del RAID.

Ampliar un LV

El caso más frecuente de ampliación que se nos presentará será el de ampliación de un Volumen Lógico. Si seguiste mi recomendación de no dar espacio en vano a los LVs, es decir dejando la mayor parte de espacio libre en el VG, cuando el espacio usado en el LV vaya creciendo tendremos que ir ampliando el LV. Gracias a que esta operación se realiza «en caliente» no supone ningún inconveniente realizarla en cualquier momento.

Podemos usar dos comandos para realizar esta tarea: lvextend y lvresize. Si bien la sintaxis de ambos es prácticamente idéntica, suelo usar lvextend que sólo amplia, evitando posibles errores con lvresize que acabaran en el LV más pequeño (y el sistema de ficheros jodido, digo… dañado). En ambos casos daremos el nombre del LV (/dev/NOMBRE_VG/NOMBRE_LV) como argumento y usaremos la opción -L para indicar el tamaño nuevo. Como argumento de la opción -L podemos usar el tamaño final (por ejemplo -L2G, para un tamaño final de 2G) o la cantidad que deseamos ampliar, poniendo un «+» delante de ésta (por ejemplo -L+1G, para ampliar un giga). Veamos un ejemplo:

## Nuestro LV tiene 40MB actualmente
# lvs
 LV VG Attr LSize Pool Origin Data% Move Log Copy% Convert
 musica multimedia -wi-ao-- 40.00m
## Pedimos una ampliación de 10MB
# lvextend -L+10M /dev/multimedia/musica 
 Rounding up size to full physical extent 12.00 MiB
 Extending logical volume musica to 52.00 MiB
 Logical volume musica successfully resized
## Como el tamaño de las extensiones físicas es de 4MB,
## el LVM ampliará 12MB (3 PEs) en vez de los 10M solicitados.
## El resultado final, 52MB
# lvs
 LV VG Attr LSize Pool Origin Data% Move Log Copy% Convert
 musica multimedia -wi-ao-- 52.00m

Aquí no acaba la tarea. Una vez ampliado el LV debemos ampliar el sistema de ficheros (si es que estamos usando el LV para un sistema de ficheros). Si nos fijamos, aunque hemos ampliado el LV, el espacio disponible en el sistema de ficheros siguen siendo los 40MB originales:

# df -h /mnt/
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/multimedia-musica 39M 4.5M 33M 13% /mnt

En función del sistema de ficheros debemos usar un comando u otro:

## Para XFS
## xfs_growfs LV 
## o
## xfs_growfs PM (PM -> Punto de Montaje, p.e. /mnt)
##
## Para reiserfs
## resize_reiserfs LV
## o
## resize_reiserfs PM
##
## Para ext3/ext4
## resize2fs LV
## En nuestro caso:
# resize2fs /dev/multimedia/musica 
resize2fs 1.42.5 (29-Jul-2012)
Filesystem at /dev/multimedia/musica is mounted on /mnt; on-line resizing required
old_desc_blocks = 1, new_desc_blocks = 1
Performing an on-line resize of /dev/multimedia/musica to 53248 (1k) blocks.
The filesystem on /dev/multimedia/musica is now 53248 blocks long
## Ahora ya tenemos los 52MB disponibles en el sistema de ficheros
# df -h /mnt/
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/multimedia-musica 51M 4.7M 43M 10% /mnt

Como se puede observar en el ejemplo anterior, el sistema de ficheros está en todo momento montado y en uso. No hay escusa para dar espacio de más a un LV y dejar «seco» el VG, impidiendo usar el espacio libre para cualquier necesidad futura, como los snapshots que veremos en un futuro post.

$ exit

LVM para torpes (II)

Si mis dibujos no te dejaron muy claro los conceptos básicos del LVM no te preocupes, ahora lo explicaré desde el principio con los comandos de gestión del LVM. Seguro que quedará más claro.

Empezar de cero a montar LVM en un sistema ya en marcha no es lo más común, ya que lo ideal es hacerlo en el momento de la instalación, pudiendo así incluir todos los discos por completo. Casi todas las distribuciones permiten hacerlo automáticamente, aunque el resultado final no suele ser ideal (ver Consideraciones finales). Cuando comprendas el funcionamiento podrás usar el instalador de tu distribución para crear una estructura LVM personalizada que tenga más sentido que la que propone el instalador sin preguntar.

Entregando dispotivos de almacenamiento al LVM (PV)

El primer paso para usar LVM es decidir que dispositivos de almacenamiento queremos usar. Pueden ser discos, dispositivos RAID por software, particiones, etc. Lo más importante en este paso es que al LVM le daremos el dispositivo para que lo gestione y, salvo raras excepciones, no volveremos a tocar el dispositivo directamente. Nada de darle una partición al LVM y luego crear un sistema de ficheros en ella. Dicho de otra forma, no le toques los PVs al LVM.

La forma de entregar un dispositivo al LVM es marcarlo como un Physical Volumen (PV). Cuando vayas a crear un PV asume que la información que contenga hasta ese momento ya no es tuya, dala por perdida. Así que cuidado con equivocarse con el nombre del dispositivo en el comando pvcreate. Este comando básicamente indica que desde su ejecución el dispositivo indicado como argumento pasa a ser de dominio del LVM. Ejemplos:

# Estos comando deben ser ejecutados con el usuario root
# Normanlment los usuarios no pueden jugar con los discos :-)
# Marcar el primer disco, por completo, como PV
pvcreate /dev/sda
# Marcar varias particiones como PV
pvcreate /dev/sda3 /dev/sdb1 /dev/sdc1
# Marcar un dispositivo RAID por software como PV
pvcreate /dev/md0

Una vez «marcado» un dispositivo como PV, podemos ver información del mismo con los comandos «pvs» y «pvdisplay«:

# pvcreate /dev/vda3
 Writing physical volume data to disk "/dev/vda3"
 Physical volume "/dev/vda3" successfully created
# pvs
 PV VG Fmt Attr PSize PFree 
 /dev/vda3 lvm2 a-- 400.00m 400.00m
# pvdisplay /dev/vda3
 "/dev/vda3" is a new physical volume of "400.00 MiB"
 --- NEW Physical volume ---
 PV Name /dev/vda3
 VG Name 
 PV Size 400.00 MiB
 Allocatable NO
 PE Size 0 
 Total PE 0
 Free PE 0
 Allocated PE 0
 PV UUID q2noaK-2apE-kkGe-MnNA-IzuE-ICDY-3MiKns

En este ejemplo cabe destacar el tamaño del PV, /dev/vda3, 400M, que están por completo libres y que en la columna «VG» (del comando «pvs«) o la fila «VG Name» (en «pvdisplay«) no hay ningún valor. Es decir, el PV está a disposición del LVM pero no pertenece a ningún VG, por lo que por ahora no podemos usarlo (Allocatable NO). Por ahora no entraré en la definición de PE, no quiero meter más conceptos y no es necesario a estas alturas.

Creando un Grupo de Volúmenes (VG)

Como comenté en la entrada anterior, un VG es una especie de disco duro virtual. Su tamaño viene dado por la suma del espacio de los PVs que lo componen. Y es del espacio disponible en el VG de donde crearemos los Volúmenes Lógicos (LVs, algo similar a las particiones). Son los LVs los que finalmente usaremos para crear sistemas de ficheros, espacio para swap, discos para máquinas virtuales, etc.

El comando de creación de un VG es extremadamente sencillo. Simplemente le daremos como primer argumento el nombre del VG que estamos creado y a continuación el/los dispositivo(s) (marcados como PVs previamente) que queremos que lo compongan:

# Creando un vg llamado "multimedia" con un PV
vgcreate multimedia /dev/vda3
  Volume group "multimedia" successfully created
# Creando un vg con más de un PV
vgcreate produccion /dev/sdb /dev/sdc /dev/sdd
  Volume group "produccion" successfully created

Importante en este punto es dar un nombre identificativo al VG. Una de las ventajas del LVM es que vamos a poder dar nombre significativos a nuestro almacenamiento. No pierdas esta ventaja llamando a los VGs algo como «vg00». Yo tengo VGs llamandos «raid» y «sinraid» en máquinas que tienen parte de los discos en RAID y otra parte no. Ese nombre me permite, a la hora de crear un LV, saber si mis datos estarán protegidos (y/o acelerados) por el RAID o están en un simple disco. Tengo máquinas que tiene un VG llamado «interno» (formado por los discos físicamente dentro de la máquina) y otro llamado «cabina», porque sus discos están en una cabina externa. Igualmente podríamos tener «producción» y «desarrollo», o «sistema» y «datos». Para gustos los colores, pero aprovecha el poder elegir el nombre 🙂 Huelga decir que es mejor evitar símbolos especiales (como espacios), acentos, eñes y esas cosas que podrían dar problemas en nombres de dispositivos.

Una vez creado el VG podemos ver información del mismo con los comandos «vgs» y «vgdisplay«:

# vgs
 VG #PV #LV #SN Attr VSize VFree 
 multimedia 1 0 0 wz--n- 396.00m 396.00m

# vgdisplay
 --- Volume group ---
 VG Name multimedia
 System ID 
 Format lvm2
 Metadata Areas 1
 Metadata Sequence No 1
 VG Access read/write
 VG Status resizable
 MAX LV 0
 Cur LV 0
 Open LV 0
 Max PV 0
 Cur PV 1
 Act PV 1
 VG Size 396.00 MiB
 PE Size 4.00 MiB
 Total PE 99
 Alloc PE / Size 0 / 0 
 Free PE / Size 99 / 396.00 MiB
 VG UUID xuYff2-maw7-0ldW-PiLv-xZ6F-NFa3-3gNPod

Con estos comandos podemos comprobar que nuestro VG se llama «multimedia», está compuesto de un PV, todavía no tiene ningún LV creado y dispone de 396MB libres. Las Physical Extensions (PE) son las unidades de asignación mínima del LVM. Por defecto son de 4MB (aunque se puede cambiar en la creación del VG). Es decir, cada vez que creemos un LV lo haremos en múltiplos de (por defecto) 4MB. Pero esto no es algo que os deba preocupar por ahora.

A por el producto final, Volúmenes Lógicos (LV)

Una vez tenemos un VG ya podemos crear los dispositivos que realmente usaremos. Los volúmenes lógicos (LV) pertenecen a un VG, del que toman su espacio. Pueden crearse, borrarse y crecer sin necesidad de reiniciar la máquina o parar servicios (bueno, para borrarlos hay que dejar de usarlos primero, obvio).

Un LV puede usar espacio de un solo PV, o de varios. En este último caso puede deberse a que vaya creciendo con el tiempo, y ya no quede espacio en el PV original, o que al crearlo hemos decidido que use varios PVs (por motivos de rendimiento, por ejemplo). Pero esto lo veremos en próximas entradas del blog. Por ahora nos centraremos en la creación de un LV simple.

Para crear un LV, con el comando lvcreate, debemos indicarle el VG al que pertenece (como argumento del comando), el tamaño (en PEs con la opción -l o en megas/gigas/teras con -L) y optionalmente, pero muy recomendable, el nombre que queremos darle (-n). Emplos:

# Un LV de 40MB en el VG multimedia para guardar música
lvcreate -L 40M -n musica multimedia

# O especificando el número de PEs (de 4MB por defecto)
lvcreate -l 10 -n musica multimedia

Una vez más, aprovecha para darle un nombre representativo del contenido que habrá en él. Desde este momento la forma de referirse al LV (para crear el sistema de ficheros, montarlo, o cualquier uso que le vayamos a dar) será: /dev/NOMBRE_DEL_VG/NOMBRE_DEL_LV. En este ejemplo: /dev/multimedia/musica. En realidad ese nombre es un enlace al dispositivo creado por el subsistema del kernel encargado del LVM, el Device Mapper. El nombre del dispositivo real puede variar y será del tipo /dev/dm-##. Por eso es importante usar /dev/VG/LV, que siempre apuntará al dispositivo real correcto. También podemos encontrarnos referencias en el sistema al LV como /dev/mapper/multimedia-musica, es decir /dev/mapper/VG-LV. Mi recomendación es que uses siempre /dev/VG/LV y así no hay líos 🙂

Al igual que en los pasos anteriores, podemos ver información sobre el LV creado con los comandos «lvs» y «lvdisplay«:

# lvs
 LV VG Attr LSize Pool Origin Data% Move Log Copy% Convert
 musica multimedia -wi-a--- 40.00m

# lvdisplay -m
 --- Logical volume ---
 LV Path /dev/multimedia/musica
 LV Name musica
 VG Name multimedia
 LV UUID KTtf7H-z5kt-68f6-8B8r-cNk0-OUBa-2cRFfe
 LV Write Access read/write
 LV Creation host, time curso, 2014-10-30 18:35:31 +0100
 LV Status available
 # open 0
 LV Size 40.00 MiB
 Current LE 10
 Segments 1
 Allocation inherit
 Read ahead sectors auto
 - currently set to 256
 Block device 253:0

 --- Segments ---
 Logical extent 0 to 9:
 Type linear
 Physical volume /dev/vda3
 Physical extents 0 to 9

Podemos ver el tamaño de nuestro LV (en megas o en LEs), el nombre que tiene, el VG al que pertenece, y si en «lvdisplay» añadimos la opción «-m» veremos en donde se encuentra localizado físicamente el LV (que PV(s) a usado el LVM para obtener el espacio del LV, destacado en negrita en el ejemplo anterior).

Ya está listo para usar. Podemos crear un sistema de ficheros en él y montarlo como cualquier otro dispositivo de almacenamiento:

# mkfs.ext4 /dev/multimedia/musica 
mke2fs 1.42.5 (29-Jul-2012)
....
# mount /dev/multimedia/musica /media/
# df /media/
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/mapper/multimedia-musica 39663 4587 33028 13% /media

Consideraciones finales

Algo que considero fundamental para poder aprovechar plenamente la flexibilidad del LVM es mantener el máximo de espacio libre en el VG. Es decir, no dar espacio «a lo loco» a los LVs antes de que éstos lo necesiten. Me mata ver como en una intalación nueva todo el espacio del VG es asignado a uno o varios LVs que apenas usan dicho espacio. De nada sirve tener gigas y gigas de espacio libre en un LV. Y un VG sin espacio sin asignar tampoco sirve para mucho (al menos hasta que se aumente con un PV nuevo). Todo espacio libre que pueda estar en el VG nos va a permitir crecer los LVs que lo necesiten o crear LVs nuevos (aunque sólo los necesitemos temporalmente). Si tenemos un VG de 1T y hoy sólo necesitamos un LV que contendrá 100G de información, no le des mucho más (tal vez 150G o 200G), pero deja el resto en el VG para cuando sea necesario. Crecer un LV es sencillo y no causa interrupciones en el servicio, encojerlo es otra historia…

$ exit