Documentation




Policy

Let’s start reviewing {{service_name}} concepts with a cornerstone entity called policy.

Policy is, generally speaking, a combination of principals (users, groups, applications), resources (reports, invoices, users, groups, etc.), possible actions on resources (e.g. read, update, delete, etc.), and effects (allow or deny). Its main responsibility is to permit or decline particular operations on specific resources for a given authenticated principal.

Policies can be represented with JSON documents containing several fields that we will describe later.

{{service_name}} supports two policy types: identity- and resource-based. The key difference between the two is that resource-based policies are always associated with a single resource using a 1-1 relation and is automatically created by {{service_name}} for each resource. Identity-based policy manages identity (user, group, application), can have various principals attached, and defines what this identity can do. Resource-based policy is attached to one resource, and defines who and what can do on that one resource. Let’s review both types in more detail.

Identity-based policy

Identity-based policies are generic policies that define what actions can be performed on what resources by which principals. You can reuse identity-based policies to grant permissions to multiple principals via policy attachment. Additionally, multiple resource IRNs can be specified for bundling permission grants.

Let’s start with an example statement that allows updating (action) an invoice (resource).

Have a look at the policy JSON representation for the above statement.


    "name": "service-invoice-43-policy",
    "type": "identity",
    "description": "Allow invoice update",
    "statements": [
        {
        "effect": "allow",
        "actions": [
            "iam:resource:update"
        ],
        "resources": [
            "irn:rc73dbh7q0:iamcore:4atcicnisg::invoice/service-invoice-43"
        ],
        "description": "Example statement description"
        }
    ]
    

You don’t have to immediately understand all the JSON fields; we’ll talk about them later. What’s important for now is that identity-based policy statements have a "resources" field. "resources" list all resource IRNs

  (irn:rc73dbh7q0:iamcore:4atcicnisg::invoice/service-invoice-43)

that the policy statement applies to.

IRN stands for iamcore Resource Name. For now, think about IRN as of entity’s fully qualified name (FQN). Later we will discuss IRNs in more detail.

Resource-based policy

Resource-based policies allow managing access to individual resources. One such policy is automatically created by {{service_name}} for each resource. You can’t reassign this policy to include multiple resources, but this type of policy provides a clear method for granular access control to an individual resource.

Additionally, resource-based policies support granting permissions to principals across accounts and/or tenants, which is not possible via identity-based policy.

Let’s continue with the example of invoice. Imagine that now we need a policy that allows viewing the invoice by somebody outside of the account and/or tenant that the invoice resides in - for example, it can be a partner company that we issued the invoice for, represented by its own account and tenant. With a resource-based policy, we can grant read access to the invoice for, let’s say, the accounting group of the partner company.

This is how such policy would look like as a JSON document:


        {
            "name": "irn:rc73dbh7q0:iamcore:4atcicnisg::invoice/service-invoice-43",
            "type": "resource",
            "description": "Individual resource policy",
            "statements": [
            {
                "effect": "allow",
                "actions": [
                "iam:resource:read"
                ],
                "principals": [
                "irn:tu73a31jf0:iamcore:1anmn3pu90::group/accounting"
                ],
                "description": "Example statement description"
            }
            ]
        }
    

You can notice that principals listed in the policy statement are residents of the different account and tenant than resource: tu73a31jf0 account (while resource’s one is rc73dbh7q0), and 1anmn3pu90 tenant (while resource’s one is 4atcicnisg). You will find out about the IRNs structure in more detail soon.

You can also see that a resource-based policy does not have the resources statement field. Since every resource-based policy is by definition related to only one resource you can think of the resources field as implicit and always containing only one resource IRN. Additionally, "name" field always points to the resource’s IRN that resource-based policy points to.

Look at the following table to briefly summarize the difference between the two policy types.

PropertyIdentity-based policyResource-based policy
Number of principals0-N0-N
Number of resources0-N1
Nameuser-defined and editableimmutable and always points to one resource

Policy structure

Now it’s time to review the policy fields.

  • name is the short name of the policy. Identity-based policy name must be non-empty, unique tenant-wide, and only contain latin letters (a-zA-Z), digits (0-9), dashes (-), and underscores (_). Resource-based policy names are automatically assigned by {{service_name}} to match the IRN of the corresponding resource, and they also include separators : and /.

  • type is a JSON string that defines whether it is a identity-based or resource-based policy. Acceptable values for this field are "identity" for the former and "resource" for the latter.

  • description is a human-readable policy metadata. You can use it to convey the meaning of the policy to the reader so they don’t have to decipher the entire policy definition.

  • statements is an array of policy allow and deny statements.

  • effect is a string that can have only two values: "allow" or "deny". As you will shortly see from the policy evaluation section, {{service_name}} always starts with an implicit deny, so at least one allow policy statement must exist for a principal to be permitted an action on a resource.

  • actions is an array of actions that can be performed on resources. In other words, actions are operations that can be performed on resources. Actions typically consist of application name that is the resource owner (currently, only iam, the short form of the {{service_name}}, is supported), resource type, and operation divided by semicolons (:): <application>:<resource-type>:<operation>. Action subtokens may contain lowercase latin letters (a-z) and dashes (-). For example, iam:user:create. Additionally, actions support a wildcard asterisk character (*), which can be used either on it’s own to match any actions, or as the last character immediately following a semicolon delimiter to match all actions with a given prefix. For example, * matches all possible resource actions, and iam:user:* matches all actions on users - create, read, update, delete.

  • principals is an array of user/group/application IRNs that the given statement applies to. Principals act as action initiators, and the policy statement defines whether to allow or deny such actions. Again, for now, think about user/group/application IRN as of their fully qualified name (FQN).

  • resources is an array of resource IRNs that the statement applies to. This field is explicitly defined in identity-based policies, but implicitly matches the corresponding resource in resource-based ones.

  • description is a human-readable statement metadata.

