main.tf 11 KB

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