forked from TrueCloudLab/policy-engine
[#71] docs: Introduce APE overview
Signed-off-by: Airat Arifullin <aarifullin@yadro.com>
This commit is contained in:
parent
0e69e48511
commit
4e69174715
5 changed files with 323 additions and 0 deletions
85
docs/ape.md
Normal file
85
docs/ape.md
Normal file
|
@ -0,0 +1,85 @@
|
|||
# Access policy engine
|
||||
|
||||
## General overview
|
||||
|
||||
### Purpose
|
||||
|
||||
Access policy engine (APE) is aimed at checking if a request can be performed over a resource by looking up the set chains of rules.
|
||||
|
||||
#### Terms
|
||||
|
||||
| Term | Description | Structure overview |
|
||||
| -------------- | -------------------------------------------------------------- | -------------- |
|
||||
| `Request` | The action that is being performed on the `Resource`. | <ul><li>`Operation` - `GetObject`,`PutObject` etc.;</li><li>`Properties` - actor's public key, actor's attributes;</li><li>`Resource`.</li></ul> |
|
||||
| `Resource` | The object that the request is being performed on. Check also [resource.md](./resource.md). | <ul><li>`Name` - strictly formatted string value;</li><li>`Properties`.</li></ul> |
|
||||
| `Chain` | A chain of `Rule`-s defined for a specific target. Chains are strictly distinguished by `Name`-s , i.e. chains with name `ingress` are not intersected with chains with name `s3`. Chains are stored in serialized format. | <ul><li>Base64-encoded `ID`;</li><li>List of `Rule`-s;</li><li>`MatchType` - defines rule status selection priority.</li></ul> |
|
||||
| `Rule` | `Rule` defines which status is returned if `Request` matches all conditions. | <ul><li>`Status`: `Allow`, `AccessDenied`, `QuotaLimitReached`, `NoRuleFound`;</li><li>`Actions` - operation defined by a schema (`GetObject`, `PutContainer` etc.);</li><li>`Resources`;</li><li>`Any` - if `true` then `Reqeust` matches `Rule` if any `Condition` is `true`;</li><li>`Conditions`.</li></ul> |
|
||||
| `Name` | `Name` of a chain (do not confuse with chain ID). `Name` defines a layer of `Chain`'s usage, so chains are distinguished by `Name`-s. Basically, `Name` refers to a protocol. | String value (`ingress`, `s3`, `iam`). |
|
||||
| `Target` | A scope of request. `Target` can be either simple (only namespace; only container; only user; only groups) or compound (namespace + container). | <ul><li>`Namespace`;</li><li>`Container`;</li><li>`User`;</li><li>`Groups`.</li></ul> |
|
||||
| `Engine` | `Engine` checks a request in a scope defined by `Target`. First, it is trying to match a request with rules defined in `LocalOverrideStorage` and, then, in `MorphRuleChainStorage`. | <ul><li>`LocalOverrideStorage` - chains stored in the local override storage have the highest priority</li><li>`MorphRuleChainStorage` - basically, chains stored in `Policy` contract;</li><li>`ChainRouter` - looks up chains and try to match them with `Request`.</li></ul> |
|
||||
|
||||
#### Details
|
||||
|
||||
Here some entities are overviewed in more detail.
|
||||
|
||||
##### Resource
|
||||
|
||||
`Resource`'s name is strictly formatted, the format is defined by a schema (`native`, `aws` etc.). Examples:
|
||||
|
||||
```bash
|
||||
# The resource is the particular object with the address within Root namespace
|
||||
native:object//HRwWbb1bJjRms33kkA21hy4JdPfARaH3fW9NfuNN6Fgj/EbxzAdz5LB4uqxuz6crWKAumBNtZyK2rKsqQP7TdZvwr
|
||||
# The resource is all objects within the container within Root namespace
|
||||
native:object//HRwWbb1bJjRms33kkA21hy4JdPfARaH3fW9NfuNN6Fgj/*
|
||||
# The resource is the particular container within the namespace
|
||||
native:container/namespace1/HRwWbb1bJjRms33kkA21hy4JdPfARaH3fW9NfuNN6Fgj
|
||||
# The resource is all containers within the namespace
|
||||
native:container/namespace1/*
|
||||
```
|
||||
|
||||
##### Rule
|
||||
|
||||
`Rule` works out if:
|
||||
|
||||
1. a requests's operation matches the rule's `Actions`;
|
||||
2. resource name matches the rule's `Resources`;
|
||||
3. if all (or at least one if `Any=true`) conditions in `Condition` is met. Each condition defines how to retrieve
|
||||
and compare the retrieved value. If `Condition`'s `Object` is set to `Resource` then the value is retrieved from the
|
||||
resource's properties (example: container zone attribute). If `Object` is set to `Request`, the it's retrieved from the request's properties (example: actor's public key).
|
||||
|
||||
###### Name matching
|
||||
|
||||
`Resource`'s name in `Rule` may contain wildcard '*' that can be considered as a regular expression:
|
||||
|
||||
```bash
|
||||
# The resource is all objects within the container within Root namespace
|
||||
native:object//HRwWbb1bJjRms33kkA21hy4JdPfARaH3fW9NfuNN6Fgj/*
|
||||
```
|
||||
|
||||
If an incoming request has such a resource name, then names are matched:
|
||||
|
||||
```bash
|
||||
# The resource is all objects within the container within Root namespace
|
||||
native:object//HRwWbb1bJjRms33kkA21hy4JdPfARaH3fW9NfuNN6Fgj/EbxzAdz5LB4uqxuz6crWKAumBNtZyK2rKsqQP7TdZvwr
|
||||
```
|
||||
|
||||
If the incoming request has such a resource name that specifies a container's object within namespace, for instance, `namespicy`,
|
||||
then matching does not work out:
|
||||
|
||||
```bash
|
||||
# The resource is all objects within the container within `namespicy` namespace:
|
||||
native:object/namespicy/HRwWbb1bJjRms33kkA21hy4JdPfARaH3fW9NfuNN6Fgj/EbxzAdz5LB4uqxuz6crWKAumBNtZyK2rKsqQP7TdZvwr
|
||||
```
|
||||
|
||||
##### Engine
|
||||
|
||||
`Engine` is trying to match the request against **the target** looking up chain rules, firstly, in `LocalOverrideStorage` (these rules are also known as *local overrides*) and then in `MorphRuleChainStorage` (contract `Policy`). Both storages iterate chain rules according to the specified priority of the targets: `namespace` -> `container` -> `user` -> `groups`.
|
||||
|
||||
#### Diagrams
|
||||
|
||||
The diagram demonstrates a scenario in Storage node. The request `A` cannot be performed as APE matched
|
||||
the request and returned `Access Denied` status. The request `B` is allowed and the client gets `OK` status.
|
||||
![Storage node](images/ape/storage_node_ape.svg)
|
||||
|
||||
The diagram demonstrates a complex scenario with S3, IAM and Storage node.
|
||||
![S3 and IAM](images/ape/s3_ape.svg)
|
61
docs/images/ape/s3_ape.puml
Normal file
61
docs/images/ape/s3_ape.puml
Normal file
|
@ -0,0 +1,61 @@
|
|||
@startuml s3 ape
|
||||
|
||||
participant "Client" as client
|
||||
|
||||
participant "IAM" as iam
|
||||
participant "IAM -> APE converter" as converter
|
||||
|
||||
box "S3" #HotPink
|
||||
participant "S3 gateway" as s3
|
||||
end box
|
||||
|
||||
box "Access Policy Engine (as s3 middleware)" #LightPink
|
||||
participant "Local override storage" as s3localOverrides
|
||||
participant "Chain router" as s3chainRouter
|
||||
end box
|
||||
|
||||
box "Policy contract (shared)"
|
||||
participant "Morph rule storage" as morphRuleStorage
|
||||
end box
|
||||
|
||||
box "Access Policy Engine (as storage middleware)" #LightGreen
|
||||
participant "Chain Router" as storageChainRouter
|
||||
participant "Local override storage" as storageLocalOverrides
|
||||
end box
|
||||
|
||||
box "Storage node" #Green
|
||||
participant "Object service" as obj
|
||||
participant "Control service" as control
|
||||
end box
|
||||
|
||||
group Request IAM to set a policy
|
||||
client -> iam : Set IAM policy
|
||||
iam -> converter : Convert IAM policy
|
||||
converter -> iam : Return APE chain
|
||||
iam -> morphRuleStorage : Store IAM policy and APE chain
|
||||
iam -> s3localOverrides : Set S3 local overrides
|
||||
iam -> client : OK
|
||||
end
|
||||
|
||||
group Request S3 to set a policy
|
||||
client -> s3 : Set bucket policy
|
||||
s3 -> converter : Convert IAM policy
|
||||
converter -> s3 : Return APE chain
|
||||
s3 -> morphRuleStorage : Store bucket policy and APE chain
|
||||
s3 -> client : OK
|
||||
end
|
||||
|
||||
group Get object
|
||||
client -> s3: GetObject
|
||||
s3 -> s3chainRouter: Check if APE allows request for S3
|
||||
note over s3chainRouter: matching the request with overrides and rules
|
||||
s3chainRouter -> s3: Status: ALLOW
|
||||
s3 -> obj: Get object
|
||||
obj -> storageChainRouter: Check if APE allows the request
|
||||
note over storageChainRouter : matching the request with overrides and rules
|
||||
storageChainRouter -> obj: Status: ALLOW
|
||||
obj -> s3: Response: OK, Object
|
||||
s3 -> client: Response: OK, Object
|
||||
end
|
||||
|
||||
@enduml
|
73
docs/images/ape/s3_ape.svg
Normal file
73
docs/images/ape/s3_ape.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 22 KiB |
46
docs/images/ape/storage_node_ape.puml
Normal file
46
docs/images/ape/storage_node_ape.puml
Normal file
|
@ -0,0 +1,46 @@
|
|||
@startuml storage node ape
|
||||
!pragma teoz true
|
||||
|
||||
participant "Administrator" as administrator
|
||||
participant "Client" as client
|
||||
|
||||
box "Storage node" #Green
|
||||
participant "Object service" as obj
|
||||
participant "Control service" as control
|
||||
end box
|
||||
|
||||
box "Access Policy Engine" #LightGreen
|
||||
participant "Local override storage" as localOverrides
|
||||
participant "Chain Router" as chainRouter
|
||||
participant "Morph rule storage" as morphRuleStorage
|
||||
end box
|
||||
|
||||
group Set local override
|
||||
client -> control: Add local override
|
||||
control -> localOverrides: Save override in DB
|
||||
localOverrides -> control: OK
|
||||
control -> client: OK
|
||||
end
|
||||
|
||||
group Update state in Policy contract
|
||||
administrator -> morphRuleStorage: Add chain
|
||||
morphRuleStorage -> administrator: OK
|
||||
end
|
||||
|
||||
group Perform a request A
|
||||
client -> obj : Sending a request
|
||||
obj -> chainRouter: Check if APE allows the request
|
||||
note over chainRouter : Fetches local overrides and rules defined for a target/targets and looks for a match
|
||||
chainRouter -> obj: APE returns status: "ACCESS DENIED"
|
||||
obj -> client: Response: "the request is denied"
|
||||
end
|
||||
|
||||
group Perform a request B
|
||||
client -> obj : Sending a request
|
||||
obj -> chainRouter: Check if APE allows the request
|
||||
note over chainRouter : Fetches local overrides and rules defined for a target/targets and looks for a match
|
||||
chainRouter -> obj: APE returns status: "ALLOW"
|
||||
obj -> client: Response: "OK"
|
||||
end
|
||||
|
||||
@enduml
|
58
docs/images/ape/storage_node_ape.svg
Normal file
58
docs/images/ape/storage_node_ape.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 17 KiB |
Loading…
Reference in a new issue