備忘録:AdGuard DNS ルール追加の自動化と権限分離の構築
1. 目的
標準ユーザー環境から、管理者権限やAPIキーを直接参照することなく、安全にAdGuard DNSのフィルタリングルールを追加するシステムを構築する。
2. システム構成
- ロジック層: Python(
urllibまたはcurlを利用したREST API操作) - インターフェース層: AppleScript(アプリ化し、ユーザー入力を受け取る)
- セキュリティ層: macOSキーチェーン(APIキーの秘匿)およびコード署名(改ざん検知)
3. 技術的実装の詳細
A. PythonによるAPI操作
AdGuard DNS API(v1)を用いたルール更新には、特定の階層構造を持つJSONをPUTメソッドで送信する必要がある。
- エンドポイント:
https://api.adguard-dns.io/oapi/v1/dns_servers/{SERVER_ID}/settings - 認証: ヘッダーに
Authorization: ApiKey {API_KEY}を付与。 - データ構造:
user_rules_settingsをルートとしたオブジェクトで送信。既存のルールを上書きしないよう、一度GETで現在のリストを取得し、配列に新規ドメインを追加して投げ返す。
Python
# ペイロード構造の例
payload = {
"user_rules_settings": {
"rules": current_rules_list,
"enabled": True
}
}
B. キーチェーンによる秘匿化
APIキーをコード内にハードコードせず、macOSのキーチェーンに保存。Pythonのkeyringライブラリを使用して取得する。 管理者ユーザーで鍵を登録し、標準ユーザーからのアクセス時に一度だけ管理者パスワードで「常に許可」を与えることで、以降のパスワード入力を省略する。
Bash
# キーチェーンへの登録コマンド
security add-generic-password -a "AdGuardUser" -s "AdGuardAPI" -w "YOUR_API_KEY"
C. AppleScriptによるGUI化
ユーザーがドメインを入力するためのダイアログを表示し、Pythonスクリプトへ引数として渡す。
AppleScript
set theDomain to text returned of (display dialog "Enter Domain:" default answer "")
do shell script "python3 /path/to/logic.py " & quoted form of theDomain
4. ハマりどころと解決策
- エンコード問題: Pythonから日本語メッセージを出力すると、実行環境のエンコード設定(ASCII)によりエラーとなる。出力メッセージを英語に統一することで回避。
- APIの405/404エラー:
/settingsエンドポイントに対し、サーバー情報全体をPUTすると拒否される。更新対象であるuser_rules_settingsだけを内包したJSONを送ることで解決。 - ライブラリのパス: 管理者側でインストールしたPythonライブラリ(
keyring等)が標準ユーザー側で見えない場合がある。python3 -m pip installでユーザー環境にも個別に導入するか、システム全体に導入して対応。
5. セキュリティ・プロトコル
- コード署名: 管理者権限で
codesignを行い、アプリの整合性を保証する。 - 権限分離: アプリの実行を標準ユーザー、鍵の所有を管理者ユーザーに分離。アプリ改ざん時には再署名が必要となり、管理者パスワードが必須となるため、セルフコントロールの強度が向上する。