コンテンツにスキップ

PII分離アーキテクチャ

Authrimは、機微なidentity valueをprotocol、authorization、admin control-plane dataから分離します。現在のモデルはruntime storage profileを前提にしており、共有D1 binding、テナント所有D1 slot、外部storage adapterのいずれを使っても、同じlogical source境界を維持します。

デフォルトの builtin:storage:shared-d1 profile は、3つのデプロイ単位D1 bindingを使います。

BindingStorage plane主なデータ
DBCore identity / protocol datatenants、OAuth clients、roles、relationships、consent records、legacy users_core、canonical identity graph tables
DB_PIISensitive identity values / PII audit datalegacy users_pii、linked identities、subject identifiers、identity_sensitive_values、PII tombstones、PII audit logs
DB_ADMINAdmin / control-plane dataadmin users/RBAC、runtime profiles、tenant database registry、field catalogs、operational jobs

KVとDurable ObjectsはこれらのD1 planeとは別です。KVはcacheや署名済みruntime snapshotに使い、Durable Objectsはsession、authorization code、refresh-token rotation、PAR、DPoP JTI、device flow、CIBA、rate limitなどのhot protocol stateを保持します。

PII分離は、hard-codedなregional bindingではなく、logical sourceとstorage sliceで制御します。

Profile挙動
builtin:storage:shared-d1デプロイ単位の DBDB_PIIDB_ADMIN bindingを使う
builtin:storage:tenant-d1control dataは共有し、テナント所有のcore/PII/audit sliceをtenant database registryで解決する
builtin:storage:external-durable設定された範囲でdurable stateを外部adapterへ移す
External SQL profilestenant settingsにcredentialを直接入れず、connection referenceを使う

tenant-D1 modeでは、tenant database routeが見つからない場合に共有D1へ暗黙fallbackしません。未対応routeはPIIを返さず失敗し、storage境界のbugで機微データが誤ったplaneに移動することを防ぎます。

新しいruntime user pathはcanonical identity graphを使います。Protocol codeは CanonicalRuntimeUserStore 経由で読み書きし、runtime codeが users_core / users_pii rowを直接扱わない構成です。

flowchart TB
    subgraph Core["Core DB: DB"]
        Subjects["identity_subjects"]
        Accounts["identity_accounts"]
        Links["subject_account_links"]
        Profiles["profiles<br/>display_name_ref"]
        Attributes["profile_attribute_values<br/>value_storage_ref, value_hash, purpose"]
        Contacts["contact_points<br/>normalized_hash, value_storage_ref, purpose"]
        Bindings["identity_bindings"]
        SearchIndexes["contact_point_search_indexes"]
    end

    subgraph PII["PII DB: DB_PII"]
        Sensitive["identity_sensitive_values<br/>value_json, value_hash"]
        LegacyPII["users_pii / linked_identities"]
        SubjectIds["subject_identifiers<br/>identifier_storage_ref"]
        Tombstones["users_pii_tombstone / pii_log"]
    end

    subgraph Control["Admin DB: DB_ADMIN"]
        RuntimeProfiles["storage_deployment_profiles"]
        TenantRegistry["tenant database registry"]
        FieldCatalogs["field_catalogs"]
    end

    Attributes -->|value_storage_ref| Sensitive
    Contacts -->|value_storage_ref| Sensitive
    Contacts --> SearchIndexes
    SubjectIds --> Sensitive
    RuntimeProfiles --> Core
    TenantRegistry --> Core
    TenantRegistry --> PII

Core graph rowはlifecycle state、metadata、hash、storage referenceを持ちます。email、phone、profile name、address、custom sensitive attributeなどの機微値は DB_PIIidentity_sensitive_values に保存します。

