cfn-guardian 0.3.4 → 0.6.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/build-gem.yml +25 -0
  3. data/.github/workflows/release-gem.yml +25 -0
  4. data/.github/workflows/release-image.yml +33 -0
  5. data/.rspec +1 -0
  6. data/Gemfile.lock +24 -24
  7. data/README.md +4 -772
  8. data/cfn-guardian.gemspec +1 -3
  9. data/docs/alarm_templates.md +130 -0
  10. data/docs/cli.md +182 -0
  11. data/docs/composite_alarms.md +24 -0
  12. data/docs/custom_checks/azure_file_check.md +28 -0
  13. data/docs/custom_checks/domain_expiry.md +10 -0
  14. data/docs/custom_checks/http.md +59 -0
  15. data/docs/custom_checks/log_group_metric_filters.md +27 -0
  16. data/docs/custom_checks/nrpe.md +29 -0
  17. data/docs/custom_checks/port.md +40 -0
  18. data/docs/custom_checks/sftp.md +73 -0
  19. data/docs/custom_checks/sql.md +44 -0
  20. data/docs/custom_checks/tls.md +25 -0
  21. data/docs/custom_metrics.md +71 -0
  22. data/docs/event_subscriptions.md +67 -0
  23. data/docs/maintenance_mode.md +85 -0
  24. data/docs/notifiers.md +33 -0
  25. data/docs/overview.md +22 -0
  26. data/docs/resources.md +93 -0
  27. data/docs/variables.md +58 -0
  28. data/lib/cfnguardian.rb +76 -62
  29. data/lib/cfnguardian/cloudwatch.rb +43 -32
  30. data/lib/cfnguardian/compile.rb +90 -4
  31. data/lib/cfnguardian/config/defaults.yaml +9 -0
  32. data/lib/cfnguardian/deploy.rb +2 -16
  33. data/lib/cfnguardian/display_formatter.rb +1 -2
  34. data/lib/cfnguardian/error.rb +4 -0
  35. data/lib/cfnguardian/models/alarm.rb +102 -30
  36. data/lib/cfnguardian/models/check.rb +30 -12
  37. data/lib/cfnguardian/models/event.rb +43 -15
  38. data/lib/cfnguardian/models/event_subscription.rb +111 -0
  39. data/lib/cfnguardian/resources/amazonmq_rabbitmq.rb +136 -0
  40. data/lib/cfnguardian/resources/azure_file.rb +20 -0
  41. data/lib/cfnguardian/resources/base.rb +126 -26
  42. data/lib/cfnguardian/resources/batch.rb +14 -0
  43. data/lib/cfnguardian/resources/ec2_instance.rb +11 -0
  44. data/lib/cfnguardian/resources/glue.rb +23 -0
  45. data/lib/cfnguardian/resources/http.rb +1 -0
  46. data/lib/cfnguardian/resources/rds_cluster.rb +14 -0
  47. data/lib/cfnguardian/resources/rds_instance.rb +80 -0
  48. data/lib/cfnguardian/resources/redshift_cluster.rb +2 -2
  49. data/lib/cfnguardian/resources/step_functions.rb +41 -0
  50. data/lib/cfnguardian/stacks/main.rb +9 -8
  51. data/lib/cfnguardian/stacks/resources.rb +35 -6
  52. data/lib/cfnguardian/version.rb +1 -1
  53. metadata +39 -10
@@ -2,7 +2,7 @@ require 'cfnguardian/string'
2
2
 
3
3
  module CfnGuardian
4
4
  module Models
5
- class Check
5
+ class BaseCheck
6
6
 
7
7
  attr_reader :type
8
8
  attr_accessor :group,
@@ -13,7 +13,9 @@ module CfnGuardian
13
13
  :runtime,
14
14
  :environment,
15
15
  :subnets,
16
- :vpc
16
+ :vpc,
17
+ :memory,
18
+ :timeout
17
19
 
18
20
  def initialize(resource)
19
21
  @type = 'Check'
@@ -26,17 +28,19 @@ module CfnGuardian
26
28
  @environment = ''
27
29
  @subnets = nil
28
30
  @vpc = nil
31
+ @memory = 128
32
+ @timeout = 120
29
33
  end
30
34
  end
31
35
 
