Skip to content

Commit

Permalink
topic rule grant publish
Browse files Browse the repository at this point in the history
  • Loading branch information
hollanddd committed Mar 17, 2021
1 parent 8c5840e commit 486be6c
Show file tree
Hide file tree
Showing 11 changed files with 514 additions and 59 deletions.
35 changes: 8 additions & 27 deletions packages/@aws-cdk/aws-iot-actions/lib/republish.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,21 @@
import * as iam from '@aws-cdk/aws-iam';
import * as iot from '@aws-cdk/aws-iot';
import { Stack, Arn } from '@aws-cdk/core';
import { singletonTopicRuleRole } from './util';

/**
* Construction properties for a Republish action.
*/
export interface RepublishProps {
/**
* The name of the MQTT topic
*/
readonly topic: string;
/**
* The Quality of Service (Qos) level to use when republishing messages.
*
* @default - 0
*/
readonly qos?: number;
/**
*
* The MQTT topic to which to republish the message.
*
* To republish to a reserved topic, which begins with `$`, use `$$` instead.
*
* For example, to republish to the device shadow topic
* `$aws/things/MyThing/shadow/update`, specify the topic as
* `$$aws/things/MyThing/shadow/update`.
*/
readonly topic: string;
/**
* The IAM role that grants access.
*
Expand All @@ -35,25 +27,14 @@ export interface RepublishProps {
/**
* Publishes to a IoT Topic
*/
export class Republish implements iot.ITopicRuleAction {
constructor(private readonly props: RepublishProps) {
export class RepublishTopic implements iot.ITopicRuleAction {
constructor(private readonly topic: iot.ITopicRule, private readonly props: RepublishProps) {
}

public bind(rule: iot.ITopicRule): iot.TopicRuleActionConfig {
const stack = Stack.of(rule);
// Allow rule to publish to topic
// TODO: accept topic rule as prop - this.props.topic.topicRuleArn;
// TODO: grantable topic rules - this.props.topic.grantPublish(rule);
const role = this.props.role || singletonTopicRuleRole(rule, [new iam.PolicyStatement({
actions: ['iot:Publish'],
resources: [
Arn.format({
resource: 'topic',
service: 'iot',
resourceName: this.props.topic,
}, stack),
],
})]);
const role = this.props.role || singletonTopicRuleRole(rule, []);
this.topic.grantPublish(role, this.props.topic);

return {
republish: {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
{
"Resources": {
"ErrorTopicA0904A23": {
"Type": "AWS::SNS::Topic"
},
"ErrorTopicPolicyA43559E4": {
"Type": "AWS::SNS::TopicPolicy",
"Properties": {
"PolicyDocument": {
"Statement": [
{
"Action": "sns:Publish",
"Effect": "Allow",
"Principal": {
"Service": "iot.amazonaws.com"
},
"Resource": {
"Ref": "ErrorTopicA0904A23"
},
"Sid": "0"
}
],
"Version": "2012-10-17"
},
"Topics": [
{
"Ref": "ErrorTopicA0904A23"
}
]
}
},
"MyNotifierTopicAllowIot154F3A47": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "iot.amazonaws.com"
}
}
],
"Version": "2012-10-17"
}
},
"DependsOn": [
"FunctionAllowIotD2ECA9CD"
]
},
"MyNotifierTopicC60F4F3C": {
"Type": "AWS::IoT::TopicRule",
"Properties": {
"TopicRulePayload": {
"Actions": [
{
"Lambda": {
"FunctionArn": {
"Fn::GetAtt": [
"Function76856677",
"Arn"
]
}
}
}
],
"AwsIotSqlVersion": "2015-10-08",
"ErrorAction": {
"Sns": {
"MessageFormat": "RAW",
"RoleArn": {
"Fn::GetAtt": [
"MyNotifierTopicAllowIot154F3A47",
"Arn"
]
},
"TargetArn": {
"Ref": "ErrorTopicA0904A23"
}
}
},
"RuleDisabled": false,
"Sql": "SELECT teapots FROM 'coffee/shop'"
}
},
"DependsOn": [
"FunctionAllowIotD2ECA9CD"
]
},
"FunctionServiceRole675BB04A": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
}
}
],
"Version": "2012-10-17"
},
"ManagedPolicyArns": [
{
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
]
]
}
]
}
},
"Function76856677": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"ZipFile": "boom"
},
"Role": {
"Fn::GetAtt": [
"FunctionServiceRole675BB04A",
"Arn"
]
},
"Handler": "index.handler",
"Runtime": "nodejs12.x"
},
"DependsOn": [
"FunctionServiceRole675BB04A"
]
},
"FunctionAllowIotD2ECA9CD": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"Action": "lambda:InvokeFunction",
"FunctionName": {
"Fn::GetAtt": [
"Function76856677",
"Arn"
]
},
"Principal": "iot.amazonaws.com",
"SourceAccount": {
"Ref": "AWS::AccountId"
}
}
},
"MyWorkTopicE967237A": {
"Type": "AWS::IoT::TopicRule",
"Properties": {
"TopicRulePayload": {
"Actions": [
{
"Republish": {
"Qos": 0,
"RoleArn": {
"Fn::GetAtt": [
"MyWorkTopicAllowIot06B368E4",
"Arn"
]
},
"Topic": "coffee/shop"
}
}
],
"AwsIotSqlVersion": "2015-10-08",
"RuleDisabled": false,
"Sql": "SELECT * FROM 'inventory'"
}
}
},
"MyWorkTopicAllowIot06B368E4": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "iot.amazonaws.com"
}
}
],
"Version": "2012-10-17"
}
}
},
"MyWorkTopicAllowIotDefaultPolicy13C30DF0": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyDocument": {
"Statement": [
{
"Action": "iot:Publish",
"Effect": "Allow",
"Resource": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":iot:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":topic/coffee/shop"
]
]
}
}
],
"Version": "2012-10-17"
},
"PolicyName": "MyWorkTopicAllowIotDefaultPolicy13C30DF0",
"Roles": [
{
"Ref": "MyWorkTopicAllowIot06B368E4"
}
]
}
}
}
}
27 changes: 27 additions & 0 deletions packages/@aws-cdk/aws-iot-actions/test/integ.kit-and-caboodle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import * as iot from '@aws-cdk/aws-iot';
import * as lambda from '@aws-cdk/aws-lambda';
import * as sns from '@aws-cdk/aws-sns';
import { App, Stack } from '@aws-cdk/core';
import * as actions from '../lib';

const app = new App();
const stack = new Stack(app, 'MyTopicRule');

const rule = new iot.TopicRule(stack, 'MyNotifierTopic', {
sql: 'SELECT teapots FROM \'coffee/shop\'',
errorAction: new actions.SnsTopic(new sns.Topic(stack, 'ErrorTopic')),
});

const func = new lambda.Function(stack, 'Function', {
code: lambda.Code.fromInline('boom'),
handler: 'index.handler',
runtime: lambda.Runtime.NODEJS_12_X,
});

rule.addAction(new actions.LambdaFunction(func));

new iot.TopicRule(stack, 'MyWorkTopic', {
sql: 'SELECT * FROM \'inventory\'',
actions: [new actions.RepublishTopic(rule, { topic: 'coffee/shop' })],
});

Loading

0 comments on commit 486be6c

Please sign in to comment.