Políticas de contraseñas en Fedora 25

Fedora server
A menudo usamos nuestro sistema Linux con configuraciones estándar en nuestras máquinas de escritorio… y en nuestros servidores. Los usuarios usan una única cuenta para administrar las máquinas, usan claves rsa sin encriptar, dichas claves rsa están en sus máquinas en discos no encriptados, no usan contraseña para loguearse, no se bloquea la cuenta por inactividad, y un largo etcétera que no quiero ni enumerar, me da mucho miedo sólo el pensarlo.

Después de éste pequeño repaso a muchos peligros que algunos de nosotros tenemos alrededor, vamos a centrarnos. Concretamente en servidores montados con Fedora 25 que es de los últimos que he tenido que configurar con unas políticas de seguridad y acceso marcadas por una compañía.

El manejo de políticas de autenticación a través de Pluggable Authentication Modules (PAM) que en su versión de Fedora 25 ha dejado de usar /etc/pam.conf por el directorio /etc/pam.d/ no está muy bien documentado, sobretodo en lo referente a qué hace cada parámetro y cómo lo podemos usar.

Para nuestro caso, cambiaremos la configuración para poder limitar intentos de password, longitud mínima, complejidad de la contraseña (3 de estas cuatro características: mayúsculas, minúsculas, números y símbolos), evitar nombre de usuario en la contraseña, revisar diccionario para no usar como contraseña cadenas ahí incluidas o forzar la política para todos los usuarios, incluido root.

Pasamos a revisar el fichero que nos interesa para realizar todos estos cambios /etc/pam.d/system-auth

#%PAM-1.0
# This file is auto-generated.
# User changes will be destroyed the next time authconfig is run.
auth        required      pam_env.so
auth        sufficient    pam_unix.so nullok try_first_pass
auth        requisite     pam_succeed_if.so uid >= 1000 quiet_success
auth        required      pam_deny.so

account     required      pam_unix.so
account     sufficient    pam_localuser.so
account     sufficient    pam_succeed_if.so uid < 1000 quiet
account     required      pam_permit.so

password    requisite     pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type=
password    sufficient    pam_unix.so sha512 shadow nullok try_first_pass use_authtok
password    required      pam_deny.so

