ANTIGRAVITY LABEN
記事一覧/アプリ開発
アプリ開発/2026-06-26上級

生成も配信も任せても、署名鍵だけは渡さない — AI 主導の配布パイプラインで鍵の管理と引き継ぎを設計する

AI Studio や Antigravity が生成から内部テスト配信までを肩代わりする時代でも、アプリの署名鍵だけは別格です。鍵を失えば、そのアプリは二度と更新できません。個人開発で複数アプリを長く運用してきた立場から、アップロード鍵とアプリ署名鍵の分離、鍵の保管、そして万一の引き継ぎまでを設計としてまとめました。

AI Studio5Antigravity271Android23Google Play5app-dev40

プレミアム記事

数年前、あるアプリのキーストアを危うく失いかけたことがあります。古い Mac を初期化する前夜、バックアップの一覧を眺めていて、.jks ファイルがどのバックアップにも入っていないことに気づきました。あの夜に気づいていなければ、そのアプリは更新する手立てを永久に失っていました。コードは生成し直せます。けれど署名鍵は、生成し直せません。

AI Studio や Antigravity が、生成から内部テスト配信までを一画面でつなぐようになったいま、配布のほとんどの工程は機械に預けられます。預けてよいのです。やり直しがきくからです。けれど署名鍵だけは性質が違います。鍵は「アプリの同一性そのもの」であり、失えばそのアプリは別物になってしまう。自動化が進んだパイプラインの中で、署名鍵をどう扱い、どこで人が握り続けるか。その線引きと実装を、長く複数アプリを運用してきた立場から設計として書きます。

まず、鍵を二種類に分ける

Google Play の署名には、性質の違う二つの鍵が関わります。ここを混同したまま自動化に載せると、渡してはいけない鍵まで機械の手の届く場所へ置いてしまいます。

ひとつはアプリ署名鍵です。ユーザーの端末に届く APK に最終的に署名される鍵で、Play アプリ署名を使っていれば Google が管理します。これはアプリの同一性の根幹で、原則として人も機械も日常的には触れません。触れないことが安全です。

もうひとつはアップロード鍵です。あなたが Play Console へ AAB を送るときに署名する鍵で、Google 側でアップロード鍵として登録されています。CI が自動でビルドを送るなら、署名に使うのはこのアップロード鍵です。重要なのは、アップロード鍵は失っても再登録できるという点です。紛失したらサポート経由で新しいアップロード鍵に差し替えられます。一方、Play アプリ署名を使わず自分でアプリ署名鍵を持っている古い構成では、その鍵を失った時点で更新は終わります。

この違いが、自動化の線引きをそのまま決めます。

鍵の種類失ったときの結果自動化に触らせてよいか
アプリ署名鍵(Play 管理)Google が保持。原則触れない触らせない(そもそも手元にない)
アップロード鍵再登録で復旧可能CI に注入してよい(保管は厳重に)
自己管理のアプリ署名鍵(旧構成)更新が永久に不可能絶対に渡さない・Play 署名へ移行を検討

私自身、いま運用している複数アプリは、可能なものはすべて Play アプリ署名へ移しました。自己管理の鍵を抱えたまま自動配信を回すのは、不可逆のリスクを毎晩通すようなものだと考えたからです。まだ移していない古いアプリがあるなら、自動化を強める前にここを片付けるのを勧めます。

鍵を平文で置かずに、自動署名へ供給する

アップロード鍵は CI に注入してよい、と書きました。とはいえ .jks をリポジトリに置いたり、パスワードをスクリプトに直書きしたりするのは論外です。生成 AI にコードを触らせる前提なら、なおさらです。鍵そのものと、鍵を開けるパスワードは、コードの世界の外に出します。

ローカルでは、鍵のパスワードを Keychain や環境変数のシークレットストアに置き、Gradle からは値を直接見せない形で渡します。

// app/build.gradle.kts — 鍵情報をコードに焼き込まず、環境から受け取る
import java.io.FileInputStream
import java.util.Properties
 
android {
    signingConfigs {
        create("release") {
            // パスは環境変数で受け取り、鍵ファイル自体はリポジトリに入れない
            val keystorePath = System.getenv("UPLOAD_KEYSTORE_PATH")
            if (keystorePath != null) {
                storeFile = file(keystorePath)
                storePassword = System.getenv("UPLOAD_KEYSTORE_PASSWORD")
                keyAlias = System.getenv("UPLOAD_KEY_ALIAS")
                keyPassword = System.getenv("UPLOAD_KEY_PASSWORD")
            }
        }
    }
    buildTypes {
        getByName("release") {
            signingConfig = signingConfigs.getByName("release")
        }
    }
}