32
- class HttpCheck < Check
36
+ class HttpCheck < BaseCheck
33
37
  def initialize(resource)
34
38
  super(resource)
35
39
  @group = 'Http'
36
40
  @name = 'HttpCheck'
37
41
  @package = 'http-check'
38
42
  @handler = 'handler.http_check'
39
- @version = '0bc33e51abb1f27729ecb170611bf6b440e71a0e'
43
+ @version = 'f739631de74f1a882163b7e584a8b4710ccbc134'
40
44
  @runtime = 'python3.7'
41
45
  end
42
46
  end
@@ -52,7 +56,7 @@ module CfnGuardian
52
56
  end
53
57
  end
54
58
 
55
- class PortCheck < Check
59
+ class PortCheck < BaseCheck
56
60
  def initialize(resource)
57
61
  super(resource)
58
62
  @group = 'Port'
@@ -75,7 +79,7 @@ module CfnGuardian
75
79
  end
76
80
  end
77
81
 
78
- class NrpeCheck < Check
82
+ class NrpeCheck < BaseCheck
79
83
  def initialize(resource)
80
84
  super(resource)
81
85
  @group = 'Nrpe'
@@ -90,7 +94,7 @@ module CfnGuardian
90
94
  end
91
95
  end
92
96
 
93
- class SslCheck < Check
97
+ class SslCheck < BaseCheck
94
98
  def initialize(resource)
95
99
  super(resource)
96
100
  @group = 'Ssl'
@@ -113,7 +117,7 @@ module CfnGuardian
113
117
  end
114
118
  end
115
119
 
116
- class DomainExpiryCheck < Check
120
+ class DomainExpiryCheck < BaseCheck
117
121
  def initialize(resource)
118
122
  super(resource)
119
123
  @group = 'DomainExpiry'
@@ -125,7 +129,7 @@ module CfnGuardian
125
129
  end
126
130
  end
127
131
 
128
- class SqlCheck < Check
132
+ class SqlCheck < BaseCheck
129
133
  def initialize(resource)
130
134
  super(resource)
131
135
  @group = 'Sql'
@@ -140,7 +144,7 @@ module CfnGuardian
140
144
  end
141
145
  end
142
146
 
143
- class ContainerInstanceCheck < Check
147
+ class ContainerInstanceCheck < BaseCheck
144
148
  def initialize(resource)
145
149
  super(resource)
146
150
  @group = 'ContainerInstance'
@@ -152,7 +156,7 @@ module CfnGuardian
152
156
  end
153
157
  end
154
158
 
155
- class TLSCheck < Check
159
+ class TLSCheck < BaseCheck
156
160
  def initialize(resource)
157
161
  super(resource)
158
162
  @group = 'TLS'
@@ -164,7 +168,7 @@ module CfnGuardian
164
168
  end
165
169
  end
166
170
 
167
- class SFTPCheck < Check
171
+ class SFTPCheck < BaseCheck
168
172
  def initialize(resource)
169
173
  super(resource)
170
174
  @group = 'SFTP'
@@ -187,5 +191,19 @@ module CfnGuardian
187
191
  end
188
192
  end
189
193
 
194
+ class AzureFileCheck < BaseCheck
195
+ def initialize(resource)
196
+ super(resource)
197
+ @group = 'AzureFile'
198
+ @name = 'AzureFileCheck'
199
+ @package = 'azure-file-check'
200
+ @handler = 'handler.file_check'
201
+ @version = 'cc37aa8fe4855570132431611b507274b390f4c1'
202
+ @runtime = 'python3.7'
203
+ @memory = 256
204
+ @timeout = 600
205
+ end
206
+ end
207
+
190
208
  end
191
209
  end
@@ -2,7 +2,7 @@ require 'cfnguardian/string'
2
2
 
3
3
  module CfnGuardian
4
4
  module Models
5
- class Event
5
+ class BaseEvent
6
6
 
7
7
  attr_reader :type
8
8
  attr_accessor :group,
@@ -31,7 +31,7 @@ module CfnGuardian
31
31
  end
32
32
  end
33
33
 
34
- class HttpEvent < Event
34
+ class HttpEvent < BaseEvent
35
35
 
36
36
  attr_accessor :endpoint,
37
37
  :method,
@@ -81,7 +81,7 @@ module CfnGuardian
81
81
  end
