cfn-guardian 0.1.0 → 0.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/.dockerignore +1 -0
  3. data/.github/workflows/build-gem.yml +25 -0
  4. data/.github/workflows/release-gem.yml +25 -0
  5. data/.github/workflows/release-image.yml +33 -0
  6. data/.rspec +1 -0
  7. data/Dockerfile +19 -0
  8. data/Gemfile.lock +39 -21
  9. data/README.md +9 -378
  10. data/cfn-guardian.gemspec +7 -5
  11. data/docs/alarm_templates.md +130 -0
  12. data/docs/cli.md +182 -0
  13. data/docs/composite_alarms.md +24 -0
  14. data/docs/custom_checks/azure_file_check.md +28 -0
  15. data/docs/custom_checks/domain_expiry.md +10 -0
  16. data/docs/custom_checks/http.md +59 -0
  17. data/docs/custom_checks/log_group_metric_filters.md +27 -0
  18. data/docs/custom_checks/nrpe.md +29 -0
  19. data/docs/custom_checks/port.md +40 -0
  20. data/docs/custom_checks/sftp.md +73 -0
  21. data/docs/custom_checks/sql.md +44 -0
  22. data/docs/custom_checks/tls.md +25 -0
  23. data/docs/custom_metrics.md +71 -0
  24. data/docs/event_subscriptions.md +67 -0
  25. data/docs/maintenance_mode.md +85 -0
  26. data/docs/notifiers.md +33 -0
  27. data/docs/overview.md +22 -0
  28. data/docs/resources.md +93 -0
  29. data/docs/variables.md +58 -0
  30. data/lib/cfnguardian.rb +325 -37
  31. data/lib/cfnguardian/cloudwatch.rb +132 -0
  32. data/lib/cfnguardian/codecommit.rb +54 -0
  33. data/lib/cfnguardian/codepipeline.rb +138 -0
  34. data/lib/cfnguardian/compile.rb +142 -18
  35. data/lib/cfnguardian/config/defaults.yaml +103 -0
  36. data/lib/cfnguardian/deploy.rb +2 -16
  37. data/lib/cfnguardian/display_formatter.rb +163 -0
  38. data/lib/cfnguardian/drift.rb +79 -0
  39. data/lib/cfnguardian/error.rb +4 -0
  40. data/lib/cfnguardian/log.rb +0 -1
  41. data/lib/cfnguardian/models/alarm.rb +193 -59
  42. data/lib/cfnguardian/models/check.rb +128 -33
  43. data/lib/cfnguardian/models/composite.rb +21 -0
  44. data/lib/cfnguardian/models/event.rb +201 -49
  45. data/lib/cfnguardian/models/event_subscription.rb +96 -0
  46. data/lib/cfnguardian/models/metric_filter.rb +28 -0
  47. data/lib/cfnguardian/resources/amazonmq_rabbitmq.rb +136 -0
  48. data/lib/cfnguardian/resources/application_targetgroup.rb +2 -0
  49. data/lib/cfnguardian/resources/azure_file.rb +20 -0
  50. data/lib/cfnguardian/resources/base.rb +155 -33
  51. data/lib/cfnguardian/resources/ec2_instance.rb +11 -0
  52. data/lib/cfnguardian/resources/ecs_service.rb +2 -2
  53. data/lib/cfnguardian/resources/http.rb +17 -1
  54. data/lib/cfnguardian/resources/internal_http.rb +74 -0
  55. data/lib/cfnguardian/resources/internal_port.rb +33 -0
  56. data/lib/cfnguardian/resources/internal_sftp.rb +58 -0
  57. data/lib/cfnguardian/resources/log_group.rb +26 -0
  58. data/lib/cfnguardian/resources/network_targetgroup.rb +1 -0
  59. data/lib/cfnguardian/resources/port.rb +25 -0
  60. data/lib/cfnguardian/resources/rds_cluster.rb +14 -0
  61. data/lib/cfnguardian/resources/rds_instance.rb +73 -0
  62. data/lib/cfnguardian/resources/redshift_cluster.rb +2 -2
  63. data/lib/cfnguardian/resources/sftp.rb +50 -0
  64. data/lib/cfnguardian/resources/sql.rb +3 -3
  65. data/lib/cfnguardian/resources/tls.rb +66 -0
  66. data/lib/cfnguardian/s3.rb +3 -2
  67. data/lib/cfnguardian/stacks/main.rb +94 -72
  68. data/lib/cfnguardian/stacks/resources.rb +111 -43
  69. data/lib/cfnguardian/string.rb +12 -0
  70. data/lib/cfnguardian/version.rb +1 -1
  71. metadata +133 -10
