レコードアクセス
オブジェクトの権限が許した後に、ユーザーがどのレコードを見たり変更したりできるかを制御します。共有モデルのデフォルト、テナントの分離、共有ルール、レコードの共有です。
レコードアクセスは、オブジェクトの権限が操作を許した後に、ユーザーがどの行を見たり変更したりできるかを制御します。
仕組み
| 仕組み | 目的 |
|---|---|
| 行レベルセキュリティ | テナントまたは組織の分離を強制します |
| 共有ルール | 宣言的な条件に基づいてアクセスを付与します |
| レコードの共有 | 特定のユーザー、チーム、ポジション、事業単位、または単位とその配下にアクセスを付与します |
| 所有 / 階層 | 所有者と事業単位のツリーを通じてアクセスを付与します |
共有モデルのデフォルト
すべてのオブジェクトは、組織全体のデフォルトを設定する sharingModel を宣言(または継承)します:private、public_read、public_read_write、controlled_by_parent。
ObjectStack 13 以降、所有者のフィールドを持ち sharingModel を宣言していないカスタムオブジェクトのデフォルトは非公開です。レコードは、共有ルール、レコードの共有、またはより広いデフォルトが公開するまで、その所有者(と管理者)にだけ見えます。開いた動作に戻すには、モデルを明示的に宣言します。
ObjectSchema.create({
name: 'crm_lead',
sharingModel: 'public_read_write',
fields: {
company: Field.text({ label: 'Company' }),
// …
},
});13 より前のエイリアス read、read_write、full は削除されました。os compile は、security-owd-unset と security-owd-alias の lint で、未設定またはエイリアスのモデルを指摘します。
デフォルトのテナント分離
セキュリティプラグインは、現在のユーザーのコンテキストを通じてテナントの分離を強制します。標準のプラットフォームのオブジェクトでは、通常の組織フィールドを持たないグローバルなテーブルを、デフォルトのルールが保護します。
顧客が実際に期待するのは次のことです。
Users only see records that belong to their organization or records
explicitly shared with them.共有ルール
共有ルールは、繰り返し適用される業務上のポリシーに使います。
- すべての地域マネージャーは、自分の地域の取引先を読める
- サポートマネージャーは、エスカレーションされたケースを見られる
- 財務は、承認済みの請求書を読める
- 監査担当者は、監査レビューのタグが付いたレコードを読める
ルールはフィールドの値に対する CEL の condition で、作成時に行のフィルターにコンパイルされます。一致したレコードは、解決された受け手(ユーザー、チーム、ポジション、事業単位、または単位とその配下)に対する sys_record_share の付与を具体化します。作成できる形式は criteria ルールだけです。
どちらのスイッチも安全側に倒れる
読み手が当然そう思ってよいことで、ObjectStack 17.0 以降にようやく真になった 2 つのことです。
- 条件のない共有ルールは何も共有しません。 条件の述語なしに保存されたルールは、以前はオブジェクトのすべてのレコード(空のフィルター)として評価されていたので、検証されない書き込み経路を通った入力ミスが、黙ってテーブル全体を公開していました。すべてに一致する条件を書くことは今は拒否され、評価器は空の条件を何にも一致しないものとして扱います。
enabled: falseの RLS ポリシーは無効です。 以前は、オフにしたポリシーも OR 分岐の付与を加え続けていたので、ポリシーをオフにしてもアクセスは取り除かれませんでした。今は、無効なポリシーは単に評価されません。
以前のリリースでアクセスを監査し、「このルールは何も付与していない」や「このポリシーはオフだ」と結論づけた場合は、explain エンジンを再実行する価値があります。答えは、メタデータが示していたより広かったかもしれません。
行レベルセキュリティは強制できないものを拒否する
ObjectStack 17.5 以降、RLS ポリシーは書かれているとおりに正確に絞り込むか、拒否するかのどちらかです。
checkのないポリシーは、そのusingで書き込みをゲートします。checkのデフォルトはusingであると常に記載されていましたが、書き込みに適用されていたのはcheckを宣言したポリシーだけだったので、ユーザーは読み戻せない行を書き込めていました。単一行の挿入や ID による更新で、その結果が適用されるすべての書き込みポリシーのusingの外にある場合、今は403 PERMISSION_DENIEDで応答します。書き込みを読み取りの範囲の外に置くことを意図したポリシーは、それを認めるcheckを宣言しなければなりません。- 強制できない述語は拒否します。 フィールドをリストと比較する(
record.status != ['closed', 'archived'])、current_user.idではなく素のcurrent_userと比較する、またはオブジェクトが宣言していないフィールドを指定すると、拒否するために書いたはずの行や書き込みそのものを認めてしまう可能性がありました。そのようなポリシーは今は安全側に倒れて失敗します。読み取りは行を返さず、書き込みは403で応答します。 - 書き込みは保存される行で判定されます。
checkと組織の壁は、beforeInsert/beforeUpdateのフックが実行された後の、エンジンが保存するとおりの行を見ます。
os validate は、出荷する前にこれらの形を報告し(rls-predicate-unenforceable、rls-predicate-unknown-field)、メタデータの保存の入口は、それを持つ権限セットを拒否します(422 INVALID_METADATA)。
レコードの共有
レコードの共有は例外のために使います。
- 1 件の商談を専門家と共有する
- エスカレーションの間、一時的なアクセスを付与する
- 外部の連携に特定のレコードへのアクセスを与える
表示範囲のトラブルシューティング
ユーザーがレコードを見られないときは、次の順で確認します。
- ユーザーは認証されていて、想定した組織にいるか?
- ユーザーはオブジェクトの
read権限を持っているか? - オブジェクトの
sharingModelは何か(ObjectStack 13 以降、カスタムオブジェクトのデフォルトはprivate)? - 行レベルセキュリティはそのレコードを許しているか?
- 適用されるべき共有ルールはあるか?
- 直接のレコードの共有はあるか?
- レコードは、想定した事業単位のサブツリーにいるユーザーが所有しているか?
- ユーザーは正しいプロジェクト / ホスト名を見ているか?
explain エンジンは、これらすべてに 1 回の呼び出しで答えます。各層の判定と、どの付与(または欠けている付与)が結果を決めたかを報告します。