Cloud Connected

Thoughts and Ideas from the Gitana Development Team

Enterprise Access Policies in Gitana 4.0 (Part 1)

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!