martes, 7 de mayo de 2013

Apache y Webrick (rails 3) con certificados ssl


Una vez instalados los módulos, procederemos con la creación del certificado. En primera instancia generamos la llave privada(private-key):
openssl genrsa -out cert.key 1024
Ahora generamos el CSR (Certificate Signing Request), usando la key generada antes:
openssl req -new -key cert.key -out cert.csr
Y ahora generamos el certificado en sí utilizando la key y el CSR:
openssl x509 -req -days 365 -in cert.csr -signkey cert.key -out cert.crt

Para Webrick

Para generar server.csr
openssl req -new -x509 -days 3650 -nodes > server.csr

-nodes option ask for some info
-days 3650 ~= 10 years

Crear un RSA Key
openssl rsa -in privkey.pem -out server.key

Crear un certificado
openssl x509 -in server.csr -out server.crt -req -signkey server.key -days 3650

Suponiendo que los archivos generados están en una carpeta csr, en la raíz de la aplicación, en script/rails agregar/modificar:

require 'rubygems'
require 'rails/commands/server'
require 'rack'
require 'webrick'
require 'webrick/https'

module Rails
    class Server < ::Rack::Server
        def default_options
            super.merge({
                :Port => 3000,
                :SSLEnable => true,
                :SSLVerifyClient => OpenSSL::SSL::VERIFY_NONE,
                :SSLPrivateKey => OpenSSL::PKey::RSA.new(
                       File.open("csr/server.key").read),
                :SSLCertificate => OpenSSL::X509::Certificate.new(
                       File.open("csr/server.crt").read),
                :SSLCertName => [["CN", WEBrick::Utils::getservername]]
            })
        end
    end
end 

Esto obliga al server a utilizar siempre https, lo cual en realidad no es tan útil teniendo en cuenta que solo usamos webrick en development.
En el caso de que tengas en producción apache, algo realmente más útil es usar rack-ssl-enforcer que nos permite usar https en algunas rutas y http en otras sin modificar el servidor (script/rails.rb).
Por ejemplo, si queremos que solo los archivos .js sean servidos por http y todo lo demás por https hacemos lo siguiente:
* Modificamos el archivo config/enviroments/production.rb y le agregamos las linea:
    # rack-ssl-enforcer
    config.middleware.use Rack::SslEnforcer, :except => [/\.js$/], :strict => true
para más información ver rack-ssl-enforcer.
De esta manera solo en producción necesitarás usar https y en development podrás usar http, que es más rápido.

Para apache

Generar un apache.pem con: openssl req -new -x509 -days 3650 -nodes -out apache.pem -keyout apache.pem donde Common Name es www.dominio_de_tu_empresa.com Luego hay que generar el link simbólico que apache utiliza que es un hash. Para esto vemos que salida obtenemos de: openssl x509 -hash -noout < apache.pem Obs: Para ejecutar el comando anterior apache.pem necesita tener permisos adecuados, luego podemos volver a aplicar permisos 600 (ver final del post). Al número que obtuvimos lo llamaremos 'hash_salida'. Usa ese número para generar el link simbólico: ln -sf apache.pem hash_salida.0 Aplicamos los debidos permisos: chmod 600 apache.pem

Y esta sería la configuración de un VirtualHost en un server que solo sirve una única aplicación:




<VirtualHost *:80>
ServerName nombre_de_dominio.com
# !!! Be sure to point DocumentRoot to 'public'!
DocumentRoot /path/de/la/aplicacion/public/
<Directory /path/de/la/aplicacion/public/>
# This relaxes Apache security settings.
AllowOverride all
# MultiViews must be turned off.
Options -MultiViews
</Directory>
ErrorLog /var/log/apache2/nombre_de_la_app/error.log
CustomLog /var/log/apache2/nombre_de_la_app/access.log combined
</VirtualHost>


NameVirtualHost *:443
<VirtualHost *:443>
ServerName nombre_de_dominio.com
# !!! Be sure to point DocumentRoot to 'public'!
DocumentRoot /path/de/la/aplicacion/public/
<Directory /path/de/la/aplicacion/public/>
# This relaxes Apache security settings.
AllowOverride all
# MultiViews must be turned off.
Options -MultiViews
</Directory>
ErrorLog /var/log/apache2/nombre_de_la_app/error.log
CustomLog /var/log/apache2/nombre_de_la_app/access.log combined
SSLEngine on
SSLCertificateFile /etc/apache2/ssl/apache.pem
</VirtualHost>