Skip to content

Commit a4ffed7

Browse files
committed
feat(query):masking policy support rbac
1 parent 06d4e1b commit a4ffed7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1111
-78
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/meta/api/src/data_mask_api.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,17 @@ pub trait DatamaskApi: Send + Sync {
4848
name_ident: &DataMaskNameIdent,
4949
) -> Result<Option<SeqV<DatamaskMeta>>, MetaError>;
5050

51+
async fn get_data_mask_id(
52+
&self,
53+
name_ident: &DataMaskNameIdent,
54+
) -> Result<Option<u64>, MetaError>;
55+
56+
async fn get_data_mask_name_by_id(
57+
&self,
58+
tenant: &Tenant,
59+
policy_id: u64,
60+
) -> Result<Option<String>, MetaError>;
61+
5162
async fn get_data_mask_by_id(
5263
&self,
5364
tenant: &Tenant,

src/meta/api/src/data_mask_api_impl.rs

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ use databend_common_meta_app::data_mask::CreateDatamaskReply;
1717
use databend_common_meta_app::data_mask::CreateDatamaskReq;
1818
use databend_common_meta_app::data_mask::DataMaskId;
1919
use databend_common_meta_app::data_mask::DataMaskIdIdent;
20+
use databend_common_meta_app::data_mask::DataMaskIdToNameIdent;
2021
use databend_common_meta_app::data_mask::DataMaskNameIdent;
22+
use databend_common_meta_app::data_mask::DataMaskNameIdentRaw;
2123
use databend_common_meta_app::data_mask::DatamaskMeta;
2224
use databend_common_meta_app::data_mask::MaskPolicyIdTableId;
2325
use databend_common_meta_app::data_mask::MaskPolicyTableIdIdent;
@@ -41,11 +43,14 @@ use crate::errors::MaskingPolicyError;
4143
use crate::fetch_id;
4244
use crate::kv_pb_api::KVPbApi;
4345
use crate::meta_txn_error::MetaTxnError;
46+
use crate::serialize_struct;
4447
use crate::txn_backoff::txn_backoff;
4548
use crate::txn_condition_util::txn_cond_eq_keys_with_prefix;
4649
use crate::txn_condition_util::txn_cond_eq_seq;
4750
use crate::txn_core_util::send_txn;
4851
use crate::txn_core_util::txn_delete_exact;
52+
use crate::txn_op_builder_util::txn_op_del;
53+
use crate::txn_op_builder_util::txn_op_put;
4954
use crate::txn_op_builder_util::txn_op_put_pb;
5055

5156
/// DatamaskApi is implemented upon kvapi::KVApi.
@@ -77,6 +82,8 @@ impl<KV: kvapi::KVApi<Error = MetaError>> DatamaskApi for KV {
7782

7883
let id = DataMaskId::new(masking_policy_id);
7984
let id_ident = DataMaskIdIdent::new_generic(name_ident.tenant(), id);
85+
let id_to_name_ident = DataMaskIdToNameIdent::new_generic(name_ident.tenant(), id);
86+
let name_raw = DataMaskNameIdentRaw::from(name_ident.clone());
8087
let id_list_key = MaskPolicyTableIdListIdent::new_from(name_ident.clone());
8188

8289
debug!(
@@ -91,9 +98,12 @@ impl<KV: kvapi::KVApi<Error = MetaError>> DatamaskApi for KV {
9198
txn.condition.push(txn_cond_eq_seq(name_ident, 0));
9299
txn.condition
93100
.push(txn_cond_eq_seq(&row_access_name_ident, 0));
101+
let name_bytes = serialize_struct(&name_raw)?;
102+
94103
txn.if_then.extend(vec![
95-
txn_op_put_pb(name_ident, &id, None)?, // name -> db_id
104+
txn_op_put_pb(name_ident, &id, None)?, // name -> masking_policy_id
96105
txn_op_put_pb(&id_ident, &meta, None)?, // id -> meta
106+
txn_op_put(&id_to_name_ident, name_bytes), // id -> name
97107
// TODO: Tentative retention for compatibility MaskPolicyTableIdListIdent related logic. It can be directly deleted later
98108
txn_op_put_pb(&id_list_key, &id_list, None)?, // data mask name -> id_list
99109
]);
@@ -159,7 +169,9 @@ impl<KV: kvapi::KVApi<Error = MetaError>> DatamaskApi for KV {
159169
}
160170

161171
// No references - drop the policy
162-
let id_ident = seq_id.data.into_t_ident(tenant);
172+
let id_ident = seq_id.data.into_t_ident(tenant.clone());
173+
let id_to_name_ident =
174+
DataMaskIdToNameIdent::new_generic(tenant, DataMaskId::new(policy_id));
163175
let mut txn = TxnRequest::default();
164176

165177
// Ensure no new references were created
@@ -168,6 +180,7 @@ impl<KV: kvapi::KVApi<Error = MetaError>> DatamaskApi for KV {
168180

169181
txn_delete_exact(&mut txn, name_ident, seq_id.seq);
170182
txn_delete_exact(&mut txn, &id_ident, seq_meta.seq);
183+
txn.if_then.push(txn_op_del(&id_to_name_ident));
171184

172185
// TODO: Tentative retention for compatibility. Can be deleted later.
173186
clear_table_column_mask_policy(self, name_ident, &mut txn).await?;
@@ -191,6 +204,27 @@ impl<KV: kvapi::KVApi<Error = MetaError>> DatamaskApi for KV {
191204
Ok(res.map(|(_, seq_meta)| seq_meta))
192205
}
193206

207+
async fn get_data_mask_id(
208+
&self,
209+
name_ident: &DataMaskNameIdent,
210+
) -> Result<Option<u64>, MetaError> {
211+
let res = self.get_pb(name_ident).await?;
212+
Ok(res.map(|seq_id| *seq_id.data))
213+
}
214+
215+
async fn get_data_mask_name_by_id(
216+
&self,
217+
tenant: &Tenant,
218+
policy_id: u64,
219+
) -> Result<Option<String>, MetaError> {
220+
let ident = DataMaskIdToNameIdent::new_generic(tenant.clone(), DataMaskId::new(policy_id));
221+
let seq_meta = self.get_pb(&ident).await?;
222+
223+
debug!(ident :% =(&ident); "get_data_mask_name_by_id");
224+
225+
Ok(seq_meta.map(|s| s.data.data_mask_name().to_string()))
226+
}
227+
194228
async fn get_data_mask_by_id(
195229
&self,
196230
tenant: &Tenant,

src/meta/api/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
extern crate databend_common_meta_types;
2121
pub mod catalog_api;
22-
mod data_mask_api;
22+
pub mod data_mask_api;
2323
mod data_mask_api_impl;
2424
pub mod data_retention_util;
2525
mod database_api;

src/meta/api/src/row_access_policy_api.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ pub trait RowAccessPolicyApi: Send + Sync {
5151
name_ident: &RowAccessPolicyNameIdent,
5252
) -> Result<Option<(SeqV<RowAccessPolicyId>, SeqV<RowAccessPolicyMeta>)>, MetaError>;
5353

54+
async fn get_row_access_policy_name_by_id(
55+
&self,
56+
tenant: &Tenant,
57+
policy_id: u64,
58+
) -> Result<Option<String>, MetaError>;
59+
5460
async fn get_row_access_policy_by_id(
5561
&self,
5662
tenant: &Tenant,

src/meta/api/src/row_access_policy_api_impl.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@ use databend_common_meta_app::row_access_policy::CreateRowAccessPolicyReply;
2020
use databend_common_meta_app::row_access_policy::CreateRowAccessPolicyReq;
2121
use databend_common_meta_app::row_access_policy::RowAccessPolicyId;
2222
use databend_common_meta_app::row_access_policy::RowAccessPolicyIdIdent;
23+
use databend_common_meta_app::row_access_policy::RowAccessPolicyIdToNameIdent;
2324
use databend_common_meta_app::row_access_policy::RowAccessPolicyMeta;
2425
use databend_common_meta_app::row_access_policy::RowAccessPolicyNameIdent;
26+
use databend_common_meta_app::row_access_policy::RowAccessPolicyNameIdentRaw;
2527
use databend_common_meta_app::row_access_policy::RowAccessPolicyTableIdIdent;
2628
use databend_common_meta_app::tenant::Tenant;
2729
use databend_common_meta_app::tenant_key::errors::ExistError;
@@ -39,11 +41,14 @@ use crate::fetch_id;
3941
use crate::kv_pb_api::KVPbApi;
4042
use crate::meta_txn_error::MetaTxnError;
4143
use crate::row_access_policy_api::RowAccessPolicyApi;
44+
use crate::serialize_struct;
4245
use crate::txn_backoff::txn_backoff;
4346
use crate::txn_condition_util::txn_cond_eq_keys_with_prefix;
4447
use crate::txn_condition_util::txn_cond_eq_seq;
4548
use crate::txn_core_util::send_txn;
4649
use crate::txn_core_util::txn_delete_exact;
50+
use crate::txn_op_builder_util::txn_op_del;
51+
use crate::txn_op_builder_util::txn_op_put;
4752
use crate::txn_op_builder_util::txn_op_put_pb;
4853

4954
/// RowAccessPolicyApi is implemented upon kvapi::KVApi.
@@ -73,8 +78,12 @@ impl<KV: kvapi::KVApi<Error = MetaError>> RowAccessPolicyApi for KV {
7378
// Create row policy by inserting these record:
7479
// name -> id
7580
// id -> policy
81+
// id -> name
7682

7783
let id_ident = RowAccessPolicyIdIdent::new_generic(name_ident.tenant(), policy_id);
84+
let id_to_name_ident =
85+
RowAccessPolicyIdToNameIdent::new_generic(name_ident.tenant(), policy_id);
86+
let name_raw = RowAccessPolicyNameIdentRaw::from(name_ident.clone());
7887

7988
debug!(
8089
id :? =(&id_ident),
@@ -89,6 +98,7 @@ impl<KV: kvapi::KVApi<Error = MetaError>> RowAccessPolicyApi for KV {
8998
txn.if_then.extend(vec![
9099
txn_op_put_pb(name_ident, &policy_id, None)?, // name -> policy_id
91100
txn_op_put_pb(&id_ident, &meta, None)?, // id -> meta
101+
txn_op_put(&id_to_name_ident, serialize_struct(&name_raw)?), // id -> name
92102
]);
93103
}
94104

@@ -151,6 +161,10 @@ impl<KV: kvapi::KVApi<Error = MetaError>> RowAccessPolicyApi for KV {
151161

152162
// No references - drop the policy
153163
let id_ident = seq_id.data.into_t_ident(tenant);
164+
let id_to_name_ident = RowAccessPolicyIdToNameIdent::new_generic(
165+
tenant.clone(),
166+
RowAccessPolicyId::new(policy_id),
167+
);
154168
let mut txn = TxnRequest::default();
155169

156170
// Ensure no new references were created
@@ -159,6 +173,7 @@ impl<KV: kvapi::KVApi<Error = MetaError>> RowAccessPolicyApi for KV {
159173

160174
txn_delete_exact(&mut txn, name_ident, seq_id.seq);
161175
txn_delete_exact(&mut txn, &id_ident, seq_meta.seq);
176+
txn.if_then.push(txn_op_del(&id_to_name_ident));
162177

163178
let (succ, _responses) = send_txn(self, txn).await?;
164179
if succ {
@@ -179,6 +194,24 @@ impl<KV: kvapi::KVApi<Error = MetaError>> RowAccessPolicyApi for KV {
179194
Ok(res)
180195
}
181196

197+
async fn get_row_access_policy_name_by_id(
198+
&self,
199+
tenant: &Tenant,
200+
policy_id: u64,
201+
) -> Result<Option<String>, MetaError> {
202+
let ident = RowAccessPolicyIdToNameIdent::new_generic(
203+
tenant.clone(),
204+
RowAccessPolicyId::new(policy_id),
205+
);
206+
let seq_meta = self.get_pb(&ident).await?;
207+
208+
debug!(ident :% =(&ident); "get_row_access_policy_name_by_id");
209+
210+
let name = seq_meta.map(|s| s.data.row_access_name().to_string());
211+
212+
Ok(name)
213+
}
214+
182215
async fn get_row_access_policy_by_id(
183216
&self,
184217
tenant: &Tenant,
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright 2021 Datafuse Labs
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
use crate::data_mask::DataMaskId;
16+
use crate::tenant_key::ident::TIdent;
17+
use crate::tenant_key::raw::TIdentRaw;
18+
19+
pub type DataMaskIdToNameIdent = TIdent<Resource, DataMaskId>;
20+
pub type DataMaskIdToNameIdentRaw = TIdentRaw<Resource, DataMaskId>;
21+
22+
pub use kvapi_impl::Resource;
23+
24+
impl DataMaskIdToNameIdent {
25+
pub fn data_mask_id(&self) -> DataMaskId {
26+
*self.name()
27+
}
28+
}
29+
30+
impl DataMaskIdToNameIdentRaw {
31+
pub fn data_mask_id(&self) -> DataMaskId {
32+
*self.name()
33+
}
34+
}
35+
36+
mod kvapi_impl {
37+
38+
use databend_common_meta_kvapi::kvapi;
39+
40+
use crate::data_mask::data_mask_id_to_name_ident::DataMaskIdToNameIdent;
41+
use crate::data_mask::data_mask_name_ident::DataMaskNameIdentRaw;
42+
use crate::tenant_key::resource::TenantResource;
43+
44+
pub struct Resource;
45+
impl TenantResource for Resource {
46+
const PREFIX: &'static str = "__fd_datamask_id_to_name";
47+
const TYPE: &'static str = "DataMaskIdToNameIdent";
48+
const HAS_TENANT: bool = false;
49+
type ValueType = DataMaskNameIdentRaw;
50+
}
51+
52+
impl kvapi::Value for DataMaskNameIdentRaw {
53+
type KeyType = DataMaskIdToNameIdent;
54+
fn dependency_keys(&self, _key: &Self::KeyType) -> impl IntoIterator<Item = String> {
55+
[]
56+
}
57+
}
58+
}

src/meta/app/src/data_mask/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
// limitations under the License.
1414

1515
pub mod data_mask_id_ident;
16+
pub mod data_mask_id_to_name_ident;
1617
pub mod data_mask_name_ident;
1718
pub mod mask_policy_policy_table_id_ident;
1819
pub mod mask_policy_table_id_list_ident;
@@ -23,7 +24,10 @@ use chrono::DateTime;
2324
use chrono::Utc;
2425
pub use data_mask_id_ident::DataMaskId;
2526
pub use data_mask_id_ident::DataMaskIdIdent;
27+
pub use data_mask_id_to_name_ident::DataMaskIdToNameIdent;
28+
pub use data_mask_id_to_name_ident::DataMaskIdToNameIdentRaw;
2629
pub use data_mask_name_ident::DataMaskNameIdent;
30+
pub use data_mask_name_ident::DataMaskNameIdentRaw;
2731
pub use mask_policy_policy_table_id_ident::MaskPolicyIdTableId;
2832
pub use mask_policy_policy_table_id_ident::MaskPolicyTableIdIdent;
2933
pub use mask_policy_table_id_list_ident::MaskPolicyTableIdListIdent;

src/meta/app/src/principal/ownership_object.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ use databend_common_meta_kvapi::kvapi::KeyCodec;
3030
/// - `table-by-catalog-id/<catalog>/<table_id>`
3131
/// - `stage-by-name/<stage_name>`
3232
/// - `udf-by-name/<udf_name>`
33+
/// - `procedure-by-id/<procedure_id>`
34+
/// - `masking-policy-by-id/<policy_id>`
3335
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug, Eq, PartialEq, Hash)]
3436
pub enum OwnershipObject {
3537
/// used on the fuse databases
@@ -68,6 +70,10 @@ pub enum OwnershipObject {
6870
Procedure {
6971
procedure_id: u64,
7072
},
73+
74+
MaskingPolicy {
75+
policy_id: u64,
76+
},
7177
}
7278

7379
impl OwnershipObject {
@@ -100,6 +106,9 @@ impl fmt::Display for OwnershipObject {
100106
OwnershipObject::Connection { name } => write!(f, "CONNECTION {name}"),
101107
OwnershipObject::Sequence { name } => write!(f, "SEQUENCE {name}"),
102108
OwnershipObject::Procedure { procedure_id } => write!(f, "PROCEDURE {procedure_id}"),
109+
OwnershipObject::MaskingPolicy { policy_id } => {
110+
write!(f, "MASKING POLICY {policy_id}")
111+
}
103112
}
104113
}
105114
}
@@ -145,6 +154,9 @@ impl KeyCodec for OwnershipObject {
145154
OwnershipObject::Procedure { procedure_id } => {
146155
b.push_raw("procedure-by-id").push_u64(*procedure_id)
147156
}
157+
OwnershipObject::MaskingPolicy { policy_id } => {
158+
b.push_raw("masking-policy-by-id").push_u64(*policy_id)
159+
}
148160
}
149161
}
150162

@@ -207,9 +219,13 @@ impl KeyCodec for OwnershipObject {
207219
let procedure_id = p.next_u64()?;
208220
Ok(OwnershipObject::Procedure { procedure_id })
209221
}
222+
"masking-policy-by-id" => {
223+
let policy_id = p.next_u64()?;
224+
Ok(OwnershipObject::MaskingPolicy { policy_id })
225+
}
210226
_ => Err(kvapi::KeyError::InvalidSegment {
211227
i: p.index(),
212-
expect: "database-by-id|database-by-catalog-id|table-by-id|table-by-catalog-id|stage-by-name|udf-by-name|warehouse-by-id|connection-by-name"
228+
expect: "database-by-id|database-by-catalog-id|table-by-id|table-by-catalog-id|stage-by-name|udf-by-name|warehouse-by-id|connection-by-name|masking-policy-by-id"
213229
.to_string(),
214230
got: q.to_string(),
215231
}),

src/meta/app/src/principal/tenant_ownership_object_ident.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,23 @@ mod tests {
271271
let parsed = TenantOwnershipObjectIdent::from_str_key(&key).unwrap();
272272
assert_eq!(role_grantee, parsed);
273273
}
274+
275+
// masking policy
276+
{
277+
let role_grantee = TenantOwnershipObjectIdent::new_unchecked(
278+
Tenant::new_literal("tenant_mask"),
279+
OwnershipObject::MaskingPolicy { policy_id: 99 },
280+
);
281+
282+
let key = role_grantee.to_string_key();
283+
assert_eq!(
284+
"__fd_object_owners/tenant_mask/masking-policy-by-id/99",
285+
key
286+
);
287+
288+
let parsed = TenantOwnershipObjectIdent::from_str_key(&key).unwrap();
289+
assert_eq!(role_grantee, parsed);
290+
}
274291
}
275292

276293
#[test]

0 commit comments

Comments
 (0)