GitHub ActionsのmacOSランナーでアプリに署名するには、Developer ID Applicationの証明書を、ランナーのキーチェーンにインポートする必要がある。ランナーは毎回新しい環境なので、ワークフローの実行ごとに、証明書をインポートする。
証明書と秘密鍵をまとめた.p12を、base64にしてGitHubのSecretsに登録しておく。ワークフローでは、Secretsから.p12を復元し、一時的なキーチェーンにインポートする。
- name: Import signing certificate
env:
CERTIFICATES_P12: ${{ secrets.CERTIFICATES_P12 }}
CERTIFICATES_P12_PASSWORD: ${{ secrets.CERTIFICATES_P12_PASSWORD }}
run: |
echo "$CERTIFICATES_P12" | base64 --decode > "$RUNNER_TEMP/certificate.p12"
security create-keychain -p actions "$RUNNER_TEMP/temp.keychain-db"
security default-keychain -s "$RUNNER_TEMP/temp.keychain-db"
security unlock-keychain -p actions "$RUNNER_TEMP/temp.keychain-db"
security import "$RUNNER_TEMP/certificate.p12" -k "$RUNNER_TEMP/temp.keychain-db" -P "$CERTIFICATES_P12_PASSWORD" -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple: -s -k actions "$RUNNER_TEMP/temp.keychain-db"
実行例は、Xcode 27.0のランナー(runs-on: xcode-27)のもの。.p12の作り方は、Developer ID証明書の記事で紹介している。
参考: 【Developer ID】アプリ配布用の署名証明書を作成する
- 前の記事: 【GitHub Releases】appcast.xmlを固定URLで配信する
- 親記事: GitHubを使い、macOSアプリを署名・公証・自動アップデート付きで公開する
- 次の記事: 【GitHub Actions】CIでだけ署名設定をDeveloper IDに切り替える
.p12をSecretsに登録する
.p12は、バイナリのファイルである。base64の文字列にして、Secretsに登録する。.p12のパスワードも、別のSecretsに登録する。
$ /usr/bin/base64 -i developer_id.p12 | tr -d '\n' | gh secret set CERTIFICATES_P12 --repo [ユーザー名]/[リポジトリ名]
$ tr -d '\n' < p12_password.txt | gh secret set CERTIFICATES_P12_PASSWORD --repo [ユーザー名]/[リポジトリ名]
gh secret setは、標準入力から値を読み取る。値をコマンドの引数に渡さないため、シェルの履歴に残らない。tr -d '\n'で、改行を取り除く。
base64には、macOS標準の/usr/bin/base64を使う。Homebrewでcoreutilsを入れていると、base64がGNU版になる場合がある。GNU版のbase64は、-Dを受け付けず、-iの意味も異なる。
$ which -a base64
/opt/homebrew/opt/coreutils/libexec/gnubin/base64
/usr/bin/base64
登録したSecretsは、名前と更新日時だけを確認できる。値は表示されない。
$ gh secret list --repo [ユーザー名]/[リポジトリ名]
CERTIFICATES_P12 [更新日時]
CERTIFICATES_P12_PASSWORD [更新日時]
keychainのコマンドの意味
ワークフローの各コマンドの意味は、次のとおりである。
| コマンド | 意味 |
|---|---|
base64 --decode > certificate.p12 | Secretsのbase64の文字列から、.p12を復元する |
security create-keychain -p actions [パス] | 一時的なキーチェーンを、パスワードactionsで作成する |
security default-keychain -s [パス] | 作成したキーチェーンを、既定のキーチェーンにする |
security unlock-keychain -p actions [パス] | キーチェーンのロックを解除する |
security import [.p12] -k [パス] -P [パスワード] -T /usr/bin/codesign | .p12をキーチェーンにインポートし、codesignのアクセスを許可する |
security set-key-partition-list -S apple-tool:,apple: -s -k actions [パス] | Appleのツール(codesignなど)が、ダイアログなしで秘密鍵を使えるようにする |
base64 --decodeは、macOS標準の/usr/bin/base64が受け付けるオプションである。-Dでも復号できるが、--decodeであれば、GNU版でも同じように動く。
キーチェーンのパスワード(actions)は、一時的なキーチェーンの中だけで使う値である。ランナーが破棄されると、キーチェーンもなくなる。
$RUNNER_TEMPは、ジョブの間だけ使える一時ディレクトリである。キーチェーンと.p12を、リポジトリのディレクトリの外に置ける。
証明書がインポートされたことを確認する
インポートの後に、security find-identityで、署名に使える証明書を確認できる。
- name: Show identities
run: security find-identity -v -p codesigning
ログには、インポートした証明書が表示される。
1 identity imported.
1) [SHA-1ハッシュ] "Developer ID Application: [名前] ([Team ID])"
1 valid identities found
このランナーのキーチェーンには、インポートした証明書だけが表示された。同じ名前の証明書が複数ある環境と違い、署名に使う証明書を取り違えない。
ランナーで署名できることは、小さなバイナリで確認できる。
- name: Sign a test binary
run: |
cp /bin/echo ./echo-test
codesign -f -s "Developer ID Application" --timestamp --options runtime ./echo-test
codesign -dv --verbose=2 ./echo-test 2>&1 | grep -E 'Authority|flags|Timestamp'
./echo-test: replacing existing signature
CodeDirectory v=20500 size=277 flags=0x10000(runtime) hashes=3+2 location=embedded
Authority=Developer ID Application: [名前] ([Team ID])
Authority=Developer ID Certification Authority
Authority=Apple Root CA
Timestamp=[署名した日時]
Secretsの値はログでマスクされる
GitHub Actionsのログでは、Secretsに登録した値が***に置き換えられる。envで渡したCERTIFICATES_P12などの値も、***と表示される。
env:
CERTIFICATES_P12: ***
CERTIFICATES_P12_PASSWORD: ***
Team IDをSecretsに登録している場合は、codesign -dvの出力に含まれるTeam IDも、***になる。
Authority=Developer ID Application: [名前] (***)
set-key-partition-listは省略しても動いた
security set-key-partition-listは、codesignが秘密鍵に、ダイアログなしでアクセスできるようにするコマンドである。GitHub Actionsのランナーで、このコマンドを省略して、.p12のインポートの後にcodesignを実行すると、署名に成功した。
- name: Import signing certificate without set-key-partition-list
run: |
echo "$CERTIFICATES_P12" | base64 --decode > "$RUNNER_TEMP/certificate.p12"
security create-keychain -p actions "$RUNNER_TEMP/temp.keychain-db"
security default-keychain -s "$RUNNER_TEMP/temp.keychain-db"
security unlock-keychain -p actions "$RUNNER_TEMP/temp.keychain-db"
security import "$RUNNER_TEMP/certificate.p12" -k "$RUNNER_TEMP/temp.keychain-db" -P "$CERTIFICATES_P12_PASSWORD" -T /usr/bin/codesign
ここまでの手順で、インポートとcodesignによる署名は、set-key-partition-listなしで成功した。xcodebuildによる署名での必要性は、確認していない。ローカルのMacや別の環境では必要になる場合があるため、一般的な手順として、set-key-partition-listも実行しておく。
キーチェーンを削除する
GitHubが提供するランナーは、ジョブごとに使い捨てである。キーチェーンを削除する必要はない。
セルフホストランナーなど、環境が使い回される場合は、ジョブの最後にキーチェーンを削除する。
- name: Delete keychain
if: always()
run: security delete-keychain "$RUNNER_TEMP/temp.keychain-db"
参考: 【macOS】CLIでカスタムKeyChainを削除する
