Skip to content

Commit

Permalink
feat(chatbot): support guardrail policies (#24114)
Browse files Browse the repository at this point in the history
Support defining guardrail policies when creating a SlackChannelConfiguration
Closes #20788

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
bjornhandersson committed Feb 12, 2023
1 parent 1e9220f commit 4c72a7d
Show file tree
Hide file tree
Showing 9 changed files with 376 additions and 0 deletions.
5 changes: 5 additions & 0 deletions packages/@aws-cdk/aws-chatbot/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,8 @@ allows you to customize the maximum number of retries and base backoff duration.
resource](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cfn-customresource.html) is added
to the stack that pre-creates the log group as part of the stack deployment, if it already doesn't exist, and sets the
correct log retention period (never expire, by default).

## Guardrails

By default slack channel will use `AdministratorAccess` managed policy as guardrail policy.
The `guardrailPolicies` property can be used to set a different set of managed policies.
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ export interface SlackChannelConfigurationProps {
* @default - Default AWS SDK retry options.
*/
readonly logRetentionRetryOptions?: logs.LogRetentionRetryOptions;

/**
* A list of IAM managed policies that are applied as channel guardrails.
* @default - The AWS managed 'AdministratorAccess' policy is applied as a default if this is not set.
*/
readonly guardrailPolicies?: iam.IManagedPolicy[];
}