session     optional      pam_keyinit.so revoke
session     required      pam_limits.so
-session     optional      pam_systemd.so
session     [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid
session     required      pam_unix.so

pam_pwquality.so es un módulo para comprobar la calidad de las contraseñas. Hay otros, como pam_cracklib o pam_passwdqc que se podrían usar en sustitución de pam_pwquality.so. Cada uno tiene sus características. La carga de uno u otro módulo se define en el fichero /etc/sysconfig/authconfig.

Nos va a interesar de pam_pwquality.so:

debug: al usar este parámetro se muestra el funcionamiento del módulo en el log del sistema
retry=3: número de intentos para introducir la cadena.
minlen=15: longitud mínima que debe usarse.
minclass=3: al menos 3 de cuatro características deben cumplirse (mayúsculas, minúsculas, símbolos y números)
reject_username: al activarlo impedimos usar la cadena nombre de usuario como parte de la contraseña tanto en orden natural como inverso.
gecoscheck=1: impedir el uso de cadenas del campo GECOS (normalmente nombre de usuario largo).
enforce_for_root: hacer que la directiva también se use con "root".

Además, este módulo carga el diccionario que tenga de manera estándar el sistema. Yo no pude hacer cargar el mío propio, pero sí pude añadir las palabra que me interesaban al que usa de manera predeterminada el sistema, de la siguiente manera:

create-cracklib-dict <fichero de texto con las cadenas> 

Finalmente la configuración quedaría como:

#%PAM-1.0
# This file is auto-generated.
# User changes will be destroyed the next time authconfig is run.
auth        required      pam_env.so
auth        sufficient    pam_unix.so nullok try_first_pass
auth        requisite     pam_succeed_if.so uid >= 1000 quiet_success
auth        required      pam_deny.so

account     required      pam_unix.so
account     sufficient    pam_localuser.so
account     sufficient    pam_succeed_if.so uid < 1000 quiet
account     required      pam_permit.so

password    requisite     pam_pwquality.so debug retry=3 minlen=15 minclass=3 reject_username gecoscheck=1 enforce_for_root
password    sufficient    pam_unix.so sha512 shadow nullok try_first_pass use_authtok
password    required      pam_deny.so

session     optional      pam_keyinit.so revoke
session     required      pam_limits.so
-session     optional      pam_systemd.so
session     [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid
session     required      pam_unix.so

Y recargamos la configuración con:


authconfig --updateall

.

CasperJS la aspiradora de datos

Aspiradora Roja

Foto: “a vacuum cleaner” by Taz Creative Commons Attribution License

Durante nuestro día a día nos encontraremos muchas veces webs con contenido importante, datos muy interesantes, que se actualizan con frecuencia y cuyos datos necesitamos para nuestro proyecto jhlspx3. Pero al ir a usar algún servicio que proporcione dicha web para acceder a los datos o descargarlos, nos daremos cuenta de que no existe ningún tipo de servicio de fácil acceso a la información o simplemente el servicio de publicación tiene un coste o complejidad que nos impide usarlo.

Si estás en esa necesidad: los datos son muy importantes para el proyecto y no puedo acceder a ellos de ninguna otra manera salvo “a mano” debes plantearte hacer uso de CasperJS.

CasperJS es un lenguaje de scripting basado en Javascript. Aporta un nivel de abstracción sobre PhantomJs. Por lo tanto, es un lenguaje usado para navegar por la web sin un entorno visual, realizar revisiones de aplicaciones online, monitorizar, capturar pantallas o automatizar acciones en cualquier página.

Ésta última característica es la que más nos interesa, ya que queremos extraer información. Mediante selectores CSS3 o XPath navegaremos hasta el contenido que nos interesa, podremos acceder a la información que contienen los elementos seleccionados y realizar acciones sobre ellos.

Las acciones más interesantes suelen ser: hacer “click” en un botón o enlace, rellenar formularios o revisar valores de tablas. La toma de decisiones en función de los resultados, el manejo de errores, los eventos, son otras de sus características.

La instalación es muy sencilla: si tienes npm instalado en tu sistema, mediante los siguientes comandos:

npm -g install phantomjs
npm -g install casperjs

Ya tendrías tu entorno preparado para trabajar.

Aquí se puede ver cómo usarlo para guardar en un array y mostrar todos los enlaces de una búsqueda:

var casper = require('casper').create();
var links;

function getLinks() {
// Rastreo de links
    var links = document.querySelectorAll('ul.navigation li a');
    return Array.prototype.map.call(links, function (e) {
        return e.getAttribute('href')
    });
}

// Abre casperjs 
casper.start('http://casperjs.org/');

casper.then(function () {
    links = this.evaluate(getLinks);
});

casper.run(function () {
    for(var i in links) {
        console.log(links[i]);
    }
    casper.done();
});

El resultado sería:

$ casperjs query-casperjs.js
http://docs.casperjs.org/en/latest/quickstart.html
http://docs.casperjs.org/en/latest/
https://github.com/casperjs/casperjs
https://groups.google.com/forum/#!forum/casperjs

Por lo tanto, CasperJS es una herramienta muy potente, para muchos de nuestros proyectos. No es sencilla o rápida de programar, pero nos permitirá automatizar o ayudar en muchas tareas.

Copiar Máquinas virtuales Azure entre suscripciones

Migrate

Es muy normal y útil tener alguna cuenta demo de Microsoft Azure, que te permite usar tu suscripción durante unos meses y tomar contacto con su plataforma. Empiezas a seguir tutoriales, crear servicios, máquinas pero en algún momento posiblemente quieras migrar o copiar las máquinas a otro entorno, por ejemplo, para poner en producción.

Empiezan los problemas, ¿ cómo migro todo a otra cuenta? Si lo que quieres es ceder tu cuenta a otra persona o entidad, no hay ningún problema, ya que puedes ponerte en contacto con Microsoft y ellos la “fusionan”. Pero y si sólo quiero copiar “alguna de mis máquinas virtuales”, no te preocupes, es una tarea un poco más engorrosa, pero se puede realizar.

El primer obstáculo es tener PowerShell para Azure. Si usas Linux, tienes que buscar un SO de Microsoft que soporte PowerShell. No vale el windows 98 que tenías cuando eras adolescente… Gasta algo de dinero, compra una licencia y ponte una máquina virtual sobre tu Linux, por ejemplo.

Hay varios tutoriales paso a paso, con los comandos que debes usar, como éste pero hay varias cosas que no funcionan correctamente… pasemos a explicarlas.

Lo primero, acceso a tu cuenta de origen y de destino:

Add-AzureAccount

Y selección de la cuenta que ahora vamos a usar, primero la de origen, para eso:

Get-AzureSubscription

Aquí toma nota del

SubscriptionName

que tienen las cuentas que vas a usar, pues tienes que “activarla” para ejecutar los comandos. Se activa con:

Select-AzureSubscription -Current -SubscriptionName elnombredetusubscripcion
Get-AzureVM

Si todo ha ido bien, ya has podido listar todas tus VM y localizar la que te interesa, ahora empieza lo bueno.
Siguiendo el tutorial que enlazamos más arriba tendrías que crear las siguientes variables:

$vmName = "EL_NOMBRE_DE_TU_VM"
$serviceName = "EL_NOMBRE_DE_TU_CLOUD_SERVICE"
$destServiceName = "EL_NOMBRE_DEL_NUEVO_CLOUD_SERVICE"
$workingDir = (Get-Location).Path

Con la última

$workingDir = (Get-Location).Path

puedes tener problemas, ya que la localización que te crea puede que no permita escribir y luego no vas a poder exportar correctamente la VM. Te recomiendo algo como:

$workingDir= "C:\ExportVMs"
if (!(Test-Path -Path $workingDir)) {

New-Item -Path $workingDir -ItemType Directory

}

Continuamos con:

$sourceVm = Get-AzureVM –ServiceName $serviceName –Name $vmName
$vmConfigurationPath = $workingDir + "\" + $vm.Name + ".xml"
$sourceVm | Export-AzureVM -Path $vmConfigurationPath
$sourceOSDisk = $sourceVm.VM.OSVirtualHardDisk
$sourceDataDisks = $sourceVm.VM. DataVirtualHardDisks

Para obtener la cuenta de almacenamiento de tu VM:

$sourceStorageName = $sourceOSDisk.MediaLink.Host -split "\." | select -First 1
$sourceStorageAccount = Get-AzureStorageAccount –StorageAccountName $sourceStorageName
$sourceStorageKey = (Get-AzureStorageKey -StorageAccountName $sourceStorageName).Primary

Asegúrate de apagar la máquina virtual:

Stop-AzureVM –ServiceName $serviceName –Name $vmName -Force

Ya vamos a proceder a copia la VM, y necesitamos cambiar de suscripción de Azure:

Select-AzureSubscription -SubscriptionName elnombredetusubscripcionnueva

Ubicación de la cuenta de almacenamiento. Suponemos que la copiamos a la misma región pero en diferente suscripción:

$location = $sourceStorageAccount.Location

Creamos una nueva cuenta de almacenamiento en la nueva suscripción:

$destStorageAccount = Get-AzureStorageAccount | ? {$_.Location -eq $location} | select -first 1
if ($destStorageAccount -eq $null)
{
$destStorageName = nuevacuentadealmacenamiento
New-AzureStorageAccount -StorageAccountName $destStorageName -Location $location
$destStorageAccount = Get-AzureStorageAccount -StorageAccountName $destStorageName
}

$destStorageName = $destStorageAccount.StorageAccountName
$destStorageKey = (Get-AzureStorageKey -StorageAccountName $destStorageName).Primary

Y todas las nuevas variables necesarias para los siguientes pasos:

$sourceContext = New-AzureStorageContext –StorageAccountName $sourceStorageName -StorageAccountKey $sourceStorageKey

$destContext = New-AzureStorageContext –StorageAccountName $destStorageName -StorageAccountKey $destStorageKey

Verificaciones:

if ((Get-AzureStorageContainer -Context $destContext -Name vhds -ErrorAction SilentlyContinue) -eq $null)

{

New-AzureStorageContainer -Context $destContext -Name vhds

}

Ya va quedando menos, nos disponemos a copiar:

$allDisks = @($sourceOSDisk) + $sourceDataDisks
$destDataDisks = @()
foreach($disk in $allDisks)
{
$blobName = $disk.MediaLink.Segments[2]
$targetBlob = Start-CopyAzureStorageBlob -SrcContainer vhds -SrcBlob $blobName -DestContainer vhds -DestBlob $blobName -Context $sourceContext -DestContext $destContext -Force
Write-Host "Copying blob $blobName"
$copyState = $targetBlob | Get-AzureStorageBlobCopyState

while ($copyState.Status -ne "Success")
{
$percent = ($copyState.BytesCopied / $copyState generic seroquel.TotalBytes) * 100
Write-Host "Completed $('{0:N2}' -f $percent)%"
sleep -Seconds 5
$copyState = $targetBlob | Get-AzureStorageBlobCopyState
}

If ($disk -eq $sourceOSDisk)
{
$destOSDisk = $targetBlob
}
Else
{
$destDataDisks += $targetBlob
}

}

Registramos los nuevos discos duros, para que sean correctamente reconocidos en la nueva suscripción:

Add-AzureDisk -OS $sourceOSDisk.OS -DiskName $sourceOSDisk.DiskName -MediaLocation $destOSDisk.ICloudBlob.Uri
foreach($currenDataDisk in $destDataDisks)
{
$diskName = ($sourceDataDisks | ? {$_.MediaLink.Segments[2] -eq $currenDataDisk.Name}).DiskName
Add-AzureDisk -DiskName $diskName -MediaLocation $currenDataDisk.ICloudBlob.Uri
}

Y finalmente, creamos la nueva VM. Mucho cuidado, porque puede dar problemas:

Get-AzureSubscription -Current | Set-AzureSubscription -CurrentStorageAccountName $destStorageName
$vmConfig = Import-AzureVM -Path $vmConfigurationPath

Tal vez tengas que haber creado una red antes, si la VM la tenía, retocar el fichero XML para que no use IPs fijas, etc. Todo depende de lo sencilla o compleja que era tu VM de origen.

 

¡¡¡¡Suerte con las migraciones!!!!

Hazte anónimo en la red

2306206890_feda251e65_zHace unos meses intenté crear algo que permitiese compartir ficheros multimedia de alguna manera sencilla. Buscando un poco rápidamente encontré un proyecto muy interesante Pirate Box. Dicho proyecto se basa en crear una red inalámbrica sin conexión a internet mediante la cual los usuarios puedan compartir sus propios ficheros. Imagínate un aula, una biblioteca, un espacio de trabajo en el cual la gente pueda compartir documentos, vídeos, fotos sin tener que depender de servicios de terceros ni compartir el mismo tiempo. Conceptualmente me gustó y lo probé, lo probamos, pero el concepto tiene que enganchar y el entorno no era el más adecuado: viernes por la mañana, primera hora, todo el mundo dormido en la oficina… nadie tenía casi nada que compartir con los demás y no era necesario. Técnicamente, lo que hace el desarrollador es modificar un firmware Open Source para routers wifi, creando una interfaz web de subida de ficheros, un chat y poco más. En cualquier caso, la sencillez de uso y en un buen entorno lo veo útil.

Como no paro de enredar, encontré otro proyecto muy interesante para crear una conexión VPN/Tor sencilla, mediante un dispositivo hardware, una Raspberry Pi al que te conectas via wifi y que permite proteger tu navegación. Dicho dispositivo se conecta a internet, securiza la conexión y crea un punto de acceso para tus dispositivos. Si viajas y te conectas a redes de hoteles o cafeterías, o simplemente quieres navegar de forma anónima o desde otro país (vease, quieres usar Netflix) esta configuración de tu Raspberry Pi te ayudará a hacer de una forma más segura y anónima.

Ataque de denegación de servicio en Feedly. DDOS to Feedly

Los usuarios de Feedly llevamos ya más de 8 horas sin poder acceder al servicio. Bien es cierto que es gratuito y que en su blog nos informan del ataque, del chantaje al que están siendo sometidos y de los cambios que están haciendo para restaurar el servicio, pero me parece poco previsor no ser capaces de restaurar el servicio con algún plan de contingencia en las horas que llevan trabajando en ello. O realmente se está diciendo que tienen un DDOS cuando en realidad está pasando otra cosa.

Mientras tanto, hoy no podré leer mis RSS diarios. Una pena. Aprovecharé para dormir más.

Discos de alto rendimiento en Microsoft Azure

El rendimiento de discos montados en las máquinas virtuales sobre Microsoft Azure tiene unas características limitadas de escritura. En el caso de máquinas virtuales Linux sobre Microsoft Azure, la solución pasa por crear una infraestructura de escritura distribuida en discos o striping de discos.

Básicamente, el sistema se basa en crear un RAID 0 sobre los discos montados en el sistema, que tienen la seguridad y estabilidad de la triple escritura para cada uno de ellos. Por lo tanto, los posibles problemas de perdidas de datos queda anulada por la propia infraestructura de Azure.

Dicho esto, nos disponemos a comprobar el rendimiento habitual de un disco sobre Microsoft Azure:

root@euclides:~# dd if=/dev/zero of=/mnt/datadrive/test.out bs=4k count=402400
402400+0 registros leídos
402400+0 registros escritos
1648230400 bytes (1,6 GB) copiados, 24,3726 s, 67,6 MB/s
root@euclides:~# dd if=/dev/zero of=/mnt/datadrive/test.out bs=8k count=202400
202400+0 registros leídos
202400+0 registros escritos
1658060800 bytes (1,7 GB) copiados, 24,3694 s, 68,0 MB/s
root@euclides:~# dd if=/dev/zero of=/mnt/datadrive/test.out bs=16k count=101200
101200+0 registros leídos
101200+0 registros escritos
1658060800 bytes (1,7 GB) copiados, 24,5432 s, 67,6 MB/s
root@euclides:~# dd if=/dev/zero of=/mnt/datadrive/test2.out bs=16k count=101200
101200+0 registros leídos
101200+0 registros escritos
1658060800 bytes (1,7 GB) copiados, 23,7428 s, 69,8 MB/s

Como se aprecia en los test del ejemplo, la escritura nunca supera los 70 MB/s

Ahora, una vez añadidos ocho discos al sistema, vamos a proceder a crear la unidad distribuida de escritura con mdadm

mdadm --verbose --create /dev/md0 --level=0 --chunk=256 --raid-devices=8 /dev/sdc /dev/sdd /dev/sde /dev/sdf /dev/sdg /dev/sdh /dev/sdi /dev/sdj

Los mejores rendimientos se consiguen con –chunk=256

Una vez creada la unidad tenemos que darle formato:

mkfs.ext3 -b 4096 -E stripe-width=512,stride=64 /dev/md0

Los parámetros se calculan de la siguiente manera:

tamaño de chunk = 256k
tamaño de block = 4k
stride = chunk / block; 256 / 4 = 64
stripe-width = stride * nº discos de RAID 0; 64 * 8 = 512

Posteriormente realizamos el montaje en el directorio /RAID, que usaremos para realizar las pruebas de escritura con la nueva configuración:

root@copernico:~# dd if=/dev/zero of=/RAID/test.out bs=4k count=402400
402400+0 registros leídos
402400+0 registros escritos
1648230400 bytes (1,6 GB) copiados, 4,51627 s, 365 MB/s
root@copernico:~# dd if=/dev/zero of=/RAID/test.out bs=8k count=202400
202400+0 registros leídos
202400+0 registros escritos
1658060800 bytes (1,7 GB) copiados, 3,61523 s, 459 MB/s
root@copernico:~# dd if=/dev/zero of=/RAID/test2.out bs=16k count=101200
101200+0 registros leídos
101200+0 registros escritos
1658060800 bytes (1,7 GB) copiados, 3,82761 s, 433 MB/s

Se puede apreciar el aumento significativo en la velocidad de escritura, llegando a los 459MB/s.

Cabe destacar que de esta manera, añadiendo el número máximo de discos que permita el tamaño de nuestra máquina, podremos crear una gran unidad de varios terabytes de capacidad, ya que el límite de tamaño de 1023G que hay en los discos Azure queda multiplicado por el número de discos.

Sólo falta realizar la configuración en fstab para que la unidad creada con mdadm se monte automáticamente al arrancar el sistema y podremos hacer uso con normalidad de nuestro nuevo disco local de alto rendimiento.