IAM-policies

iam-policies

NPM code style: prettier Build Status NPM downloads Coverage Status deno doc semantic-release

About

Define custom IAM Policies by allowed or denied set of actions against a set of resources with optional context and conditions.

Deny rules trump allow rules.

This is based of @ddt/iam and AWS Reference Policies .

Install

npm install --save iam-policies

Or

yarn add iam-policies

Deno import

// @deno-types="https://raw.githubusercontent.com/roggervalf/iam-policies/master/dist/main.d.ts"
import {
  ActionBasedPolicy,
  IdentityBasedPolicy,
  ResourceBasedPolicy
} from "https://raw.githubusercontent.com/roggervalf/iam-policies/master/dist/main.es.js"

or

// @deno-types="https://deno.land/x/iam_policies@master/dist/main.d.ts"
import {
  ActionBasedPolicy,
  IdentityBasedPolicy,
  ResourceBasedPolicy
} from "https://deno.land/x/iam_policies@master/dist/main.es.js"

Features

Supports these glob features:

Usage

Examples

First, we should get our policies classes:

const {
  ActionBasedPolicy,
  IdentityBasedPolicy,
  ResourceBasedPolicy
} = require("iam-policies")

Effect property allow

const allowExample = new IdentityBasedPolicy({
  statements: [
    {
      effect: "allow", // optional, defaults to allow
      resource: ["secrets:${user.id}:*"], // embedded value by context
      action: ["read", "write"]
    },
    {
      resource: ["bd:company:*"],
      action: "create"
    }
  ]
})

const contextForAllowExample = { user: { id: 456 } }

allowExample.evaluate({
  action: "read",
  resource: "secrets:456:ultraSecret",
  context: contextForAllowExample
}) // true
allowExample.evaluate({
  action: "create",
  resource: "secrets:456:ultraSecret",
  context: contextForAllowExample
}) // false
allowExample.evaluate({
  action: "create",
  resource: "bd:company:account",
  context: contextForAllowExample
}) // true
allowExample.evaluate({
  action: "read",
  resource: "bd:company:account",
  context: contextForAllowExample
}) // false

Effect property deny

const denyExample = new IdentityBasedPolicy({
  statements: [
    {
      resource: ["secrets:${user.bestFriends}:*"],
      action: "read"
    },
    {
      effect: "deny",
      resource: "secrets:123:*",
      action: "read"
    }
  ]
})

const contextForDenyExample = { user: { bestFriends: [123, 563, 1211] } }

denyExample.evaluate({
  action: "read",
  resource: "secrets:563:super-secret",
  context: contextForDenyExample
}) // true
denyExample.evaluate({
  action: "read",
  resource: "secrets:123:super-secret",
  context: contextForDenyExample
}) // false

Not Action property

const notActionExample = new IdentityBasedPolicy({
  statements: [
    {
      resource: "bd:company:*",
      notAction: "update"
    }
  ]
})

notActionExample.evaluate({
  action: "delete",
  resource: "bd:company:account"
}) // true
notActionExample.evaluate({
  action: "update",
  resource: "bd:company:account"
}) // false

Not Resource property

const notResourceExample = new IdentityBasedPolicy({
  statements: [
    {
      notResource: ["bd:roles:*"],
      action: "update"
    }
  ]
})

notResourceExample.evaluate({
  action: "update",
  resource: "photos"
}) // true
notResourceExample.evaluate({
  action: "update",
  resource: "bd:roles:admin"
}) // false

Allow everything

const adminExample = new IdentityBasedPolicy({
  statements: [
    {
      resource: "*",
      action: "*"
    }
  ]
})

adminExample.evaluate({
  action: "read",
  resource: "someResource"
}) // true
adminExample.evaluate({
  action: "write",
  resource: "otherResource"
}) // true

Conditions property

const conditionResolver = {
  greaterThan: function (data, expected) {
    return data > expected
  }
}

