This pattern will create an EventBridge Scheduler to start State Manager Association once in AWS Systems Manager every 5 minutes.
package main
import (
"github.com/aws/aws-cdk-go/awscdk/v2"
"github.com/aws/aws-cdk-go/awscdk/v2/awsec2"
"github.com/aws/aws-cdk-go/awscdk/v2/awsiam"
"github.com/aws/aws-cdk-go/awscdk/v2/awsscheduler"
"github.com/aws/aws-cdk-go/awscdk/v2/awsssm"
"github.com/aws/constructs-go/constructs/v10"
"github.com/aws/jsii-runtime-go"
)
type EventbridgeScheduleSsmCdkGoStackProps struct {
awscdk.StackProps
}
func NewEventbridgeScheduleSsmCdkGoStack(scope constructs.Construct, id string, props *EventbridgeScheduleSsmCdkGoStackProps) awscdk.Stack {
var sprops awscdk.StackProps
if props != nil {
sprops = props.StackProps
}
stack := awscdk.NewStack(scope, &id, &sprops)
// Create a VPC for Security Group
vpc := awsec2.NewVpc(stack, jsii.String("TheVPC"), &awsec2.VpcProps{
Cidr: jsii.String("10.10.0.0/24"),
})
securityGroup := awsec2.NewCfnSecurityGroup(stack, jsii.String("TestingSecurityGroup"), &awsec2.CfnSecurityGroupProps{
GroupDescription: jsii.String("Security Group for State Manager Association Demo"),
GroupName: jsii.String("TestingSecurityGroup"),
SecurityGroupEgress: []interface{}{
&awsec2.CfnSecurityGroup_EgressProperty{
IpProtocol: jsii.String("-1"),
CidrIp: jsii.String("0.0.0.0/0"),
},
},
SecurityGroupIngress: []interface{}{
&awsec2.CfnSecurityGroup_IngressProperty{
IpProtocol: jsii.String("TCP"),
CidrIp: jsii.String("0.0.0.0/0"),
FromPort: jsii.Number(22),
ToPort: jsii.Number(22),
},
&awsec2.CfnSecurityGroup_IngressProperty{
IpProtocol: jsii.String("TCP"),
CidrIp: jsii.String("0.0.0.0/0"),
FromPort: jsii.Number(3389),
ToPort: jsii.Number(3389),
},
},
VpcId: vpc.VpcId(),
})
// Create an Automation role
automationRole := awsiam.NewRole(stack, jsii.String("automation-role"), &awsiam.RoleProps{
AssumedBy: awsiam.NewServicePrincipal(jsii.String("ssm.amazonaws.com"), &awsiam.ServicePrincipalOpts{}),
Description: jsii.String("Automation role for revoking the public SSH and RDP access in security group"),
})
// prepare Security Group ARN
securityGroupArn := "arn:aws:ec2:*:" + *(awscdk.Aws_ACCOUNT_ID()) + ":security-group/" + *(securityGroup.AttrGroupId())
// Create IAM Policy for automation role
automationPolicy := awsiam.NewPolicyStatement(&awsiam.PolicyStatementProps{
Actions: &[]*string{jsii.String("ec2:RevokeSecurityGroupIngress")},
Effect: awsiam.Effect_ALLOW,
Resources: &[]*string{jsii.String(securityGroupArn)},
})
// Attach the IAM policy to the automation role
automationRole.AddToPolicy(automationPolicy)
// Prepare State Manager Association parameters
associationParams := map[string][]string{
"AutomationAssumeRole": []string{*(automationRole.RoleArn())},
"GroupId": []string{*(securityGroup.AttrGroupId())},
}
// Create a State Manager Association
association := awsssm.NewCfnAssociation(stack, jsii.String("DemoAssociation"), &awsssm.CfnAssociationProps{
Name: jsii.String("AWS-DisablePublicAccessForSecurityGroup"),
AssociationName: jsii.String("DemoAssociation"),
Parameters: associationParams,
})
// Create a scheduler role
schedulerRole := awsiam.NewRole(stack, jsii.String("scheduler-role"), &awsiam.RoleProps{
AssumedBy: awsiam.NewServicePrincipal(jsii.String("scheduler.amazonaws.com"), &awsiam.ServicePrincipalOpts{}),
Description: jsii.String("Scheduler role for starting association"),
})
// prepare association ARN
associationArn := "arn:aws:ssm:*:" + *(awscdk.Aws_ACCOUNT_ID()) + ":association/" + *(association.AttrAssociationId())
// Create IAM Policy for scheduler role
schedulerEventPolicy := awsiam.NewPolicyStatement(&awsiam.PolicyStatementProps{
Actions: &[]*string{jsii.String("ssm:StartAssociationsOnce")},
Effect: awsiam.Effect_ALLOW,
Resources: &[]*string{jsii.String(associationArn)},
})
// Attach the IAM policy to the scheduler role
schedulerRole.AddToPolicy(schedulerEventPolicy)
// Create an EventBridge Scheduler to start association once every 5 minutes
awsscheduler.NewCfnSchedule(stack, jsii.String("demo-schedule"), &awsscheduler.CfnScheduleProps{
FlexibleTimeWindow: &awsscheduler.CfnSchedule_FlexibleTimeWindowProperty{
Mode: jsii.String("OFF"),
},
ScheduleExpression: jsii.String("rate(5 minute)"),
Target: &awsscheduler.CfnSchedule_TargetProperty{
Arn: jsii.String("arn:aws:scheduler:::aws-sdk:ssm:startAssociationsOnce"),
RoleArn: schedulerRole.RoleArn(),
Input: jsii.String("{\"AssociationIds\": [\"" + *(association.AttrAssociationId()) + "\"]}"),
},
})
return stack
}
func main() {
defer jsii.Close()
app := awscdk.NewApp(nil)
NewEventbridgeScheduleSsmCdkGoStack(app, "EventbridgeScheduleSsmCdkGoStack", &EventbridgeScheduleSsmCdkGoStackProps{
awscdk.StackProps{
Env: env(),
},
})
app.Synth(nil)
}
// env determines the AWS environment (account+region) in which our stack is to
// be deployed. For more information see: https://docs.aws.amazon.com/cdk/latest/guide/environments.html
func env() *awscdk.Environment {
// If unspecified, this stack will be "environment-agnostic".
// Account/Region-dependent features and context lookups will not work, but a
// single synthesized template can be deployed anywhere.
//---------------------------------------------------------------------------
return nil
}
git clone https://github.com/aws-samples/serverless-patterns
cd serverless-patterns/eventbridge-schedule-ssm-cdk-go