web-dev-qa-db-ja.com

HerokuからのSSHトンネリング

Herokuでホストされているサービスを提供しています。これにより、ユーザーはデータベースを使用して自分のデータについてレポートできます。私の顧客はHerokuアプリをデータベースに接続する必要があります。それらのいくつかは明らかにインターネット上でデータを平文で通過させることを恐れています。

Herokuでアプリ(Play Framework/Java)からマシンにSSHトンネルを開くことは可能ですか?

注意:私は HerokuからリモートDBへのSSHトンネリング? を知っていますが、その質問では、組み込みのHeroku dbを使用することが可能でした。

ありがとう、エイドリアン

29
Adrien

はい、できます。

これでこのパスをたどりました:はい、それはis herokuから外部データベースへのSSHトンネルをセットアップすることが可能です。 [注:私の特定のアプリはRuby on Railsで記述されていますが、ここに記載されているソリューションはHerokuでホストされているすべての言語で機能するはずです。

問題の声明

Herokuでアプリを実行しています。アプリは、分析のためにデータを取得する外部のMySQLデータベース(AWSでホストされている)にアクセスする必要があります。 MySQLデータベースへのアクセスはsshキーで保護されています。つまり、パスワードでアクセスすることはできません。sshキーペアが必要です。 Herokuは各dynoを新しく開始するので、適切な資格情報を使用してSSHトンネルをセットアップするにはどうすればよいですか?

短い答え

スクリプトファイルを作成します(ssh_setup.shなど)。 $ {HOME} /。profile.d/ssh_setup.shに置きます。 Herokuは$ {HOME} /。profile.d内のファイルに気づき、dynoを作成するときにそれを実行します。スクリプトファイルを使用して〜/ .ssh/id_rsaおよび〜/ .ssh/id_rsa.pubを設定し、トンネルモードでsshを起動します。

完全なレシピ

1.外部DBにアクセスするためのキーペアを生成する

鍵ペアを作成し、〜/ .ssh/heroku_id_rsaおよび〜/ .ssh/heroku_id_rsa.pubに保存します。空のパスフレーズを使用します(そうでない場合、Heroku dynoは起動時にプロンプ​​トを表示しようとします):

$ 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.外部DBへのsshアクセスをテストする

PUBLICキー(〜/ .ssh/heroku_id_rsa.pub)を外部DBの管理者に送信し、そのキーを使用してアクセスを要求します。その後、ローカルマシンのシェルウィンドウに次のように入力できます。

$ ssh -v -i ~/.ssh/heroku_id_rsa -N -L 3307:${REMOTE_MYSQL_Host}:3306 ${TUNNEL_USER}@${TUNNEL_SITE}

どこ

  • $ {REMOTE_MYSQL_Host}は、リモートデータベースのアドレスです。私たちの場合、それはlong_complicated_string.us-west-2.rds.amazonaws.comのようなものです
  • $ {TUNNEL_USER}は、データベースにアクセスするサイトのユーザーアカウントです。
  • $ {TUNNEL_SITE}は、データベースにアクセスするマシンのアドレスです

次のものを含むデバッグ出力の長い文字列が表示されます。

debug1: Authentication succeeded (publickey).
...
debug1: forking to background
debug1: Entering interactive session.

おめでとう。自分のマシンで外部データベースへのトンネリングを設定しました。 Herokuに同じことをするように説得するために...

3.構成変数を設定する

〜/ .ssh/heroku_id_rsaおよび〜/ .ssh/heroku_id_rsa.pubの内容を、起動時にHeroku dynoの対応するディレクトリにコピーすることが目的ですが、実際には秘密鍵をスクリプトファイル。

代わりに、Hyokuの構成変数を使用します。これは、dynoの起動時にシェル環境変数を簡単に(かつ安全に)設定します。

$ heroku config:set HEROKU_PRIVATE_KEY=`cat ~/.ssh/heroku_rsa_id`
$ heroku config:set HEROKU_PUBLIC_KEY=`cat ~/.ssh/heroku_rsa_id.pub`

ここでは、機密性の高い他のいくつかの変数も設定します。

$ 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.スクリプトファイルのバージョン1.0を作成する

プロジェクトのホームディレクトリに、.profile.dディレクトリを作成します。そのディレクトリで、以下を作成します。

# 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.設定をプッシュし、Herokuでテストします

あなたはドリルを知っています...

$ git add .
$ git commit -m 'launching ssh when Heroku dyno starts up'
$ git Push heroku master

やってみて...

$ heroku run sh

次のようなものが表示される場合があります。

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)?

これは、dynoが続行するためにユーザー入力を必要とすることを意味するため、問題です。しかし、これを修正しようとしています。以下はやや醜いハックですが、動作します。 (誰かがより良い解決策を持っている場合は、コメントしてください!)

6.スクリプトファイルのバージョン2.0を作成する

(上から続行)プロンプトにyesと答え、スクリプトを最後まで実行させます。次に、known_hostsファイルの出力をキャプチャします。

heroku $ cat ~/.ssh/known_hosts
|1|longstringofstuff= ecdsa-sha2-nistp256 more stuff=
|1|morestuff= ecdsa-sha2-nistp256 yetmorestuff=

その出力をコピーして、「preload the known_hosts」コメントの下のssh-setup.shファイルに貼り付け、次のように編集します。

# 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. v2をプッシュしてテストする

あなたはドリルを知っています...

$ git add .
$ git commit -m 'preload known_hosts file to avoid Prompt'
$ git Push heroku master

やってみて。運が良ければ、次のようなものが表示されます。

$ heroku run sh
Running `sh` attached to terminal... up, run.1926
bash: creating public and private key files
bash: launching tunnel

8.デバッグ

トンネルが適切に設定されていない場合は、スクリプトファイルのSSHコマンドに-v(詳細)引数を追加してみてください。

SSH_CMD="ssh -v -f -i ${HOME}/.ssh/heroku_id_rsa -N -L ${LOCAL_PORT}:${REMOTE_MYSQL_Host}:${MYSQL_PORT} ${REMOTE_USER}@${REMOTE_SITE}"

git add ... git commit ... git Pushシーケンスを繰り返し、heroku run shを呼び出します。大量のデバッグ出力が出力されます。私の頭脳よりも多くの頭脳を持つシステム管理者の友人は、その出力をデコードして、問題がどこにあるかを教えてくれるはずです。

9.(Railsのみ):DBの構成

Railsを実行している場合は、Railsアプリ内でデータベースにアクセスする方法が必要です。そうですか?config/database.ymlファイルに以下を追加します(適切な名前を変更します) :

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

注意すべき重要な点は、ホストはローカルホスト(127.0.0.1)であり、ポート(3307)はスクリプトでsshに指定された-L引数と一致する必要があることです。

-L 3307:${REMOTE_MYSQL_Host}:3306

要約すれば

他の場所で言われていることにもかかわらず、Herokuからトンネルを介してリモートデータベースにアクセスできます。上記のレシピは多くの仮定を行っていますが、いくつかのカスタマイズにより、特定のニーズに対応するはずです。

さあ、寝ます。

61
fearless_fool