@@ -4,8 +4,8 @@ require 'cfnguardian/string'
4
4
  module CfnGuardian::Resource
5
5
  class Sql < Base
6
6
 
7
- def initialize(resource)
8
- super(resource)
7
+ def initialize(resource, override_group = nil)
8
+ super(resource, override_group)
9
9
  @resource_list = resource['Hosts']
10
10
  @environment = resource['Environment']
11
11
  end
@@ -24,7 +24,7 @@ module CfnGuardian::Resource
24
24
  def default_events()
25
25
  @resource_list.each do |host|
26
26
  host['Queries'].each do |query|
27
- @events.push(CfnGuardian::Models::SqlEvent.new(host,query['Query']))
27
+ @events.push(CfnGuardian::Models::SqlEvent.new(host,query['Query'],@environment))
28
28
  end
29
29
  end
30
30
  end
@@ -0,0 +1,66 @@
1
+ module CfnGuardian::Resource
2
+ class TLS < Base
3
+
4
+ def default_alarms
5
+
6
+ versions = @resource.fetch('Versions',['SSLv2','SSLv3','TLSv1','TLSv1.1','TLSv1.2'])
7
+
8
+ if versions.include? "SSLv2"
9
+ alarm = CfnGuardian::Models::TLSAlarm.new(@resource)
10
+ alarm.name = "TLSVersionSSLv2"
11
+ alarm.metric_name = "SSLv2"
12
+ alarm.comparison_operator = 'GreaterThanThreshold'
13
+ alarm.threshold = 0
14
+ @alarms.push(alarm)
15
+ end
16
+
17
+ if versions.include? "SSLv3"
18
+ alarm = CfnGuardian::Models::TLSAlarm.new(@resource)
19
+ alarm.name = "TLSVersionSSLv3"
20
+ alarm.metric_name = "SSLv3"
21
+ alarm.comparison_operator = 'GreaterThanThreshold'
22
+ alarm.threshold = 0
23
+ @alarms.push(alarm)
24
+ end
25
+
26
+ if versions.include? "SSLv3"
27
+ alarm = CfnGuardian::Models::TLSAlarm.new(@resource)
28
+ alarm.name = "TLSVersionTLSv1"
29
+ alarm.metric_name = "TLSv1"
30
+ @alarms.push(alarm)
31
+ end
32
+
33
+ if versions.include? "SSLv3"
34
+ alarm = CfnGuardian::Models::TLSAlarm.new(@resource)
35
+ alarm.name = "TLSVersionTLSv1.1"
36
+ alarm.metric_name = "TLSv1.1"
37
+ @alarms.push(alarm)
38
+ end
39
+
40
+ if versions.include? "SSLv3"
41
+ alarm = CfnGuardian::Models::TLSAlarm.new(@resource)
42
+ alarm.name = "TLSVersionTLSv1.2"
43
+ alarm.metric_name = "TLSv1.2"
44
+ @alarms.push(alarm)
45
+ end
46
+
47
+ if @resource.has_key?('CheckMax')
48
+ alarm = CfnGuardian::Models::TLSAlarm.new(@resource)
49
+ alarm.name = "TLSVersionMax"
50
+ alarm.metric_name = 'MaxVersion'
51
+ alarm.threshold = 3
52
+ alarm.evaluation_periods = 2
53
+ @alarms.push(alarm)
54
+ end
55
+ end
56
+
57
+ def default_events
58
+ @events.push(CfnGuardian::Models::TLSEvent.new(@resource))
59
+ end
60
+
61
+ def default_checks
62
+ @checks.push(CfnGuardian::Models::TLSCheck.new(@resource))
63
+ end
64
+
65
+ end
66
+ end
@@ -4,10 +4,11 @@ module CfnGuardian
4
4
  class S3