CREATE TABLE IF NOT EXISTS identity_subjects (
id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL DEFAULT 'default',
subject_type TEXT NOT NULL,
lifecycle_state TEXT NOT NULL DEFAULT 'active',
display_label TEXT,
primary_account_id TEXT,
risk_tier TEXT,
assurance_level TEXT,
metadata_json TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
deleted_at INTEGER
);
CREATE TABLE IF NOT EXISTS identity_accounts (
id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL DEFAULT 'default',
account_type TEXT NOT NULL,
lifecycle_state TEXT NOT NULL DEFAULT 'active',
legacy_user_id TEXT,
primary_subject_id TEXT,
display_label TEXT,
metadata_json TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
deleted_at INTEGER
);
CREATE TABLE IF NOT EXISTS profiles (
id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL DEFAULT 'default',
subject_id TEXT NOT NULL,
profile_type TEXT NOT NULL DEFAULT 'person',
lifecycle_state TEXT NOT NULL DEFAULT 'active',
locale TEXT,
zoneinfo TEXT,
display_name_ref TEXT,
metadata_json TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
deleted_at INTEGER
);
CREATE TABLE IF NOT EXISTS profile_attribute_values (
id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL DEFAULT 'default',
profile_id TEXT NOT NULL,
catalog_entry_id TEXT NOT NULL,
value_type TEXT NOT NULL,
value_json TEXT,
value_storage_ref TEXT,
value_hash TEXT,
classification TEXT NOT NULL DEFAULT 'internal',
purpose TEXT,
is_primary INTEGER NOT NULL DEFAULT 0,
display_order INTEGER NOT NULL DEFAULT 0,
lifecycle_state TEXT NOT NULL DEFAULT 'active',
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
deleted_at INTEGER
);
CREATE TABLE IF NOT EXISTS contact_points (
id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL DEFAULT 'default',
subject_id TEXT,
account_id TEXT,
contact_type TEXT NOT NULL,
purpose TEXT NOT NULL DEFAULT 'primary',
normalized_hash TEXT,
value_storage_ref TEXT,
display_label TEXT,
is_primary INTEGER NOT NULL DEFAULT 0,
verification_state TEXT NOT NULL DEFAULT 'unverified',
lifecycle_state TEXT NOT NULL DEFAULT 'active',
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
deleted_at INTEGER
);
CREATE TABLE IF NOT EXISTS identity_sensitive_values (
id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL DEFAULT 'default',
owner_type TEXT NOT NULL,
owner_id TEXT NOT NULL,
value_key TEXT NOT NULL,
value_json TEXT,
value_hash TEXT,
classification TEXT NOT NULL DEFAULT 'sensitive',
lifecycle_state TEXT NOT NULL DEFAULT 'active',
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
UNIQUE (tenant_id, owner_type, owner_id, value_key)
);

Migration baselineにはlegacy compatibility tableも残っています。upgradeや一部management pathでは重要ですが、新しいruntime user writeはcanonical identity graphへprojectされます。

CREATE TABLE users_core (
id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL DEFAULT 'default',
email_verified INTEGER DEFAULT 0,
phone_number_verified INTEGER DEFAULT 0,
email_domain_hash TEXT,
password_hash TEXT,
is_active INTEGER DEFAULT 1,
user_type TEXT NOT NULL DEFAULT 'end_user',
pii_partition TEXT NOT NULL DEFAULT 'default',
pii_status TEXT NOT NULL DEFAULT 'pending',
lifecycle_state TEXT DEFAULT 'active',
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
last_login_at INTEGER
);
CREATE TABLE IF NOT EXISTS users_pii (
id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL DEFAULT 'default',
pii_class TEXT NOT NULL DEFAULT 'PROFILE',
email TEXT NOT NULL,
email_blind_index TEXT,
phone_number TEXT,
name TEXT,
given_name TEXT,
family_name TEXT,
address_country TEXT,
declared_residence TEXT,
custom_attributes_json TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);

Core側の検索surfaceは、plaintext PIIを必要としない構成にします。現在のschemaは以下をサポートします。

用途Core-side fieldPII-side field
Email/contact lookupcontact_points.normalized_hash, contact_point_search_indexes.index_valueidentity_sensitive_values.value_json
Profile displayprofiles.display_name_ref, profile_attribute_values.value_storage_ref対応する identity_sensitive_values row
Pairwise subject identifierscanonical migration後の subject_identifiers.identifier_value_hash / identifier_storage_ref必要時のみsensitive identifier value
Field catalog metadataDB_ADMIN.field_catalog_entries実際のsensitive field valueは DB_PII に保持

PII deletionはPII plane上のtombstoneとaudit recordで管理します。

CREATE TABLE IF NOT EXISTS users_pii_tombstone (
id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL DEFAULT 'default',
email_blind_index TEXT,
deleted_at INTEGER NOT NULL,
deleted_by TEXT,
deletion_reason TEXT,
retention_until INTEGER NOT NULL,
deletion_metadata TEXT,
created_at INTEGER,
updated_at INTEGER
);
CREATE TABLE IF NOT EXISTS pii_log (
id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL,
user_id TEXT NOT NULL,
anonymized_user_id TEXT NOT NULL,
change_type TEXT NOT NULL,
affected_fields TEXT NOT NULL,
values_r2_key TEXT,
values_encrypted TEXT,
retention_until INTEGER NOT NULL,
created_at INTEGER NOT NULL
);
  1. Feature codeでD1 binding名をhard-codeせず、runtime profile経由でstorageを解決する。
  2. Sensitive attribute valueは identity_sensitive_values に置き、core graph tableにはhash、reference、state、metadataを置く。
  3. Legacy users_core / users_pii はcompatibility surfaceとして扱い、新しいruntime identity featureの主モデルにしない。
  4. Storage planeをまたぐJOINをしない。Core rowとsensitive valueはrepository/runtime store layerから個別に取得する。
  5. tenant-D1 routingが関わるcache scopeには、storage profile ID、source generation、schema versionを含める。