Skip to main content
Deno 2 is finally here 🎉️
Learn more

iam-policies

NPM JavaScript Style Guide 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

Features

Supports these glob features:

Usage

Examples

First, we should get our policies classes:

const { IdentityBasedPolicy, ResourceBasedPolicy } = require('iam-policies');

Effect property allow

const allowExample = new IdentityBasedPolicy([
  {
    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([
  {
    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([
  {
    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([
  {
    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([
  {
    resource: '*',
    action: '*'
  }
]);

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

Conditions property

const conditions = {
  greatherThan: function(data, expected) {
    return data > expected;
  }
};

const conditionExample = new IdentityBasedPolicy(
  [
    {
      resource: 'secrets:*',
      action: ['read', 'write'],
      condition: {
        greatherThan: {
          'user.age': 18
        }
      }
    }
  ],
  conditions
);

conditionExample.evaluate({
  action: 'read',
  resource: 'secrets:sshhh',
  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([
  {
    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([
  {
    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(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.

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(
  Statement,
  conditionResolver
);

Properties

Name Type Default Required Description
Statement object[] undefined true The Statement element is the main element for a policy. The Statement element can contain a single statement or an array of individual statements.
Statement[].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.
Statement[].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.
Statement[].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.
Statement[].resource string or string[] undefined true The resource element specifies the object or objects that the statement covers. Statements must include either a resource or a notResource element.
Statement[].notResource string or string[] undefined true The notResource element is an advanced policy element that explicitly matches every resource except those specified. Statements 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.
Statement[].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.
Statement[].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.
Statement[].condition["conditionType"]["conditionKey"] (string or number or boolean) or (string or number or boolean)[] undefined false The conditionKey should be a custom string path attribute for a specific context attribute. Note: attributes must be separated but dots (.).

Methods

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(
  Statement,
  conditionResolver
);

Properties

Name Type Default Required Description
Statement object[] undefined true The Statement element is the main element for a policy. The Statement element can contain a single statement or an array of individual statements.
Statement[].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.
Statement[].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. Statements must include either an principal or notPrincipal element.
Statement[].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. Statements must include either an principal or notPrincipal element.
Statement[].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.
Statement[].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.
Statement[].resource string or string[] undefined true The resource element specifies the object or objects that the statement covers. Statements could include either a resource or a notResource element.
Statement[].notResource string or string[] undefined true The notResource element is an advanced policy element that explicitly matches every resource except those specified. Statements 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.
Statement[].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.
Statement[].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.
Statement[].condition["conditionType"]["conditionKey"] (string or number or boolean) or (string or number or boolean)[] undefined false The conditionKey should be a custom string path attribute for a specific context attribute. Note: attributes must be separated but dots (.).

Methods

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 true It represents the principal you are asking.
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.
principalType string undefined true 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 true It represents the principal you are asking.
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.
principalType string undefined true 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 true It represents the principal you are asking.
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.
principalType string undefined true It represents the principalType (principal attribute if the statement have principal object) you are asking.

getValueFromPath(data, path) Function

Get object value from path.

const { getValueFromPath } = require('iam-policies');

const value = getValueFromPath(data, path);

Params

Name Type Default Required Description
data object undefined true It is our context.
path string undefined true It is the value path from data. Separate attribute names by dots (.).

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.

Contributing

Fork the repo, make some changes, submit a pull-request! Here is the contributing doc that has some details.

License

MIT © roggervalf