5
5
  include Logging
6
6
 
7
- attr_reader :bucket
7
+ attr_reader :bucket, :path
8
8
 
9
- def initialize(bucket)
9
+ def initialize(bucket,path='')
10
10
  @bucket = set_bucket_name(bucket)
11
+ @path = path
11
12
  end
12
13
 
13
14
  def set_bucket_name(bucket)
@@ -5,31 +5,87 @@ module CfnGuardian
5
5
  class Main
6
6
  include CfnDsl::CloudFormation
7
7
 
8
- def build_template(stacks,checks)
8
+ attr_reader :parameters, :template
9
+
10
+ def initialize()
11
+ @parameters = []
9
12
  @template = CloudFormation("Guardian main stack")
10
-
11
- %w(Critical Warning Task Informational).each do |name|
13
+ end
14
+
15
+ def build_template(stacks,checks,topics,maintenance_groups,ssm_parameters)
16
+ parameters = {}
17
+
18
+ topics.each do |name, sns|
12
19
  parameter = @template.Parameter(name)
13
20
  parameter.Type 'String'
14
21
  parameter.Description "SNS topic ARN for #{name} notifications"
22
+ parameter.Default sns
23
+ parameters[name] = Ref(name)
15
24
  end
16
25
 
17
- parameters = {
18
- Critical: Ref(:Critical),
19
- Warning: Ref(:Warning),
20
- Task: Ref(:Task),
21
- Informational: Ref(:Informational)
22
- }
23
-
24
- build_iam_role()
26
+ maintenance_groups.each do |group|
27
+ topic = @template.SNS_Topic(group)
28
+ topic.TopicName group
29
+ topic.Tags([{ Key: 'Environment', Value: 'guardian' }])
30
+ parameters[group] = Ref(group)
31
+ end
25
32
 
26
- checks.each {|check| parameters["#{check[:name]}Function#{check[:environment]}"] = add_lambda(check)}
27
- stacks.each {|stack| add_stack(stack['Name'],stack['TemplateURL'],parameters)}
33
+ add_iam_role(ssm_parameters)
34
+
35
+ checks.each {|check| parameters["#{check.name}Function#{check.environment}"] = add_lambda(check)}
36
+ stacks.each {|stack| add_stack(stack['Name'],stack['TemplateURL'],parameters,stack['Reference'])}
28
37
 
29
- return @template
38
+ @parameters = parameters.keys
30
39
  end
31
40
 
32
- def build_iam_role()
41
+ def add_iam_role(ssm_parameters)
42
+ policies = []
43
+ policies << {
44
+ PolicyName: 'logging',
45
+ PolicyDocument: {
46
+ Version: '2012-10-17',
47
+ Statement: [{
48
+ Effect: 'Allow',
49
+ Action: [ 'logs:CreateLogGroup', 'logs:CreateLogStream', 'logs:PutLogEvents' ],
50
+ Resource: 'arn:aws:logs:*:*:*'
51
+ }]
52
+ }
53
+ }
54
+ policies << {
55
+ PolicyName: 'metrics',
56
+ PolicyDocument: {
57
+ Version: '2012-10-17',
58
+ Statement: [{
59
+ Effect: 'Allow',
60
+ Action: [ 'cloudwatch:PutMetricData' ],
61
+ Resource: '*'
62
+ }]
63
+ }
64
+ }
65
+ policies << {
66
+ PolicyName: 'attach-network-interface',
67
+ PolicyDocument: {
68
+ Version: '2012-10-17',
69
+ Statement: [{
70
+ Effect: 'Allow',
71
+ Action: [ 'ec2:CreateNetworkInterface', 'ec2:DescribeNetworkInterfaces', 'ec2:DeleteNetworkInterface' ],
72
+ Resource: '*'
73
+ }]
74
+ }
75
+ }
76
+ if ssm_parameters.any?
77
+ policies << {
78
+ PolicyName: 'ssm-parameters',
79
+ PolicyDocument: {
80
+ Version: '2012-10-17',
81
+ Statement: [{
82
+ Effect: 'Allow',
83
+ Action: [ 'ssm:GetParameter', 'ssm:GetParametersByPath', 'ssm:GetParameters' ],
84
+ Resource: ssm_parameters.map {|param| FnSub("arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter#{param}") }
85
+ }]
86
+ }
87
+ }
88
+ end
33
89
  @template.declare do
