remote - heroku ssh key
TĂșneles SSH de Heroku (1)
Sí tu puedes.
Habiendo recorrido este camino: sí, es posible configurar un túnel SSH desde heroku a una base de datos externa. [NOTA: Mi aplicación en particular fue escrita en Ruby on Rails, pero la solución dada aquí debería funcionar para cualquier idioma alojado en Heroku.]
Planteamiento del problema
Estoy ejecutando una aplicación en Heroku. La aplicación necesita acceder a una base de datos MySQL externa (alojada en AWS) de la que toma datos para analizarlos. El acceso a la base de datos MySQL está protegido por claves ssh, es decir, no puede acceder a él con una contraseña: necesita un par de claves ssh. Dado que Heroku comienza cada nuevo dyno, ¿cómo puede configurar un túnel SSH con las credenciales adecuadas?
Respuesta corta
Cree un archivo de script, diga ssh_setup.sh. Póngalo en $ {HOME} /. Profile.d / ssh_setup.sh. Heroku notará cualquier archivo en $ {HOME} /. Profile.d y lo ejecutará cuando cree su dinamómetro. Use el archivo de script para configurar ~ / .ssh / id_rsa y ~ / .ssh / id_rsa.pub y luego inicie ssh en modo túnel.
La Receta Completa
1. Generar par de llaves para acceder a la base de datos externa.
Cree un par de claves y guárdelo en ~ / .ssh / heroku_id_rsa y ~ / .ssh / heroku_id_rsa.pub. Use una frase de contraseña vacía (de lo contrario, el dino Heroku intentará solicitarla cuando se inicie):
$ ssh-keygen -t rsa -C "[email protected]"
Generating public/private rsa key pair.
Enter file in which to save the key (/home/.ssh/id_rsa): /home/.ssh/heroku_id_rsa
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/.ssh/heroku_id_rsa.
Your public key has been saved in /home/.ssh/heroku_id_rsa.pub.
2. Probar el acceso ssh a la base de datos externa
Envíe su clave PÚBLICA (~ / .ssh / heroku_id_rsa.pub) al administrador de la base de datos externa y solicite acceso con esa clave. Después de eso, debería poder escribir lo siguiente en una ventana de shell en su máquina local:
$ ssh -v -i ~/.ssh/heroku_id_rsa -N -L 3307:${REMOTE_MYSQL_HOST}:3306 ${TUNNEL_USER}@${TUNNEL_SITE}
dónde
- $ {REMOTE_MYSQL_HOST} es la dirección de la base de datos remota. En nuestro caso, es algo así como long_complicated_string.us-west-2.rds.amazonaws.com
- $ {TUNNEL_USER} es la cuenta de usuario en el sitio que accede a la base de datos
- $ {TUNNEL_SITE} es la dirección de la máquina que accede a la base de datos
Debería obtener una larga cadena de resultados de depuración que incluyen lo siguiente:
debug1: Authentication succeeded (publickey).
...
debug1: forking to background
debug1: Entering interactive session.
Felicidades. Ha configurado un túnel en su propia máquina a la base de datos externa. Ahora convencer a Heroku para que haga lo mismo ...
3. Configurar las variables de configuración.
El objetivo es copiar el contenido de ~ / .ssh / heroku_id_rsa y ~ / .ssh / heroku_id_rsa.pub en los directorios correspondientes de su Dino Heroku cada vez que se inicie, pero REALMENTE no desea exponer su clave privada en un archivo de comandos.
En su lugar, usaremos las variables de configuración de Heroku, que simplemente (y de manera segura) configuran las variables de entorno de shell al iniciar el dinamómetro.
$ heroku config:set HEROKU_PRIVATE_KEY=`cat ~/.ssh/heroku_rsa_id`
$ heroku config:set HEROKU_PUBLIC_KEY=`cat ~/.ssh/heroku_rsa_id.pub`
Mientras estamos en ello, también configuraremos algunas otras variables potencialmente sensibles:
$ heroku config:set REMOTE_MYSQL_HOST=<your value of REMOTE_MYSQL_HOST from above>
$ heroku config:set TUNNEL_USER=<your value of TUNNEL_USER from above>
$ heroku config:set TUNNEL_SITE=<your value of TUNNEL_SITE from above>
4. Crea la versión 1.0 de tu archivo de script
En el directorio de inicio de su proyecto, cree un directorio .profile.d. En ese directorio, crea lo siguiente:
# file: .profile.d/ssh-setup.sh
#!/bin/bash
echo $0: creating public and private key files
# Create the .ssh directory
mkdir -p ${HOME}/.ssh
chmod 700 ${HOME}/.ssh
# Create the public and private key files from the environment variables.
echo "${HEROKU_PUBLIC_KEY}" > ${HOME}/.ssh/heroku_id_rsa.pub
chmod 644 ${HOME}/.ssh/heroku_id_rsa.pub
# Note use of double quotes, required to preserve newlines
echo "${HEROKU_PRIVATE_KEY}" > ${HOME}/.ssh/heroku_id_rsa
chmod 600 ${HOME}/.ssh/heroku_id_rsa
# Preload the known_hosts file (see "version 2" below)
# Start the SSH tunnel if not already running
SSH_CMD="ssh -f -i ${HOME}/.ssh/heroku_id_rsa -N -L 3307:${REMOTE_MYSQL_HOST}:3306 ${REMOTE_USER}@${REMOTE_SITE}"
PID=`pgrep -f "${SSH_CMD}"`
if [ $PID ] ; then
echo $0: tunnel already running on ${PID}
else
echo $0 launching tunnel
$SSH_CMD
fi
5. Presiona la configuración y pruébala en Heroku
Ya sabes que hacer...
$ git add .
$ git commit -m ''launching ssh when Heroku dyno starts up''
$ git push heroku master
Darle un giro...
$ heroku run sh
Puedes ver algo como:
Running `sh` attached to terminal... up, run.1926
bash: creating public and private key files
bash: launching tunnel
The authenticity of host ''example.com (11.22.33.44)'' can''t be established.
ECDSA key fingerprint is 1f:aa:bb:cc:dd:ee:ff:11:22:33:44:55:66:77:88:99.
Are you sure you want to continue connecting (yes/no)?
Esto es un problema, ya que significa que el dinamómetro necesita la entrada del usuario para continuar. Pero estamos a punto de arreglar eso. Lo que sigue es un truco algo feo, pero funciona. (Si alguien tiene una mejor solución, por favor comente!)
6. Crea la versión 2.0 de tu archivo de script
(Continuando desde arriba) Responda yes
a la solicitud y deje que el script se ejecute hasta completarse. Ahora vamos a capturar la salida del archivo known_hosts:
heroku $ cat ~/.ssh/known_hosts
|1|longstringofstuff= ecdsa-sha2-nistp256 more stuff=
|1|morestuff= ecdsa-sha2-nistp256 yetmorestuff=
Copie esa salida y péguela en su archivo ssh-setup.sh bajo el comentario "Precargar los hosts_ conocidos", y edítela para que se vea así:
# Preload the known_hosts file (see "version 2" below)
echo ''|1|longstringofstuff= ecdsa-sha2-nistp256 more stuff=
|1|morestuff= ecdsa-sha2-nistp256 yetmorestuff='' > ${HOME}/.ssh/known_hosts
# Start the SSH tunnel if not already running
... etc ...
7. Empuje y pruebe v2
Ya sabes que hacer...
$ git add .
$ git commit -m ''preload known_hosts file to avoid prompt''
$ git push heroku master
Darle un giro. Con suerte, deberías ver algo como esto:
$ heroku run sh
Running `sh` attached to terminal... up, run.1926
bash: creating public and private key files
bash: launching tunnel
8. depuración
Si el túnel no se configura correctamente, intente pendiente un argumento -v (detallado) para el comando SSH en el archivo de script:
SSH_CMD="ssh -v -f -i ${HOME}/.ssh/heroku_id_rsa -N -L ${LOCAL_PORT}:${REMOTE_MYSQL_HOST}:${MYSQL_PORT} ${REMOTE_USER}@${REMOTE_SITE}"
Repita el git add ... git commit ... git push
y llama a heroku run sh
. Se imprimirá una gran cantidad de salida de depuración. Un amigo sysadmin con más cerebros que yo debería poder decodificar esa salida para decirle dónde está el problema.
9. (Sólo rieles): Configuración de la base de datos
Si está ejecutando Rails, necesitará una forma de acceder a la base de datos dentro de su aplicación Rails, ¿verdad? Agregue lo siguiente a su archivo config/database.yml
(cambiando los nombres apropiados):
mysql_legacy:
adapter: mysql2
database: mysql_legacy
username: <%= ENV[''LEGACY_DB_USERNAME''] || ''root'' %>
password: <%= ENV[''LEGACY_DB_PASSWORD''] || '''' %>
host: 127.0.0.1
port: 3307
Lo importante a tener en cuenta es que el host es el host local (127.0.0.1) y el puerto (3307) debe coincidir con el argumento -L dado a ssh en el script:
-L 3307:${REMOTE_MYSQL_HOST}:3306
En resumen
A pesar de lo que se ha dicho en otra parte, puede hacer un túnel desde Heroku para acceder a una base de datos remota. La receta anterior hace MUCHAS suposiciones, pero con algunas personalizaciones debería funcionar para sus necesidades específicas.
Ahora voy a dormir un poco ...
Estoy proporcionando un servicio alojado en Heroku que permite a los usuarios informar sobre sus propios datos, utilizando su base de datos. Mis clientes tienen que conectar mi aplicación Heroku a su base de datos. Algunos de ellos, obviamente, tienen miedo de dejar que los datos transiten a través de Internet.
¿Es posible con Heroku abrir un túnel SSH desde mi aplicación (Play Framework / Java) a sus máquinas?
NB: ¿Soy consciente de que SSH está haciendo un túnel a un DB remoto desde Heroku? pero en esa pregunta, usar el db Heroku incorporado era posible.
Gracias adrien