main.tf 11 KB

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