const conditionExample = new IdentityBasedPolicy({
  statements: [
    {
      resource: "secrets:*",
      action: ["read", "write"],
      condition: {
        greaterThan: {
          "user.age": 18
        }
      }
    }
  ],
  conditionResolver
})

conditionExample.evaluate({
  action: "read",
  resource: "secrets:code",
  context: { user: { age: 19 } }
}) // true
conditionExample.evaluate({
  action: "read",
  resource: "secrets:admin:super-secret",
  context: {
    user: { age: 18 }
  }
}) // false

Principal property

const principalExample = new ResourceBasedPolicy({
  statements: [
    {
      principal: "1",
      effect: "allow",
      resource: ["secrets:user:*"],
      action: ["read", "write"]
    },
    {
      principal: { id: "2" },
      resource: "bd:company:*",
      notAction: "update"
    }
  ]
})

principalExample.evaluate({
  principal: "1",
  action: "read",
  resource: "secrets:user:name"
}) // true
principalExample.evaluate({
  principal: "2",
  action: "read",
  resource: "secrets:user:super-secret"
}) // false
principalExample.evaluate({
  principal: "2",
  action: "read",
  resource: "bd:company:name",
  principalType: "id"
}) // true
principalExample.evaluate({
  principal: "2",
  action: "update",
  resource: "bd:company:name",
  principalType: "id"
}) // false

Not Principal property

const notPrincipalExample = new ResourceBasedPolicy({
  statements: [
    {
      notPrincipal: ["1", "2"],
      resource: ["secrets:bd:*"],
      action: "read"
    },
    {
      notPrincipal: { id: "3" },
      resource: "secrets:admin:*",
      action: "read"
    }
  ]
})

notPrincipalExample.evaluate({
  principal: "3",
  action: "read",
  resource: "secrets:bd:tables"
}) // true
notPrincipalExample.evaluate({
  principal: "1",
  action: "read",
  resource: "secrets:bd:tables"
}) // false
notPrincipalExample.evaluate({
  principal: "1",
  action: "read",
  resource: "secrets:admin:friends",
  principalType: "id"
}) // true
notPrincipalExample.evaluate({
  principal: "3",
  action: "read",
  resource: "secrets:admin:friends",
  principalType: "id"
}) // false

Using can and cannot

const canAndCannotStatements = [
  {
    effect: "allow", // again, this is optional, as it already defaults to allow
    resource: ["website:${division.companyId}:${division.countryId}:*/*"],
    action: ["create", "update", "delete"]
  },
  {
    effect: "deny",
    resource: ["website:${division.companyId}:${division.countryId}:city/lima"],
    action: "delete"
  }
]

const inclusivePolicy = new IdentityBasedPolicy({
  statements: canAndCannotStatements
})

const contextCanAndCannot = {
  division: {
    companyId: 123,
    countryId: 456
  }
}

const canAndCannotDeniedArgument = {
  action: "delete",
  resource: "website:123:456:city/lima",
  context: contextCanAndCannot
}

inclusivePolicy.evaluate(canAndCannotDeniedArgument) // false
// So far, we are not sure whether the argument is denied or not present.

inclusivePolicy.can(canAndCannotDeniedArgument) // true
// It's present as an allow policy, so it must be explicitly denied, right?

inclusivePolicy.cannot(canAndCannotDeniedArgument) // true
// I knew it!

const canAndCannotNotPresentArgument = {
  action: "read",
  resource: "website:123:456:}city/lima",
  context: contextCanAndCannot
}

inclusivePolicy.evaluate(canAndCannotNotPresentArgument) // false
// Again, the user doesn't have access here, but why? Let's investigate..

inclusivePolicy.can(canAndCannotNotPresentArgument) // false
// It's not present as an allow policy, but is it explicitly denied?

inclusivePolicy.cannot(canAndCannotNotPresentArgument) // false
// Nope, it just isn't there.

ActionBasedPolicy Class

Attach managed and simple inline policies to grant actions only.

const { ActionBasedPolicy } = require("iam-policies")

const actionBasedPolicy = new ActionBasedPolicy({
  statements,
  conditionResolver,
  context
})

