Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: adjust usage of Statement for schema #51

Merged
merged 1 commit into from
Mar 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 106 additions & 56 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,34 @@
# Amazon Verified Permissions L2 CDK Construct

This repo contains the implementation of an L2 CDK Construct for Amazon Verified Permissions

# Project Stability

This construct is still versioned with alpha/v0 major version and we could introduce breaking changes even without a major version bump. Our goal is to keep the API stable & backwards compatible as much as possible but we currently cannot guarantee that. Once we'll publish v1.0.0 the breaking changes will be introduced via major version bumps.

# Getting Started

## Policy Store
Define a Policy Store with defaults (No schema & Validation Settings Mode set to OFF)

Define a Policy Store with defaults (No schema & Validation Settings Mode set to OFF):

```ts
const test = new PolicyStore(scope, 'PolicyStore')
const test = new PolicyStore(scope, "PolicyStore");
```

Define a Policy Store without Schema definition (Validation Settings Mode must be set to OFF)
Define a Policy Store without Schema definition (Validation Settings Mode must be set to OFF):

```ts
const validationSettingsOff = {
mode: ValidationSettingsMode.OFF,
};
const test = new PolicyStore(scope, 'PolicyStore', {
const test = new PolicyStore(scope, "PolicyStore", {
validationSettings: validationSettingsOff,
})
});
```

Define a Policy Store with Schema definition (a STRICT Validation Settings Mode is strongly suggested for Policy Stores with schemas):

```ts
const validationSettingsStrict = {
mode: ValidationSettingsMode.STRICT,
Expand All @@ -36,8 +42,8 @@ const cedarJsonSchema = {
actions: {
viewPhoto: {
appliesTo: {
principalTypes: ['User'],
resourceTypes: ['Photo'],
principalTypes: ["User"],
resourceTypes: ["Photo"],
},
},
},
Expand All @@ -46,26 +52,44 @@ const cedarJsonSchema = {
const cedarSchema = {
cedarJson: JSON.stringify(cedarJsonSchema),
};
const policyStore = new PolicyStore(scope, 'PolicyStore', {
const policyStore = new PolicyStore(scope, "PolicyStore", {
schema: cedarSchema,
validationSettings: validationSettingsStrict,
});
```

Define a Policy Store with Schema definition from file:

```ts
const validationSettingsStrict = {
mode: ValidationSettingsMode.STRICT,
};
const cedarSchema = {
cedarJson: Statement.fromFile("assets/policy-store-schema.json"),
};
const policyStore = new PolicyStore(scope, "PolicyStore", {
schema: cedarSchema,
validationSettings: validationSettingsStrict,
});
```

## Identity Source
Define Identity Source with required properties

Define Identity Source with required properties:

```ts
const userPool = new UserPool(scope, 'UserPool'); // Creating a new Cognito UserPool
new IdentitySource(scope, 'IdentitySource', {
configuration: {
cognitoUserPoolConfiguration: {
userPool: userPool,
},
}
const userPool = new UserPool(scope, "UserPool"); // Creating a new Cognito UserPool
new IdentitySource(scope, "IdentitySource", {
configuration: {
cognitoUserPoolConfiguration: {
userPool: userPool,
},
},
});
```

Define Identity Source with all the properties
Define Identity Source with all the properties:

```ts
const validationSettingsStrict = {
mode: ValidationSettingsMode.STRICT,
Expand All @@ -79,8 +103,8 @@ const cedarJsonSchema = {
actions: {
viewPhoto: {
appliesTo: {
principalTypes: ['User'],
resourceTypes: ['Photo'],
principalTypes: ["User"],
resourceTypes: ["Photo"],
},
},
},
Expand All @@ -89,27 +113,27 @@ const cedarJsonSchema = {
const cedarSchema = {
cedarJson: JSON.stringify(cedarJsonSchema),
};
const policyStore = new PolicyStore(scope, 'PolicyStore', {
const policyStore = new PolicyStore(scope, "PolicyStore", {
schema: cedarSchema,
validationSettings: validationSettingsStrict,
});
const userPool = new UserPool(scope, 'UserPool'); // Creating a new Cognito UserPool
new IdentitySource(scope, 'IdentitySource', {
configuration: {
cognitoUserPoolConfiguration: {
clientIds: [
'&ExampleCogClientId;',
],
userPool: userPool,
},
const userPool = new UserPool(scope, "UserPool"); // Creating a new Cognito UserPool
new IdentitySource(scope, "IdentitySource", {
configuration: {
cognitoUserPoolConfiguration: {
clientIds: ["&ExampleCogClientId;"],
userPool: userPool,
},
policyStore: policyStore,
principalEntityType: 'PETEXAMPLEabcdefg111111',
},
policyStore: policyStore,
principalEntityType: "PETEXAMPLEabcdefg111111",
});
```

