Skip to content
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
1 change: 1 addition & 0 deletions packages/aws-cdk-lib/aws-stepfunctions/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export * from './input';
export * from './types';
export * from './condition';
export * from './state-machine';
export * from './state-machine-grants';
export * from './state-machine-fragment';
export * from './state-transition-metrics';
export * from './chain';
Expand Down
157 changes: 157 additions & 0 deletions packages/aws-cdk-lib/aws-stepfunctions/lib/state-machine-grants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import * as stepfunctions from './stepfunctions.generated';
import * as iam from '../../aws-iam';
import { Arn, ArnFormat, Stack } from '../../core';

/**
* Properties for StateMachineGrants
*/
export interface StateMachineGrantsProps {
/**
* The resource on which actions will be allowed
*/
readonly resource: stepfunctions.IStateMachineRef;
}

/**
* Collection of grant methods for a IStateMachineRef
*/
export class StateMachineGrants {
/**
* Creates grants for StateMachineGrants
*
* @internal
*/
public static _fromStateMachine(resource: stepfunctions.IStateMachineRef): StateMachineGrants {
return new StateMachineGrants({
resource: resource,
});
}

protected readonly resource: stepfunctions.IStateMachineRef;

private constructor(props: StateMachineGrantsProps) {
this.resource = props.resource;
}

/**
* Grant the given identity task response permissions on a state machine
*/
public taskResponse(grantee: iam.IGrantable): iam.Grant {
const actions = ['states:SendTaskSuccess', 'states:SendTaskFailure', 'states:SendTaskHeartbeat'];
return iam.Grant.addToPrincipal({
actions: actions,
grantee: grantee,
resourceArns: [stepfunctions.CfnStateMachine.arnForStateMachine(this.resource)],
});
}

/**
* Grant the given identity permission to redrive the execution of the state machine
*/
public redriveExecution(grantee: iam.IGrantable): iam.Grant {
const actions = ['states:RedriveExecution'];
return iam.Grant.addToPrincipal({
actions: actions,
grantee: grantee,
resourceArns: [stepfunctions.CfnStateMachine.arnForStateMachine(this.resource) + ':*'],
});
}

/**
* Grant the given identity permissions to read results from state
* machine.
*/
public read(grantee: iam.IGrantable): iam.Grant {
iam.Grant.addToPrincipal({
grantee: grantee,
actions: [
'states:ListExecutions',
'states:ListStateMachines',
],
resourceArns: [stepfunctions.CfnStateMachine.arnForStateMachine(this.resource)],
});
iam.Grant.addToPrincipal({
grantee: grantee,
actions: [
'states:DescribeExecution',
'states:DescribeStateMachineForExecution',
'states:GetExecutionHistory',
],
resourceArns: [this.executionArn() + ':*'],
});
return iam.Grant.addToPrincipal({
grantee: grantee,
actions: [
'states:ListActivities',
'states:DescribeStateMachine',
'states:DescribeActivity',
],
resourceArns: ['*'],
});
}

/**
* Grant the given identity permissions to start an execution of this state
* machine.
*
* @param grantee The principal
*/
public startExecution(grantee: iam.IGrantable): iam.Grant {
return iam.Grant.addToPrincipal({
grantee: grantee,
actions: ['states:StartExecution'],
resourceArns: [this.resource.stateMachineRef.stateMachineArn],
});
}

/**
* Grant the given identity permissions to start a synchronous execution of
* this state machine.
*
* @param grantee The principal
*/
public startSyncExecution(grantee: iam.IGrantable): iam.Grant {
return iam.Grant.addToPrincipal({
grantee: grantee,
actions: ['states:StartSyncExecution'],
resourceArns: [this.resource.stateMachineRef.stateMachineArn],
});
}

/**
* Grant the given identity permissions to start an execution of
* this state machine.
*
* @param grantee The principal
*/
public execution(grantee: iam.IGrantable, ...actions: string[]) {
return iam.Grant.addToPrincipal({
grantee: grantee,
actions,
resourceArns: [this.executionArn() + ':*'],
});
}

/**
* Grant the given identity custom permissions
*/
public actions(identity: iam.IGrantable, ...actions: string[]): iam.Grant {
return iam.Grant.addToPrincipal({
grantee: identity,
actions,
resourceArns: [this.resource.stateMachineRef.stateMachineArn],
});
}

/**
* Returns the pattern for the execution ARN's of the state machine
*/
private executionArn(): string {
return Stack.of(this.resource).formatArn({
resource: 'execution',
service: 'states',
resourceName: Arn.split(this.resource.stateMachineRef.stateMachineArn, ArnFormat.COLON_RESOURCE_NAME).resourceName,
arnFormat: ArnFormat.COLON_RESOURCE_NAME,
});
}
}
91 changes: 21 additions & 70 deletions packages/aws-cdk-lib/aws-stepfunctions/lib/state-machine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ import { CustomerManagedEncryptionConfiguration } from './customer-managed-key-e
import { EncryptionConfiguration } from './encryption-configuration';
import { buildEncryptionConfiguration } from './private/util';
import { StateGraph } from './state-graph';
import { StateMachineGrants } from './state-machine-grants';
import { StatesMetrics } from './stepfunctions-canned-metrics.generated';
import { CfnStateMachine } from './stepfunctions.generated';
import { CfnStateMachine, IStateMachineRef, StateMachineReference } from './stepfunctions.generated';
import { IChainable, QueryLanguage } from './types';
import * as cloudwatch from '../../aws-cloudwatch';
import * as iam from '../../aws-iam';
import * as logs from '../../aws-logs';
import * as s3_assets from '../../aws-s3-assets';
import { Arn, ArnFormat, Duration, IResource, RemovalPolicy, Resource, Stack, Token, ValidationError } from '../../core';
import { ArnFormat, Duration, IResource, RemovalPolicy, Resource, Stack, Token, ValidationError } from '../../core';
import { addConstructMetadata, MethodMetadata } from '../../core/lib/metadata-resource';
import { propertyInjectable } from '../../core/lib/prop-injectable';