Properties

Name Type Default Required Description
statements object[] undefined true The statements is the main element for a policy. The statements element can contain an array of individual statements.
statements[]
.sid
string uuid false The sid element should be a unique identifier. It is automatically generated with a uuid in case it is undefined.
statements[]
.effect
string allow false The effect element specifies whether the statement results in an allow or an explicit deny. Valid values for Effect are allow and deny.
statements[]
.action
string or string[] undefined false The action element describes the specific action or actions that will be allowed or denied. Each statement must include either an action or notAction element.
statements[]
.notAction
string or string[] undefined false The notAction element is an advanced policy element that explicitly matches everything except the specified list of actions. Each statement must include either an action or notAction element. Using notAction can result in a shorter policy by listing only a few actions that should not match, rather than including a long list of actions that will match. When using notAction, you should keep in mind that actions specified in this element are the only actions in that are limited. This, in turn, means that all of the applicable actions or services that are not listed are allowed if you use the Allow effect. In addition, such unlisted actions or services are denied if you use the deny effect. When you use notAction with the resource element, you provide scope for the policy.
statements[]
.condition
object undefined false The condition element (or Condition block) lets you specify conditions for when a policy is in effect. In the condition element, you build expressions in which you use condition operators (equal, less than, etc.) to match the condition keys and values in the policy against keys and values in the request context.
statements[]
.condition["conditionType"]
object undefined false The conditionType name should be replaced with a custom string attribute for a specific condition that should be match with one conditionResolver element.
statements[]
.condition["conditionType"]
["conditionKey"]
any undefined false The conditionKey should be a custom string path attribute for a specific context attribute. Note: attributes must be separated but dots (.).
conditionResolver object undefined false The conditionResolver should contain a function in each attribute to resolve an specific embedded condition in our statements.
conditionResolver
["conditionKey"]
function undefined false The conditionKey should match with a function name that will be used as a resolver in condition evaluation. There are 2 parameters for this function: data (first parameter) that will be evaluated with expected (second parameter), returning a true or false.
context object undefined false The context has those properties that will be embedded in our statements.

Methods

actionBasedPolicy.addStatement(statement)

public: Add a new statement to this Policy.

actionBasedPolicy.getStatements()

public: Returns statements[] (statements array).

actionBasedPolicy.getContext()

public: Returns context object.

actionBasedPolicy.setContext(context)

public: Sets context object.

actionBasedPolicy.getConditionResolver()

public: Returns conditionResolver object.

actionBasedPolicy.setConditionResolver(conditionResolver)

public: Sets conditionResolver object.

actionBasedPolicy.evaluate({action, context})

public: Verify if action is allowed (true) or denied (false).

Params
Name Type Default Required Description
action string undefined true It represents the action you are asking.
context object undefined false It represents the properties that will be embedded into your actions.

actionBasedPolicy.can({action, context})

public: Verify if action is allowed (true) or not present (false).

Params
Name Type Default Required Description
action string undefined true It represents the action you are asking.
context object undefined false It represents the properties that will be embedded into your actions.

actionBasedPolicy.cannot({action, context})

public: Verify if action for specific resource is denied (true) or not present (false).

Params
Name Type Default Required Description
action string undefined true It represents the action you are asking.
context object undefined false It represents the properties that will be embedded into your actions.

actionBasedPolicy.generateProxy(object, options)

public: Generate a Proxy for the object param.

Params
Name Type Default Required Description
object object undefined true It's the object that is going to be wrapped with a Proxy.
options object { get:{ allow:true }, set:{ allow:true } } false It should contains attributes to modify the default behavior.
options
.get
object { allow:true } false It should contain get function handler options for the Proxy instance.
options
.get.allow
boolean true false It should allow to use the get function handler.
options
.get.propertyMap
object {} false It should serve as a mapping for different property names in get function handler.
options
.set
object { allow:true } false It should contain set function handler options for the Proxy instance.
options
.set.allow
boolean true false It should allow to use the set function handler.
options
.set.propertyMap
object {} false It should serve as a mapping for different property names in set function handler.

IdentityBasedPolicy Class

Attach managed and inline policies to identities (users, groups to which users belong, or roles). Identity-based policies grant permissions to an identity.

const { IdentityBasedPolicy } = require("iam-policies")

const identityBasedPolicy = new IdentityBasedPolicy({
  statements,
  conditionResolver
})

Properties

Name Type Default Required Description
statements object[] undefined true The statements element is the main element for a policy. The statements element can contain an array of individual statements.
statements[]
.sid
string uuid false The sid element should be a unique identifier. It is automatically generated with a uuid in case it is undefined.
statements[]
.effect
string allow false The effect element specifies whether the statement results in an allow or an explicit deny. Valid values for Effect are allow and deny.
statements[]
.action
string or string[] undefined false The action element describes the specific action or actions that will be allowed or denied. Statements must include either an action or notAction element.
statements[]
.notAction
string or string[] undefined false The notAction element is an advanced policy element that explicitly matches everything except the specified list of actions. Statements must include either an action or notAction element. Using notAction can result in a shorter policy by listing only a few actions that should not match, rather than including a long list of actions that will match. When using notAction, you should keep in mind that actions specified in this element are the only actions in that are limited. This, in turn, means that all of the applicable actions or services that are not listed are allowed if you use the Allow effect. In addition, such unlisted actions or services are denied if you use the deny effect. When you use notAction with the resource element, you provide scope for the policy.
statements[]
.resource
string or string[] undefined true The resource element specifies the object or objects that the statement covers. Each statement must include either a resource or a notResource element.
statements[]
.notResource
string or string[] undefined true The notResource element is an advanced policy element that explicitly matches every resource except those specified. Each statement must include either an resource or notResource element. Using notResource can result in a shorter policy by listing only a few resources that should not match, rather than including a long list of resources that will match.
statements[]
.condition
object undefined false The condition element (or Condition block) lets you specify conditions for when a policy is in effect. In the condition element, you build expressions in which you use condition operators (equal, less than, etc.) to match the condition keys and values in the policy against keys and values in the request context.
statements[]
.condition["conditionType"]
object undefined false The conditionType name should be replaced with a custom string attribute for a specific condition that should be match with one conditionResolver element.
statements[]
.condition["conditionType"]
["conditionKey"]
any undefined false The conditionKey should be a custom string path attribute for a specific context attribute. Note: attributes must be separated but dots (.).
conditionResolver object undefined false The conditionResolver should contain a function in each attribute to resolve an specific embedded condition in our statements.
conditionResolver
["conditionKey"]
function undefined false The conditionKey should match with a function name that will be used as a resolver in condition evaluation. There are 2 parameters for this function: data (first parameter) that will be evaluated with expected (second parameter), returning a true or false.
context object undefined false The context has those properties that will be embedded in our statements.

Methods

identityBasedPolicy.addStatement(statement)

public: Add a new statement to this Policy.

identityBasedPolicy.getStatements()

public: Returns statements[] (statements array).

identityBasedPolicy.getContext()

public: Returns context object.

identityBasedPolicy.setContext(context)

public: Sets context object.

identityBasedPolicy.getConditionResolver()

public: Returns conditionResolver object.

identityBasedPolicy.setConditionResolver(conditionResolver)

public: Sets conditionResolver object.

identityBasedPolicy.evaluate({action, resource, context})

public: Verify if action for specific resource is allowed (true) or denied (false).

Params
Name Type Default Required Description
action string undefined true It represents the action you are asking.
resource string undefined true It represents the resource for the action you are asking.
context object undefined false It represents the properties that will be embedded into your resources.

identityBasedPolicy.can({action, resource, context})

public: Verify if action for specific resource is allowed (true) or not present (false).

Params
Name Type Default Required Description
action string undefined true It represents the action you are asking.
resource string undefined true It represents the resource for the action you are asking.
context object undefined false It represents the properties that will be embedded into your resources.

identityBasedPolicy.cannot({action, resource, context})