82
82
  end
83
83
 
84
- class PortEvent < Event
84
+ class PortEvent < BaseEvent
85
85
  def initialize(resource)
86
86
  super(resource)
87
87
  @group = 'Port'
@@ -112,7 +112,7 @@ module CfnGuardian
112
112
  end
113
113
  end
114
114
 
115
- class NrpeEvent < Event
115
+ class NrpeEvent < BaseEvent
116
116
  def initialize(resource,environment,command)
117
117
  super(resource)
118
118
  @group = 'Nrpe'
@@ -121,6 +121,7 @@ module CfnGuardian
121
121
  @host = resource['Id']
122
122
  @environment = environment
123
123
  @region = resource.fetch('Region',"${AWS::Region}")
124
+ @hash = Digest::MD5.hexdigest "#{resource['Id']}#{command}"
124
125
  @command = command
125
126
  end
126
127
 
@@ -134,13 +135,13 @@ module CfnGuardian
134
135
  end
135
136
  end
136
137
 
137
- class SslEvent < Event
138
+ class SslEvent < BaseEvent
138
139
  def initialize(resource)
139
140
  super(resource)
140
141
  @group = 'Ssl'
141
142
  @name = 'SslEvent'
142
143
  @target = 'SslCheckFunction'
143
- @cron = "0 12 * * ? *"
144
+ @cron = resource.fetch('Schedule', "0 12 * * ? *")
144
145
  @url = resource['Id']
145
146
  @region = resource.fetch('Region',"${AWS::Region}")
146
147
  end
@@ -163,7 +164,7 @@ module CfnGuardian
163
164
  end
164
165
  end
165
166
 
166
- class DomainExpiryEvent < Event
167
+ class DomainExpiryEvent < BaseEvent
167
168
 
168
169
  attr_accessor :domain,
169
170
  :region
@@ -173,7 +174,7 @@ module CfnGuardian
173
174
  @group = 'DomainExpiry'
174
175
  @name = 'DomainExpiryEvent'
175
176
  @target = 'DomainExpiryCheckFunction'
176
- @cron = "0 12 * * ? *"
177
+ @cron = resource.fetch('Schedule', "0 12 * * ? *")
177
178
  @domain = resource['Id']
178
179
  @region = resource.fetch('Region',"${AWS::Region}")
179
180
  end
@@ -183,7 +184,7 @@ module CfnGuardian
183
184
  end
184
185
  end
185
186
 
186
- class SqlEvent < Event
187
+ class SqlEvent < BaseEvent
187
188
  def initialize(resource,query,environment)
188
189
  super(resource)
189
190
  @group = 'Sql'
@@ -221,13 +222,13 @@ module CfnGuardian
221
222
  end
222
223
  end
223
224
 
224
- class ContainerInstanceEvent < Event
225
+ class ContainerInstanceEvent < BaseEvent
225
226
  def initialize(resource)
226
227
  super(resource)
227
228
  @group = 'ContainerInstance'
228
229
  @name = 'ContainerInstanceEvent'
229
230
  @target = 'ContainerInstanceCheckFunction'
230
- @cron = "0/5 * * * ? *"
231
+ @cron = resource.fetch('Schedule', "0/5 * * * ? *")
231
232
  @cluster = resource['Id']
232
233
  end
233
234
 
@@ -236,13 +237,13 @@ module CfnGuardian
236
237
  end
237
238
  end
238
239
 
239
- class SFTPEvent < Event
240
+ class SFTPEvent < BaseEvent
240
241
  def initialize(resource)
241
242
  super(resource)
242
243
  @group = 'SFTP'
243
244
  @name = 'SFTPEvent'
244
245
  @target = 'SFTPCheckFunction'
245
- @cron = "0/5 * * * ? *"
246
+ @cron = resource.fetch('Schedule', "0/5 * * * ? *")
246
247
  @host = resource['Id']
247
248
  @user = resource['User']
248
249
  @port = resource.fetch('Port', nil)
@@ -288,13 +289,13 @@ module CfnGuardian
288
289
  end
289
290
  end
290
291
 
291
- class TLSEvent < Event
292
+ class TLSEvent < BaseEvent
292
293
  def initialize(resource)
293
294
  super(resource)
