Security & Compliance
Role Based Access Control
Fennel supports creating custom roles with extremely fine-grained "column" level access control.
Fennel's Access Control Model
The access boundary of any role in Fennel can be defined as any combination of the following three kinds of controls:
- Tag controls
- Modes of access
- Branch controls
1. Tag Controls
Entities like datasets/features can be given tags and roles can be created that guard access to say datasets with a particular tag.
These tags are automatically inherited across the lineage graph. For instance, if a dataset had a tag 'PII', any other derived dataset depending on it will automatically inherit 'PII' tag. This inheritance works recursively across any number of hops.
Sometimes it's desirable to terminate the propagation of a tag, say because PII information has been sufficiently deanonymized. This can be accomplished by tagging the entity with '~tag' (i.e. same tag with but ~ sign). Let's seen an example:
1@source(webhook.endpoint("movie"), disorder="1d", cdc="upsert")
2@meta(tags=["PII"])
3@dataset(index=True)
4class User:
5 uid: int = field(key=True)
6 city: str
7 updated_at: datetime
8
9@source(webhook.endpoint("txn"), disorder="1d", cdc="append")
10@meta(tags=["stripe"])
11@dataset
12class Transaction:
13 uid: int
14 amount: float
15 at: datetime
16
17@meta(tags=["~PII"])
18@dataset(index=True)
19class TxnByCity:
20 city: str = field(key=True)
21 total: float
22 at: datetime
23
24 @pipeline
25 @inputs(Transaction, User)
26 def fn(cls, txn: Dataset, user: Dataset) -> Dataset:
27 joined = txn.join(user, how="inner", on=["uid"])
28 return joined.groupby("city").aggregate(
29 total=Sum(of="amount", window=Continuous("forever")),
30 )
31
32@featureset
33class UserFeatures:
34 uid: int
35 city: str = F(User.city, default="unknown")
36 total_in_hometown: float = F(TxnByCity.total, default=0.0)
python
In the above example, dataset TxnByCity
inherits "PII" from User
and "stripe"
from Transaction
. However, the "PII" tag is canceled because it has "~PII" on
itself. So finally, it has "~PII" and "stripe" tags.
Further, feature UserFeatures.city
inherits "PII" from User
and UserFeatures.total_in_hometown
inherits "PII" from UserFeatures.city
and "~PII" & "stripe" from TxnByCity
resulting in final tag of only "stripe".
2. Modes of Access
Fennel distinguishes between four distinct modes of access - a) read definitions, b) write definitions, c) read data, d) write data.
That is, role A may be able to only read definition of a dataset, another role B may be able to both read/write the definitions but can not see any data whereas another role may be able to see data but not edit definitions.
3. Branch Controls
Roles can also be tied to specific branches, if desired. For instance, it's possible to build a role that can see data in branches b1, b2 but can only see definitions in another branch.
Putting It Together
Here is a screenshot of the role creation flow from Fennel console showing all three of these controls:
Here are some examples of the kind of real world situations that can be modeled via Fennel roles:
- Only CI/CD system can deploy to prod Fennel, not individual developers. However, developers should still be able to see definitions.
- There is special PII data which can only be used by data scientists working on safety problems but not by others. However, non-PII data should be visible to everyone.
- A multi-national company has offices in many countries. Some customer data is deemed sensitive and should only be visible to employees within that country. Non-sensitive data is visible to everyone across the globe.
Service Accounts & Tokens
Fennel also supports creating service accounts (as opposed to user accounts) for API access as well as creating/invalidating tokens that have the same permissions as the account they are attached to.
All API access to Fennel servers require a valid token for authentication carrying enough permissions needed for authorizing the action.