Policy evaluation

Let’s review the {{service_name}} policy evaluation flow to see how {{service_name}} decides whether to allow or deny operation on a resource for a principal.

{{service_name}} policy evaluation flow

{{service_name}} implicitly assumes any decision to be a deny unless it encounters a policy that allows the operation. An allow decision is made only if there is a matching allow statement and no matching deny statements.

This conceptually simple behavior allows constructing policy combinations to represent even the most sophisticated business rules for scenarios of arbitrary complexity while retaining the desired level of access granularity. Remember that you can use both user, group, application IRNs as principals. Moreover, you can use resource IRN wildcards: more on these in a bit.

iamcore Resource Name (IRN)

iamcore Resource Name (IRN) is a fully qualified name string that uniquely identifies a resource or a principal.

IRNs have the following format:

irn:<account ID>:<application>:<tenant ID>:[<pool>]:<resource type>[/<resource path>]/<resource ID>

Let us review the IRN tokens in more detail.

  • irn—static prefix used to visually identify IRNs among other identifier strings.

  • <account ID>—unique account identifier. Usually account ID consists of lowercase latin letters (a-z), digits (0-9), and has length of 10 characters, but every {{service_name}} installation also has one system account ID - root. Examples: rc73dbh7q0, root, etc.

  • <application>—short identifier of the application name that owns the resource. For example: iamcore, myapp, etc. Currently, only iamcore is supported.

  • <tenant ID>—unique tenant identifier. Usually tenant ID consists of lowercase latin letters (a-z), digits (0-9), and has length of 10 characters. Examples: 4atcicnisg, 17g5l2ijc0, etc.

  • <pool>—optional pool that the resource belongs to. Pools provide resource isolation within tenants. Further, pools may be nested, in which case the complete hierarchy must be specified in the IRN, starting with the root pool and using slash (/) as a separator. Pool nesting is a powerful concept that can be used for representing large, hierarchical organizations, or even third parties such as distributors, regional offices, etc. For example: my-division, my-division/my-subdivision, my-division/my-subdivision/my-sub-subdivision, etc.

Pools are not supported in this version of the {{service_name}}. This IRN token is reserved and must remain empty for all resources. {:.note}

  • <resource type>—type of the resource identified by the IRN, e.g. user, invoice, device, and others.

  • <resource path>—optional path the resource resides in, as defined at the discretion of the owner application. Path can be nested, typically to represent a physical or logical location of the resource. If present, the resource path must be non-empty and start with a slash (/). In case of a nested path, this token becomes composite with sub-tokens also separated by slashes. For example: /directory-1, /directory-1/sub-directory-2, etc.

  • <resource ID>—unique resource identifier as defined by the application. This may be an username, file name, invoice ID, etc. For example: alice, myfile, 52870, 5766b7e9-1f16-443d-8e4a-553f70733aa7, etc.

Let’s have a look at a complete IRN. You should now be able to identify its constituent tokens and understand their meaning.


        irn:rc73dbh7q0:iamcore:4atcicnisg:my-division:invoice/directory-1/service-invoice-43
        ^         ^         ^         ^         ^          ^                ^
        account ID  application  tenant ID  pool  resource type  resource path  resource ID
    

IRN (sub-)tokens consist of latin letters (a-zA-Z), digits (0-9), dashes (-), underscores (_), at signs (@), and dots (.). Semicolon (:) and slash (/) are reserved separators for IRN tokens and subtokens, respectively. Finally, asterisk (*) is reserved for wildcard IRNs, which is our next subject.

IRN wildcards

As you have seen from {{service_name}} policy structure, IRNs play an important role in policy definition. To make it easier to create reusable policies, {{service_name}} supports wildcards in policy IRNs.

To define a wildcard IRN, use the special asterisk sign (*). There are several rules for valid wildcard IRNs:

  • only one asterisk is allowed

  • asterisk must be the last character

  • asterisk must follow an IRN token or subtoken delimiter (: or /, respectively), except in the * blanket IRN that matches everything

Let’s review a few examples of IRN wildcards:

  • * and irn:*—both match any well-formed IRNs. The shorter form is considered canonical and preferred ({{service_name}} converts any irn:* wildcards into *).

  • irn:rc73dbh7q0:*—matches IRNs of any resources in account rc73dbh7q0

  • irn:rc73dbh7q0:iamcore:*—matches IRNs of any {{service_name}} owned resources in account rc73dbh7q0

  • irn:rc73dbh7q0:iamcore:4atcicnisg:*—matches IRNs of any {{service_name}} owned resources in tenant 4atcicnisg

  • irn:rc73dbh7q0:iamcore:4atcicnisg::user/*—matches any {{service_name}} users in tenant 4atcicnisg

  •   irn:rc73dbh7q0:iamcore:4atcicnisg::user/divisionA/*—matches any {{service_name}}
    users in tenant 4atcicnisg under the divisionA path, including nested paths

By using IRN wildcards to define policy statements, you can dramatically reduce the number of needed policies and and their management requirements.

Management interface

{{service_name}} exposes an HTTP-based management interface with the following endpoints:

  • GET /health returns 200 OK if the service is up and running properly, and 500 Internal Server Error otherwise. In case of errors, the response payload contains their human-redable descriptions. This endpoint can be used by Kubernetes for liveness and readiness probing.

  • GET /metrics provides service metrics in Prometheus text-based format.

Having trouble finding answers?

Worry not, we're here to give you some extra help.