CI では、鍵ファイルを Base64 で暗号化シークレットに格納し、ジョブの一時領域にだけ展開して、終了時に確実に消します。鍵が平文でディスクに残る時間を、ビルドの数分間だけに限定するわけです。

# GitHub Actions の例 — 鍵は一時展開し、後始末まで含めて門にする
- name: Restore upload keystore
  env:
    KEYSTORE_B64: ${{ secrets.UPLOAD_KEYSTORE_B64 }}
  run: |
    echo "$KEYSTORE_B64" | base64 -d > "$RUNNER_TEMP/upload.jks"
    echo "UPLOAD_KEYSTORE_PATH=$RUNNER_TEMP/upload.jks" >> "$GITHUB_ENV"
 
- name: Build & sign AAB
  env:
    UPLOAD_KEYSTORE_PASSWORD: ${{ secrets.UPLOAD_KEYSTORE_PASSWORD }}
    UPLOAD_KEY_ALIAS: ${{ secrets.UPLOAD_KEY_ALIAS }}
    UPLOAD_KEY_PASSWORD: ${{ secrets.UPLOAD_KEY_PASSWORD }}
  run: ./gradlew bundleRelease
 
- name: Shred keystore
  if: always()
  run: shred -u "$RUNNER_TEMP/upload.jks" 2>/dev/null || rm -f "$RUNNER_TEMP/upload.jks"

if: always() を付けた後始末を必ず置くのが肝心です。ビルドが失敗しても鍵ファイルが残らないようにします。AI エージェントに自動署名まで回させるとき、私が最初に固定したのはこの「展開と消去を対にする」型でした。鍵が出ている時間を最小化すれば、生成コードや一時ログに鍵が紛れ込む経路を狭められます。

注意したいのは、shredrm で消えるのはファイルだけだということです。ビルドログに鍵やパスワードを誤って出力していないかは、別途確認します。署名ステップの標準出力をそのままログに流す設定だと、稀に内部情報が漏れます。ログのマスキング設定を一度確認しておくと安心です。

ここまでお読みいただきありがとうございます。

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
アップロード鍵とアプリ署名鍵を分け、自動化に触らせてよい鍵と絶対に渡さない鍵を線引きする考え方
鍵を平文で置かずに自動署名へ供給する、CI とローカルでの保管・注入の実装手順
鍵紛失・漏洩・本人不在という三つの不可逆に対する、復旧と引き継ぎの運用設計
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

お読みいただきありがとうございます

Antigravity Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

関連記事

アプリ開発2026-06-24
生成から実機、内部テスト配信まで一手でつながった日に、私が手放さなかったもの — AI Studio の一気通貫を個人開発の配信フローに据える
AI Studio がテキストから Kotlin/Compose アプリを生成し、エミュレータ・実機・Play 内部テストまで一画面でつなぐようになりました。便利さの裏で「配信の瞬間」をどこまで機械に預け、どこを自分の手で握るか。個人開発で複数アプリを抱える立場からの線引きと、その境界を支える実装をまとめました。
アプリ開発2026-06-26
埋め込みエミュレータでは緑なのに、実機で初めて崩れる — AI 生成 Compose アプリに実機差を塞ぐ検証ゲートを置く
AI Studio はテキストから Kotlin/Compose アプリを生成し、埋め込みエミュレータで動かし、USB で実機へ送るところまで一画面でつなぎました。けれどエミュレータで通った画面が、手元の実機で初めて崩れることがあります。個人開発で複数アプリを抱える立場から、生成物に実機差を塞ぐ検証ゲートを据える設計をまとめました。
アプリ開発2026-06-25
AI Studio で作ったアプリを自分の端末に入れたら署名が合わないと弾かれた話
AI Studio で生成した Kotlin/Compose アプリを USB で実機へ転送したら INSTALL_FAILED_UPDATE_INCOMPATIBLE で弾かれる——。Google Play 公開済みアプリと同じパッケージ名のデバッグ署名ビルドを上書きできない理由と、本番アプリを消さずに試す手順をまとめます。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →