🐥

AutoPrivacy DataCleanRoomを実践してデータ共有がどう行われるのか理解する

に公開

はじめに

こんにちは、株式会社 Acompany の北谷です。最近モンハンワイルズの王トゥナに苦戦中です。今回は自社製品である AutoPrivacy DataCleanRoom(AutoPrivacyDCR) を実際に触って、二者間でプライバシーを保護しながら安全にデータを共有・処理できるのかを確かめてみました。今回は APC-CLI(AutoPrivacyCloud-CLI) を使って Cleanroom 環境でクロス集計を行った体験を、準備から実行まで含めてまとめます。

AutoPrivacy DataCleanRoomとは

AutoPrivacy DataCleanRoom(AutoPrivacy DCR) は、複数の参加者が生のデータを互いに共有することなく、隔離環境内で安全に処理を実行して結果を受け取ることができるサービスです。

AutoPrivacy DataCleanRoom の特徴

AutoPrivacy DataCleanRoom の特徴として、TEE(Trusted Execution Environment) 環境を利用していることが挙げられます。この TEE 環境ではメモリが暗号化されており、特権管理者や弊社 Acompany であっても中身を見ることができません。

実行環境の準備

クライアント動作環境

  • Python 3.10
  • macOS(arm64)

今回は MacOS を使用しましたが、Linux(x86_64) でも実行が可能です。

ソースコード

チュートリアルが公開されているので、こちらを参考に進めます。

サーバーのセットアップ

今回は、開発チームにデータクリーンルームの環境をセットアップしてもらい、接続情報を含んだメールを送信してもらいました。
実際の場合も同様に、接続情報を含んだメールが送信される予定です。

環境変数の設定

メールに記載された接続情報を環境変数に反映します。
設定例を以下に記載します。

# プロファイル設定
$ export profile1=user1
$ export profile2=user2

# API設定(サービス提供者から提供されたconfig.tomlファイルから取得)
$ export API_URL="<環境ごとのAPI URL>"
$ export ATTESTATION_URL="<アテステーションに使用するURL>"
$ export ATTESTATION_API_VERSION="2025-06-01"
$ export MR_ENCLAVE="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$ export MR_SIGNER="bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"

# 各ユーザーの認証情報(サービス提供者から提供)
$ export CLIENT_ID1="<client_id_1>"
$ export CLIENT_SECRET1="<client_secret_1>"
$ export CLIENT_ID2="<client_id_2>"
$ export CLIENT_SECRET2="<client_secret_2>"

# プロジェクトID
$ export PROJECT_ID="proj-test"

# 設定ファイル
$ export ENCRYPTED_FILES_PATH="encrypted-files.yaml"

APC-CLIのセットアップ

1. APC-CLIのダウンロードとインストール

今回は macOS 向けのバイナリをダウンロードします。

# OS判定とダウンロード(macOS ARM64の場合)
$ wget https://github.com/acompany-develop/apc-cli/releases/download/$APC_CLI_VERSION/apc-darwin-arm64.zip
$ unzip apc-darwin-arm64.zip
$ mv apc-darwin-arm64 apc
$ chmod +x apc
$ rm apc-darwin-arm64.zip

2. プロファイル設定

ユーザープロファイルを設定します。対話型で、API URL から順に入力していきます。
1つのユーザープロファイルが、データコラボレーションにおける1つのパーティーに対応すると考えてもらえるとわかりやすいです。
入力を続けていくと、User ID 以降の値が出力されました。
各プロファイル設定時に生成されるUser IDは、後の入出力設定で使用するため記録しておきます。

# User1のプロファイル設定
$ apc configure --profile $profile1
API URL: ()
Attestation URL: ()
Attestation API Version: ()
Attestation MR Enclave: ()
Attestation MR Signer: ()
Client ID: ()
Client Secret:
User ID: Vfpq3adYwxrCTrvqX78dubT1zflLNnUu0L4t4gVZTk4=
Credentials saved to: /Users/yuki.kitaya/.apc/credentials
Configuration saved to: /Users/yuki.kitaya/.apc/config/user1/config.toml
# User2のプロファイル設定
$ apc configure --profile $profile2
API URL: ()
Attestation URL: ()
Attestation API Version: ()
Attestation MR Enclave: ()
Attestation MR Signer: ()
Client ID: ()
Client Secret:
User ID: NdqhjVf1l5-rU_dUV_eAYoLObG3TlYw8cJ0t3LVffxE=
Credentials saved to: /Users/yuki.kitaya/.apc/credentials
Configuration saved to: /Users/yuki.kitaya/.apc/config/user2/config.toml

3. 入出力設定ファイルの作成

先ほど生成された User ID を元にして、入出力できるユーザーの権限管理用のファイルを作成します。
今回は、input_1 と output_1 には user1 がアクセスでき、input_2 と output_2 には user2 のみがアクセスできるように設定しました。

# encrypted-files.yaml
inputs:
  input_1: &user_1_id <USER_1_ID>  # User1のID
  input_2: &user_2_id <USER_2_ID>  # User2のID
outputs:
  output_1: *user_1_id
  output_2: *user_2_id

Cleanroom の実行フロー

1. 認証とヘルスチェック

各プロファイルごとにログインし、DCRサーバーにアクセスできるか確認します。

# 各プロファイルでログイン
$ apc auth-login --profile $profile1
2025-09-28 17:07:25 [INFO]: Login for Profile: user1 success!
$ apc auth-login --profile $profile2
2025-09-28 17:07:32 [INFO]: Login for Profile: user2 success!
# ヘルスチェック
$ apc healthcheck --profile $profile1
API is healthy !
$ apc healthcheck --profile $profile2
API is healthy !

2. プロジェクト設定

弊社が事前にデータコラボレーションを行うプロジェクトを作成しているので、それを指定します。

$ apc set-project $PROJECT_ID --profile $profile1
2025-09-28 17:08:07 [INFO]: Project: proj-P60VfXoD, set for Profile: user1, with Role : OWNER

$ apc set-project $PROJECT_ID --profile $profile2
2025-09-28 17:08:10 [INFO]: Project: proj-P60VfXoD, set for Profile: user2, with Role : COLLABORATOR

3. 関数の準備

今回はサンプルリポジトリで実装されている cross_table 関数を使用します。
functions/cross_table から関数をダウンロードしておきます。

$ export FUNCTION_SOURCE_PATH=functions/cross_table

# 依存ライブラリのインストール
$ pip install --platform manylinux2014_x86_64 \
    --only-binary=:all: \
    --python-version 3.10  \
    --target=$FUNCTION_DIRECTORY_PATH/packages \
    -r $FUNCTION_SOURCE_PATH/requirements.txt

4. 関数のアップロードとデプロイ

関数を、DCR上のストレージにアップロードします。
アップロードされると、FunctionStoragePath が発行されるので控えておきます。

# 関数ストレージへのアップロード
$ apc function-storage upload --source $FUNCTION_DIRECTORY_PATH --profile $profile1
2025-09-28 17:16:20 [INFO]: Uploading function with the following parameters:
    Source: functions/cross_table/function
2025-09-28 17:18:14 [INFO]: FunctionStoragePath: fs://k5uwRqwWZLba2GwJM4XQAHqczhN7bBCxjsaS0Ol7luQ=
2025-09-28 17:18:14 [INFO]: Function uploaded successfully.

アップロードした関数をDCR内で使用できるよう、デプロイを行います。

# Cleanroomアプリケーションのデプロイ
$ apc cleanroom deploy \
    --source $FUNCTION_DIRECTORY_PATH \
    --name cross_table_app \
    --runtime python3.10 \
    --handler handler.run \
    --encrypted-files $ENCRYPTED_FILES_PATH \
    --memory 2 \
    --profile $profile1
2025-09-28 17:19:30 [INFO]: Deploying cleanroom with the following parameters:
    Source: fs://k5uwRqwWZLba2GwJM4XQAHqczhN7bBCxjsaS0Ol7luQ=
    Name: cross_table_app
    Runtime: python3.10
    Handler: handler.run
    EncryptedFiles: encrypted-files.yaml
    Memory(GB): 2
2025-09-28 17:19:31 [INFO]: EPC Data: Total = 4 GB, Available = 3 GB
2025-09-28 17:19:31 [INFO]: FunctionStoragePath: fs://k5uwRqwWZLba2GwJM4XQAHqczhN7bBCxjsaS0Ol7luQ=
2025-09-28 17:19:31 [INFO]: Creating worker with enclave size 2 GB...
2025-09-28 17:19:33 [INFO]: Worker created: exEg0d9BC2LAuZ6RFeDcfQ==
2025-09-28 17:19:33 [INFO]: Waiting for worker to be ready...
2025-09-28 17:19:44 [INFO]: EPC Data: Total = 4 GB, Available = 1 GB
2025-09-28 17:19:49 [INFO]: CleanRoom deployed successfully.

5. データのコピーと実行

user1, user2 の持つデータをそれぞれアプリケーションの対応するパスにアップロードします。

# 各ユーザーからデータをCleanroomにコピー
$ apc cleanroom data cp $INPUT_1_PATH cross_table_app:input_1 --profile $profile1
2025-09-28 17:25:28 [INFO]: worker_id: exEg0d9BC2LAuZ6RFeDcfQ==
2025-09-28 17:25:28 [INFO]: work_id: CY_BMxgUEE9xDiQD9r2vcCBYtszI7-Hrmr0ciukCXjU=
2025-09-28 17:25:28 [INFO]: nonce: 4SJ2geJ7_A78lOLJhO1HEw==
2025-09-28 17:25:30 [INFO]: Handshake: OK.
2025-09-28 17:25:30 [INFO]: Uploading ./functions/cross_table/inputs/input_1 to cross_table_app:input_1 ...
2025-09-28 17:25:30 [INFO]: Directory size check passed. Total size: 0.00GB
2025-09-28 17:25:30 [INFO]: Packaging files:
        input_1.csv
2025-09-28 17:25:30 [INFO]: Encrypting input ZIP file...
2025-09-28 17:25:31 [INFO]: Input file uploaded successfully.
$ apc cleanroom data cp $INPUT_2_PATH cross_table_app:input_2 --profile $profile2
2025-09-28 17:26:51 [INFO]: worker_id: exEg0d9BC2LAuZ6RFeDcfQ==
2025-09-28 17:26:51 [INFO]: work_id: CY_BMxgUEE9xDiQD9r2vcCBYtszI7-Hrmr0ciukCXjU=
2025-09-28 17:26:51 [INFO]: nonce: 4SJ2geJ7_A78lOLJhO1HEw==
2025-09-28 17:26:53 [INFO]: Handshake: OK.
2025-09-28 17:26:53 [INFO]: Uploading ./functions/cross_table/inputs/input_2 to cross_table_app:input_2 ...
2025-09-28 17:26:53 [INFO]: Directory size check passed. Total size: 0.00GB
2025-09-28 17:26:53 [INFO]: Packaging files:
        input_2.csv
2025-09-28 17:26:53 [INFO]: Encrypting input ZIP file...
2025-09-28 17:26:54 [INFO]: Input file uploaded successfully.

実際にデプロイした関数を実行してみます。
実行状況は Work status として確認することができます。

# Cleanroom上で関数実行
$ apc cleanroom run cross_table_app --profile $profile1
2025-09-28 17:27:08 [INFO]: Start run cleanroom...: 'cross_table_app'
2025-09-28 17:27:08 [INFO]: End run cleanroom...: 'cross_table_app'
2025-09-28 17:27:09 [INFO]: Work status: idle.
2025-09-28 17:27:12 [INFO]: Work status: completed.
2025-09-28 17:27:12 [INFO]: Work status: completed.
        Message: None

実行が完了したので、出力データをコピーします。
事前に指定したユーザーとデータの組み合わせでのみ、出力データをダウンロードできます。

# 結果のダウンロード
$ apc cleanroom data cp cross_table_app:output_1 $OUTPUT_1_PATH --profile $profile1
2025-09-28 17:27:42 [INFO]: Using cached shared secret.
2025-09-28 17:27:42 [INFO]: Downloading from cross_table_app:output_1 to ./functions/cross_table/outputs/output_1
2025-09-28 17:27:42 [INFO]: Decrypting output ZIP file...
2025-09-28 17:27:42 [INFO]: Extracted file:
        app.log
        output_1.csv
2025-09-28 17:27:42 [INFO]: Output file downloaded successfully.
$ apc cleanroom data cp cross_table_app:output_2 $OUTPUT_2_PATH --profile $profile2
2025-09-28 17:27:53 [INFO]: Using cached shared secret.
2025-09-28 17:27:53 [INFO]: Downloading from cross_table_app:output_2 to ./functions/cross_table/outputs/output_2
2025-09-28 17:27:53 [INFO]: Decrypting output ZIP file...
2025-09-28 17:27:53 [INFO]: Extracted file:
        app.log
        output_2.csv
2025-09-28 17:27:53 [INFO]: Output file downloaded successfully.

6. クリーンアップ

実行が終わったら、デプロイした関数とアップロードした関数を削除します。

# Cleanroomアプリケーションの削除
$ apc cleanroom delete cross_table_app --profile $profile1

# 関数ストレージの削除
$ apc function-storage delete <FUNCTION_STORAGE_PATH> --profile $profile1

使用したデータと出力結果

実際の入力データ

User1のデータ (input_1.csv):

id,height,weight
id1,170,70
id2,180,60
id3,170,60
id4,170,70
id5,180,60
id6,180,60
id7,180,60
id8,180,60
id9,170,60

User2のデータ (input_2.csv):

id,dominant
id1,right
id2,right
id3,right
id4,left
id5,left
id6,right
id7,right
id8,left
id9,right

処理結果

結合後のデータ:
このデータは TEE 環境内で一時的に生成されるため、誰からも見ることはできません。

