Skip to content

Commit

Permalink
updated readme and privatized method
Browse files Browse the repository at this point in the history
  • Loading branch information
Conroy committed Jun 11, 2020
1 parent 7af46e4 commit eefe702
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 106 deletions.
92 changes: 87 additions & 5 deletions packages/@aws-cdk/aws-stepfunctions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -508,22 +508,104 @@ new stepfunctions.StateMachine(stack, 'MyStateMachine', {
});
```

## Granting actions to a role
## State Machine Permission Grants

Grant access to a state machine by passing an iam role:
IAM roles, users, or groups which need to be able to work with a State Machine should be granted IAM permissions.

Any object that implements the `IGrantable` interface (has an associated principal) can be granted permissions by calling:

- `stateMachine.grantStartExecution(principal)` - grants the principal the ability to start an execution
- `stateMachine.grantRead(principal)` - grants the principal read access
- `stateMachine.grantTaskResponse(principal)` - grants the principal the ability to send success, failure, and heartbeat
- `stateMachine.grant(principal, actions, resourceArn)` - grants the principal the specific IAM action specified

### Read Permissions

Grant `read` access to a state machine by calling the `grantRead()` API.

```ts
stateMachine.grantStartExecution(role);
const role = new iam.Role(stack, 'Role', {
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
});

const stateMachine = new sfn.StateMachine(stack, 'StateMachine', {
definition,
});

//give role read access to state machine
stateMachine.grantRead(role);
```

The following read permissions are provided to a service principal by the `grantRead()` API:

- `states:ListExecutions` - to state machine
- `states:ListStateMachines` - to state machine
- `states:DescribeExecution` - to executions
- `states:DescribeStateMachineForExecution` - to executions
- `states:GetExecutionHistory` - to executions
- `states:ListActivities` - to `*`
- `states:DescribeStateMachine` - to `*`
- `states:DescribeActivity` - to `*`

### Start Execution Permission

Grant permission to start an execution of a state machine by calling the `grantStartExecution()` API.

```ts
const role = new iam.Role(stack, 'Role', {
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
});

const stateMachine = new sfn.StateMachine(stack, 'StateMachine', {
definition,
});

//give role permission to start execution of state machine
stateMachine.grantStartExecution(role);
```

The following permission is provided to a service principal by the `grantStartExecution()` API:

- `states:StartExecution` - to state machine

### Task Response Permissions

Grant task response permissions to a service principal by calling the `grantStartExecution()` API.

```ts
const role = new iam.Role(stack, 'Role', {
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
});

const stateMachine = new sfn.StateMachine(stack, 'StateMachine', {
definition,
});

//give role task response permissions
stateMachine.grantTaskResponse(role);
```

Prescribe more fine-grained iam actions control:
The following task response permissions are provided to a service principal by the `grantTaskResponse()` API:

- `states:SendTaskSuccess` - to `*`
- `states:SendTaskFailure` - to `*`
- `states:SendTaskHeartbeat` - to `*`

They are scoped to `*` because IAM says that for these actions, "policies granting access must specify "*" in the resource element."

### Custom Permissions

You can add any set of permissions to a stream by calling the `grant()` API.

```ts
stateMachine.grant(role, ['states:ListExecution'], stateMachine.stateMachineArn);
const user = new iam.User(stack, 'MyUser');

const stateMachine = new sfn.StateMachine(stack, 'StateMachine', {
definition,
});