## Policy
Define a Policy and add it to a specific Policy Store

Define a Policy and add it to a specific Policy Store:

```ts
const statement = `permit(
principal,
Expand All @@ -119,32 +143,33 @@ const statement = `permit(
true
};`;

const description = 'Test policy assigned to the test store';
const description = "Test policy assigned to the test store";
const validationSettingsOff = {
mode: ValidationSettingsMode.OFF,
};
const policyStore = new PolicyStore(scope, 'PolicyStore', {
validationSettings: validationSettingsOff,
const policyStore = new PolicyStore(scope, "PolicyStore", {
validationSettings: validationSettingsOff,
});

// Create a policy and add it to the policy store
const policy = new Policy(scope, 'MyTestPolicy', {
definition: {
const policy = new Policy(scope, "MyTestPolicy", {
definition: {
static: {
statement,
description,
statement,
description,
},
},
policyStore: policyStore,
},
policyStore: policyStore,
});
```

Define a policy with a template linked definition
Define a policy with a template linked definition:

```ts
const validationSettingsOff = {
mode: ValidationSettingsMode.OFF,
};
const policyStore = new PolicyStore(scope, 'PolicyStore', {
const policyStore = new PolicyStore(scope, "PolicyStore", {
validationSettings: validationSettingsOff,
});
const policyTemplateStatement = `
Expand All @@ -153,47 +178,72 @@ permit (
action in [TinyTodo::Action::"ReadList", TinyTodo::Action::"ListTasks"],
resource == ?resource
);`;
const template = new PolicyTemplate(scope, 'PolicyTemplate', {
const template = new PolicyTemplate(scope, "PolicyTemplate", {
statement: policyTemplateStatement,
policyStore: policyStore,
});

const policy = new Policy(scope, 'MyTestPolicy', {
const policy = new Policy(scope, "MyTestPolicy", {
definition: {
templateLinked: {
policyTemplate: template,
principal: {
entityId: 'exampleId',
entityType: 'exampleType',
entityId: "exampleId",
entityType: "exampleType",
},
resource: {
entityId: 'exampleId',
entityType: 'exampleType',
entityId: "exampleId",
entityType: "exampleType",
},
},
},
policyStore: policyStore,
});
```

Define a Policy with a statement from file:

```ts
const description = "Test policy assigned to the test store";
const validationSettingsOff = {
mode: ValidationSettingsMode.OFF,
};
const policyStore = new PolicyStore(scope, "PolicyStore", {
validationSettings: validationSettingsOff,
});

// Create a policy and add it to the policy store
const policy = new Policy(scope, "MyTestPolicy", {
definition: {
static: {
statement: Statement.fromFile("assets/policy-statement.cedar"),
description,
},
},
policyStore: policyStore,
});
```

## Policy Template
Define a Policy Template referring to a Cedar Statement in local file

Define a Policy Template referring to a Cedar Statement in local file:

```ts
const validationSettingsOff = {
mode: ValidationSettingsMode.OFF,
};
const policyStore = new PolicyStore(scope, 'PolicyStore', {
const policyStore = new PolicyStore(scope, "PolicyStore", {
validationSettings: validationSettingsOff,
});
new PolicyTemplate(scope, 'PolicyTemplate', {
description: 'Allows sharing photos in full access mode',
new PolicyTemplate(scope, "PolicyTemplate", {
description: "Allows sharing photos in full access mode",
policyStore: policyStore,
statement: Statement.fromFile('assets/template-statement.cedar'),
statement: Statement.fromFile("assets/template-statement.cedar"),
});
```

# Notes
* This project is following the AWS CDK Official Design Guidelines (see https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md) and the AWS CDK New Constructs Creation Guide (see here https://github.com/aws/aws-cdk/blob/main/docs/NEW_CONSTRUCTS_GUIDE.md).

* Feedback is a gift: if you find something wrong or you've ideas to improve please open an issue or a pull request
- This project is following the AWS CDK Official Design Guidelines (see https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md) and the AWS CDK New Constructs Creation Guide (see here https://github.com/aws/aws-cdk/blob/main/docs/NEW_CONSTRUCTS_GUIDE.md).

- Feedback is a gift: if you find something wrong or you've ideas to improve please open an issue or a pull request
6 changes: 3 additions & 3 deletions src/statement.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { readFileSync } from 'fs';
/*
* Represents the Policy Statement.
* Represents a Cedar Statement (Schema or Policy).
*/
export class Statement {
/**
Expand All @@ -10,7 +10,7 @@ export class Statement {
*/
public static fromInline(statement: string): string {
if (statement.length === 0) {
throw new Error('Policies inline statement cannot be empty');
throw new Error('Statement cannot be empty');
}
return statement;
}
Expand All @@ -22,7 +22,7 @@ export class Statement {
*/
public static fromFile(path: string): string {
if (path.length === 0) {
throw new Error('Policy path cannot be empty');
throw new Error('Path cannot be empty');
}
return readFileSync(path, 'utf-8');
}
Expand Down
29 changes: 29 additions & 0 deletions test/policy-store.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { readFileSync } from 'fs';
import { ArnFormat, Aws, Stack } from 'aws-cdk-lib';
import { Template } from 'aws-cdk-lib/assertions';
import * as iam from 'aws-cdk-lib/aws-iam';
Expand Down Expand Up @@ -102,6 +103,34 @@ describe('Policy Store creation', () => {
},
);
});

test('Creating Policy Store with validation settings and schema (mode = STRICT) from file', () => {
// GIVEN
const stack = new Stack(undefined, 'Stack');

// WHEN
new PolicyStore(stack, 'PolicyStore', {
validationSettings: {
mode: ValidationSettingsMode.STRICT,
},
schema: {
cedarJson: Statement.fromFile('test/schema.json'),
},
});

// THEN
Template.fromStack(stack).hasResourceProperties(
'AWS::VerifiedPermissions::PolicyStore',
{
ValidationSettings: {
Mode: ValidationSettingsMode.STRICT,
},
Schema: {
CedarJson: readFileSync('test/schema.json', 'utf-8'),
},
},
);
});
});

describe('Policy Store grant to IGrantable', () => {
Expand Down
26 changes: 26 additions & 0 deletions test/policy-template.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { readFileSync } from 'fs';
import { Stack } from 'aws-cdk-lib';
import { Template } from 'aws-cdk-lib/assertions';
import { CfnPolicyStore } from 'aws-cdk-lib/aws-verifiedpermissions';
Expand Down Expand Up @@ -87,4 +88,29 @@ describe('Policy template reference existing policy template', () => {
// THEN
expect(policyTemplate.policyTemplateId).toBe(policyTemplateId);
});

test('Policy Template with Statement from file', () => {
// GIVEN
const stack = new Stack(undefined, 'Stack');

const policyStore = new PolicyStore(stack, 'PolicyStore', {
validationSettings: {
mode: ValidationSettingsMode.OFF,
},
});

// WHEN
new PolicyTemplate(stack, 'PolicyTemplate', {
statement: Statement.fromFile('test/statement.cedar'),
policyStore,
});

// THEN
Template.fromStack(stack).hasResourceProperties(
'AWS::VerifiedPermissions::PolicyTemplate',
{
Statement: readFileSync('test/statement.cedar', 'utf-8'),
},
);
});
});
Loading
Loading