Mostrando entradas con la etiqueta devops. Mostrar todas las entradas
Mostrando entradas con la etiqueta devops. Mostrar todas las entradas

miércoles, 20 de agosto de 2014

Capistrano y Monit

Últimamente me ha pasado un par de veces que al hacer una subida a producción, Capistrano y Monit no se llevan muy bien.

El problema es que en el deploy se reinician algunos servicios, como Sidekiq, y si coincide con el chequeo de Monit, se lanza otro reinicio, con el resultado de tener 2 Sidekiq arrancados en producción.

Tambien puede pasar que quieras parar algún servicio manualmente, por ejemplo Unicorn desde una tarea de Capistrano y Monit lo levante automáticamente.

Afortunadamente, la solución es simple, consiste en añadir unas tareas en Capistrano y dar permisos al usuario de la aplicación para ejecutar Monit.

Para ejecutar los comandos de Monit, se necesitan permisos de sudo, pero por seguridad, no queremos dar acceso sudo sin más. Tampoco interesa dar acceso a toda la funcionalidad de Monit, ya que se podría parar cualquier servicio monitorizado con Monit externo a la aplicación.

Así que solo daremos permiso para ver el estado de la monitorización (monit summary) y parar o iniciar la monitorización (monit monitor y monit unmonitor)

La forma de conseguirlo es tan simple como añadir un nuevo fichero /etc/sudoers.d/monit con esos permisos
my_user ALL = NOPASSWD: /usr/bin/monit summary, /usr/bin/monit unmonitor *, /usr/bin/monit monitor *
No le pedimos la contraseña al usuario para ejecutar estos comandos, ya que el usuario no tiene contraseña asignada (solo le permitimos acceder por medio de clave pública).

Y ese mismo fichero creado desde ansible

- name: Allow execute monit commands to users
  action: 'lineinfile dest=/etc/sudoers.d/monit state=present create=yes regexp="{{item}}" line="{{item}} ALL = NOPASSWD: /usr/bin/monit summary, /usr/bin/monit unmonitor *, /usr/bin/monit monitor *" validate="visudo -cf %s"'
  with_items:
    - my_user
Una vez que tenemos permisos, creamos un módulo de capistrano con las diferentes tareas a ejecutar en lib/capistrano/tasks


namespace :monit do
  desc 'Monit summary'
  task :summary do
    on roles :app do
      puts capture :sudo, :monit, :summary
    end
  end

  desc 'Monit unmonitor'
  task :unmonitor do
    on roles :app do
      puts capture :sudo, :monit, :unmonitor, :sidekiq
    end
  end

  desc 'Monit monitor'
  task :monitor do
    on roles :app do
      puts capture :sudo, :monit, :monitor, :sidekiq
    end
  end
end

Y invocamos esas tareas al empezar y al acabar el deploy

after 'deploy:starting',  'monit:unmonitor'
after 'deploy:finished',  'monit:monitor'
Además, la tarea summary permite al usuario monitorizar el estado del servidor desde línea de comandos
$ cap production monit summary
...
System 'teowaki.com'                Running
Process 'sidekiq'                   Running
Process 'sshd'                      Running
Filesystem 'rootfs'                 Accessible
...
Por último, comentar que la gema capistrano-sidekiq incluye algunas tareas similares, pero no me cuadraba su uso en mi caso, ya que me obliga a cambiar el nombre del servicio monitorizado.

miércoles, 28 de mayo de 2014

Bootstrap con Ansible

La semana pasada en el grupo DevOps de Madrid, hubo una magnífica charla introductoria de Maykel Moya sobre Ansible. Parte de lo que explico en este post lo contó con una demo en directo.

Estuve hablando con Javier Vidal sobre el tema y al día siguiente me comento en twitter



Y en lugar de compartirselo sólo a Javi, he creado esta entrada en el blog :)

Para ello, he separado el role de bootstraping de nuestra instalación de Teowaki en un proyecto independiente y lo he configurado con Vagrant, para poder probarlo en local sin problemas.

El proyecto está disponible en github.

Los pasos para probarlo son:

Instalar Vagrant en local (previamente debe estar instalado VirtualBox). He optado por instalarlo a partir del .deb en lugar de a partir de apt porque la opción apt me instalaba los paquetes de ruby 1.9, y ruby ya lo tengo instalado en local con RVM.

$ wget https://dl.bintray.com/mitchellh/vagrant/vagrant_1.6.2_x86_64.deb
$ sudo dpkg -i vagrant_1.6.2_x86_64.deb
$ vagrant -v
Vagrant 1.6.2
$ vagrant init ubuntu/trusty64
A `Vagrantfile` has been placed in this directory. You are now
ready to `vagrant up` your first virtual environment! Please read
the comments in the Vagrantfile as well as documentation on
`vagrantup.com` for more information on using Vagrant.

Una vez instalado, simplemente con vagrant up levantamos el servidor, que escucha por defecto por ssh en el puerto 2222 en localhost

Más información sobre la instalación en las páginas de Vagrant y Ansible.

El siguiente paso es configurar el servidor en Ansible, que es tan simple como definir en un fichero hosts los datos de conexión al servidor. En mi caso he definido un grupo de servidores 'development' que incluye al servidor dev

[development]
dev ansible_ssh_host=127.0.0.1 ansible_ssh_port=2222

Por otra parte configuro la conexión a vagrant en ansible.cfg, de forma que no hay que escribirla en cada conexión desde ansible

[defaults]
hostfile = hosts
private_key_file=~/.vagrant.d/insecure_private_key
remote_user = vagrant

Y probamos que la conexión al servidor desde ansible funciona

$ ansible dev -m ping
dev | success >> {
    "changed": false, 
    "ping": "pong"
}

