main.tf 11 KB

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