public: Verify if action for specific resource is denied (true) or not present (false).

Params
Name Type Default Required Description
action string undefined true It represents the action you are asking.
resource string undefined true It represents the resource for the action you are asking.
context object undefined false It represents the properties that will be embedded into your resources.

ResourceBasedPolicy Class

Attach inline policies to resources. Resource-based policies grant permissions to the principal that is specified in the policy.

const { ResourceBasedPolicy } = require("iam-policies")

const resourceBasedPolicy = new ResourceBasedPolicy({
  statements,
  conditionResolver,
  context
})

Properties

Name Type Default Required Description
statements object[] undefined true The statements element is the main element for a policy. The statements element can contain an array of individual statements.
statements[]
.sid
string uuid false The sid element should be a unique identifier. It is automatically generated with a uuid in case it is undefined.
statements[]
.effect
string allow false The effect element specifies whether the statement results in an allow or an explicit deny. Valid values for Effect are allow and deny.
statements[]
.principal
string or string[] undefined false The principal element in a policy to specify the principal that is allowed or denied access to a resource. Each statement could include either an principal or notPrincipal.
statements[]
.notPrincipal
string or string[] undefined false The notPrincipal element specifies the principal that is not allowed or denied access to a resource. The notPrincipal element enables you to specify an exception to a list of principals. Use this element to deny access to all principals except the one named in the notPrincipal element. Each statement could include either an principal or notPrincipal element.
statements[]
.action
string or string[] undefined false The action element describes the specific action or actions that will be allowed or denied. Each statement must include either an action or notAction element.
statements[]
.notAction
string or string[] undefined false The notAction element is an advanced policy element that explicitly matches everything except the specified list of actions. Each statement must include either an action or notAction element. Using notAction can result in a shorter policy by listing only a few actions that should not match, rather than including a long list of actions that will match. When using notAction, you should keep in mind that actions specified in this element are the only actions in that are limited. This, in turn, means that all of the applicable actions or services that are not listed are allowed if you use the Allow effect. In addition, such unlisted actions or services are denied if you use the deny effect. When you use notAction with the resource element, you provide scope for the policy.
statements[]
.resource
string or string[] undefined true The resource element specifies the object or objects that the statement covers. Each statement could include either a resource or a notResource element.
statements[]
.notResource
string or string[] undefined true The notResource element is an advanced policy element that explicitly matches every resource except those specified. Each statement could include either an resource or notResource element. Using notResource can result in a shorter policy by listing only a few resources that should not match, rather than including a long list of resources that will match.
statements[]
.condition
object undefined false The condition element (or Condition block) lets you specify conditions for when a policy is in effect. In the condition element, you build expressions in which you use condition operators (equal, less than, etc.) to match the condition keys and values in the policy against keys and values in the request context.
statements[]
.condition["conditionType"]
object undefined false The conditionType name should be replaced with a custom string attribute for a specific condition that should be match with one conditionResolver element.
statements[]
.condition["conditionType"]
["conditionKey"]
any undefined false The conditionKey should be a custom string path attribute for a specific context attribute. Note: attributes must be separated but dots (.).
conditionResolver object undefined false The conditionResolver should contain a function in each attribute to resolve an specific embedded condition in our statements.
conditionResolver
["conditionKey"]
function undefined false The conditionKey should match with a function name that will be used as a resolver in condition evaluation. There are 2 parameters for this function: data (first parameter) that will be evaluated with expected (second parameter), returning a true or false.
context object undefined false The context has those properties that will be embedded in our statements.

Methods

resourceBasedPolicy.addStatement(statement)

public: Add a new statement to this Policy.

resourceBasedPolicy.getStatements()

public: Returns statements[] (statements array).

resourceBasedPolicy.getContext()

public: Returns context object.

resourceBasedPolicy.setContext(context)

public: Sets context object.

resourceBasedPolicy.getConditionResolver()

public: Returns conditionResolver object.

resourceBasedPolicy.setConditionResolver(conditionResolver)

public: Sets conditionResolver object.

