CFアプリ開発と管理#18 アプリへのSSHアクセス

Cloud Foundryコマンドラインインターフェイス（cf CLI）を使用すると、Cloud Foundryアプリケーションインスタンスを実行しているリモートホスト仮想マシン（VM）に安全にログインできます。 このトピックでは、アプリケーションへのSSHアクセスを有効にし、そのようなアクセスの許可を有効化、無効化、および確認するコマンドについて説明します。

*このページでは、cf CLI v6.13.0以降を前提としています。*

cf CLIは、Cloud Controller `/v2/info` エンドポイント内の`app_ssh_oauth_client`識別子を検索します、そして、この識別子を使用してUAAサーバにSSH認証コードを問い合わせます。ターゲットVM側では、SSHプロキシは`/v2/info`にリストされている`app_ssh_endpoint`を介してクラウドコントローラに接続し、SSHアクセスの許可を確認します。

*注意事項: このコンテンツは Cloud Foundry Documentaion [Accessing Apps with SSH](https://docs.cloudfoundry.org/devguide/deploy-apps/ssh-apps.html) (last updated: April 4, 2017) からの独自の翻訳とコメントです。内容を保証するものではありません。*


## アプリSSHコマンド

|cf CLI Command |Purpose |
|:--            |:--     |
|`cf enable-ssh`<br>`cf disable-ssh`<br>`cf allow-space-ssh`<br>`cf disallow-space-ssh`|	[Enable and Disable SSH Access](https://docs.cloudfoundry.org/devguide/deploy-apps/ssh-apps.html#enable-disable-ssh) |
|`cf ssh-enabled`<br>`cf space-ssh-allowed`|SSH アクセス許可のチェック|
|`cf ssh` | [アプリ・コンテナに安全にログイン](https://docs.cloudfoundry.org/devguide/deploy-apps/ssh-apps.html#ssh-command) |
|`cf ssh-code` | ssh, scp, and sftp など[非CF SSHツールを使用してアプリケーションコンテナに安全にログインできるようにする](https://docs.cloudfoundry.org/devguide/deploy-apps/ssh-apps.html#other-ssh-access) |


## SSHアクセスの有効/無効化

クラウドオペレータは、Cloud Foundryのデプロイメント全体でアプリケーションSSHを許可または禁止することができます。 詳細については、「[Cloud Foundry SSHアクセスの設定](https://docs.cloudfoundry.org/running/config-ssh.html)」を参照してください。

アプリへのSSHアクセスを許可するデプロイでは、スペースの開発者は個々のアプリケーションへのSSHアクセスを有効または無効にすることができ、スペース管理者はスペース内で実行されているすべてのアプリケーションへのSSHアクセスを有効または無効にできます。

### アプリ・レベルのSSHアクセス設定

[`cf enable-ssh`](http://cli.cloudfoundry.org/ja-JP/cf/enable-ssh.html)がアプリのすべてのインスタンスにSSHアクセスを有効にする。

~~~
$ cf enable-ssh MY-AWESOME-APP
~~~

[`cf disable-ssh`](http://cli.cloudfoundry.org/ja-JP/cf/disable-ssh.html)がアプリのすべてのインスタンスにSSHアクセスを禁止する。

~~~
$ cf disable-ssh MY-AWESOME-APP
~~~

### スペース・レベルのSSHアクセス設定

[`cf allow-space-ssh`](http://cli.cloudfoundry.org/ja-JP/cf/allow-space-ssh.html) allows SSH access into all apps in a space:

~~~
$ cf allow-space-ssh SPACE-NAME
~~~

[`cf disallow-space-ssh`](http://cli.cloudfoundry.org/ja-JP/cf/disallow-space-ssh.html) disallows SSH access into all apps in a space:

~~~
$ cf disallow-space-ssh SPACE-NAME
~~~



### SSHアクセス許可の確認
[`cf ssh-enabled`](http://cli.cloudfoundry.org/ja-JP/cf/ssh-enabled.html)は、SSHでアプリへアクセスできるかどうかを確認します。

~~~
$ cf ssh-enabled MY-AWESOME-APP
ssh support is disabled for 'MY-AWESOME-APP'
~~~

[`cf space-ssh-allowed`](http://cli.cloudfoundry.org/ja-JP/cf/space-ssh-allowed.html) は、スペース内で実行されているすべてのアプリがSSHでアクセス可能かどうかをチェックします。

~~~
$ cf space-ssh-allowed SPACE-NAME
ssh support is enabled in space 'SPACE-NAME'
~~~


## cf SSHを使用したアプリ・コンテナへのログイン
デプロイメント、スペース、およびアプリ・レベルでSSHアクセスが許可されている場合は、`cf ssh APP-NAME`コマンドを実行して、アプリケーションをホストするVMとの対話型SSHセッションを開始できます。 デフォルトでは、コマンドはアプリケーションの最初のインスタンスを実行しているコンテナ（インデックス0のインスタンス）にアクセスします。

~~~
$ cf ssh MY-AWESOME-APP
~~~

アプリケーションをホストするVMにログインすると、[Cloud Foundry Diego Operator Toolkit（cfdot）](https://docs.cloudfoundry.org/running/monitoring-test.html#cfdot)のようなツールを使用して、アプリステータス診断を実行できます。 詳細は、Githubの[cfdot repo](https://github.com/cloudfoundry/cfdot)を参照してください。



### 一般的なcf SSHフラグ
[cf ssh](http://cli.cloudfoundry.org/ja-JP/cf/ssh.html)コマンドは、次のフラグを使用してカスタマイズすることができます。これらのフラグのほとんどは、UnixまたはLinuxの`ssh`コマンドのフラグを模倣します。詳細については、`cf ssh --help`コマンドを実行してください。


* `-i`フラグは、アプリケーションの特定のインスタンスを対象とします。 MY-AWESOME-APPの3番目のインスタンス`index=2`をホストするVMコンテナにログインするには、次のコマンドを実行します。

~~~
$ cf ssh MY-AWESOME-APP -i 2
~~~

* `-L`フラグはローカルポート転送を有効にし、マシン上の出力ポートをアプリケーションVM上の入力ポートにバインドします。ローカルポートとアプリケーションのVMポートとポート番号を渡します。コロンはすべて区切ります。ローカルネットワークインタフェースの前に置くことも、デフォルトのローカルホストを使用することもできます。

~~~
$ cf ssh MY-AWESOME-APP -L [LOCAL-NETWORK-INTERFACE:]LOCAL-PORT:REMOTE-HOST-NAME:REMOTE-HOST-PORT
~~~

* `-N`フラグは、リモートマシン上でコマンド・プロンプトを返すことをスキップします。これは、ホストVM上でコマンドを実行する必要がない場合は、ローカルポート転送を設定します。

* `--request-pseudo-tty`フラグと`--force-pseudo-tty`フラグを使用すると、端末行出力を生成するのではなく、疑似ttyモードでSSHセッションを実行できます。


## SSHセッション環境

対話型SSHセッションの環境をビルドパックベースのアプリケーションの環境と同じ環境変数と作業ディレクトリで一致させるには、セッションを開始した後で次のコマンドを実行します。

~~~
export HOME=/home/vcap/app
export TMPDIR=/home/vcap/tmp
cd /home/vcap/app
~~~

以下のコマンドを実行する前に、`/home/vcap/app/.profile` と `/home/vcap/app/.profile.d`ディレクトリの両方のファイルの内容が、実行中のアプリケーションにとって望ましくない動作をしないことを確認してください。
` .profile.d`ディレクトリーには buildpack 固有の初期設定タスクが含まれ、`.profile`ファイルにはアプリケーション固有の初期設定タスクが含まれます。

`profile` と `.profile.d`スクリプトが望ましくない方向へ、インスタンスを変更する場合は、環境設定に必要なコマンドだけを実行してください。

~~~
[ -d /home/vcap/app/.profile.d ] && for f in /home/vcap/app/.profile.d/*.sh; do source "$f"; done
source /home/vcap/app/.profile
~~~

上記のコマンドを実行すると、`VCAP_APPLICATION`環境変数の値は、`host`、`instance_id`、`instance_index`、または`port`フィールドが設定されていないため、アプリ・プロセス環境の値と若干異なります。これらのフィールドは、[VCAP_APPLICATION](https://docs.cloudfoundry.org/devguide/deploy-apps/environment-variable.html#VCAP-APPLICATION)ドキュメントで説明されているように、他の環境変数で使用できます。


## CLIを使用しないアプリケーションSSHアクセス
もし、あなたがSSH権限を持っている場合は、`cf ssh`に加えて、`ssh`、`scp`、`sftp`などの他のSSHクライアントを使用してアプリケーションにアクセスできます。

以下の手順に従って、ホストVM上で実行されているSSHプロキシに情報を渡す特別に形成されたユーザー名でログインし、アプリ・インスタンスに安全に接続します。パスワードには、cf ssh-codeによって生成されたワンタイムSSH認証コードを使用します。

1. `cf app MY-AWESOME-APP --guid`を実行し、ターゲット・アプリのGUIDを記録します。

~~~
$ cf app MY-AWESOME-APP --guid
abcdefab-1234-5678-abcd-1234abcd1234
~~~


2. デプロイメントのCloud Controllerの`/v2/info`エンドポイントを照会します。 `app_ssh_endpoint`フィールドと`app_ssh_host_key_fingerprint`フィールドのドメイン名とポートを記録します。 `app_ssh_host_key_fingerprint`とターゲットVM上のSSHプロキシから返されたフィンガープリントを比較します。

~~~
$ cf curl / v2 / info
{
...
"app_ssh_endpoint"： "ssh.MY-DOMAIN.com:2222"、
"app_ssh_host_key_fingerprint"： "a6：14：c0：ea：42：07：b2：f7：53：2c：0b：60：e0：00：21：6c"
...
}
~~~

3. `cf ssh-code`を実行すると、SSHパスワードの代わりにワンタイムの認証コードが取得できます。 `cf ssh-code |pbcopy` を実行すると、自動的にコードがクリップボードにコピーされます。

~~~
$ cf ssh-code
E1x89n
~~~

4. sshなどのコマンドを実行して、アプリケーションインスタンスに接続します。ユーザー名には、`cf:APP-GUID/APP-INSTANCE-INDEX@SSH-ENDPOINT`という形式の文字列を使用します。ここで、`APP-GUID`と`SSH-ENDPOINT`は前の手順からのものです。ポート番号については、上記の`SSH-PORT`を使用してください。 `APP-INSTANCE-INDEX`は、アクセスするインスタンスのインデックスです。 

上記の例では、次のコマンドを実行して、アプリケーションの最初のインスタンスをホストするコンテナにsshを実行します。

~~~
$ ssh -p 2222 cf：abcdefab-1234-5678-abcd-1234abcd1234/0@ssh.MY-DOMAIN.com
~~~

または、`scp`を使用してファイルを転送するには、次のコマンドを実行します。

~~~
$ scp -P 2222 -o User=cf:abcdefab-1234-5678-abcd-1234abcd1234/0 ssh.MY-DOMAIN.com:REMOTE-FILE-TO-RETRIEVE LOCAL-FILE-DESTINATION
~~~


5. SSHプロキシがそのRSAフィンガープリントを報告するとき、それが上記の記録された`app_ssh_host_key_fingerprint`と一致することを確認してください。パスワードの入力を求められたら、`cf ssh-code`が返す認証コードを貼り付けます。

~~~
$ ssh -p 2222 cf:abcdefab-1234-5678-abcd-1234abcd1234/0@ssh.MY-DOMAIN.com
The authenticity of host '[ssh.MY-DOMAIN.com]:2222 ([203.0.113.5]:2222)' can't be established.
RSA key fingerprint is a6:14:c0:ea:42:07:b2:f7:53:2c:0b:60:e0:00:21:6c.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[ssh.MY-DOMAIN.com]:2222 [203.0.113.5]:2222' (RSA) to the list of known hosts.
cf:d0a2e11d-e6ca-4120-b32d-140@ssh.ketchup.cf-app.com's password:
vcap@ce4l5164kws:~$
~~~


これで、アプリケーション・インスタンスに安全に接続しました。

## コンテナ認証へのプロキシ
SSHセキュリティの第2層が各コンテナ内で実行されます。 SSHプロキシは、ターゲット・コンテナ内のSSHデーモンとハンドシェークを試みるとき、アプリケーション・インスタンスへのルート内の`diego-ssh`キーに関連する次のフィールドを使用します。この内部層は目に見えない形で動作し、ユーザーの操作は必要ありませんが、ここではSSHセキュリティー図を完成させるために説明します。

### CONTAINER_PORT（必須）
`container_port`は、SSHデーモンがリッスンしているコンテナ内のポートを示します。プロキシは、クライアントの認証後にこのポートのホスト側のマッピングに接続しようとします。

### HOST_FINGERPRINT（オプション）
存在する場合、`host_fingerprint`は、予想される、SSHデーモンのホストの公開鍵のフィンガープリントを定義します。実際のターゲットのホスト鍵のフィンガープリントが予想されるフィンガープリントと一致しない場合、接続は終了します。フィンガープリントには、`ssh-keygen -l`によって生成された16進文字列のみを含める必要があります。

### USER（オプション）
`user`は、コンテナーのSSHデーモンとの認証時に使用するユーザーIDを宣言します。これはルーティングデータの必須部分ではありませんが、パスワード認証に必要であり、公開鍵認証に必要となる可能性があります。

### パスワード（オプション）
`password`は、コンテナのsshデーモンとのパスワード認証時に使用するパスワードを宣言します。

### PRIVATE_KEY（オプション）
`private_key`は、コンテナのSSHデーモンで認証する際に使用する秘密鍵を宣言します。キーが存在する場合、そのキーはPEMでエンコードされたRSAまたはDSA公開鍵でなければなりません。


#### Example Application Process

~~~
{
  "process_guid": "ssh-process-guid",
  "domain": "ssh-experiments",
  "rootfs": "preloaded:cflinuxfs2",
  "instances": 1,
  "start_timeout": 30,
  "setup": {
    "download": {
      "artifact": "diego-sshd",
      "from": "http://file-server.service.cf.internal.example.com:8080/v1/static/diego-sshd/diego-sshd.tgz",
      "to": "/tmp",
      "cache_key": "diego-sshd"
    }
  },
  "action": {
    "run": {
      "path": "/tmp/diego-sshd",
      "args": [
          "-address=0.0.0.0:2222",
          "-authorizedKey=ssh-rsa ..."
      ],
      "env": [],
      "resource_limits": {}
    }
  },
  "ports": [ 2222 ],
  "routes": {
    "diego-ssh": {
      "container_port": 2222,
      "private_key": "PEM encoded PKCS#1 private key"
    }
  }
}
~~~


## デーモンの発見
SSHプロキシ経由でアクセスできるようにするには、コンテナはSSHデーモンをホストし、マップされたポートを介して公開し、`diego-ssh`ルートに、そのポートをアドバタイズする必要があります。 プロキシがターゲットプロセスまたはルートを見つけることができない場合、ユーザー認証は失敗します。

~~~
   "routes"：{
     "diego-ssh"：{"container_port"：2222}
   }
~~~

Diegoシステムは、有効なポリシーを反映するCloud Foundryアプリケーション用の適切なプロセス定義を生成します。