cocoapods‑keys を使ってシークレットをソースコードと分離して安全に扱う

cocoapods‑keys を使ってシークレットをソースコードと分離して安全に扱う

Clock Icon2025.05.09

はじめに

API キーやシークレットをソースコードにハードコーディングすると、GitHub を公開した際に流出リスクが生じる。

cocoapods‑keys は key の名前だけを Podfile に記述し、値は開発者のローカル Keychain に格納する CocoaPods プラグインだ。プロジェクト内へは難読化された stub だけが生成されるため、比較的安全にバイナリへ埋め込める。

この記事では cocoapods‑keys を導入し、アプリ起動直後に Text でAPI キーの値を表示するところまでを解説する。

動作環境

  • macOS 15.4.1(24E263)
  • Xcode 16.2
  • Homebrew 4.4.31
  • CocoaPods 1.16.2
  • cocoapods‑keys '818f9d2'
    • 注意:'818f9d2' はバージョンではなくコミット ID 固定

1. CocoaPods と cocoapods‑keys をインストール

bundle init で Gemfile を生成し、下記を追記してインストールする。

# frozen_string_literal: true

source "https://rubygems.org"

# gem "rails"
gem "cocoapods"
gem "cocoapods-keys", ref: '818f9d2'

bundle install 後に bundle exec pod --versionbundle exec pod keys --help が通れば準備は完了だ。

2. Xcode プロジェクトを CocoaPods 対応にする

bundle exec pod init で Podfile を生成し、次のように編集する。

platform :ios, "18.0"

plugin "cocoapods-keys", {
  :project => "SampleCocoaPodsKeys",
  :keys    => [
    "ApiKey",
    "ApiBaseUrl"
  ]
}

target "SampleCocoaPodsKeys" do
  use_frameworks!
  # Pods for SampleCocoaPodsKeys
end

post_install do |installer|
  installer.pods_project.targets.each do |t|
    t.build_configurations.each do |c|
      c.build_settings["IPHONEOS_DEPLOYMENT_TARGET"] = "18.0"
    end
  end
end

:keys に列挙した文字列が環境変数名となる。ハイフン付きキーは避け、API-KEY ではなく ApiKey のように記述する。

3. pod install でキー値を入力

bundle exec pod install の初回実行時、Podfile へ書いたキーごとに値の入力を求められる。入力した値は、ローカルPCのKeychainに保存される。

20250509195157

値をあとから変更したい場合

bundle exec pod keys set ApiKey "abcd1234"
bundle exec pod keys set ApiBaseUrl "https://api.example.com"

保存済みの値は bundle exec pod keys get ApiKey で確認できる。

4. 生成物を確認

Pods/ 配下に CocoaPodsKeys モジュールが追加される。

20250509195906

生成された SampleCocoaPodsKeysKeys.m は難読化済みソースだ。シークレットとソースを分離する意味が薄れるため、このファイル群は Git へコミットしないよう .gitignore に追加する。

# cocoapods‑keys stub
Pods/CocoaPodsKeys/**

5. SwiftUI からキーを読む

Keys フレームワークを import し、生成クラスからプロパティを取得する。デバッグビルドのみキーを表示する場合は #if DEBUG を使う。

import SwiftUI
import Keys

struct ContentView: View {
    private let keys = SampleCocoaPodsKeysKeys() // 自動生成されたクラス名

    var body: some View {
        VStack {
#if DEBUG
            Text("API KEY: \(keys.apiKey)")
            Text("BASE URL: \(keys.apiBaseUrl)")
#endif
        }
        .padding()
    }
}

#Preview {
    ContentView()
}

アプリを実行した結果は以下の通り。

20250509201311

トラブルシューティング

rsync の Sandbox エラーが出る

以下のようなエラーが発生した場合は、Build SettingsのUser Script SandboxingNo に変更すると解決する。

Sandbox: rsync(58413) deny(1) file-write-create /Users/ch3cooh/Library/Developer/Xcode/DerivedData/SampleCocoaPodsKeys-cfrvgzlpnlcswcaspcgbzzumdzyd/Build/Products/Debug-iphonesimulator/SampleCocoaPodsKeys.app/Frameworks/Keys.framework/_CodeSignature

CI で Keychain が使えない

ローカルPCではKeychainにシークレットの値を保存した。CIではKeychainを使えない。CI環境では、シークレットの環境変数を設定することで、そちらの値を使ってくれるようになる。

まとめ

  • Podfile の cocoapods‑keys へ Key 名だけを列挙する
  • pod install 時に Keychain へ安全に保存される
  • Swift からは ProjectNameKeys().apiKey の形式で参照できる

これでリポジトリへシークレットをコミットせずに済む。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.