294
295
  @group = 'TLS'
295
296
  @name = 'TLSEvent'
296
297
  @target = 'TLSCheckFunction'
297
- @cron = "0/5 * * * ? *"
298
+ @cron = resource.fetch('Schedule', "0/5 * * * ? *")
298
299
  @host = resource['Id']
299
300
  @port = resource.fetch('Port', 443)
300
301
  @check_max = resource.fetch('MaxSupported', nil)
@@ -312,5 +313,32 @@ module CfnGuardian
312
313
  end
313
314
  end
314
315
 
316
+ class AzureFileEvent < BaseEvent
317
+ def initialize(resource)
318
+ super(resource)
319
+ @group = 'AzureFile'
320
+ @name = 'AzureFileEvent'
321
+ @target = 'AzureFileCheckFunction'
322
+ @cron = resource.fetch('Schedule', "0/5 * * * ? *")
323
+ @storage_account = resource['Id']
324
+ @container = resource['Container']
325
+ @connection_string = resource['ConnectionString']
326
+ @search = resource['Search']
327
+ end
328
+
329
+ def payload
330
+ return {
331
+ 'STORAGE_ACCOUNT' => @storage_account,
332
+ 'CONTAINER' => @container,
333
+ 'CONNECTION_STRING' => @connection_string,
334
+ 'SEARCH' => @search
335
+ }.to_json
336
+ end
337
+
338
+ def ssm_parameters
339
+ return [@connection_string]
340
+ end
341
+ end
342
+
315
343
  end
316
344
  end