Sin el fichero de configuración la instrucción habría sido:

$ ansible dev -i hosts --private-key=~/.vagrant.d/insecure_private_key -u vagrant -m ping

Una vez comprobado que conectamos, cambiamos el fichero development.yml con la configuración local y ya podemos instalar el servidor


$ ansible-playbook bootstrap.yml

Por último, las tareas incluídas en el role son:
  • Instalación y actualización de paquetes de ubuntu
  • Copia de ficheros de configuración, en este caso solo /etc/environment
  • Configuración del locale
  • Creación de usuarios, asignando grupos y clave pública
  • Configuración de seguridad, instalando Fail2ban y cambiando ssh para que no permita ni acceso SSH de root ni acceso con contraseña (sólo por clave pública)
  • Instalación y configuración de Nullmailer y Mandrill. El motivo de uso lo explique en mi anterior post
  • Instalación de la monitorización de servidores de NewRelic


  • Para que funcione correctamente la instalación se debe actualizar el fichero development.yml con la configuración local (usuarios y sus claves públicas, emails, dominio, claves de acceso a Mandrill y NewRelic, ...) tal y como cuento en el README del proyecto.


    lunes, 24 de marzo de 2014

    Configurando SSL en nginx

    Informe SSL de teowaki.com por sslabs.com


    La configuración básica de SSL en nginx es muy sencilla. Lo primero es tener una versión de nginx compilada con el módulo ngx_http_ssl_module. Si usas la versión estandar de tu distribución linux lo más seguro es que ya tenga soporte. Puedes comprobarlo con

    $ nginx -V
    ...
    configure arguments: --prefix=/usr/share/nginx ...--with-http_ssl_module ...
    

    En el virtual host indicaremos que vamos a usar SSL y el path de los ficheros de certificados. El proveedor donde contrates el certificado te dirá los pasos para generar estos ficheros. Como ejemplo las instrucciones de Comodo y Linode

    server {
      listen        443 ssl;
    
      ssl_certificate      /path_to/cert.crt;
      ssl_certificate_key  /path_to/cert.key;
    
    }
    

    Simplemente con estas tres líneas ya tenemos nuestro servidor con soporte SSL funcionando. Pero para que tu configuración sea óptima, hay cuantos parámetros más a tener en cuenta.


    SPDY

    SPDY es un protocolo creado por google para reducir el tiempo de carga de las páginas web. Está soportado en Firefox y Chrome desde hace tiempo y en IE desde la version 11.

    Al igual que para tener soporte de SSL, se debe compilar nginx con el módulo correspondiente, ngx_http_spdy_module.

    Como me da mucha pereza compilar nginx cada vez que lanzan una nueva versión, tenemos dos alternativas, usar binarios precompilados por Passenger o usar un ppa que incluya ese módulo

    He optado por la segunda opción, usando los paquetes de Chris Lea. Están compilados usando la versión de desarrollo de nginx. Aunque es la versión de desarrollo es una versión estable que tambien usan en la web de nginx tal como explican en las FAQ.

    La configuración de nuevo es tan simple como añadir spdy en la directiva listen

      listen        443 ssl spdy;
    


    TLS

    La configuración por defecto de nginx soporta SSL v3 y TLS versiones 1.0, 1.1 y 1.2.

    Todos los navegadores modernos soportan TLS, y SSL v3 es un protocolo antiguo y tiene algunos problemas de seguridad, así que he decidido deshabilitarlo

      # enables TLS protocols, but not SSL which is weak and should no longer be used.
      ssl_protocols TLSv1 TLSv1.1 TLSv1.2;


    Strict Transport Security (HSTS)

    Si vamos a usar siempre conexión segura con nuestro servidor, añadiendo la cabecera Strict Transport Security, indicamos al navegador que aunque el usuario escriba la URL con http, siempre debe conectarse de forma segura usando https.

    Es una buena práctica de seguridad y muchos servicios como Twitter o Paypal añaden esta cabecera en sus respuestas.

      # Remember this setting for 365 days
      add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
    

    Ciphers

    Hay mucha literatura sobre los algoritmos de cifrado que se deberían permitir, en nuestro caso he optado por seguir las recomendaciones de Comodo.

    Actualización 23-04-2014: Basado en este post sobre SSL Ciphers, he actualizado la configuración, desactivando RC4.

    Tambien he añadido otra directiva para que sea el servidor el que decida que protocolo usar entre los disponibles en lugar de dejar la elección al cliente.

      # Disables all weak ciphers
      ssl_prefer_server_ciphers on;
      ssl_ciphers ALL:!aNULL:!ADH:!eNULL:!LOW:!EXP:RC4+RSA:+HIGH:+MEDIUM;
      ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS;
    




    OCSP Stapling

    Al conectarse el navegador a una web segura, hace una petición adicional a la autoridad certificadora para asegurarse de que el certificado es válido usando OCSP (Online Certificate Status Protocol).

    Por medio de OCSP Stapling, se evita esa petición adicional incluyendo la respuesta OCSP en la misma conexión SSL, con lo que reducimos el tiempo de conexión.

    Puedes leer más en Cloudfare, en la Wikipedia, y comprobar si tu servidor lo soporta siguiendo las instrucciones de Unmitigated Risk.

      # enable ocsp stapling
      ssl_stapling on;
    


    SSL Session

    Por último, siguiendo las recomendaciones de nginx para reducir la carga del procesador habilitamos la caché de sesiones SSL y aumentamos el timeout

      ssl_session_cache    shared:SSL:10m;
      ssl_session_timeout  10m;
    



    Con esta configuración conseguimos una implementación SSL robusta y eficiente. Si conoces algún truco o mejora, por favor, dejalo en los comentarios, gracias!