GitHub ActionsでSSHを使う

# はじめに

現在ベータ版で、来月正式リリースが予定されている[GitHub Actions](https://github.co.jp/features/actions)。
v2になってからは、[HCL](https://github.com/hashicorp/hcl)ではなくYAMLで書けるようになったり、実行環境のOSを選べるようになったりと機能が充実してきたので、これから使われる機会が増えていくと思います。

このGitHub ActionsをCDに使う場合、SSHが必要になることがあります。

そんなときにはこの記事のことを思い出すと幸せになれるかもしれません。

## 2020/09/20追記

v2で仕様が変わったので、本記事の内容も更新しました。
v2が出て半年以上放置していました。ごめんなさい。

# 対象者

* GitHub上でアプリケーションを開発している
    * 特にウェブアプリケーションの開発でこの記事が役に立つかも
* GitHub Actionsを使ってデプロイしたい
    * GitHubへのイベント（ブランチへのマージやリリースタグの作成等）をトリガーにして、開発環境や本番環境にデプロイしたい
* **デプロイにSSHを使う**
    * SCPとかSFTPとかrsync over SSHとか
* **デプロイ用シェルスクリプトを自前で用意している**
    * SSH以外にもいろいろな処理を行っていて、一連の処理をスクリプト化しているような場合

# やりたいこと

## SSHやSCPを単独で使うのではなく、スクリプト内で実行したい

SSHやSCPを**単独で使う**だけ（SSHサーバー上でコマンドを実行するだけ、特定のファイルをコピーするだけetc）なら、[GitHub Marketplace](https://github.com/marketplace)に登録されているactionの中に有用なものがあると思います。

* [SCP](https://github.com/marketplace?type=actions&query=SCP)
* [rsync](https://github.com/marketplace?type=actions&query=rsync)

しかし、スクリプトファイル内でSSHを使う場合はこれらのactionを使えません。
例えばこんなとき。

1. SSHの前後でいろいろな処理を行っている
    * 例1: SCP前にビルド処理を行っている
    * 例2: pushされたブランチによって転送先を変更したいので、そのための分岐処理を行っている（`develop`ブランチなら開発環境、`master`ブランチなら本番環境等）
1. GitHubへの依存度を減らすためにスクリプトファイルを使いたい
    * SSH前後に処理が必要な場合でもGitHub Actionsなら一連の処理をYAMLファイルで記述できますが、それだとGitHubへの依存度が高くなるのでスクリプトファイルを使いたい場合
1. 以前に作ったデプロイ用スクリプトを再利用したい
    * 以前にGitHub Actions以外のCI/CDを使っていて、そこで作ったデプロイ用スクリプトを再利用したい場合

## SSHで鍵認証を使いたい

GitHub Actionsの実行環境（Windows, macOS, Ubuntu）には、いずれもsshコマンドが標準で入っています。
そのため、SSHを使うこと自体は簡単にできます。

しかし、当然ながらSSHサーバーへの接続鍵（`authorized_keys`に登録されている鍵）はGitHub Actionsの実行環境に存在しないので、そのままでは鍵認証を行えません。

かといって、パスワード認証はセキュリティー上使いたくない場合も多いでしょう。

# 解決方法

上記の問題は、**GitHub Actionsの実行環境にSSH鍵（＋接続先サーバーの公開鍵）を登録**できれば解決します。

Marketplaceを探したところ、これをやってくれるactionが見つからなかったので**作ってみました**。

[![Install SSH Key](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221555/51ec2e1f-8f29-cf74-02a4-174295da5ec6.png)](https://github.com/marketplace/actions/install-ssh-key)

**長い前フリ**ですが、これの紹介と使い方の説明が本記事の主題です。

# 使い方

## 鍵を登録

最初に注意事項ですが、**秘密鍵は極秘情報なので、Gitでバージョン管理してはいけません**。

以下のようにしてプロジェクトに鍵を登録してください。

GitHubのプロジェクトページの`Settings` - `Secrets` - `Add a new secret`の順にクリックし、例えば以下のような名前でそれぞれ登録してください。別の名前でも構いません。

* `SSH_KEY` - SSH秘密鍵
* `KNOWN_HOSTS` - サーバーの公開鍵＋ホスト名/IPアドレス（`.ssh/known_hosts`ファイルのフォーマット）

`KNOWN_HOSTS`は公開情報なのでGit管理しても問題ないかもしれませんが、とりあえず全てSecretsに登録しておきます。

## デプロイスクリプトを用意

次に、リポジトリにデプロイスクリプトを追加してください。
ここでは`deploy.sh`という名前で用意したとします。

内容はたとえばこのようになるでしょう。
必要に応じてビルド処理や転送先の切り替え処理などを入れてください。

```bash:deploy.sh
#!/bin/bash
# outputディレクトリ内のファイルをrsync over SSHで転送
rsync -acvz --delete ./output/ user@remote:/path/to/deploy/
# サービスを再起動
ssh user@remote "<run restart or graceful-reload command>"
```

## ワークフローファイルを記述

リポジトリに`.github/workflows/deploy.yml`ファイルを作り、以下のように記述してください。
ファイル名は変えても構いませんが、**ディレクトリ名は変えてはいけません**。

ワークフローファイルの書き方の詳細は、[GitHub Actionsのワークフロー構文](https://help.github.com/ja/articles/workflow-syntax-for-github-actions)を参照してください。

```yaml:deploy.yml
on:
  release:
    types:
    - published # 新しいリリースが作成されたときに実行
name: Deploy
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
    - name: Install SSH key
      uses: shimataro/ssh-key-action@v1
      with: # shimataro/ssh-key-actionに渡すパラメーター
        key: ${{ secrets.SSH_KEY }} # 必須
        name: id_rsa # 省略可
        known_hosts: ${{ secrets.KNOWN_HOSTS }} # 必須
    - name: run deploy script
      run: bash deploy.sh
```

`secrets.SSH_KEY`等は、上で登録したSSH鍵等の名前と同じものを指定してください。

最初のステップ（`Install SSH Key`）で、以下の処理が行われます。

* `key`で指定した秘密鍵を`.ssh/id_rsa`に保存
* `known_hosts`で指定したサーバー公開鍵を`.ssh/known_hosts`に保存

ファイルのパーミッションは、それぞれ適切なものに設定されます。

**以上で、リリースの作成をトリガーとして`deploy.sh`が実行されるようになります**。

## 諸注意

`name`は省略できます。省略した場合は`"id_rsa"`が使われます。

`known_hosts`はv1では省略できましたが、v2ではセキュリティー上の理由により必須としました。時々[`known_hosts`を省略可能にしてほしいという要望](https://github.com/shimataro/ssh-key-action/issues/143)がありますが、対応する予定はありませんのでご了承ください。

# 3行で

長くなったので3行でまとめます。

* GitHub Actions便利だよ
* スクリプト内でSSHを使いたいときは[Install SSH Key](https://github.com/marketplace/actions/install-ssh-key)を使うといいよ
* v2からは`known_hosts`も必須になったよ
* **ついでにStarつけてくれたらうれしいな**（4行目）

# GitHub Actionsについての資料

* [GitHub Actions](https://github.co.jp/features/actions) - GitHub Actionsについて
* [GitHub Actionsのワークフロー構文](https://help.github.com/ja/articles/workflow-syntax-for-github-actions) - GitHub Actionsを使うときのYAMLファイルの書き方
* [GitHub Actionsのメタデータ構文](https://help.github.com/ja/articles/metadata-syntax-for-github-actions) - actionを作ってみたい方はこちらもどうぞ