//give my user permission to send task success to state machine
stateMachine.grant(user, ['states:SendTaskSuccess'], '*');
```

## Future work
Expand Down
38 changes: 20 additions & 18 deletions packages/@aws-cdk/aws-stepfunctions/lib/state-machine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,15 +125,6 @@ export interface StateMachineProps {
*/
abstract class StateMachineBase extends Resource implements IStateMachine {

public get executionArn(): string {
return Arn.format({
resource: 'execution',
service: 'states',
resourceName: Arn.parse(this.stateMachineArn, ':').resourceName,
sep: ':',
}, this.stack);
}

/**
* Import a state machine
*/
Expand Down Expand Up @@ -165,7 +156,10 @@ abstract class StateMachineBase extends Resource implements IStateMachine {
public grantRead(identity: iam.IGrantable): iam.Grant {
iam.Grant.addToPrincipal({
grantee: identity,
actions: ['states:ListExecutions'],
actions: [
'states:ListExecutions',
'states:ListStateMachines',
],
resourceArns: [this.stateMachineArn],
});
iam.Grant.addToPrincipal({
Expand All @@ -175,12 +169,11 @@ abstract class StateMachineBase extends Resource implements IStateMachine {
'states:DescribeStateMachineForExecution',
'states:GetExecutionHistory',
],
resourceArns: [`${this.executionArn}:*`],
resourceArns: [`${this.executionArn()}:*`],
});
return iam.Grant.addToPrincipal({
grantee: identity,
actions: [
'states:ListStateMachines',
'states:ListActivities',
'states:DescribeStateMachine',
'states:DescribeActivity',
Expand All @@ -192,6 +185,9 @@ abstract class StateMachineBase extends Resource implements IStateMachine {
/**
* Grant the given identity permissions to access task responses of the
* state machine.
*
* IAM Policy Simulator says "this action does not support resource-level permissions.
* Policies granting access must specify "*" in the resource element."
*/
public grantTaskResponse(identity: iam.IGrantable): iam.Grant {
return iam.Grant.addToPrincipal({
Expand All @@ -215,6 +211,18 @@ abstract class StateMachineBase extends Resource implements IStateMachine {
resourceArns: [resourceArn],
});
}

/**
* Returns the pattern for the execution ARN's of the state machine
*/
private executionArn(): string {
return Stack.of(this).formatArn({
resource: 'execution',
service: 'states',
resourceName: Arn.parse(this.stateMachineArn, ':').resourceName,
sep: ':',
});
}
}

/**
Expand Down Expand Up @@ -303,12 +311,6 @@ export class StateMachine extends StateMachineBase {
resourceName: this.physicalName,
sep: ':',
});
// this.executionArn = Arn.format({
// resource: 'execution',
// service: 'states',
// resourceName: this.physicalName,
// sep: ':',
// }, this.stack);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,30 +73,6 @@
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": "states:DescribeExecution",
"Effect": "Allow",
"Resource": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":states:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":execution::*"
]
]
}
}
],
"Version": "2012-10-17"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,5 @@ const role = new iam.Role(stack, 'Role', {
});

stateMachine.grantTaskResponse(role);
stateMachine.grant(role, ['states:DescribeExecution'], `${stateMachine.executionArn}:*`);

app.synth();
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,10 @@ describe('State Machine Resources', () => {
PolicyDocument: {
Statement: [
{
Action: 'states:ListExecutions',
Action: [
'states:ListExecutions',
'states:ListStateMachines',
],
Effect: 'Allow',
Resource: {
Ref: 'StateMachine2E01A3A5',
Expand Down Expand Up @@ -279,7 +282,6 @@ describe('State Machine Resources', () => {
},
{
Action: [
'states:ListStateMachines',
'states:ListActivities',
'states:DescribeStateMachine',
'states:DescribeActivity',
Expand Down Expand Up @@ -360,48 +362,17 @@ describe('State Machine Resources', () => {
});

// WHEN
stateMachine.grant(role, ['states:DescribeExecution'], `${stateMachine.executionArn}:*`);
stateMachine.grant(role, ['states:ListExecution'], stateMachine.stateMachineArn);

// THEN
expect(stack).toHaveResource('AWS::IAM::Policy', {
PolicyDocument: {
Statement: [
{
Action: 'states:DescribeExecution',
Action: 'states:ListExecution',
Effect: 'Allow',
Resource: {
'Fn::Join': [
'',
[
'arn:',
{
Ref: 'AWS::Partition',
},
':states:',
{
Ref: 'AWS::Region',
},
':',
{
Ref: 'AWS::AccountId',
},
':execution:',
{
'Fn::Select': [
6,
{
'Fn::Split': [
':',
{
Ref: 'StateMachine2E01A3A5',
},
],
},
],
},
':*',
],
],
Ref: 'StateMachine2E01A3A5',
},
},
],
Expand Down Expand Up @@ -497,35 +468,16 @@ describe('State Machine Resources', () => {
});

// WHEN
stateMachine.grant(role, ['states:DescribeExecution'], `${stateMachine.executionArn}:*`);
stateMachine.grant(role, ['states:ListExecution'], stateMachine.stateMachineArn);

// THEN
expect(stack).toHaveResource('AWS::IAM::Policy', {
PolicyDocument: {
Statement: [
{
Action: 'states:DescribeExecution',
Action: 'states:ListExecution',
Effect: 'Allow',
Resource: {
'Fn::Join': [
'',
[
'arn:',
{
Ref: 'AWS::Partition',
},
':states:',
{
Ref: 'AWS::Region',
},
':',
{
Ref: 'AWS::AccountId',
},
':execution:*',
],
],
},
Resource: stateMachine.stateMachineArn,
},
],
Version: '2012-10-17',
Expand Down

0 comments on commit eefe702

Please sign in to comment.