Enterprise Access Policies in Gitana 4.0 (Part 1)
Aug 5
In this article, we'll take a look at Access Policies -- a powerful, new feature in Gitana 4.0 that allows organizations to set up and guarantee compliance with complex, enterprise-wide security requirements. Access Policies build upon the existing access control facilities provided which include per-object ACLs and broader, team-based ACLs. They extend those capabilities by allowing administrators to express access rights in a broad sweeping and prescriptive manner -- one that allows for customization and rule-based configuration, defining access constraints that span your entire platform, go across projects, across users and across all of your content via centralized and managed policy control documents.
The Access Policy
An Access Policy document is a JSON document that defines one or more conditional statements. Each statement conditionally grants or revokes one or more authorities against a resource. If effect, each statement is a rule that is evaluated for the current user against the given resource and a determination is made of what authorities to bestow.
The basic structure of an Access Policy document looks like this:
{
"title": "{title}",
"statements": [{
"action": "{action}",
"roles": [],
"conditions": [{
"type": "{conditionType},
"config": {
...
}
]}
}]
}
Access Policies can be assigned to Users, Groups and Teams. By assigning an Access Policy to a Group or a Team, all members of that group or team will receive the grants or revocations prescribed by the Access Policy. This includes sub-groups or principals members with nested memberships.
Finally, Access Policies can be assigned at multiple scopes. A platform
-scoped Access Policy will be evaluated universally across all of your Gitana resources (including within Projects). Where as a project
-scoped Access Policy is applicable only to the resources of a specific project.
Using scopes, you can centrally manage Access Policies that span the entire organization as well as centrally manage Access Policies that are then assigned project-by-project to fine tune access control rights within any given project. You may also wish to permit Project Administrators to have rights to further extend Access Policies within their individual projects or constrain that very ability, depending on your specific needs.
Access Policies in Practice
We've pulled together a few examples on how Access Policies are most commonly put to use across our customer base. We've also compiled a few simple examples to help demonstrate what Access Policies are all about.
Let's take a look at a few examples, starting with the simplest of cases.
Grant the Consumer Role to Everything
You can write an unconditional Access policy by simply omitting the conditions
array.
This Access policy will grant the Consumer role to all resources.
{
"title": "Consumer of all Resources",
"statements": [{
"action": "grant",
"roles": ["consumer"]
}]
}
Notes:
- If this Access Policy were assigned at the Platform scope, it would grant Consumer rights to a principal for everything on the tenant platform.
- If it were assigned to a specific Project, it would grant Consumer rights to a principal for everything within the project.
This includes the Project itself, the Stack, the Master Branch, any other Branch and all content on all Branches.
Needless to say, this kind of Access Policy isn't typically used. It's provided here as a starting point. Let's see some more!
Grant the Consumer Role to Content Nodes
We can improve on the previous example by constraining the grant to content nodes only. To do so, we can introduce a Condition. Specifically, we'll use the type
condition to constrain the statement to apply only to resources of type node
.
{
"title": "Consumer of all Content Nodes",
"statements": [{
"action": "grant",
"roles": ["consumer"],
"conditions": [{
"type": "type",
"config": {
"type": "node"
}
}]
}]
}
Notes:
- If this Access Policy were assigned at the Platform scope, it would grant Consumer rights to a principal for all content nodes across all projects on the tenant platform.
- If it were assigned to a specific Project, it would grant Consumer rights to a principal for all content nodes within that specific project.
You can learn more about the type
condition here:
https://gitana.io/documentation/gitana/4.0/engine/security/access-policies/conditions/type.html
Grant the Consumer Role to Content Nodes in specific Projects
Suppose we wanted to apply the previous example at the Platform level but have it only apply to specific projects. We can use the or
condition coupled with the project
condition to build out the boolean logic for the binding.
Imagine that we have two projects that host content for "level 4" vendors. The first Project might be named FedEx
and the second project might be named UPS
. We can constrain our Access Policy to those two projects by Title like this:
{
"title": "Consumer of all Content Nodes for Level 4 Vendor Projects",
"statements": [{
"action": "grant",
"roles": ["consumer"],
"conditions": [{
"type": "type",
"config": {
"type": "node"
}
}, {
"type": "or",
"config": {
"conditions": [{
"type": "project",
"config": {
"title": "FedEx"
}
}, {
"type": "project",
"config": {
"title": "UPS"
}
}]
}
}]
}]
}
Note that the conditions
array elements have an implicit and
amongst them.
This Access Policy would be assigned at the Platform level and would only evaluate against resources within the FedEx or UPS projects.
Since the titles of Project can potentially change, we could improve this by sle also elect to constrain by ID, like this:
{
"title": "Consumer of all Content Nodes for Level 4 Vendor Projects",
"statements": [{
"action": "grant",
"roles": ["consumer"],
"conditions": [{
"type": "type",
"config": {
"type": "node"
}
}, {
"type": "or",
"config": {
"conditions": [{
"type": "project",
"config": {
"id": "db247ccd3539f5aa0ef8"
}
}, {
"type": "project",
"config": {
"id": "ada21783fc8761831bbb"
}
}]
}
}]
}]
}
That's not bad. However, we can improve this even further.
Suppose we simply tagged Projects with a property called vendor_level
which identified the level of subscription. Then we could just tag the UPS and FedEx projects with vendor_level
set to 4
.
Now our Access Policy can be simplified:
{
"title": "Consumer of all Content Nodes for Level 4 Vendor Projects",
"statements": [{
"action": "grant",
"roles": ["consumer"],
"conditions": [{
"type": "type",
"config": {
"type": "node"
}
}, {
"type": "project",
"config": {
"property": "vendor_level",
"value": 4
}
}]
}]
}
Much better! This Access Policy will automatically be applied to any Projects with the designated vendor_level
. This means we can add, remove and update Projects as we wish and the Access Policy system will dynamically apply our provisioned access rights as we go!
It's also worth noting that any and all conditional rules will perform Regular Expression matching whenever textual content is being compared. In the examples above, we used simple text matches. But we could also imagine a more contrived example where we might want this Access Policy to apply to all Projects that start with the letter A
. You could adjust the Condition like this:
{
"type": "project",
"config": {
"title": "^A.*"
}
}
That's it.
You can use RegEx expressions anyplace where text conditions are concerned. Use them for multi-value matches, prefix or suffix matches, partial matches and much more!
You can learn more about the project
condition here:
https://gitana.io/documentation/gitana/4.0/engine/security/access-policies/conditions/project.html
You can learn more about the or
condition here:
https://gitana.io/documentation/gitana/4.0/engine/security/access-policies/conditions/or.html
You can learn more about the and
condition here:
https://gitana.io/documentation/gitana/4.0/engine/security/access-policies/conditions/and.html
More to Come!
In the next article, we'll continue looking at more complex and interesting examples of Access Policies. We'll take a look at revokes and ordering. And we'll cover examples that employ conditions around Branches and further Content properties including locale, path and aspect-injected, nested property paths!