/**
Expand Down Expand Up @@ -293,6 +299,7 @@ export class SlackChannelConfiguration extends SlackChannelConfigurationBase {
slackChannelId: props.slackChannelId,
snsTopicArns: cdk.Lazy.list({ produce: () => this.notificationTopics.map(topic => topic.topicArn) }, { omitEmpty: true } ),
loggingLevel: props.loggingLevel?.toString(),
guardrailPolicies: cdk.Lazy.list({ produce: () => props.guardrailPolicies?.map(policy => policy.managedPolicyArn) }, { omitEmpty: true } ),
});

// Log retention
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"version": "29.0.0",
"files": {
"6c1ea5243130449f4b215f7eac487f2dd07715c6751857440bbbfeb883e736ce": {
"source": {
"path": "ChatbotGuardrailsInteg.template.json",
"packaging": "file"
},
"destinations": {
"current_account-current_region": {
"bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
"objectKey": "6c1ea5243130449f4b215f7eac487f2dd07715c6751857440bbbfeb883e736ce.json",
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
}
}
}
},
"dockerImages": {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
{
"Resources": {
"MySlackChannelConfigurationRole1D3F23AE": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "chatbot.amazonaws.com"
}
}
],
"Version": "2012-10-17"
}
}
},
"MySlackChannelA8E0B56C": {
"Type": "AWS::Chatbot::SlackChannelConfiguration",
"Properties": {
"ConfigurationName": "test-channel",
"IamRoleArn": {
"Fn::GetAtt": [
"MySlackChannelConfigurationRole1D3F23AE",
"Arn"
]
},
"SlackChannelId": "C0187JABUE9",
"SlackWorkspaceId": "T49239U4W",
"GuardrailPolicies": [
{
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":iam::aws:policy/CloudWatchReadOnlyAccess"
]
]
}
]
}
}
},
"Parameters": {
"BootstrapVersion": {
"Type": "AWS::SSM::Parameter::Value<String>",
"Default": "/cdk-bootstrap/hnb659fds/version",
"Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]"
}
},
"Rules": {
"CheckBootstrapVersion": {
"Assertions": [
{
"Assert": {
"Fn::Not": [
{
"Fn::Contains": [
[
"1",
"2",
"3",
"4",
"5"
],
{
"Ref": "BootstrapVersion"
}
]
}
]
},
"AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI."
}
]
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"version":"29.0.0"}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
{
"version": "29.0.0",
"artifacts": {
"ChatbotGuardrailsInteg.assets": {
"type": "cdk:asset-manifest",
"properties": {
"file": "ChatbotGuardrailsInteg.assets.json",
"requiresBootstrapStackVersion": 6,
"bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version"
}
},
"ChatbotGuardrailsInteg": {
"type": "aws:cloudformation:stack",
"environment": "aws://unknown-account/unknown-region",
"properties": {
"templateFile": "ChatbotGuardrailsInteg.template.json",
"validateOnSynth": false,
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}",
"cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}",
"stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/6c1ea5243130449f4b215f7eac487f2dd07715c6751857440bbbfeb883e736ce.json",
"requiresBootstrapStackVersion": 6,
"bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version",
"additionalDependencies": [
"ChatbotGuardrailsInteg.assets"
],
"lookupRole": {
"arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}",
"requiresBootstrapStackVersion": 8,
"bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version"
}
},
"dependencies": [
"ChatbotGuardrailsInteg.assets"
],
"metadata": {
"/ChatbotGuardrailsInteg/MySlackChannel/ConfigurationRole/Resource": [
{
"type": "aws:cdk:logicalId",
"data": "MySlackChannelConfigurationRole1D3F23AE"
}
],
"/ChatbotGuardrailsInteg/MySlackChannel/Resource": [
{
"type": "aws:cdk:logicalId",
"data": "MySlackChannelA8E0B56C"
}
],
"/ChatbotGuardrailsInteg/BootstrapVersion": [
{
"type": "aws:cdk:logicalId",
"data": "BootstrapVersion"
}
],
"/ChatbotGuardrailsInteg/CheckBootstrapVersion": [
{
"type": "aws:cdk:logicalId",
"data": "CheckBootstrapVersion"
}
]
},
"displayName": "ChatbotGuardrailsInteg"
},
"Tree": {
"type": "cdk:tree",
"properties": {
"file": "tree.json"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
{
"version": "tree-0.1",
"tree": {
"id": "App",
"path": "",
"children": {
"ChatbotGuardrailsInteg": {
"id": "ChatbotGuardrailsInteg",
"path": "ChatbotGuardrailsInteg",
"children": {
"MyPolicy": {
"id": "MyPolicy",
"path": "ChatbotGuardrailsInteg/MyPolicy",
"constructInfo": {
"fqn": "@aws-cdk/core.Resource",
"version": "0.0.0"
}
},
"MySlackChannel": {
"id": "MySlackChannel",
"path": "ChatbotGuardrailsInteg/MySlackChannel",
"children": {
"ConfigurationRole": {
"id": "ConfigurationRole",
"path": "ChatbotGuardrailsInteg/MySlackChannel/ConfigurationRole",
"children": {
"ImportConfigurationRole": {
"id": "ImportConfigurationRole",
"path": "ChatbotGuardrailsInteg/MySlackChannel/ConfigurationRole/ImportConfigurationRole",
"constructInfo": {
"fqn": "@aws-cdk/core.Resource",
"version": "0.0.0"
}
},
"Resource": {
"id": "Resource",
"path": "ChatbotGuardrailsInteg/MySlackChannel/ConfigurationRole/Resource",
"attributes": {
"aws:cdk:cloudformation:type": "AWS::IAM::Role",
"aws:cdk:cloudformation:props": {
"assumeRolePolicyDocument": {
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "chatbot.amazonaws.com"
}
}
],
"Version": "2012-10-17"
}
}
},
"constructInfo": {
"fqn": "@aws-cdk/aws-iam.CfnRole",
"version": "0.0.0"
}
}
},
"constructInfo": {
"fqn": "@aws-cdk/aws-iam.Role",
"version": "0.0.0"
}
},
"Resource": {
"id": "Resource",
"path": "ChatbotGuardrailsInteg/MySlackChannel/Resource",
"attributes": {
"aws:cdk:cloudformation:type": "AWS::Chatbot::SlackChannelConfiguration",
"aws:cdk:cloudformation:props": {
"configurationName": "test-channel",
"iamRoleArn": {
"Fn::GetAtt": [
"MySlackChannelConfigurationRole1D3F23AE",
"Arn"
]
},
"slackChannelId": "C0187JABUE9",
"slackWorkspaceId": "T49239U4W",
"guardrailPolicies": [
{
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":iam:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":Policy/CloudWatchReadOnlyAccess"
]
]
}
]
}
},
"constructInfo": {
"fqn": "@aws-cdk/aws-chatbot.CfnSlackChannelConfiguration",
"version": "0.0.0"
}
}
},
"constructInfo": {
"fqn": "@aws-cdk/aws-chatbot.SlackChannelConfiguration",
"version": "0.0.0"
}
},
"BootstrapVersion": {
"id": "BootstrapVersion",
"path": "ChatbotGuardrailsInteg/BootstrapVersion",
"constructInfo": {
"fqn": "@aws-cdk/core.CfnParameter",
"version": "0.0.0"
}
},
"CheckBootstrapVersion": {
"id": "CheckBootstrapVersion",
"path": "ChatbotGuardrailsInteg/CheckBootstrapVersion",
"constructInfo": {
"fqn": "@aws-cdk/core.CfnRule",
"version": "0.0.0"
}
}
},
"constructInfo": {
"fqn": "@aws-cdk/core.Stack",
"version": "0.0.0"
}
},
"Tree": {
"id": "Tree",
"path": "Tree",
"constructInfo": {
"fqn": "constructs.Construct",
"version": "10.1.237"
}
}
},
"constructInfo": {
"fqn": "@aws-cdk/core.App",
"version": "0.0.0"
}
}
}
24 changes: 24 additions & 0 deletions packages/@aws-cdk/aws-chatbot/test/integ.chatbot-guardrails.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import * as iam from '@aws-cdk/aws-iam';
import * as cdk from '@aws-cdk/core';
import * as chatbot from '../lib';

class ChatbotGuardrailsInteg extends cdk.Stack {
constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
super(scope, id, props);

const guardrailPolicy = iam.ManagedPolicy.fromAwsManagedPolicyName('CloudWatchReadOnlyAccess');

new chatbot.SlackChannelConfiguration(this, 'MySlackChannel', {
slackChannelConfigurationName: 'test-channel',
slackWorkspaceId: 'T49239U4W', // modify to your slack workspace id
slackChannelId: 'C0187JABUE9', // modify to your slack channel id
guardrailPolicies: [guardrailPolicy],
});
}
}

const app = new cdk.App();

new ChatbotGuardrailsInteg(app, 'ChatbotGuardrailsInteg');

app.synth();
Loading

0 comments on commit 4c72a7d

Please sign in to comment.