@@ -0,0 +1,111 @@
1
+ module CfnGuardian
2
+ module Models
3
+ class BaseEventSubscription
4
+
5
+ attr_reader :type, :group
6
+ attr_writer :detail
7
+ attr_accessor :name,
8
+ :enabled,
9
+ :hash,
10
+ :topic,
11
+ :resource_id,
12
+ :resource_arn,
13
+ :source,
14
+ :detail_type,
15
+ :detail
16
+
17
+ def initialize(resource)
18
+ @type = 'EventSubscription'
19
+ @group = self.class.name.split('::').last
20
+ @name = ''
21
+ @hash = Digest::MD5.hexdigest resource['Id']
22
+ @enabled = true
23
+ @events = []
24
+ @topic = 'Events'
25
+ @resource_id = resource['Id']
26
+ @resource_arn = ''
27
+ @source = ''
28
+ @detail_type = ''
29
+ @detail = {}
30
+ end
31
+
32
+ def detail
33
+ return @detail
34
+ end
35
+ end
36
+
37
+ class RDSEventSubscription < BaseEventSubscription
38
+ attr_accessor :source_id, :rds_event_category, :message
39
+
40
+ def initialize(resource)
41
+ super(resource)
42
+ @source = 'aws.rds'
43
+ @detail_type = 'RDS DB Instance Event'
44
+ @source_id = ''
45
+ @rds_event_category = ''
46
+ @message = ''
47
+ end
48
+
49
+ def detail
50
+ return {
51
+ EventCategories: [@rds_event_category],
52
+ SourceType: [@source_type],
53
+ SourceIdentifier: ["rds:#{@resource_id}"],
54
+ Message: [@message]
55
+ }
56
+ end
57
+ end
58
+
59
+ class RDSInstanceEventSubscription < RDSEventSubscription
60
+ def initialize(resource)
61
+ super(resource)
62
+ @source_type = 'DB_INSTANCE'
63
+ end
64
+ end
65
+
66
+ class RDSClusterEventSubscription < RDSEventSubscription
67
+ def initialize(resource)
68
+ super(resource)
69
+ @source_type = 'DB_CLUSTER'
70
+ end
71
+ end
72
+
73
+ class Ec2InstanceEventSubscription < BaseEventSubscription
74
+ def initialize(resource)
75
+ super(resource)
76
+ @source = 'aws.ec2'
77
+ end
78
+ end
79
+
80
+ class BatchEventSubscription < BaseEventSubscription
81
+ def initialize(resource)
82
+ super(resource)
83
+ @source = 'aws.batch'
84
+ end
85
+ end
86
+
87
+ class GlueEventSubscription < BaseEventSubscription
88
+ def initialize(resource)
89
+ super(resource)
90
+ @source = 'aws.glue'
91
+ end
92
+ end
93
+
94
+ class ApiGatewayEventSubscription < BaseEventSubscription; end
95
+ class ApplicationTargetGroupEventSubscription < BaseEventSubscription; end
96
+ class AmazonMQBrokerEventSubscription < BaseEventSubscription; end
97
+ class CloudFrontDistributionEventSubscription < BaseEventSubscription; end
98
+ class AutoScalingGroupEventSubscription < BaseEventSubscription; end
99
+ class DynamoDBTableEventSubscription < BaseEventSubscription; end
100
+ class Ec2InstanceEventSubscription < BaseEventSubscription; end
101
+ class ECSClusterEventSubscription < BaseEventSubscription; end
102
+ class ECSServiceEventSubscription < BaseEventSubscription; end
103
+ class ElastiCacheReplicationGroupEventSubscription < BaseEventSubscription; end
104
+ class ElasticLoadBalancerEventSubscription < BaseEventSubscription; end
105
+ class ElasticFileSystemEventSubscription < BaseEventSubscription; end
106
+ class LambdaEventSubscription < BaseEventSubscription; end
107
+ class NetworkTargetGroupEventSubscription < BaseEventSubscription; end
108
+ class RedshiftClusterEventSubscription < BaseEventSubscription; end
109
+ class StepFunctionsSubscription < BaseEventSubscription; end
110
+ end
111
+ end
@@ -0,0 +1,136 @@
1
+ module CfnGuardian::Resource
2
+ class AmazonMQRabbitMQBroker < Base
3
+
4
+ def default_alarms
5
+ alarm = CfnGuardian::Models::AmazonMQRabbitMQBrokerAlarm.new(@resource)
6
+ alarm.name = 'ConnectionCountCritical'
7
+ alarm.metric_name = 'ConnectionCount'
8
+ alarm.comparison_operator = 'GreaterThanThreshold'
9
+ alarm.statistic = 'Maximum'
10
+ alarm.threshold = 50
11
+ alarm.evaluation_periods = 5
12
+ alarm.treat_missing_data = 'notBreaching'
13
+ @alarms.push(alarm)
14
+
15
+ alarm = CfnGuardian::Models::AmazonMQRabbitMQBrokerAlarm.new(@resource)
16
+ alarm.name = 'ConnectionCountWarn'
17
+ alarm.metric_name = 'ConnectionCount'
18
+ alarm.comparison_operator = 'GreaterThanThreshold'
19
+ alarm.statistic = 'Maximum'
20
+ alarm.threshold = 25
21
+ alarm.evaluation_periods = 5
22
+ alarm.treat_missing_data = 'notBreaching'
23
+ alarm.alarm_action = 'Warning'
24
+ @alarms.push(alarm)
25
+
26
+ alarm = CfnGuardian::Models::AmazonMQRabbitMQBrokerAlarm.new(@resource)
27
+ alarm.name = 'MessageCountCritical'
28
+ alarm.metric_name = 'MessageCount'
29
+ alarm.comparison_operator = 'GreaterThanThreshold'
30
+ alarm.statistic = 'Maximum'
31
+ alarm.threshold = 500
32
+ alarm.evaluation_periods = 5
33
+ alarm.treat_missing_data = 'notBreaching'
34
+ @alarms.push(alarm)
35
+
36
+ alarm = CfnGuardian::Models::AmazonMQRabbitMQBrokerAlarm.new(@resource)
37
+ alarm.name = 'MessageCountWarn'
38
+ alarm.metric_name = 'MessageCount'
39
+ alarm.comparison_operator = 'GreaterThanThreshold'
40
+ alarm.statistic = 'Maximum'
41
+ alarm.threshold = 250
42
+ alarm.evaluation_periods = 5
43
+ alarm.treat_missing_data = 'notBreaching'
44
+ alarm.alarm_action = 'Warning'
45
+ @alarms.push(alarm)
46
+
47
+ end
48
+ end
49
+
50
+ class AmazonMQRabbitMQQueue < Base
51
+
52
+ def default_alarms
53
+
54
+ alarm = CfnGuardian::Models::AmazonMQRabbitMQQueueAlarm.new(@resource)
55
+ alarm.name = 'MessageCountHighWarn'
56
+ alarm.metric_name = 'MessageCount'
57
+ alarm.comparison_operator = 'GreaterThanThreshold'
58
+ alarm.statistic = 'Maximum'
59
+ alarm.threshold = 100
60
+ alarm.evaluation_periods = 5
61
+ alarm.treat_missing_data = 'notBreaching'
62
+ alarm.alarm_action = 'Warning'
63
+ @alarms.push(alarm)
64
+
65
+ end
66
+ end
67
+
68
+ class AmazonMQRabbitMQNode < Base
69
+
70
+ def default_alarms
71
+ alarm = CfnGuardian::Models::AmazonMQRabbitMQNodeAlarm.new(@resource)
72
+ alarm.name = 'SystemCpuUtilizationCritical'
73
+ alarm.metric_name = 'SystemCpuUtilization'
74
+ alarm.comparison_operator = 'GreaterThanThreshold'
75
+ alarm.statistic = 'Maximum'
76
+ alarm.threshold = 95
77
+ alarm.evaluation_periods = 10
78
+ alarm.treat_missing_data = 'notBreaching'
79
+ @alarms.push(alarm)
80
+
81
+ alarm = CfnGuardian::Models::AmazonMQRabbitMQNodeAlarm.new(@resource)
82
+ alarm.name = 'SystemCpuUtilizationHighBase'
83
+ alarm.metric_name = 'SystemCpuUtilization'
84
+ alarm.comparison_operator = 'GreaterThanThreshold'
85
+ alarm.statistic = 'Maximum'
86
+ alarm.threshold = 75
87
+ alarm.evaluation_periods = 30
88
+ alarm.treat_missing_data = 'notBreaching'
89
+ alarm.alarm_action = 'Warning'
90
+ @alarms.push(alarm)
91
+
92
+ alarm = CfnGuardian::Models::AmazonMQRabbitMQNodeAlarm.new(@resource)
93
+ alarm.name = 'RabbitMQMemUsedCritical'
94
+ alarm.metric_name = 'RabbitMQMemUsed'
95
+ alarm.comparison_operator = 'GreaterThanThreshold'
96
+ alarm.statistic = 'Maximum'
97
+ alarm.threshold = 390000000
98
+ alarm.evaluation_periods = 5
99
+ alarm.treat_missing_data = 'notBreaching'
100
+ @alarms.push(alarm)
101
+
102
+ alarm = CfnGuardian::Models::AmazonMQRabbitMQNodeAlarm.new(@resource)
103
+ alarm.name = 'RabbitMQMemUsedWarn'
104
+ alarm.metric_name = 'RabbitMQMemUsed'
105
+ alarm.comparison_operator = 'GreaterThanThreshold'
106
+ alarm.statistic = 'Maximum'
107
+ alarm.threshold = 350000000
108
+ alarm.evaluation_periods = 5
109
+ alarm.treat_missing_data = 'notBreaching'
110
+ alarm.alarm_action = 'Warning'
111
+ @alarms.push(alarm)
112
+
113
+ alarm = CfnGuardian::Models::AmazonMQRabbitMQNodeAlarm.new(@resource)
114
+ alarm.name = 'RabbitMQDiskFreeLimitCritical'
115
+ alarm.metric_name = 'RabbitMQDiskFreeLimit'
116
+ alarm.comparison_operator = 'LessThanThreshold'
117
+ alarm.statistic = 'Maximum'
118
+ alarm.threshold = 1200000000
119
+ alarm.evaluation_periods = 5
120
+ alarm.treat_missing_data = 'notBreaching'
121
+ @alarms.push(alarm)
122
+
123
+ alarm = CfnGuardian::Models::AmazonMQRabbitMQNodeAlarm.new(@resource)
124
+ alarm.name = 'RabbitMQDiskFreeLimitWarn'
125
+ alarm.metric_name = 'RabbitMQDiskFreeLimit'
126
+ alarm.comparison_operator = 'LessThanThreshold'
127
+ alarm.statistic = 'Maximum'
128
+ alarm.threshold = 1200000000
129
+ alarm.evaluation_periods = 5
130
+ alarm.treat_missing_data = 'notBreaching'
131
+ alarm.alarm_action = 'Warning'
132
+ @alarms.push(alarm)
133
+
134
+ end
135
+ end
136
+ end