shape: (9, 4)
┌─────┬────────┬────────┬──────────┐
│ id  ┆ height ┆ weight ┆ dominant │
│ --- ┆ ---    ┆ ---    ┆ ---      │
│ str ┆ i64    ┆ i64    ┆ str      │
╞═════╪════════╪════════╪══════════╡
│ id1 ┆ 170    ┆ 70     ┆ right    │
│ id2 ┆ 180    ┆ 60     ┆ right    │
│ id3 ┆ 170    ┆ 60     ┆ right    │
│ id4 ┆ 170    ┆ 70     ┆ left     │
│ id5 ┆ 180    ┆ 60     ┆ left     │
│ id6 ┆ 180    ┆ 60     ┆ right    │
│ id7 ┆ 180    ┆ 60     ┆ right    │
│ id8 ┆ 180    ┆ 60     ┆ left     │
│ id9 ┆ 170    ┆ 60     ┆ right    │
└─────┴────────┴────────┴──────────┘

クロス集計結果(閾値2以上):

shape: (3, 4)
┌────────────────┬──────────┬────────┬────────┐
│ number_of_rows ┆ dominant ┆ height ┆ weight │
│ ---            ┆ ---      ┆ ---    ┆ ---    │
│ u32            ┆ str      ┆ i64    ┆ i64    │
╞════════════════╪══════════╪════════╪════════╡
│ 2              ┆ left     ┆ 180    ┆ 60     │
│ 3              ┆ right    ┆ 180    ┆ 60     │
│ 2              ┆ right    ┆ 170    ┆ 60     │
└────────────────┴──────────┴────────┴────────┘

検証結果の解釈

  1. データ結合: 両ユーザーのデータがID列で正常に結合された
  2. 属性組み合わせ分析: height、weight、dominantの組み合わせごとに件数を集計
  3. プライバシー保護: 件数が閾値(2件)未満のグループは出力されず、個人の特定リスクを低減

この検証により、AutoPrivacy DCRの基本的な動作原理と、実際のデータ処理における有用性が確認できました。

実践を通じて得られた知見

技術的評価

セキュリティ面:

  • TEE環境によるデータの完全な保護が実現されており、プライバシー保護の要件を満たしている
  • 認証からデプロイ、実行まで各段階で詳細なログが提供され、操作の透明性が確保されている

操作性・UX面:

  • APC-CLIのコマンド体系が一貫しており、学習コストが低い
  • 進行状況が分かりやすい
  • 実行中のステータスがリアルタイムで表示される

学習コストと導入の容易さ:

  • エンジニアであれば1-2時間程度で基本的な操作を習得可能
  • 対話形式の設定により、設定漏れを防げる仕組みが有効
  • ただし、初回の環境変数設定には慎重さが必要で、チェックリストがあると良い

まとめ

AutoPrivacy DataCleanRoomは、プライバシーを保護しながらデータ共有と集計を行う実用的なソリューションです。

CLIとして提供しているため、定常的な分析業務やETLパイプラインへの組み込みが容易であり、日本語チュートリアルも公開しているため導入時の学習コストは比較的低くなっています。

また、AutoPrivacy DataCleanRoomはTEEを用いた暗号学的手法でデータを保護しており、検証プロセスを適切に抽象化することで、ユーザーは複雑な暗号処理を意識することなく安全なデータコラボレーションを実現できる点も特徴です。

企業間でのデータ活用やプライバシーに配慮したデータ分析を検討されている方は、ぜひ一度お試しください。

適用が期待される具体的なシーン

企業間でのデータ活用:

  • 複数の小売企業による消費者行動分析(個人を特定せずに購買パターンを分析)
  • 金融機関間での不正検知モデルの共同開発(取引データを直接共有せずに学習)
  • 製薬会社間での臨床データ統合分析(患者プライバシーを保護しながら症例数を拡大)

コスト・リソース面での現実性:

  • 設定作業:初回は半日程度、2回目以降は1時間程度で環境構築が可能
  • 運用コスト:処理時間とサーバーリソース使用量が明確で、予算計画が立てやすい
  • メンテナンス:定期的なクリーンアップ作業(関数削除等)が必要だが、運用負荷は軽微

今後の展望

今回の実践を通じて、AutoPrivacy DataCleanRoomが、実際の業務で使用可能であることが確認できました。企業間でのデータ活用や共同研究において、プライバシー保護技術の需要は今後さらに高まることが予想されますが、AutoPrivacy DataCleanRoomはデータコラボレーション実現のための有力な選択肢の一つといえます。

記事を読んでいただきありがとうございました。AutoPrivacy DataCleanRoomに興味を持っていただけた方は、サービスページからお問い合わせください。

参考資料

Acompany

Discussion