cloudwatch_metrics_and_alarms.tf 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. ########################
  2. # TO BE DISABLED
  3. #
  4. # These alerts have been recreated in Splunk, where they return far more useful information.
  5. # These alerts only say, "Something happened" and don't explain what/where/how, so they're
  6. # mostly useless.
  7. #
  8. # I plan to disable them completely once I gain confidence in the splunk alerts
  9. locals {
  10. alarm_namespace = "cis"
  11. }
  12. # Notification via Splunk Alert: "CIS 3.1 - Unauthorized API Calls"
  13. resource "aws_cloudwatch_log_metric_filter" "unauthorized_api_calls" {
  14. name = "UnauthorizedAPICalls"
  15. pattern = "{ ($.errorCode = \"*UnauthorizedOperation\") || ($.errorCode = \"AccessDenied*\") }"
  16. log_group_name = var.log_group_name
  17. metric_transformation {
  18. name = "UnauthorizedAPICalls"
  19. namespace = local.alarm_namespace
  20. value = "1"
  21. default_value = 0
  22. }
  23. depends_on = [module.cloudtrail-logging]
  24. }
  25. resource "aws_cloudwatch_metric_alarm" "unauthorized_api_calls" {
  26. alarm_name = "UnauthorizedAPICalls"
  27. comparison_operator = "GreaterThanOrEqualToThreshold"
  28. evaluation_periods = "1"
  29. metric_name = aws_cloudwatch_log_metric_filter.unauthorized_api_calls.id
  30. namespace = local.alarm_namespace
  31. period = "300"
  32. statistic = "Sum"
  33. threshold = "50"
  34. alarm_description = "Monitoring unauthorized API calls will help reveal application errors and may reduce time to detect malicious activity."
  35. alarm_actions = ["arn:${var.aws_partition}:sns:${var.aws_region}:${local.c2_account}:account-alerts"]
  36. insufficient_data_actions = []
  37. depends_on = [module.cloudtrail-logging]
  38. }
  39. # This doesn't match the CIS exactly, because we do our MFA through okta instead of through AWS, so MFA is false for our
  40. # logins. Instead, we make sure they come in via okta and to the correct account.
  41. #
  42. # Okta handles our MFA, so MFA is always set to false for our logins. Lets just make sure they use the correct account(s).
  43. #
  44. # Notification via Splunk Alert: "CIS 3.2 - Management Console sign-in without MFA"
  45. resource "aws_cloudwatch_log_metric_filter" "no_mfa_console_signin" {
  46. name = "NoMFAConsoleSignin"
  47. pattern = "{ ($.eventName = \"ConsoleLogin\") && ($.additionalEventData.MFAUsed != \"Yes\") && ( ($.additionalEventData.SamlProviderArn NOT EXISTS) || (($.additionalEventData.SamlProviderArn != \"arn:aws-us-gov:iam::701290387780:saml-provider/OKTA\") && ($.additionalEventData.SamlProviderArn != \"arn:aws:iam::471284459109:saml-provider/OKTA\"))) }"
  48. log_group_name = var.log_group_name
  49. metric_transformation {
  50. name = "NoMFAConsoleSignin"
  51. namespace = local.alarm_namespace
  52. value = "1"
  53. default_value = 0
  54. }
  55. depends_on = [module.cloudtrail-logging]
  56. }
  57. resource "aws_cloudwatch_metric_alarm" "no_mfa_console_signin" {
  58. alarm_name = "NoMFAConsoleSignin"
  59. comparison_operator = "GreaterThanOrEqualToThreshold"
  60. evaluation_periods = "1"
  61. metric_name = aws_cloudwatch_log_metric_filter.no_mfa_console_signin.id
  62. namespace = local.alarm_namespace
  63. period = "300"
  64. statistic = "Sum"
  65. threshold = "1"
  66. alarm_description = "Monitoring for single-factor console logins will increase visibility into accounts that are not protected by MFA."
  67. alarm_actions = ["arn:${var.aws_partition}:sns:${var.aws_region}:${local.c2_account}:account-alerts"]
  68. insufficient_data_actions = []
  69. }
  70. # Notification via Splunk Alert: "CIS 3.3 - Root Account Usage"
  71. resource "aws_cloudwatch_log_metric_filter" "root_usage" {
  72. name = "RootUsage"
  73. pattern = "{ $.userIdentity.type = \"Root\" && $.userIdentity.invokedBy NOT EXISTS && $.eventType != \"AwsServiceEvent\" }"
  74. log_group_name = var.log_group_name
  75. metric_transformation {
  76. name = "RootUsage"
  77. namespace = local.alarm_namespace
  78. value = "1"
  79. default_value = 0
  80. }
  81. depends_on = [module.cloudtrail-logging]
  82. }
  83. resource "aws_cloudwatch_metric_alarm" "root_usage" {
  84. alarm_name = "RootUsage"
  85. comparison_operator = "GreaterThanOrEqualToThreshold"
  86. evaluation_periods = "1"
  87. metric_name = aws_cloudwatch_log_metric_filter.root_usage.id
  88. namespace = local.alarm_namespace
  89. period = "300"
  90. statistic = "Sum"
  91. threshold = "1"
  92. alarm_description = "Monitoring for root account logins will provide visibility into the use of a fully privileged account and an opportunity to reduce the use of it."
  93. alarm_actions = ["arn:${var.aws_partition}:sns:${var.aws_region}:${local.c2_account}:account-alerts"]
  94. insufficient_data_actions = []
  95. }
  96. # Notification via Splunk Alert: "CIS 3.4 - IAM policy changes"
  97. resource "aws_cloudwatch_log_metric_filter" "iam_changes" {
  98. name = "IAMChanges"
  99. pattern = "{($.eventName=DeleteGroupPolicy)||($.eventName=DeleteRolePolicy)||($.eventName=DeleteUserPolicy)||($.eventName=PutGroupPolicy)||($.eventName=PutRolePolicy)||($.eventName=PutUserPolicy)||($.eventName=CreatePolicy)||($.eventName=DeletePolicy)||($.eventName=CreatePolicyVersion)||($.eventName=DeletePolicyVersion)||($.eventName=AttachRolePolicy)||($.eventName=DetachRolePolicy)||($.eventName=AttachUserPolicy)||($.eventName=DetachUserPolicy)||($.eventName=AttachGroupPolicy)||($.eventName=DetachGroupPolicy)}"
  100. log_group_name = var.log_group_name
  101. metric_transformation {
  102. name = "IAMChanges"
  103. namespace = local.alarm_namespace
  104. value = "1"
  105. default_value = 0
  106. }
  107. depends_on = [module.cloudtrail-logging]
  108. }
  109. resource "aws_cloudwatch_metric_alarm" "iam_changes" {
  110. alarm_name = "IAMChanges"
  111. comparison_operator = "GreaterThanOrEqualToThreshold"
  112. evaluation_periods = "1"
  113. metric_name = aws_cloudwatch_log_metric_filter.iam_changes.id
  114. namespace = local.alarm_namespace
  115. period = "300"
  116. statistic = "Sum"
  117. threshold = "1"
  118. alarm_description = "Monitoring changes to IAM policies will help ensure authentication and authorization controls remain intact."
  119. alarm_actions = ["arn:${var.aws_partition}:sns:${var.aws_region}:${local.c2_account}:account-alerts"]
  120. insufficient_data_actions = []
  121. }
  122. # Notification via Splunk Alert: "CIS 3.5 - CloudTrail configuration changes"
  123. resource "aws_cloudwatch_log_metric_filter" "cloudtrail_cfg_changes" {
  124. name = "CloudTrailCfgChanges"
  125. pattern = "{ ($.eventName = CreateTrail) || ($.eventName = UpdateTrail) || ($.eventName = DeleteTrail) || ($.eventName = StartLogging) || ($.eventName = StopLogging) }"
  126. log_group_name = var.log_group_name
  127. metric_transformation {
  128. name = "CloudTrailCfgChanges"
  129. namespace = local.alarm_namespace
  130. value = "1"
  131. default_value = 0
  132. }
  133. depends_on = [module.cloudtrail-logging]
  134. }
  135. resource "aws_cloudwatch_metric_alarm" "cloudtrail_cfg_changes" {
  136. alarm_name = "CloudTrailCfgChanges"
  137. comparison_operator = "GreaterThanOrEqualToThreshold"
  138. evaluation_periods = "1"
  139. metric_name = aws_cloudwatch_log_metric_filter.cloudtrail_cfg_changes.id
  140. namespace = local.alarm_namespace
  141. period = "300"
  142. statistic = "Sum"
  143. threshold = "1"
  144. alarm_description = "Monitoring changes to CloudTrail's configuration will help ensure sustained visibility to activities performed in the AWS account."
  145. alarm_actions = ["arn:${var.aws_partition}:sns:${var.aws_region}:${local.c2_account}:account-alerts"]
  146. insufficient_data_actions = []
  147. }
  148. # Notification via Splunk Alert: "CIS 3.6 - Console Signin Failures"
  149. resource "aws_cloudwatch_log_metric_filter" "console_signin_failures" {
  150. name = "ConsoleSigninFailures"
  151. pattern = "{ ($.eventName = ConsoleLogin) && ($.errorMessage = \"Failed authentication\") }"
  152. log_group_name = var.log_group_name
  153. metric_transformation {
  154. name = "ConsoleSigninFailures"
  155. namespace = local.alarm_namespace
  156. value = "1"
  157. default_value = 0
  158. }
  159. depends_on = [module.cloudtrail-logging]
  160. }
  161. resource "aws_cloudwatch_metric_alarm" "console_signin_failures" {
  162. alarm_name = "ConsoleSigninFailures"
  163. comparison_operator = "GreaterThanOrEqualToThreshold"
  164. evaluation_periods = "1"
  165. metric_name = aws_cloudwatch_log_metric_filter.console_signin_failures.id
  166. namespace = local.alarm_namespace
  167. period = "300"
  168. statistic = "Sum"
  169. threshold = "1"
  170. alarm_description = "Monitoring failed console logins may decrease lead time to detect an attempt to brute force a credential, which may provide an indicator, such as source IP, that can be used in other event correlation."
  171. alarm_actions = ["arn:${var.aws_partition}:sns:${var.aws_region}:${local.c2_account}:account-alerts"]
  172. insufficient_data_actions = []
  173. }
  174. # Notification via Splunk Alert: "CIS 3.7 - Disable or Delete CMK"
  175. resource "aws_cloudwatch_log_metric_filter" "disable_or_delete_cmk" {
  176. name = "DisableOrDeleteCMK"
  177. pattern = "{ ($.eventSource = kms.amazonaws.com) && (($.eventName = DisableKey) || ($.eventName = ScheduleKeyDeletion)) }"
  178. log_group_name = var.log_group_name
  179. metric_transformation {
  180. name = "DisableOrDeleteCMK"
  181. namespace = local.alarm_namespace
  182. value = "1"
  183. default_value = 0
  184. }
  185. depends_on = [module.cloudtrail-logging]
  186. }
  187. resource "aws_cloudwatch_metric_alarm" "disable_or_delete_cmk" {
  188. alarm_name = "DisableOrDeleteCMK"
  189. comparison_operator = "GreaterThanOrEqualToThreshold"
  190. evaluation_periods = "1"
  191. metric_name = aws_cloudwatch_log_metric_filter.disable_or_delete_cmk.id
  192. namespace = local.alarm_namespace
  193. period = "300"
  194. statistic = "Sum"
  195. threshold = "1"
  196. alarm_description = "Monitoring failed console logins may decrease lead time to detect an attempt to brute force a credential, which may provide an indicator, such as source IP, that can be used in other event correlation."
  197. alarm_actions = ["arn:${var.aws_partition}:sns:${var.aws_region}:${local.c2_account}:account-alerts"]
  198. insufficient_data_actions = []
  199. }
  200. # Notification via Splunk Alert: "CIS 3.8 - S3 Bucket Policy Change"
  201. resource "aws_cloudwatch_log_metric_filter" "s3_bucket_policy_changes" {
  202. name = "S3BucketPolicyChanges"
  203. pattern = "{ ($.eventSource = s3.amazonaws.com) && (($.eventName = PutBucketAcl) || ($.eventName = PutBucketPolicy) || ($.eventName = PutBucketCors) || ($.eventName = PutBucketLifecycle) || ($.eventName = PutBucketReplication) || ($.eventName = DeleteBucketPolicy) || ($.eventName = DeleteBucketCors) || ($.eventName = DeleteBucketLifecycle) || ($.eventName = DeleteBucketReplication)) }"
  204. log_group_name = var.log_group_name
  205. metric_transformation {
  206. name = "S3BucketPolicyChanges"
  207. namespace = local.alarm_namespace
  208. value = "1"
  209. default_value = 0
  210. }
  211. depends_on = [module.cloudtrail-logging]
  212. }
  213. resource "aws_cloudwatch_metric_alarm" "s3_bucket_policy_changes" {
  214. alarm_name = "S3BucketPolicyChanges"
  215. comparison_operator = "GreaterThanOrEqualToThreshold"
  216. evaluation_periods = "1"
  217. metric_name = aws_cloudwatch_log_metric_filter.s3_bucket_policy_changes.id
  218. namespace = local.alarm_namespace
  219. period = "300"
  220. statistic = "Sum"
  221. threshold = "1"
  222. alarm_description = "Monitoring changes to S3 bucket policies may reduce time to detect and correct permissive policies on sensitive S3 buckets."
  223. alarm_actions = ["arn:${var.aws_partition}:sns:${var.aws_region}:${local.c2_account}:account-alerts"]
  224. insufficient_data_actions = []
  225. }
  226. # Notification via Splunk Alert: "CIS 3.9 - AWS Config Service Changes"
  227. resource "aws_cloudwatch_log_metric_filter" "aws_config_changes" {
  228. name = "AWSConfigChanges"
  229. pattern = "{ ($.eventSource = config.amazonaws.com) && (($.eventName=StopConfigurationRecorder)||($.eventName=DeleteDeliveryChannel)||($.eventName=PutDeliveryChannel)||($.eventName=PutConfigurationRecorder)) }"
  230. log_group_name = var.log_group_name
  231. metric_transformation {
  232. name = "AWSConfigChanges"
  233. namespace = local.alarm_namespace
  234. value = "1"
  235. default_value = 0
  236. }
  237. depends_on = [module.cloudtrail-logging]
  238. }
  239. resource "aws_cloudwatch_metric_alarm" "aws_config_changes" {
  240. alarm_name = "AWSConfigChanges"
  241. comparison_operator = "GreaterThanOrEqualToThreshold"
  242. evaluation_periods = "1"
  243. metric_name = aws_cloudwatch_log_metric_filter.aws_config_changes.id
  244. namespace = local.alarm_namespace
  245. period = "300"
  246. statistic = "Sum"
  247. threshold = "1"
  248. alarm_description = "Monitoring changes to AWS Config configuration will help ensure sustained visibility of configuration items within the AWS account."
  249. alarm_actions = ["arn:${var.aws_partition}:sns:${var.aws_region}:${local.c2_account}:account-alerts"]
  250. insufficient_data_actions = []
  251. }
  252. # Notification via Splunk Alert: "CIS 3.10 - Security Group Changes"
  253. resource "aws_cloudwatch_log_metric_filter" "security_group_changes" {
  254. name = "SecurityGroupChanges"
  255. pattern = "{ ($.eventName = AuthorizeSecurityGroupIngress) || ($.eventName = AuthorizeSecurityGroupEgress) || ($.eventName = RevokeSecurityGroupIngress) || ($.eventName = RevokeSecurityGroupEgress) || ($.eventName = CreateSecurityGroup) || ($.eventName = DeleteSecurityGroup)}"
  256. log_group_name = var.log_group_name
  257. metric_transformation {
  258. name = "SecurityGroupChanges"
  259. namespace = local.alarm_namespace
  260. value = "1"
  261. default_value = 0
  262. }
  263. depends_on = [module.cloudtrail-logging]
  264. }
  265. resource "aws_cloudwatch_metric_alarm" "security_group_changes" {
  266. alarm_name = "SecurityGroupChanges"
  267. comparison_operator = "GreaterThanOrEqualToThreshold"
  268. evaluation_periods = "1"
  269. metric_name = aws_cloudwatch_log_metric_filter.security_group_changes.id
  270. namespace = local.alarm_namespace
  271. period = "300"
  272. statistic = "Sum"
  273. threshold = "1"
  274. alarm_description = "Monitoring changes to security group will help ensure that resources and services are not unintentionally exposed."
  275. alarm_actions = ["arn:${var.aws_partition}:sns:${var.aws_region}:${local.c2_account}:account-alerts"]
  276. insufficient_data_actions = []
  277. }
  278. # Notification via Splunk Alert: "CIS 3.11 - Network ACL Changes"
  279. resource "aws_cloudwatch_log_metric_filter" "nacl_changes" {
  280. name = "NACLChanges"
  281. pattern = "{ ($.eventName = CreateNetworkAcl) || ($.eventName = CreateNetworkAclEntry) || ($.eventName = DeleteNetworkAcl) || ($.eventName = DeleteNetworkAclEntry) || ($.eventName = ReplaceNetworkAclEntry) || ($.eventName = ReplaceNetworkAclAssociation) }"
  282. log_group_name = var.log_group_name
  283. metric_transformation {
  284. name = "NACLChanges"
  285. namespace = local.alarm_namespace
  286. value = "1"
  287. default_value = 0
  288. }
  289. depends_on = [module.cloudtrail-logging]
  290. }
  291. resource "aws_cloudwatch_metric_alarm" "nacl_changes" {
  292. alarm_name = "NACLChanges"
  293. comparison_operator = "GreaterThanOrEqualToThreshold"
  294. evaluation_periods = "1"
  295. metric_name = aws_cloudwatch_log_metric_filter.nacl_changes.id
  296. namespace = local.alarm_namespace
  297. period = "300"
  298. statistic = "Sum"
  299. threshold = "1"
  300. alarm_description = "Monitoring changes to NACLs will help ensure that AWS resources and services are not unintentionally exposed."
  301. alarm_actions = ["arn:${var.aws_partition}:sns:${var.aws_region}:${local.c2_account}:account-alerts"]
  302. insufficient_data_actions = []
  303. }
  304. # Notification via Splunk Alert: "CIS 3.12 - Network Gateway Changes"
  305. resource "aws_cloudwatch_log_metric_filter" "network_gw_changes" {
  306. name = "NetworkGWChanges"
  307. pattern = "{ ($.eventName = CreateCustomerGateway) || ($.eventName = DeleteCustomerGateway) || ($.eventName = AttachInternetGateway) || ($.eventName = CreateInternetGateway) || ($.eventName = DeleteInternetGateway) || ($.eventName = DetachInternetGateway) }"
  308. log_group_name = var.log_group_name
  309. metric_transformation {
  310. name = "NetworkGWChanges"
  311. namespace = local.alarm_namespace
  312. value = "1"
  313. default_value = 0
  314. }
  315. depends_on = [module.cloudtrail-logging]
  316. }
  317. resource "aws_cloudwatch_metric_alarm" "network_gw_changes" {
  318. alarm_name = "NetworkGWChanges"
  319. comparison_operator = "GreaterThanOrEqualToThreshold"
  320. evaluation_periods = "1"
  321. metric_name = aws_cloudwatch_log_metric_filter.network_gw_changes.id
  322. namespace = local.alarm_namespace
  323. period = "300"
  324. statistic = "Sum"
  325. threshold = "1"
  326. alarm_description = "Monitoring changes to network gateways will help ensure that all ingress/egress traffic traverses the VPC border via a controlled path."
  327. alarm_actions = ["arn:${var.aws_partition}:sns:${var.aws_region}:${local.c2_account}:account-alerts"]
  328. insufficient_data_actions = []
  329. }
  330. # Notification via Splunk Alert: "CIS 3.13 - Route Table Changes"
  331. resource "aws_cloudwatch_log_metric_filter" "route_table_changes" {
  332. name = "RouteTableChanges"
  333. pattern = "{ ($.eventName = CreateRoute) || ($.eventName = CreateRouteTable) || ($.eventName = ReplaceRoute) || ($.eventName = ReplaceRouteTableAssociation) || ($.eventName = DeleteRouteTable) || ($.eventName = DeleteRoute) || ($.eventName = DisassociateRouteTable) }"
  334. log_group_name = var.log_group_name
  335. metric_transformation {
  336. name = "RouteTableChanges"
  337. namespace = local.alarm_namespace
  338. value = "1"
  339. default_value = 0
  340. }
  341. depends_on = [module.cloudtrail-logging]
  342. }
  343. resource "aws_cloudwatch_metric_alarm" "route_table_changes" {
  344. alarm_name = "RouteTableChanges"
  345. comparison_operator = "GreaterThanOrEqualToThreshold"
  346. evaluation_periods = "1"
  347. metric_name = aws_cloudwatch_log_metric_filter.route_table_changes.id
  348. namespace = local.alarm_namespace
  349. period = "300"
  350. statistic = "Sum"
  351. threshold = "1"
  352. alarm_description = "Monitoring changes to route tables will help ensure that all VPC traffic flows through an expected path."
  353. alarm_actions = ["arn:${var.aws_partition}:sns:${var.aws_region}:${local.c2_account}:account-alerts"]
  354. insufficient_data_actions = []
  355. }
  356. # Notification via Splunk Alert: "CIS 3.14 - VPC Changes"
  357. resource "aws_cloudwatch_log_metric_filter" "vpc_changes" {
  358. name = "VPCChanges"
  359. pattern = "{ ($.eventName = CreateVpc) || ($.eventName = DeleteVpc) || ($.eventName = ModifyVpcAttribute) || ($.eventName = AcceptVpcPeeringConnection) || ($.eventName = CreateVpcPeeringConnection) || ($.eventName = DeleteVpcPeeringConnection) || ($.eventName = RejectVpcPeeringConnection) || ($.eventName = AttachClassicLinkVpc) || ($.eventName = DetachClassicLinkVpc) || ($.eventName = DisableVpcClassicLink) || ($.eventName = EnableVpcClassicLink) }"
  360. log_group_name = var.log_group_name
  361. metric_transformation {
  362. name = "VPCChanges"
  363. namespace = local.alarm_namespace
  364. value = "1"
  365. default_value = 0
  366. }
  367. depends_on = [module.cloudtrail-logging]
  368. }
  369. resource "aws_cloudwatch_metric_alarm" "vpc_changes" {
  370. alarm_name = "VPCChanges"
  371. comparison_operator = "GreaterThanOrEqualToThreshold"
  372. evaluation_periods = "1"
  373. metric_name = aws_cloudwatch_log_metric_filter.vpc_changes.id
  374. namespace = local.alarm_namespace
  375. period = "300"
  376. statistic = "Sum"
  377. threshold = "1"
  378. alarm_description = "Monitoring changes to VPC will help ensure that all VPC traffic flows through an expected path."
  379. alarm_actions = ["arn:${var.aws_partition}:sns:${var.aws_region}:${local.c2_account}:account-alerts"]
  380. insufficient_data_actions = []
  381. }