34
90
  IAM_Role(:LambdaExecutionRole) do
35
91
  AssumeRolePolicyDocument({
@@ -40,42 +96,8 @@ module CfnGuardian
40
96
  Action: [ 'sts:AssumeRole' ]
41
97
  }]
42
98
  })
43
- Path '/'
44
- Policies([
45
- {
46
- PolicyName: 'logging',
47
- PolicyDocument: {
48
- Version: '2012-10-17',
49
- Statement: [{
50
- Effect: 'Allow',
51
- Action: [ 'logs:CreateLogGroup', 'logs:CreateLogStream', 'logs:PutLogEvents' ],
52
- Resource: 'arn:aws:logs:*:*:*'
53
- }]
54
- }
55
- },
56
- {
57
- PolicyName: 'metrics',
58
- PolicyDocument: {
59
- Version: '2012-10-17',
60
- Statement: [{
61
- Effect: 'Allow',
62
- Action: [ 'cloudwatch:PutMetricData' ],
63
- Resource: '*'
64
- }]
65
- }
66
- },
67
- {
68
- PolicyName: 'attach-network-interface',
69
- PolicyDocument: {
70
- Version: '2012-10-17',
71
- Statement: [{
72
- Effect: 'Allow',
73
- Action: [ 'ec2:CreateNetworkInterface', 'ec2:DescribeNetworkInterfaces', 'ec2:DeleteNetworkInterface' ],
74
- Resource: '*'
75
- }]
76
- }
77
- }
78
- ])
99
+ Path '/guardian/'
100
+ Policies(policies)
79
101
  Tags([
80
102
  { Key: 'Name', Value: 'guardian-lambda-role' },
81
103
  { Key: 'Environment', Value: 'guardian' }
@@ -86,59 +108,59 @@ module CfnGuardian
86
108
 
87
109
  def add_lambda(check)
88
110
  vpc_config = {}
89
-
90
- if check.has_key?(:vpc)
111
+ if !check.vpc.nil?
91
112
  @template.declare do
92
- EC2_SecurityGroup("#{check[:name]}SecurityGroup#{check[:environment]}") do
93
- VpcId check[:vpc]
94
- GroupDescription "Guardian lambda function #{check[:class]} check"
113
+ EC2_SecurityGroup("#{check.name}SecurityGroup#{check.environment}") do
114
+ VpcId check.vpc
115
+ GroupDescription "Guardian lambda function #{check.group} check"
95
116
  Tags([
96
- { Key: 'Name', Value: "guardian-#{check[:name]}-#{check[:environment]}" },
117
+ { Key: 'Name', Value: "guardian-#{check.name}-#{check.environment}" },
97
118
  { Key: 'Environment', Value: 'guardian' }
98
119
  ])
99
120
  end
100
121
  end
101
122
 
102
- vpc_config[:SecurityGroupIds] = Ref("#{check[:name]}SecurityGroup#{check[:environment]}")
103
- vpc_config[:SubnetIds] = check[:subnets]
123
+ vpc_config[:SecurityGroupIds] = [Ref("#{check.name}SecurityGroup#{check.environment}")]
124
+ vpc_config[:SubnetIds] = check.subnets
104
125
  end
105
126
 
106
127
  @template.declare do
107
- Lambda_Function("#{check[:name]}Function#{check[:environment]}") do
128
+ Lambda_Function("#{check.name}Function#{check.environment}") do
108
129
  Code({
109
- S3Bucket: FnSub("base2.lambda.${AWS::Region}"),
110
- S3Key: "#{check[:package]}/#{check[:version]}/handler.zip"
130
+ S3Bucket: FnSub("base2.guardian.lambda.checks.${AWS::Region}"),
131
+ S3Key: "#{check.package}/master/#{check.version}.zip"
111
132
  })
112
- Handler check[:handler]
113
- MemorySize 128
114
- Runtime check[:runtime]
115
- Timeout 120
133
+ Handler check.handler
134
+ MemorySize check.memory
135
+ Runtime check.runtime
136
+ Timeout check.timeout
116
137
  Role FnGetAtt(:LambdaExecutionRole, :Arn)
117
138
  VpcConfig vpc_config unless vpc_config.empty?
118
139
  Tags([
119
- { Key: 'Name', Value: "guardian-#{check[:name]}-#{check[:class]}" },
140
+ { Key: 'Name', Value: "guardian-#{check.name}-#{check.group}" },
120
141
  { Key: 'Environment', Value: 'guardian' }
121
142
  ])
122
143
  end
123
144
 
124
- Lambda_Permission("#{check[:name]}Permissions#{check[:environment]}") do
125
- FunctionName Ref("#{check[:name]}Function#{check[:environment]}")
145
+ Lambda_Permission("#{check.name}Permissions#{check.environment}") do
146
+ FunctionName Ref("#{check.name}Function#{check.environment}")
126
147
  Action 'lambda:InvokeFunction'
127
148
  Principal 'events.amazonaws.com'
128
149
  end
129
150
  end
130
151
 
131
- return FnGetAtt("#{check[:name]}Function#{check[:environment]}", :Arn)
152
+ return FnGetAtt("#{check.name}Function#{check.environment}", :Arn)
132
153
  end
133
154
 
134
- def add_stack(name,url,stack_parameters)
155
+ def add_stack(name,url,stack_parameters,stack_id)
135
156
  @template.declare do
136
157
  CloudFormation_Stack(name) do
137
158
  Parameters stack_parameters
138
159
  TemplateURL url
139
160
  TimeoutInMinutes 15
140
161
  Tags([
141
- { Key: 'Name', Value: "guardian-stack-#{name}" }
162
+ { Key: 'Name', Value: "guardian-stack-#{name}" },
163
+ { Key: 'guardian:stack-id', Value: "stk#{stack_id}"}
142
164
  ])
143
165
  end
144
166
  end
@@ -1,80 +1,148 @@
1
1
  require 'cfndsl'
2
+ require 'digest/md5'
3
+ require 'cfnguardian/cloudwatch'
2
4
 
3
5
  module CfnGuardian
4
6
  module Stacks
5
7
  class Resources
6
8
  include CfnDsl::CloudFormation
7
9
 
8
- def build_template(resources)
9
- @template = CloudFormation("Guardian nested stack")
10
-
11
- %w(Critical Warning Task Informational).each do |name|
10
+ attr_reader :template
11
+
12
+ def initialize(parameters,stack_id)
13
+ @stack_id = stack_id
14
+
15
+ @template = CloudFormation("Guardian nested - stack-id:stk#{@stack_id}")
16
+ parameters.each do |name|
12
17
  parameter = @template.Parameter(name)
13
18
  parameter.Type 'String'
14
- parameter.Description "SNS topic ARN for #{name} notifications"
15
19
  end
16
-
20
+ end
21
+
22
+ def build_template(resources)
17
23
  resources.each do |resource|
18
- case resource[:type]
24
+ case resource.type
19
25
  when 'Alarm'
20
26
  add_alarm(resource)
21
27
  when 'Event'
22
28
  add_event(resource)
29
+ when 'Composite'
30
+ add_composite_alarm(resource)
31
+ when 'MetricFilter'
32
+ add_metric_filter(resource)
33
+ when 'EventSubscription'
34
+ add_event_subscription(resource)
23
35
  else
24
- puts "Warn: #{resource[:type]} is a unsuported resource type"
36
+ puts "Warn: #{resource.type} is a unsuported resource type"
25
37
  end
26
38
  end
27
-
28
- return @template
29
39
  end
30
-
31
- def add_alarm(resource)
40
+
41
+ def add_alarm(alarm)
42
+ actions = alarm.alarm_action.kind_of?(Array) ? alarm.alarm_action.map{|action| Ref(action)} : [Ref(alarm.alarm_action)]
43
+ actions.concat alarm.maintenance_groups.map {|mg| Ref(mg)} if alarm.maintenance_groups.any?
44
+ stack_id = @stack_id
45
+
32
46
  @template.declare do
33
- CloudWatch_Alarm("#{resource[:resource_name]}#{resource[:class]}#{resource[:name]}#{resource[:type]}"[0..255]) do
47
+ CloudWatch_Alarm("#{alarm.resource_hash}#{alarm.group}#{alarm.name.gsub(/[^0-9a-zA-Z]/i, '')}#{alarm.type}"[0..255]) do
34
48
  ActionsEnabled true
35
- AlarmDescription "Guardian alarm #{resource[:class]} #{resource[:resource]} #{resource[:name]}"
36
- AlarmName "#{resource[:class]}-#{resource[:resource]}-#{resource[:name]}"
37
- ComparisonOperator resource[:comparison_operator]
38
- Dimensions resource[:dimensions].map {|k,v| {Name: k, Value: v}}
39
- EvaluationPeriods resource[:evaluation_periods]
40
- Statistic resource[:statistic]
41
- Period resource[:period]
42
- Threshold resource[:threshold]
43
- MetricName resource[:metric_name]
44
- Namespace resource[:namespace]
45
- AlarmActions [Ref(resource[:alarm_action])]
46
- OKActions [Ref(resource[:alarm_action])]
47
- TreatMissingData resource[:treat_missing_data] unless resource[:treat_missing_data].nil?
48
- DatapointsToAlarm resource[:datapoints_to_alarm] unless resource[:datapoints_to_alarm].nil?
49
- ExtendedStatistic resource[:extended_statistic] unless resource[:extended_statistic].nil?
50
- EvaluateLowSampleCountPercentile resource[:evaluate_low_sample_count_percentile] unless resource[:evaluate_low_sample_count_percentile].nil?
51
- Unit resource[:unit] unless resource[:unit].nil?
49
+ AlarmDescription "Guardian alarm #{alarm.name} for the resource #{alarm.resource_id} in alarm group #{alarm.group}"
50
+ AlarmName CfnGuardian::CloudWatch.get_alarm_name(alarm) + "-stk#{stack_id}"
51
+ ComparisonOperator alarm.comparison_operator
52
+ Dimensions alarm.dimensions.map {|k,v| {Name: k, Value: v}} unless alarm.dimensions.nil?
53
+ EvaluationPeriods alarm.evaluation_periods
54
+ Statistic alarm.statistic if alarm.extended_statistic.nil?
55
+ Period alarm.period
56
+ Threshold alarm.threshold
57
+ MetricName alarm.metric_name
58
+ Namespace alarm.namespace
59
+ AlarmActions actions
60
+ OKActions actions
61
+ TreatMissingData alarm.treat_missing_data unless alarm.treat_missing_data.nil?
62
+ DatapointsToAlarm alarm.datapoints_to_alarm unless alarm.datapoints_to_alarm.nil?
63
+ ExtendedStatistic alarm.extended_statistic unless alarm.extended_statistic.nil?
64
+ EvaluateLowSampleCountPercentile alarm.evaluate_low_sample_count_percentile unless alarm.evaluate_low_sample_count_percentile.nil?
65
+ Unit alarm.unit unless alarm.unit.nil?
52
66
  end
53
67
  end
54
68
  end
55
69
 
56
- def add_event(resource)
57
- @template.declare do
58
- Parameter(resource[:target]) do
59
- Type 'String'
60
- Description "Lamba funtion Arn for #{resource[:class]} #{resource[:type]}"
61
- end
62
-
63
- Events_Rule("#{resource[:class]}#{resource[:type]}#{resource[:hash]}"[0..255]) do
70
+ def add_event(event)
71
+ @template.declare do
72
+ Events_Rule("#{event.group}#{event.type}#{event.hash}"[0..255]) do
64
73
  State 'ENABLED'
65
- Description "Guardian scheduled #{resource[:class]} #{resource[:type]}"
66
- ScheduleExpression "cron(#{resource[:cron]})"
74
+ Description "Guardian scheduled #{event.group} #{event.type}"
75
+ ScheduleExpression "cron(#{event.cron})"
67
76
  Targets([
68
77
  {
69
- Arn: Ref(resource[:target]),
70
- Id: resource[:hash],
71
- Input: FnSub(resource[:payload])
78
+ Arn: Ref(event.target),
79
+ Id: event.hash,
80
+ Input: FnSub(event.payload)
72
81
  }
73
82
  ])
74
83
  end
75
84
  end
76
85
  end
77
86
 
87
+ def add_composite_alarm(alarm)
88
+ stack_id = @stack_id
89
+
90
+ @template.declare do
91
+ CloudWatch_CompositeAlarm(alarm.name.gsub(/[^0-9a-zA-Z]/i, '')) do
92
+
93
+ AlarmDescription alarm.description
94
+ AlarmName "guardian-#{alarm.name}-stk#{stack_id}"
95
+ AlarmRule alarm.rule
96
+
97
+ unless alarm.alarm_action.nil?
98
+ ActionsEnabled true
99
+ AlarmActions [Ref(alarm.alarm_action)]
100
+ # InsufficientDataActions [Ref(alarm.alarm_action)]
101
+ # OKActions [Ref(alarm.alarm_action)]
102
+ end
103
+
104
+ end
105
+ end
106
+ end
107
+
108
+ def add_metric_filter(filter)
109
+ @template.declare do
110
+ Logs_MetricFilter("#{filter.name.gsub(/[^0-9a-zA-Z]/i, '')}#{filter.type}") do
111
+ LogGroupName filter.log_group
112
+ FilterPattern filter.pattern
113
+ MetricTransformations([
114
+ {
115
+ MetricValue: filter.metric_value,
116
+ MetricName: filter.metric_name,
117
+ MetricNamespace: filter.metric_namespace
118
+ }
119
+ ])
120
+ end
121
+ end
122
+ end
123
+
124
+ def add_event_subscription(subscription)
125
+ event_pattern = {}
126
+ event_pattern['detail-type'] = [subscription.detail_type]
127
+ event_pattern['source'] = [subscription.source]
128
+ event_pattern['resources'] = [subscription.resource_arn] unless subscription.resource_arn.empty?
129
+ event_pattern['detail'] = subscription.detail unless subscription.detail.empty?
130
+
131
+ @template.declare do
132
+ Events_Rule("#{subscription.group}#{subscription.name}#{subscription.hash}"[0..255]) do
133
+ State subscription.enabled ? 'ENABLED' : 'DISABLED'
134
+ Description "Guardian event subscription #{subscription.group} #{subscription.name} for resource #{subscription.resource_id}"
135
+ EventPattern event_pattern
136
+ Targets [
137
+ {
138
+ Arn: Ref(subscription.topic),
139
+ Id: "#{subscription.topic}Notifier"
140
+ }
141
+ ]
142
+ end
143
+ end
144
+ end
145
+
78
146
  end
79
147
  end
80
148
  end