Expand Down Expand Up @@ -215,87 +216,53 @@ abstract class StateMachineBase extends Resource implements IStateMachine {
*/
public abstract readonly grantPrincipal: iam.IPrincipal;

/**
* Collection of grant methods for a StateMachine
*/
public grants = StateMachineGrants._fromStateMachine(this);

public get stateMachineRef(): StateMachineReference {
return {
stateMachineArn: this.stateMachineArn,
};
}

/**
* Grant the given identity permissions to start an execution of this state
* machine.
*/
public grantStartExecution(identity: iam.IGrantable): iam.Grant {
return iam.Grant.addToPrincipal({
grantee: identity,
actions: ['states:StartExecution'],
resourceArns: [this.stateMachineArn],
});
return this.grants.startExecution(identity);
}

/**
* Grant the given identity permissions to start a synchronous execution of
* this state machine.
*/
public grantStartSyncExecution(identity: iam.IGrantable): iam.Grant {
return iam.Grant.addToPrincipal({
grantee: identity,
actions: ['states:StartSyncExecution'],
resourceArns: [this.stateMachineArn],
});
return this.grants.startSyncExecution(identity);
}

/**
* Grant the given identity permissions to read results from state
* machine.
*/
public grantRead(identity: iam.IGrantable): iam.Grant {
iam.Grant.addToPrincipal({
grantee: identity,
actions: [
'states:ListExecutions',
'states:ListStateMachines',
],
resourceArns: [this.stateMachineArn],
});
iam.Grant.addToPrincipal({
grantee: identity,
actions: [
'states:DescribeExecution',
'states:DescribeStateMachineForExecution',
'states:GetExecutionHistory',
],
resourceArns: [`${this.executionArn()}:*`],
});
return iam.Grant.addToPrincipal({
grantee: identity,
actions: [
'states:ListActivities',
'states:DescribeStateMachine',
'states:DescribeActivity',
],
resourceArns: ['*'],
});
return this.grants.read(identity);
}

/**
* Grant the given identity task response permissions on a state machine
*/
public grantTaskResponse(identity: iam.IGrantable): iam.Grant {
return iam.Grant.addToPrincipal({
grantee: identity,
actions: [
'states:SendTaskSuccess',
'states:SendTaskFailure',
'states:SendTaskHeartbeat',
],
resourceArns: [this.stateMachineArn],
});
return this.grants.taskResponse(identity);
}

/**
* Grant the given identity permissions on all executions of the state machine
*/
public grantExecution(identity: iam.IGrantable, ...actions: string[]) {
return iam.Grant.addToPrincipal({
grantee: identity,
actions,
resourceArns: [`${this.executionArn()}:*`],
});
return this.grants.execution(identity, ...actions);
}

/**
Expand All @@ -309,11 +276,7 @@ abstract class StateMachineBase extends Resource implements IStateMachine {
* Grant the given identity custom permissions
*/
public grant(identity: iam.IGrantable, ...actions: string[]): iam.Grant {
return iam.Grant.addToPrincipal({
grantee: identity,
actions,
resourceArns: [this.stateMachineArn],
});
return this.grants.actions(identity, ...actions);
}

/**
Expand Down Expand Up @@ -395,18 +358,6 @@ abstract class StateMachineBase extends Resource implements IStateMachine {
return this.cannedMetric(StatesMetrics.executionTimeAverage, props);
}

/**
* 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.split(this.stateMachineArn, ArnFormat.COLON_RESOURCE_NAME).resourceName,
arnFormat: ArnFormat.COLON_RESOURCE_NAME,
});
}

private cannedMetric(
fn: (dims: { StateMachineArn: string }) => cloudwatch.MetricProps,
props?: cloudwatch.MetricOptions): cloudwatch.Metric {
Expand Down Expand Up @@ -657,7 +608,7 @@ export class StateMachine extends StateMachineBase {
/**
* A State Machine
*/
export interface IStateMachine extends IResource, iam.IGrantable {
export interface IStateMachine extends IResource, iam.IGrantable, IStateMachineRef {
/**
* The ARN of the state machine
* @attribute
Expand Down
Loading