resourceBasedPolicy.evaluate({principal, action, resource, context, principalType})

public: Verify if action for specific resource is allowed (true) or denied (false).

Params
Name Type Default Required Description
principal string undefined false It represents the principal you are asking.
action string undefined true It represents the action you are asking.
resource string undefined false It represents the resource for the action you are asking.
context object undefined false It represents the properties that will be embedded into your resources.
principalType string undefined false It represents the principalType (principal attribute if the statement have principal object) you are asking.

resourceBasedPolicy.can({principal, action, resource, context, principalType})

public: Verify if action for specific resource is allowed (true) or not present (false).

Params
Name Type Default Required Description
principal string undefined false It represents the principal you are asking.
action string undefined true It represents the action you are asking.
resource string undefined false It represents the resource for the action you are asking.
context object undefined false It represents the properties that will be embedded into your resources.
principalType string undefined false It represents the principalType (principal attribute if the statement have principal object) you are asking.

resourceBasedPolicy.cannot({principal, action, resource, context, principalType})

public: Verify if action for specific resource is denied (true) or not present (false).

Params
Name Type Default Required Description
principal string undefined false It represents the principal you are asking.
action string undefined true It represents the action you are asking.
resource string undefined false It represents the resource for the action you are asking.
context object undefined false It represents the properties that will be embedded into your resources.
principalType string undefined false It represents the principalType (principal attribute if the statement have principal object) you are asking.

Condition Operators

There is a predefined condition operator to be used as part of conditionResolver in case user don't pass any.

Boolean condition operators

Boolean conditions let you construct condition elements that restrict access based on comparing a key to true or false.

Name First Parameter Expected Parameter Description
bool boolean boolean Boolean matching.

Date condition operators

Date conditions let you construct condition elements that restrict access based on comparing a key to date/time value.

Name First Parameter Expected Parameter Description
dateEquals Date or string Date or string Matching a specific date.
dateNotEquals Date or string Date or string Negated matching.
dateLessThan Date or string Date or string Matching before a specific date and time.
dateLessThanEquals Date or string Date or string Matching at or before a specific date and time.
dateGreaterThan Date or string Date or string Matching after a specific date and time.
dateGreaterThanEquals Date or string Date or string Matching at or after a specific date and time.

Numeric condition operators

Numeric condition operators let you construct condition elements that restrict access based on comparing a key to an integer or decimal value.

Name First Parameter Expected Parameter Description
numericEquals number number Exact matching.
numericNotEquals number number Negated matching.
numericLessThan number number Less than matching.
numericLessThanEquals number number Less than or equals matching.
numericGreaterThan number number Greater than matching.
numericGreaterThanEquals number number Greater than or equals matching.

String condition operators

String condition operators let you construct condition elements that restrict access based on comparing a key to a string value.

Name First Parameter Expected Parameter Description
stringEquals string string Exact matching, case sensitive.
stringNotEquals string string Negated matching.
stringEqualsIgnoreCase string string Exact matching, ignoring case.
stringNotEqualsIgnoreCase string string Negated matching, ignoring case.
stringLike string string Case-sensitive matching. The values can include a multi-character match wildcard (*) anywhere in the string.
stringLikeIfExists string string Case-sensitive matching if exists. The values can include a multi-character match wildcard (*) anywhere in the string.

getValueFromPath(data, path) Function

Get object value from path.

const { getValueFromPath } = require("iam-policies")

const value = getValueFromPath(data, path, defaultValue)

Params

Name Type Default Required Description
data object undefined true It is our context.
path Array or string undefined true It is the value path from data. Separate attribute names by dots (.).
defaultValue any undefined false It is the value returned for undefined resolved values.

applyContext(str, context) Function

Get string with context value embedded into it.

const { applyContext } = require("iam-policies")

const embeddedStr = applyContext(str, context)

Params

Name Type Default Required Description
str string undefined true It could contain embedded path values into it by using (${}).
context object undefined false It represents the context that should be embedded into str.

License

MIT © roggervalf