main.tf 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. # Kenisis firehose stream
  2. # Record Transformation Required, called "processing_configuration" in Terraform
  3. resource "aws_kinesis_firehose_delivery_stream" "kinesis_firehose" {
  4. name = var.firehose_name
  5. destination = "splunk"
  6. s3_configuration {
  7. role_arn = aws_iam_role.kinesis_firehose.arn
  8. prefix = var.s3_prefix
  9. bucket_arn = aws_s3_bucket.kinesis_firehose_s3_bucket.arn
  10. buffer_size = var.kinesis_firehose_buffer
  11. buffer_interval = var.kinesis_firehose_buffer_interval
  12. compression_format = var.s3_compression_format
  13. }
  14. splunk_configuration {
  15. hec_endpoint = var.hec_url
  16. hec_token = var.hec_token
  17. hec_acknowledgment_timeout = var.hec_acknowledgment_timeout
  18. hec_endpoint_type = var.hec_endpoint_type
  19. s3_backup_mode = var.s3_backup_mode
  20. processing_configuration {
  21. enabled = "true"
  22. processors {
  23. type = "Lambda"
  24. parameters {
  25. parameter_name = "LambdaArn"
  26. parameter_value = "${aws_lambda_function.firehose_lambda_transform.arn}:$LATEST"
  27. }
  28. parameters {
  29. parameter_name = "RoleArn"
  30. parameter_value = aws_iam_role.kinesis_firehose.arn
  31. }
  32. }
  33. }
  34. cloudwatch_logging_options {
  35. enabled = var.enable_fh_cloudwatch_logging
  36. log_group_name = aws_cloudwatch_log_group.kinesis_logs.name
  37. log_stream_name = aws_cloudwatch_log_stream.kinesis_logs.name
  38. }
  39. }
  40. tags = var.tags
  41. }
  42. #S3 Bucket for Kinesis Firehose s3_backup_mode
  43. #Certificate CRLs need to be publicly accessible
  44. # tfsec:ignore:aws-s3-enable-versioning tfsec:ignore:aws-s3-no-public-buckets tfsec:ignore:aws-s3-enable-bucket-logging tfsec:ignore:aws-s3-block-public-acls
  45. resource "aws_s3_bucket" "kinesis_firehose_s3_bucket" { # tfsec:ignore:aws-s3-block-public-policy tfsec:ignore:aws-s3-ignore-public-acls tfsec:ignore:aws-s3-specify-public-access-block
  46. # checkov:skip=CKV_AWS_18: see tfsec ignore - logging not enabled
  47. # checkov:skip=CKV_AWS_21: see tfsec ignore - S3 object versioning is disabled
  48. # checkov:skip=CKV_AWS_144: S3 bucket has no cross-region replication enabled
  49. bucket = var.s3_bucket_name
  50. tags = var.tags
  51. }
  52. resource "aws_s3_bucket_acl" "kinesis_firehose_s3_bucket" {
  53. bucket = aws_s3_bucket.kinesis_firehose_s3_bucket.id
  54. acl = "private"
  55. }
  56. resource "aws_kms_key" "kinesis_firehose_s3_bucket" {
  57. enable_key_rotation = true
  58. deletion_window_in_days = 30
  59. tags = var.tags
  60. }
  61. resource "aws_s3_bucket_server_side_encryption_configuration" "kinesis_firehose_s3_bucket" {
  62. bucket = aws_s3_bucket.kinesis_firehose_s3_bucket.id
  63. rule {
  64. apply_server_side_encryption_by_default {
  65. kms_master_key_id = aws_kms_key.kinesis_firehose_s3_bucket.arn
  66. sse_algorithm = "aws:kms"
  67. }
  68. }
  69. }
  70. resource "aws_s3_bucket_lifecycle_configuration" "kinesis_firehose_s3_bucket" {
  71. bucket = aws_s3_bucket.kinesis_firehose_s3_bucket.id
  72. rule {
  73. id = "expire-old-logs"
  74. status = "Enabled"
  75. filter {
  76. prefix = ""
  77. }
  78. expiration {
  79. days = var.s3_expiration
  80. }
  81. noncurrent_version_expiration {
  82. noncurrent_days = var.s3_expiration
  83. }
  84. abort_incomplete_multipart_upload {
  85. days_after_initiation = 7
  86. }
  87. }
  88. }
  89. resource "aws_s3_bucket_public_access_block" "kinesis_firehose_s3_bucket" {
  90. count = var.s3_bucket_block_public_access_enabled
  91. bucket = aws_s3_bucket.kinesis_firehose_s3_bucket.id
  92. block_public_acls = true
  93. block_public_policy = true
  94. ignore_public_acls = true
  95. restrict_public_buckets = true
  96. }
  97. # Cloudwatch logging group for Kinesis Firehose
  98. # tfsec:ignore:aws-cloudwatch-log-group-customer-key # OK to use AWS key for this
  99. resource "aws_cloudwatch_log_group" "kinesis_logs" {
  100. name = "/aws/kinesisfirehose/${var.firehose_name}"
  101. retention_in_days = var.cloudwatch_log_retention
  102. tags = var.tags
  103. }
  104. # Create the stream
  105. resource "aws_cloudwatch_log_stream" "kinesis_logs" {
  106. name = var.log_stream_name
  107. log_group_name = aws_cloudwatch_log_group.kinesis_logs.name
  108. }
  109. ## handle the sensitivity of the hec_token variable
  110. #data "aws_kms_secrets" "splunk_hec_token" {
  111. # secret {
  112. # name = "hec_token"
  113. # payload = var.hec_token
  114. #
  115. # context = var.encryption_context
  116. # }
  117. #}
  118. # Role for the transformation Lambda function attached to the kinesis stream
  119. resource "aws_iam_role" "kinesis_firehose_lambda" {
  120. name = var.kinesis_firehose_lambda_role_name
  121. path = "/lambda/"
  122. description = "Role for Lambda function to transformation CloudWatch logs into Splunk compatible format"
  123. force_detach_policies = true
  124. assume_role_policy = <<POLICY
  125. {
  126. "Statement": [
  127. {
  128. "Effect": "Allow",
  129. "Action": "sts:AssumeRole",
  130. "Principal": {
  131. "Service": "lambda.amazonaws.com"
  132. }
  133. }
  134. ],
  135. "Version": "2012-10-17"
  136. }
  137. POLICY
  138. tags = var.tags
  139. }
  140. data "aws_iam_policy_document" "lambda_policy_doc" {
  141. # checkov:skip=CKV_AWS_111: see tfsec aws-iam-no-policy-wildcard ignore comment
  142. statement {
  143. actions = [
  144. "logs:GetLogEvents",
  145. ]
  146. resources = [
  147. var.arn_cloudwatch_logs_to_ship,
  148. ]
  149. effect = "Allow"
  150. }
  151. statement {
  152. actions = [
  153. "firehose:PutRecordBatch",
  154. ]
  155. resources = [
  156. aws_kinesis_firehose_delivery_stream.kinesis_firehose.arn,
  157. ]
  158. }
  159. statement {
  160. actions = [
  161. "logs:PutLogEvents",
  162. ]
  163. # tfsec:ignore:aws-iam-no-policy-wildcards - baseline this setting first. We use wildcards in policies
  164. resources = [
  165. "*",
  166. ]
  167. effect = "Allow"
  168. }
  169. statement {
  170. actions = [
  171. "logs:CreateLogGroup",
  172. ]
  173. # tfsec:ignore:aws-iam-no-policy-wildcards - baseline this setting first. We use wildcards in policies
  174. resources = [
  175. "*",
  176. ]
  177. effect = "Allow"
  178. }
  179. statement {
  180. actions = [
  181. "logs:CreateLogStream",
  182. ]
  183. # tfsec:ignore:aws-iam-no-policy-wildcards - baseline this setting first. We use wildcards in policies
  184. resources = [
  185. "*",
  186. ]
  187. effect = "Allow"
  188. }
  189. # FTD: Needs KMS access
  190. statement {
  191. actions = [
  192. "kms:GenerateDataKey",
  193. "kms:Decrypt"
  194. ]
  195. # tfsec:ignore:aws-iam-no-policy-wildcards - baseline this setting first. We use wildcards in policies
  196. resources = [
  197. "*",
  198. ]
  199. effect = "Allow"
  200. }
  201. }
  202. resource "aws_iam_policy" "lambda_transform_policy" {
  203. name = var.lambda_iam_policy_name
  204. policy = data.aws_iam_policy_document.lambda_policy_doc.json
  205. }
  206. resource "aws_iam_role_policy_attachment" "lambda_policy_role_attachment" {
  207. role = aws_iam_role.kinesis_firehose_lambda.name
  208. policy_arn = aws_iam_policy.lambda_transform_policy.arn
  209. }
  210. # Create the lambda function
  211. # The lambda function to transform data from compressed format in Cloudwatch to something Splunk can handle (uncompressed)
  212. # tfsec:ignore:aws-lambda-enable-tracing We do not enable X-Ray Tracing for Lambda
  213. resource "aws_lambda_function" "firehose_lambda_transform" {
  214. # checkov:skip=CKV_AWS_50: see tfsec ignore X-Ray Tracing
  215. function_name = var.lambda_function_name
  216. description = "Transform data from CloudWatch format to Splunk compatible format"
  217. filename = data.archive_file.lambda_function.output_path
  218. role = aws_iam_role.kinesis_firehose_lambda.arn
  219. handler = "kinesis-firehose-cloudwatch-logs-processor.handler"
  220. source_code_hash = data.archive_file.lambda_function.output_base64sha256
  221. runtime = var.nodejs_runtime
  222. timeout = var.lambda_function_timeout
  223. tags = var.tags
  224. }
  225. # kinesis-firehose-cloudwatch-logs-processor.js was taken by copy/paste from the AWS UI. It is predefined blueprint
  226. # code supplied to AWS by Splunk.
  227. data "archive_file" "lambda_function" {
  228. type = "zip"
  229. source_file = "${path.module}/files/kinesis-firehose-cloudwatch-logs-processor.js"
  230. output_path = "${path.module}/files/kinesis-firehose-cloudwatch-logs-processor.zip"
  231. }
  232. # Role for Kenisis Firehose
  233. resource "aws_iam_role" "kinesis_firehose" {
  234. name = var.kinesis_firehose_role_name
  235. path = "/aws_services/"
  236. description = "IAM Role for Kenisis Firehose"
  237. force_detach_policies = true
  238. assume_role_policy = <<POLICY
  239. {
  240. "Version": "2012-10-17",
  241. "Statement": [
  242. {
  243. "Principal": {
  244. "Service": "firehose.amazonaws.com"
  245. },
  246. "Action": "sts:AssumeRole",
  247. "Effect": "Allow"
  248. }
  249. ]
  250. }
  251. POLICY
  252. tags = var.tags
  253. }
  254. data "aws_iam_policy_document" "kinesis_firehose_policy_document" {
  255. # checkov:skip=CKV_AWS_111: see tfsec aws-iam-no-policy-wildcard ignore comment
  256. statement {
  257. actions = [
  258. "s3:AbortMultipartUpload",
  259. "s3:GetBucketLocation",
  260. "s3:GetObject",
  261. "s3:ListBucket",
  262. "s3:ListBucketMultipartUploads",
  263. "s3:PutObject",
  264. ]
  265. # tfsec:ignore:aws-iam-no-policy-wildcards - baseline this setting first. We use wildcards in policies
  266. resources = [
  267. aws_s3_bucket.kinesis_firehose_s3_bucket.arn,
  268. "${aws_s3_bucket.kinesis_firehose_s3_bucket.arn}/*",
  269. ]
  270. effect = "Allow"
  271. }
  272. statement {
  273. actions = [
  274. "lambda:InvokeFunction",
  275. "lambda:GetFunctionConfiguration",
  276. ]
  277. resources = [
  278. "${aws_lambda_function.firehose_lambda_transform.arn}:$LATEST",
  279. ]
  280. }
  281. statement {
  282. actions = [
  283. "logs:PutLogEvents",
  284. ]
  285. resources = [
  286. aws_cloudwatch_log_group.kinesis_logs.arn,
  287. aws_cloudwatch_log_stream.kinesis_logs.arn,
  288. ]
  289. effect = "Allow"
  290. }
  291. # FTD: Needs KMS access
  292. statement {
  293. actions = [
  294. "kms:GenerateDataKey",
  295. "kms:Decrypt"
  296. ]
  297. # tfsec:ignore:aws-iam-no-policy-wildcards - baseline this setting first. We use wildcards in policies
  298. resources = [
  299. "*",
  300. ]
  301. effect = "Allow"
  302. }
  303. }
  304. resource "aws_iam_policy" "kinesis_firehose_iam_policy" {
  305. name = var.kinesis_firehose_iam_policy_name
  306. policy = data.aws_iam_policy_document.kinesis_firehose_policy_document.json
  307. }
  308. resource "aws_iam_role_policy_attachment" "kinesis_fh_role_attachment" {
  309. role = aws_iam_role.kinesis_firehose.name
  310. policy_arn = aws_iam_policy.kinesis_firehose_iam_policy.arn
  311. }
  312. resource "aws_iam_role" "cloudwatch_to_firehose_trust" {
  313. name = var.cloudwatch_to_firehose_trust_iam_role_name
  314. path = "/aws_services/"
  315. description = "Role for CloudWatch Log Group subscription"
  316. force_detach_policies = true
  317. assume_role_policy = <<ROLE
  318. {
  319. "Statement": [
  320. {
  321. "Effect": "Allow",
  322. "Action": "sts:AssumeRole",
  323. "Principal": {
  324. "Service": "logs.${var.region}.amazonaws.com"
  325. }
  326. }
  327. ],
  328. "Version": "2012-10-17"
  329. }
  330. ROLE
  331. }
  332. # tfsec:ignore:aws-iam-no-policy-wildcards - baseline this setting first. We use wildcards in policies
  333. data "aws_iam_policy_document" "cloudwatch_to_fh_access_policy" {
  334. # checkov:skip=CKV_AWS_111: see tfsec aws-iam-no-policy-wildcard ignore comment
  335. statement {
  336. actions = [
  337. "firehose:*",
  338. ]
  339. effect = "Allow"
  340. resources = [
  341. aws_kinesis_firehose_delivery_stream.kinesis_firehose.arn,
  342. ]
  343. }
  344. statement {
  345. actions = [
  346. "iam:PassRole",
  347. ]
  348. effect = "Allow"
  349. resources = [
  350. aws_iam_role.cloudwatch_to_firehose_trust.arn,
  351. ]
  352. }
  353. # FTD: Needs KMS access
  354. statement {
  355. actions = [
  356. "kms:GenerateDataKey",
  357. "kms:Decrypt"
  358. ]
  359. # tfsec:ignore:aws-iam-no-policy-wildcards - baseline this setting first. We use wildcards in policies
  360. resources = [
  361. "*",
  362. ]
  363. effect = "Allow"
  364. }
  365. }
  366. resource "aws_iam_policy" "cloudwatch_to_fh_access_policy" {
  367. name = var.cloudwatch_to_fh_access_policy_name
  368. description = "Cloudwatch to Firehose Subscription Policy"
  369. policy = data.aws_iam_policy_document.cloudwatch_to_fh_access_policy.json
  370. }
  371. resource "aws_iam_role_policy_attachment" "cloudwatch_to_fh" {
  372. role = aws_iam_role.cloudwatch_to_firehose_trust.name
  373. policy_arn = aws_iam_policy.cloudwatch_to_fh_access_policy.arn
  374. }
  375. resource "aws_cloudwatch_log_subscription_filter" "cloudwatch_log_filter" {
  376. name = var.cloudwatch_log_filter_name
  377. role_arn = aws_iam_role.cloudwatch_to_firehose_trust.arn
  378. destination_arn = aws_kinesis_firehose_delivery_stream.kinesis_firehose.arn
  379. log_group_name = var.name_cloudwatch_logs_to_ship
  380. filter_pattern = var.subscription_filter_pattern
  381. }