結城です。
Firefox、Thunderbird、Google Chrome、Microsoft Edgeなどのアプリケーション用の拡張機能(WebExtensions)は、セキュリティ上の制限のために、任意のローカルファイルへのアクセスや外部の任意のプロセスの起動といった処理を行えません。 そういった処理が必要な場合は、処理を代行する小型のネイティブアプリケーションであるNative Messaging Hostを別途開発して、API経由で実行する1必要があります。
当社のメール誤送信対策製品「FlexConfirmMail」のThunderbirdアドオン版も、一部の機能でNative Messaging Hostを使用しています。 このNative Messaging Hostは今までWindows用の物のみを提供していましたが、当社の法人向けThunderbirdサポートサービスのお客さまからのご要望に基づいて、FlexConfirmMail 4.1.5からはmacOS用のバイナリも提供するようになりました。 この過程で、macOS向けにNative Messaging Hostを頒布する際の知見が溜まったため、その要点を簡単に解説します。
現在のmacOSでのソフトウェアの配布について
現在のmacOSでは、誰もが自由に・無制限にソフトウェアを頒布できるとは言い難いです。 正確には、頒布はできるのですが、それを受け取った側のユーザーが容易に実行できるようにするのにハードルがある、という状況です。
2019年にリリースされたmacOS 10.15 Catalina以降のバージョンでは、「悪意ある開発者によって作成されたソフトウェアを、ユーザーが実行してしまう(その結果、攻撃の被害を受ける)」という状況が発生しにくくなるように、公証(Notarization)という仕組みが導入されています。 これは、ソフトウェアの頒布用パッケージをApple社が事前に審査2するようにして、審査済みのパッケージでなければインストール操作をブロックする、というセキュリティ機構です。 公証されていないパッケージのインストールには少々トリッキーな操作が必要3ですし、そもそも、インストール時に表示されるメッセージがそれなりに物騒なので、この状態では一般の使用者向けには頒布しにくいです。
macOS用のFlexConfirmMailのNative Messaging Hostをお客さまに提供するにあたり、組織内で配布するパッケージは公証済みの物が望まれていました。 そのため、Native Messaging Hostのパッケージに公証をすることになった4次第です。
公証済みpkgファイルの作成手順
macOS向けのコンソールアプリ5を配布する方法には、HomebrewやMacPortsなどのパッケージ管理システムのリポジトリーにパッケージを収録してもらう方法(ソフトウェア開発者向け)と、自分でpkg形式のインストールパッケージを配布する方法(一般ユーザー向け)の2通りがあります。 Native Messaging Hostの使用者はWebブラウザーやEメールクライアントの使用者ということで、ソフトウェア開発者には限られないため、後者の方法(pkg形式)で配布するのが妥当です。
pkg形式のインストールパッケージの作り方は、過去の記事で詳しく解説していますが、そちらには公証を前提とした手順が含まれていません。
また、そちらの記事ではFluentdプロジェクト固有の事情からインストーラの動作を色々とカスタマイズしていますが、今回のmacOS向けの最小構成のNative Messaging Hostは、実行可能ファイルとJSON形式のマニフェストファイルの2つを /Library/Application Support/Mozilla/NativeMessagingHosts/
に配置するだけで成立します。
よって、ここでは最も単純な内容のpkg形式のインストールパッケージの作成手順をなぞりつつ、公証を受けるために必要な追加の手順について解説します。
macOS環境の調達とXCodeのインストール
今回配布したいNative Messaging HostはGo言語で開発しており、Goはクロスビルドが可能です。 よって、Native Messaging HostのmacOS用バイナリの作成自体にはmacOSは不要です。
しかしながら、pkg形式のファイルの作成や、ファイルへのデジタル署名、公証の手続きなど、必須の作業のいくつかはmacOS環境でXCodeのツールを使って行わなくてはなりません。 まずは新品なり中古なりで、macOS機を1台調達し、XCodeをインストールしておきましょう。
以降で説明する手順ではXCodeのGUIは使わず、CLIのツールだけを使います。 ただ、XCodeは利用許諾に同意していない状態だとCLIのツールが期待通りに動作しません。 インストールが終わったら一度XCodeを起動して、利用許諾に同意しておくのを忘れないようにしましょう。
Apple Developer Programへの登録
配布物の公証を受けるには、macOS機の調達費用に加えて、毎年12980円の出費が必要です。
「インストールパッケージの公証」と、その前提となる「実行可能ファイルへのデジタル署名」には、証明書が必要となります。 この証明書は、自己署名証明書(いわゆるオレオレ証明書)や一般のオブジェクト署名証明書ではなく、Apple Developer PortalのWebサービスを用いて発行する必要があり、証明書を発行するためにはApple Developer Programに登録しなくてはなりません。 12980円というのは、このApple Developer Programで必要な年間の登録料です。
Apple Developer ProgramはApple ID単位で登録する必要があり、Apple IDは複数人での共用が禁止されています。 公証作業を行う人が2人以上いる場合(2人で交代交代にやる、などの場合)は、担当者ごとにApple IDを作成してApple Developer Programに登録しないといけないようです。 今回は、筆者の業務用個人メールアドレス「yuki@clear-code.com」でApple IDを作成しました。
また、Apple Developer Programへの登録にあたっては、そのアカウントで2ファクタ認証(多要素認証)が有効化されている必要があります。 忘れずに設定しておきましょう。
会社の担当者としてApple Developer Programに登録する際は、以下の事も必要になります。
- 登録時に、会社の一意な識別子となるD-U-N-S番号が必要です。自社のD-U-N-S番号が何であるかは、総務省担当者の方などに問い合わせてください。もしまだ無い場合は、日本でD-U-N-S番号の管理を行っている東京商工リサーチ社のサービスから取得を申請する必要があります(こちらも有償です)。
- 担当者として会社を代表する権限があるかどうかを確認するために、申請手続きの過程で会社に別途連絡が来ます(申請時に、確認先の指名を求められます)。会社への問い合わせを受ける部署のどなたかにあらかじめ了承を取り、「AppleからApple Developer Program登録の件でこのような確認の連絡が来る予定なので、対応をお願いします」と根回しをしておくのを忘れないようにしましょう。
署名と公証の作業のための初期設定
Apple Developer Programへの登録が完了したら、公証を受けるために必要な物を揃えていきます。
- アプリケーション用パスワードを発行する。
- 会社のチームIDを調べる。 Apple Developer ProgramのWebサイトでログイン済みの状態で、ページ上部の「Account」から「メンバーシップの詳細」へ遷移した先のページに「チームID」という情報がありますので、これを手元に控える。 ここでは仮に「ABCDE12FGH」だったと仮定します。
- App 用パスワードを使って Apple ID で App にサインインするの説明に従って、Appパスワードを発行する。
今回は公証作業用に発行するので、
Pkg Notarization
という名前で発行することにします(ほかの名前にしても問題無いですが、後の説明を適宜読み替える必要があります)。
- notarytoolの初期設定を行う。
-
公証を行うCLIツールであるnotarytoolを使うための初期設定として、公証に必要な認証情報をキーチェインに保存する。 ターミナル(端末)を開き、以下の要領でコマンド列を実行します。
% xcrun notarytool store-credentials --apple-id "Apple ID(メールアドレス)" --team-id "チームID"
ここまでの例を当てはめると、具体的には以下のようになります。
% xcrun notarytool store-credentials --apple-id "yuki@clear-code.com" --team-id "ABCDE12FGH"
-
パスワードの入力を求められるので、現在ログイン中のアカウントのパスワードではなく、先程作成したAppパスワードの方を入力する。 「Success.」と表示されればOKです。
-
- デジタル署名6用の証明書を作成する。
公証は「私が作った物は安全である、ということをAppleが保証する」仕組みですが、「あなたがダウンロードしたファイルやAppleに渡ったファイルは、私が作った物と確実に同一である(他者の手が入っていない)、ということを保証する」のがデジタル署名です。
公証を受けるためには、pkgファイルと、その中に含まれる実行ファイルの両方にデジタル署名を施す必要があり、その作業のための証明書7を用意しなくてはなりません。
- Appleに証明書を発行してもらうために必要な、証明書リクエストを作成する。
- macOSでFinderを開き、「アプリケーション」→「ユーティリティ」→「キーチェーンアクセス」を起動する。
- メニューバーの「キーチェーンアクセス」から「証明書アシスタント」→「認証局に証明書を要求」を選択する。
- 「メールアドレス」はApple IDのメールアドレス、「通称」は自社の会社名、「CAのメールアドレス」は空欄とし、「ディスクに保存」→「続ける」を実行する。
ここまでの例を当てはめると、「メールアドレス」は
yuki@clear-code.com
、「通称」はClearCode Inc.
のようになります。 - 「CertificateSigningRequest.certSign」というファイルが作成されるので、任意の位置に保存する。 このファイルが「証明書リクエスト」の実体です。
- 実行ファイルに署名するためのコード署名証明書を発行する。
- Apple Developer Portalのページ最下部のリンク一覧からCertificates, Identifiers & Profilesを開く。
- 「Create a certificate」で証明書の作成を開始する。
- 「Developer ID Application - This certificate is used to code sign your app for distribution outside of the Mac App Store.」を選択して「Continue」する。
- 「Previous Sub-CA」を選択し、「Choose File」で先程作成した「CertificateSigningRequest.certSign」を選択して「Continue」する。
- 「Download Your Certificate」と表示されるので、ダウンロードする。「developerID_application.cer」がダウンロードされる。 このファイルがコード署名用の証明書の実体です。
- 「developerID_application.cer」をダブルクリックして、キーチェーンアクセスのアプリにインポートする。 これで、CLIから実行ファイルに署名できるようになります。
- 毎回の署名作業を簡単にするため、コード署名用の証明書の名前を環境変数に設定する。
.zshrc
や.bashrc
などにexport APPLICATION_CERT_NAME="$(security find-identity -v | grep -E -o '(Developer ID Application:[^"]+")')
という行を追記し、環境変数APPLICATION_CERT_NAME
で証明書の名前を参照できるようにしておきます。 また、この作業に続けて実際の署名作業を行うのであれば、今設定ファイルに追記した内容をそのままシェル上で実行するか、source ~/.zshrc
やsource ~/.bashrc
などとして設定ファイルを再読み込みします。
- pkgファイルに署名するためのパッケージ署名用証明書を作成する。
- Apple Developer Portalのページ最下部のリンク一覧からCertificates, Identifiers & Profilesを開く。
- 「Create a certificate」で証明書の作成を開始する。
- 「Developer ID Installer - This certificate is used to sign your app's Installer Package for distribution outside of the Mac App Store.」を選択して「Continue」する。
- 「Previous Sub-CA」を選択し、「Choose File」で先程作成した「CertificateSigningRequest.certSign」を選択して「Continue」する。
- 「Download Your Certificate」と表示されるので、ダウンロードする。「developerID_installer.cer」がダウンロードされる。 このファイルがパッケージ署名用の証明書の実体です。
- 「developerID_installer.cer」をダブルクリックして、キーチェーンアクセスのアプリにインポートする。 これで、CLIからpkgファイルに署名できるようになります。
- 毎回の署名作業を簡単にするため、パッケージ署名用の証明書の名前を環境変数に設定する。
.zshrc
や.bashrc
などにexport INSTALLER_CERT_NAME="$(security find-identity -v | grep -E -o '(Developer ID Installer:[^"]+")')
という行を追記し、環境変数INSTALLER_CERT_NAME
で証明書の名前を参照できるようにしておきます。 また、この作業に続けて実際の署名作業を行うのであれば、今設定ファイルに追記した内容をそのままシェル上で実行するか、source ~/.zshrc
やsource ~/.bashrc
などとして設定ファイルを再読み込みします。
- Appleに証明書を発行してもらうために必要な、証明書リクエストを作成する。
以上で準備は完了です。
実行ファイルへの署名からpkgの生成、公証まで
すべての準備ができたら、いよいよ配布物の作成です。 以下の手順は、新バージョンのリリースの度に実施することになります。
- 配布したい実行ファイルに署名を行う。
- 実行ファイル(今回はNative Messaging Host本体である
host
)のあるディレクトリーにcd
する。 codesign --force --options runtime --sign "$APPLICATION_CERT_NAME" ./host
と実行する。 このとき、オプションの指定で--options runtime
を忘れると、後の手順で公証に失敗してしまうので、注意して下さい。- キーチェーンにアクセスするためにパスワード入力を求められるので、現在のアカウントのログインパスワードを入力する。
codesign -dvvv ./host
を実行して、実行ファイルの署名の情報を表示し、署名が期待通りに行われたことを確認する。
- 実行ファイル(今回はNative Messaging Host本体である
- pkgファイルを作成する。
以下は、実行ファイルとマニフェストファイルの2つだけを含み、それらのファイルを
/Library/Application Support/Mozilla/NativeMessagingHosts/
に配置するだけの、最小構成のNative Messaging HostであるFlexConfirmMail Native Messaging Hostの場合の手順です。- 簡単のため、
NMH_NAME=com.clear_code.flexible_confirm_mail_we_host
として、Native Messaging Hostの識別子をシェル変数に格納する。 NMH_PKG_TMP="$(mktmp -d)"
で、作業用ディレクトリーを作成する。cp "$NMH_NAME.json" "$NMH_PKG_TMP/"
で、マニフェストファイルを作業用ディレクトリーに配置する。mkdir -p "$NMH_PKG_TMP/$NMH_NAME"; cp host "$NMH_PKG_TMP/$NMH_NAME/"
で、署名済みの実行ファイルを作業用ディレクトリーに配置する。chmod 644 "$NMH_PKG_TMP/$NMH_NAME.json"; chmod 755 "$NMH_PKG_TMP/$NMH_NAME/host"
で、マニフェストファイルと実行ファイルに適切なパーミッションを設定する。pkgbuild --root "$NMH_PKG_TMP" --identifier "$NMH_NAME" --install-location '/Library/Application Support/Mozilla/NativeMessagingHosts/' --version "$(./host -v)" "$NMH_NAME.pkg"
で、アプリ名・インストール先・バージョン番号を指定してpkgファイルを作成する。
- 簡単のため、
- pkgファイルに署名を行う。
- 生成したpkgファイルがあるディレクトリーで
productsign --sign "$INSTALLER_CERT_NAME" "./$NMH_NAME.pkg" "./$NMH_NAME.signed.pkg"
と実行する。 - キーチェーンにアクセスするためにパスワード入力を求められるので、現在のアカウントのログインパスワードを入力する。
Wrote signed product archive to ...
と出力されれば、署名は完了です。 pkgutil --check-signature "./$NMH_NAME.signed.pkg"
を実行して、pkgファイルの署名の情報を検証する。 署名が期待通りに行われていれば、この操作は特にエラーにならずに成功します。
- 生成したpkgファイルがあるディレクトリーで
- 署名済みのpkgファイルに公証を得る。
xcrun notarytool submit "$PWD/$NMH_NAME.signed.pkg" --keychain-profile "Pkg Notarization" --wait
で、公証を行う。xcrn notarytool submit
による公証の申請は本来は非同期で、「コマンドの実行に成功した後で頃合いを見計らって公証の結果のステータスを調べる」ということをする必要があります。--wait
を指定することで、公証が終わるまで待ってから結果が表示されるという、同期的なCLIのツールのように振る舞うようになります。Accepted
と表示されれば公証成功です。Invalid
と表示された場合、何らかのトラブルが起こって公証に失敗しています。id
欄に公証申請の識別子となるUUIDが含まれているので、これを控えた上でxcrun notarytool log 申請のUUID --keychain-profile "Pkg Notarization" error.log
を実行してエラーログを保存し、その内容を確認して、エラーの原因を取り除きましょう。 筆者の場合、以下の理由での失敗を経験しました。- pkgファイルは署名済みだったが、実行ファイルが未署名だった。 公証を得るには、実行ファイルもpkgファイルも両方とも署名されている必要があります。
- pkgファイルに格納された実行ファイルへの署名時に
--options runtime
の指定を忘れていた。 これは実行ファイルをHardened Runtime対応とするための物で、公証を得るには実行ファイルがHardened Runtime対応になっている必要があります。
xcrun stapler staple "$PWD/$NMH_NAME.signed.pkg"
を実行して、公証の情報をpkgファイルに付与する。 pkgファイルが公証されているかどうかはAppleのサーバーに問い合わせなければ確認できないのですが、この工程を経ることで、「このpkgファイルは公証されている」という情報をpkgファイル自体に付与して、オフライン状態でも安心してインストールできる状態になります。
FlexConfirmMail Native Messaging Hostでは、この定型の操作をシェルスクリプトにしておき、Windows等でビルドした実行ファイルをmacOS環境に持ち込んで、pkgの作成までを半自動で行えるようにしています。
まとめ
以上、FlexConfirmMailのNative Messaging HostのmacOS版の場合を例に引きながら、macOS用非GUIアプリの配布・インストール用パッケージについて、作成手順や公証手順をご紹介しました。
当社では、自社開発のFirefox/Thunderbirdアドオンや、自由なライセンスで公開されている既存のアドオンについて、法人の客さまに対する有償でのサポートの一環として、ご要望に基づきカスタマイズや改修・パッケージ提供などを行っています。 Firefox/Thunderbirdアドオンの導入や運用でお困りの企業ご担当者さまは、お問い合わせフォームよりご連絡下さい。
-
Native Messaging Hostだけは例外的に、ネイティブアプリケーションであってもAPI経由で起動できるようになっています。 ↩
-
既知のマルウェアが含まれていないかどうかなどのセキュリティスキャンを自動で行う、という形になっている模様です。 ↩
-
実際には、ソフトウェア開発者などの上級者向けの方法として、Finder上でファイルをControl-左クリック(2ボタン以上のマウスでは右クリック)して「開く」を選択することで、セキュリティ機構を迂回してのインストールは可能です。 ↩
-
簡単にはインストールできない状態(インストール時に一手間が必要な状態)のままでも構わなければ、未公証のパッケージを公開する事自体には問題はありません。今回は、お客さまの環境で一般のユーザーがインストールを行う前提があったために、このような判断となった模様です。 ↩
-
Native Messaging HostはGUIを持つ事もできます(実際、FlexConfirmMailのNative Messaging Hostはファイル選択ダイアログを開く機能を含んでいます)が、Finderからファイルをダブルクリックして起動するような使い方はできませんので、ここではコンソールアプリとして扱っています。 ↩
-
電子情報に暗号技術を使って署名を施す技術を「デジタル署名」と呼びます。「電子署名」は、液晶ペンタプレットによる署名の直筆などを含む、電子的手段での署名を実現する技術の総称です。 ↩
-
いわゆる秘密鍵。 ↩