GCEへのSSH接続の各種方法について、IAMロールやSSH認証鍵などの仕様まとめ

- ローカルとVPC間の閉域接続は無し
- プロジェクトはどの組織にも所属していない

## ざっくりとした場合分け
### SSH接続のための機能
Google CloudのGoogle Compute Engineにおいては、インスタンスへのSSH接続方法として以下の2つの機能が存在します
- プロジェクトまたはインスタンスのメタデータによる公開鍵管理
- OS Login

### SSH接続方法
次の3つの方法でSSH接続を行うことが可能です
- コンソール
    ![console.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2697194/9177b1f6-c392-9373-06e4-d048d2580ee8.png)
- gcloudコマンド
    - `gcloud compute ssh ${インスタンス名}`
- sshコマンドまたはサードパーティ製ツール（Tera Termなど）

### その他
- 外部IPの有無
    - Identity-Aware Proxy (IAP)使用

## [プロジェクトまたはインスタンスのメタデータによる公開鍵管理](https://cloud.google.com/compute/docs/instances/ssh#metadata-managed_ssh_connections)
タイトルの通り、プロジェクトまたはインスタンスのメタデータで公開鍵を管理します
コンソールだと
- プロジェクト : サイドバーの「メタデータ」→「SSH 認証鍵」
- インスタンス : 該当インスタンスの「詳細」にある項目「SSH 認証鍵」

でそれぞれ現存する公開鍵が確認可能です

gcloudコマンドだと
- プロジェクト : `gcloud compute project-info describe`
- インスタンス : `gcloud compute instances describe ${インスタンス名}`

で確認可能です

### 権限
- プロジェクトのメタデータに公開鍵を追加する（[参考](https://cloud.google.com/compute/docs/connect/add-ssh-keys#add_ssh_keys_to_project_metadata)）
    - `compute.projects.setCommonInstanceMetadata` (プロジェクトに対して)
    - `iam.serviceAccounts.actAs` (プロジェクトに対して)
- インスタンスのメタデータに公開鍵を追加する（[参考](https://cloud.google.com/compute/docs/connect/add-ssh-keys#after-vm-creation)）
    - `compute.instances.setMetadata` (インスタンスに対して)

### SSH接続方法 : コンソール
インスタンスのメタデータに一時的に有効な公開鍵を追加します
秘密鍵はブラウザのセッションに保存されるようです

### SSH接続方法 : gcloudコマンド
まずはプロジェクトのメタデータに永続的に有効な公開鍵を追加します
必要な権限が無い等の理由で失敗した場合は、インスタンスのメタデータに永続的に有効な公開鍵を追加します

また、
- 秘密鍵はローカルに「.ssh/google_compute_engine」
- 公開鍵はローカルに「.ssh/google_compute_engine.pub」

として保存されます

## [OS Login](https://cloud.google.com/compute/docs/oslogin)
OS Loginは、Google Cloudの各アカウントとLinuxユーザを関連付けし、IAMベースでの権限管理ができる機能です
使用するGoogle Cloudアカウントに付与されているロールに応じて、SSHの許可やOSの管理者権限の有無を設定できます

プロジェクトやインスタンスのメタデータに以下を追加することで有効化されます
- キー : `enable-oslogin`
- 値 : `TRUE`

公開鍵はGoogle Cloudアカウントに紐付けられる形で管理され、
`gcloud compute os-login ssh-keys`コマンドを用いることで確認や追加、削除等が可能です（[参考](https://cloud.google.com/sdk/gcloud/reference/compute/os-login/ssh-keys)）

### 権限（[参考](https://cloud.google.com/compute/docs/oslogin/set-up-oslogin#grant-iam-roles)）
- OSの管理者権限を付与せずに、SSHログインを許可
    - Compute OS ログイン（ID : `roles/compute.osLogin`）ロール
- OSの管理者権限を付与して、SSHログインを許可
    - Compute OS 管理者ログイン（ID : `roles/compute.osAdminLogin`）ロール
- **インスタンスにサービスアカウントがアタッチされている場合、該当サービスアカウントにアクセスできる必要がある**
    - サービス アカウント ユーザー（ID : `roles/iam.serviceAccountUser`）ロール
        - `iam.serviceAccounts.actAs`が付与されていればよい

### SSH接続方法 : コンソール
Google Cloudアカウントに一時的に有効な公開鍵を追加します
秘密鍵はブラウザのセッションに保存されるようです
（[参考](https://cloud.google.com/compute/docs/instances/ssh#os_login-managed_ssh_connections)）

### SSH接続方法 : gcloudコマンド
Google Cloudアカウントに永続的に有効な公開鍵を追加します

また、「プロジェクトまたはインスタンスのメタデータによる公開鍵管理」同様
- 秘密鍵はローカルに「.ssh/google_compute_engine」
- 公開鍵はローカルに「.ssh/google_compute_engine.pub」

として保存されます

## IAP
> IAP を経由して SSH トラフィックをトンネリングすることにより、外部 IP アドレスを持たない Linux インスタンスに接続できます。

([ドキュメント](https://cloud.google.com/iap/docs/using-tcp-forwarding?hl=ja#tunneling_ssh_connections))

### 権限
- IAPを用いたSSH接続（[参考](https://cloud.google.com/iap/docs/using-tcp-forwarding?hl=ja#permission-details)）
    - `iap.tunnelInstances.accessViaIAP`

### ファイアウォール
- 「35.235.240.0/20」からの22番ポートへのアクセスを許可する（[参考](https://cloud.google.com/iap/docs/using-tcp-forwarding#create-firewall-rule)）

### SSH接続方法 : コンソール
基本的にはIAPを使用します

IAPを使用しない場合は、Google CloudのIP範囲全体のトラフィックを許可する必要があります（[参考](https://cloud.google.com/compute/docs/troubleshooting/troubleshooting-ssh?hl=ja#connection_failed)）
一応jsonファイルとしてまとまっていますが、量が膨大なのでかなり大変そうです
（簡単に一括で許可する方法ってあったりするのでしょうか？）

### SSH接続方法 : gcloudコマンド
以下の場合、IAPを使用します（[参考](https://cloud.google.com/iap/docs/using-tcp-forwarding#tunneling_ssh_connections)）
- インスタンスに外部IPが付与されていない
- `--tunnel-through-iap`フラグを使用

## SSH接続方法 : sshコマンド
以下のコマンドを実行して、出力されたコマンドを実行することで接続可能です
※ 事前に公開鍵を設定しておく必要があります
```
gcloud compute ssh ${インスタンス名} --dry-run
```

また、インスタンスに外部IPが付与されている場合は、以下のコマンドで自動的に「.ssh/config」が生成されます
※ ただし、Userパラメータは設定されないため、ユーザ名の指定は別途必要
```
gcloud compute config-ssh
```

細かいポイント
- OS Loginが有効な場合、Linuxユーザと紐付いているGoogle Cloudアカウントに適切な権限が付与されていないとアクセス不可