アプリ申請自動化とAppleID2ファクタ認証

# はじめに
2019年にAppleDeveloperProgramのAppleIDは2ファクタ認証が必須となりました。(AccountHolderというもっとも権限を持つアカウントのみ)

この2ファクタ認証が有効になることにより、
CIサービスを用いたアプリ申請自動化にどのような影響が出るのか
またその回避策を改めてまとめた記事です。

この記事はfastlaneを中心に情報をまとめます。

# 2ファクタ認証 OFFが最もシンプル
はじめに述べてしまいますが、
もっともシンプルな解決策は2ファクタ認証を有効化**していない**アカウントを用意することです。
運用上、それが難しい方がこの記事でなんらかの解決策を見出して頂けると嬉しいです。

# 前提情報
### アプリ申請の手順
今回はアプリ申請に関わる手順を以下のものとします。

1. 証明書とProvisioningProfileを取得または作成
1. ipaファイルをAppstoreConnectにアップロード
1. ストア情報のアップロード (説明文やスクショ等)
1. 再コンパイルの完了を待つ
1. アプリ審査提出
1. 再コンパイル後のdSYMをダウンロード
1. firebase等にdSYMをアップロード

これらの手順のなかでも、AppleIDの2ファクタ認証の影響を受けるものと
FastlaneのActionを表にしたものが以下です。
※ `deliver`が2つあるのは、用途により認証に必要な情報が違うためです

| Fastlane Action | 用途 |
|:--|:--|
| match | 証明書及びProfisioningProfileの管理 |
| deliver | ipaのアップロード |
| deliver | ストア情報のアップロード |
| download_dsyms | 再コンパイル後のdSYMをダウンロード |

# 2ファクタ認証の回避方法
確認コードの入力を回避しインタラクティブモードでなくとも (CIサービス等で) アプリ申請を行う方法。
大きく分けて2つあります。

### Sessionを利用する
AppleIDのログインクッキーが環境変数 `FASTLANE_SESSION` に設定されていれば2ファクタ認証を回避できます。
(所定のディレクトリにクッキー情報をファイルで配置する方法もあります)
**ただし、クッキーは有効期限が1ヶ月と限られており、定期的に再認証が必要となります。**
また、このSessionはアクセスする地域が大きく異なると無効となる点も注意が必要です。
例) 日本のローカルマシンで生成したクッキーをクラウド(北米)で利用する
Bitriseでは[このような](https://blog.bitrise.io/app-store-connect-2fa-solved-on-bitrise)対策が取られています。

#### Sessionを利用する際に必要な情報

|概要|環境変数名|
|:--|:--|
|アプリ申請可能なAppleID|FASTLANE_USER|
|アプリ申請可能なAppleIDのパスワード|FASTLANE_PASSWORD|
|アプリケーション固有パスワード<br>ipaファイルのアップロード時にのみ必要|FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD|
|2ファクタ認証成功時に得られるクッキー<br>**有効期限1ヶ月**|FASTLANE_SESSION|
|証明書やProvisioningProfileを複合化するパスワード|MATCH_PASSWORD|

### AppStoreConnect APIを利用する
アクセス用の証明書を生成することで2ファクタ認証を回避できるAPIが公開されています。
この方法を利用すると恒久的に2ファクタ認証を回避できますが、提供されている機能は限られています。Fastlane Actionとの対応表が以下です。

| Fastlane Action | 用途 | AppStoreConnect API対応 |
|:--|:--|:--|
| match | 証明書及びProfisioningProfileの管理 |○|
| deliver | ipaのアップロード |○|
| deliver | ストア情報のアップロード |○|
| download_dsyms | 再コンパイル後のdSYMをダウンロード |×|


# 追加情報
## FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORDの生成方法
1. [Appleアカウントの管理](https://appleid.apple.com/)にアクセス
2. セキュリティ項目のパスワード生成をクリック
<img width="990" alt="スクリーンショット 2020-03-28 10.51.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14646/2eeb5e9d-0c34-02cb-9d38-d60dd5e3d93a.png">
3. 任意の名前をつける
<img width="451" alt="スクリーンショット 2020-03-28 10.51.17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14646/679cb66b-510e-7361-5e41-3da418115775.png">

4. 得られるパスワードが `FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD` として利用可能
<img width="449" alt="スクリーンショット 2020-03-28 10.51.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14646/f1905a6f-d0cd-40fc-c97d-9617f1b3b207.png">



## FASTLANE_SESSIONの生成方法
[fastlane spaceship](https://github.com/fastlane/fastlane/tree/master/spaceship) を利用します。
このspaceshipはAppstoreConnectへの認証やAppstoreConnectAPIラッパーとなっており、
deliverやdownload_dsymsの内部で利用されています。

以下のコマンドを実行すると、
パスワードの入力や確認コードの入力が求められます。

```
fastlane spaceauth -u user@email.com
```

認証に成功すると、`~/.fastlane/user@email.com/cookie`にクッキーが保存されます。
このファイルの内容を環境変数 `FASTLANE_SESSION` として利用することができます。

## AppStoreConnect API Keyの発行方法
1. [AppStoreConnectのユーザーページ](https://appstoreconnect.apple.com/access/api)にアクセスし
**APIキーを生成** ボタンをクリックします。
![スクリーンショット 2020-12-16 12.50.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14646/01cbe33c-9731-677d-46bd-1e07817d5923.png)

2. 任意の名前をつけ、アクセス権を決定します。 (Deliverに利用するのであればApp Manager以上を付与)
![スクリーンショット 2020-12-16 12.51.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14646/3df607f3-4bb1-f281-901d-16398c8eb5f1.png)

3. APIキーファイル、IssuerID、KeyIDの3つを利用することでAPIを利用可能です。
[fastlaneでの利用](https://docs.fastlane.tools/app-store-connect-api/#using-app_store_connect_api_key)
![スクリーンショット 2020-12-16 12.51.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14646/4e65f6d9-527c-6135-ba00-c556e7de9897.png)


# まとめ
- 2ファクタ認証を回避するには2つの方法がある
1. Sessionを利用する
    - メリット
        - fastlaneのすべての機能が利用できる
    - デメリット
        - 月に1度、セッションを更新しなければならない
2. AppStoreConnect APIを利用する
    - メリット
        - 恒久的に2ファクタ認証を回避できる
    - デメリット
        - fastlaneのすべての機能が利用**できない**