# AWS KMS Configuration for DPDPA Personal Data Encryption
# Version: 1.0
# Last Updated: 2026-04-02
# Legal Reference: DPDPA 2023, DPDP Rules 2025 Rule 6(1)(a)
#
# Purpose: Deploy AWS KMS Customer Master Keys (CMKs) for encrypting personal data
# at rest (S3, RDS, DynamoDB, EBS). Includes automatic key rotation, CloudTrail
# logging, and least-privilege key policies.

terraform {
  required_version = ">= 1.5.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

variable "environment" {
  description = "Environment: production, staging, development"
  type        = string
  default     = "production"
  validation {
    condition     = contains(["production", "staging", "development"], var.environment)
    error_message = "environment must be production, staging, or development"
  }
}

variable "data_classification" {
  description = "Data classification tier"
  type        = string
  default     = "personal_data"
  validation {
    condition     = contains(["personal_data", "sensitive_personal_data", "highly_sensitive"], var.data_classification)
    error_message = "Invalid data classification"
  }
}

# Data source for current AWS account
data "aws_caller_identity" "current" {}
data "aws_region" "current" {}

# KMS Key for Personal Data Encryption
resource "aws_kms_key" "personal_data" {
  description             = "DPDPA ${var.data_classification} encryption key (${var.environment})"
  deletion_window_in_days = 30  # 30-day recovery window before permanent deletion
  enable_key_rotation     = true  # Automatic annual key rotation (industry practice supporting Rule 6(1)(a); the Rule sets no rotation period)
  multi_region            = false  # Single-region key (change to true for multi-region DR)

  tags = {
    Name               = "dpdpa-${var.data_classification}-${var.environment}"
    Environment        = var.environment
    DataClassification = var.data_classification
    Compliance         = "DPDPA-Rule-6-1-a"
    ManagedBy          = "Terraform"
  }
}

# KMS Key Alias for easier reference
resource "aws_kms_alias" "personal_data" {
  name          = "alias/dpdpa-${var.data_classification}-${var.environment}"
  target_key_id = aws_kms_key.personal_data.key_id
}

# KMS Key Policy (Least Privilege)
resource "aws_kms_key_policy" "personal_data" {
  key_id = aws_kms_key.personal_data.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Sid    = "Enable IAM User Permissions"
        Effect = "Allow"
        Principal = {
          AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"
        }
        Action   = "kms:*"
        Resource = "*"
      },
      {
        Sid    = "Allow Application Service Accounts to Encrypt/Decrypt"
        Effect = "Allow"
        Principal = {
          AWS = [
            # Add your application IAM roles here
            # Example: "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/app-api-role",
            # Example: "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/app-worker-role",
          ]
        }
        Action = [
          "kms:Encrypt",
          "kms:Decrypt",
          "kms:GenerateDataKey",
          "kms:DescribeKey"
        ]
        Resource = "*"
      },
      {
        Sid    = "Allow AWS Services to Use Key"
        Effect = "Allow"
        Principal = {
          Service = [
            "s3.amazonaws.com",
            "rds.amazonaws.com",
            "dynamodb.amazonaws.com",
            "ec2.amazonaws.com"
          ]
        }
        Action = [
          "kms:Decrypt",
          "kms:GenerateDataKey"
        ]
        Resource = "*"
        Condition = {
          StringEquals = {
            "kms:ViaService" = [
              "s3.${data.aws_region.current.name}.amazonaws.com",
              "rds.${data.aws_region.current.name}.amazonaws.com",
              "dynamodb.${data.aws_region.current.name}.amazonaws.com",
              "ec2.${data.aws_region.current.name}.amazonaws.com"
            ]
          }
        }
      },
      {
        Sid    = "Allow CloudWatch Logs to Use Key"
        Effect = "Allow"
        Principal = {
          Service = "logs.${data.aws_region.current.name}.amazonaws.com"
        }
        Action = [
          "kms:Encrypt",
          "kms:Decrypt",
          "kms:GenerateDataKey"
        ]
        Resource = "*"
      }
    ]
  })
}

# CloudTrail for KMS Key Usage Auditing
resource "aws_cloudtrail" "kms_audit" {
  count = var.environment == "production" ? 1 : 0  # Only in production

  name                          = "dpdpa-kms-audit-${var.environment}"
  s3_bucket_name                = aws_s3_bucket.cloudtrail_logs[0].id
  include_global_service_events = true
  is_multi_region_trail         = false
  enable_log_file_validation    = true

  event_selector {
    read_write_type           = "All"
    include_management_events = true

    # Log all KMS API calls
    data_resource {
      type   = "AWS::KMS::Key"
      values = [aws_kms_key.personal_data.arn]
    }
  }

  tags = {
    Name        = "DPDPA KMS Audit Trail"
    Environment = var.environment
    Compliance  = "DPDPA-Rule-6-1-a"
  }
}

# S3 Bucket for CloudTrail Logs
resource "aws_s3_bucket" "cloudtrail_logs" {
  count = var.environment == "production" ? 1 : 0

  bucket = "dpdpa-kms-audit-logs-${data.aws_caller_identity.current.account_id}-${var.environment}"

  tags = {
    Name        = "DPDPA KMS Audit Logs"
    Environment = var.environment
  }
}

# Enable versioning on CloudTrail logs bucket
resource "aws_s3_bucket_versioning" "cloudtrail_logs" {
  count = var.environment == "production" ? 1 : 0

  bucket = aws_s3_bucket.cloudtrail_logs[0].id

  versioning_configuration {
    status = "Enabled"
  }
}

# Encrypt CloudTrail logs bucket
resource "aws_s3_bucket_server_side_encryption_configuration" "cloudtrail_logs" {
  count = var.environment == "production" ? 1 : 0

  bucket = aws_s3_bucket.cloudtrail_logs[0].id

  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm = "AES256"
    }
  }
}

# CloudTrail logs bucket policy
resource "aws_s3_bucket_policy" "cloudtrail_logs" {
  count = var.environment == "production" ? 1 : 0

  bucket = aws_s3_bucket.cloudtrail_logs[0].id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Sid    = "AWSCloudTrailAclCheck"
        Effect = "Allow"
        Principal = {
          Service = "cloudtrail.amazonaws.com"
        }
        Action   = "s3:GetBucketAcl"
        Resource = aws_s3_bucket.cloudtrail_logs[0].arn
      },
      {
        Sid    = "AWSCloudTrailWrite"
        Effect = "Allow"
        Principal = {
          Service = "cloudtrail.amazonaws.com"
        }
        Action   = "s3:PutObject"
        Resource = "${aws_s3_bucket.cloudtrail_logs[0].arn}/*"
        Condition = {
          StringEquals = {
            "s3:x-amz-acl" = "bucket-owner-full-control"
          }
        }
      }
    ]
  })
}

# CloudWatch Log Group for KMS Key Rotation Alerts
resource "aws_cloudwatch_log_metric_filter" "kms_rotation_disabled" {
  count = var.environment == "production" ? 1 : 0

  name           = "dpdpa-kms-rotation-disabled"
  log_group_name = "/aws/cloudtrail/${var.environment}"
  pattern        = "{ $.eventName = DisableKeyRotation && $.requestParameters.keyId = \"${aws_kms_key.personal_data.key_id}\" }"

  metric_transformation {
    name      = "KMSRotationDisabled"
    namespace = "DPDPA/Compliance"
    value     = "1"
  }
}

# CloudWatch Alarm for Key Rotation Disabled
resource "aws_cloudwatch_metric_alarm" "kms_rotation_alert" {
  count = var.environment == "production" ? 1 : 0

  alarm_name          = "dpdpa-kms-rotation-disabled-${var.environment}"
  comparison_operator = "GreaterThanThreshold"
  evaluation_periods  = 1
  metric_name         = "KMSRotationDisabled"
  namespace           = "DPDPA/Compliance"
  period              = 60
  statistic           = "Sum"
  threshold           = 0
  alarm_description   = "Alert when KMS key rotation is disabled for DPDPA personal data key"
  alarm_actions       = []  # Add SNS topic ARN for notifications

  tags = {
    Name        = "DPDPA KMS Rotation Alert"
    Environment = var.environment
  }
}

# Outputs
output "kms_key_id" {
  description = "KMS Key ID"
  value       = aws_kms_key.personal_data.key_id
}

output "kms_key_arn" {
  description = "KMS Key ARN"
  value       = aws_kms_key.personal_data.arn
}

output "kms_alias" {
  description = "KMS Key Alias"
  value       = aws_kms_alias.personal_data.name
}

output "key_rotation_enabled" {
  description = "Whether automatic key rotation is enabled"
  value       = aws_kms_key.personal_data.enable_key_rotation
}

# Usage Examples:
# terraform init
# terraform plan -var="environment=production" -var="data_classification=personal_data"
# terraform apply -var="environment=production"
#
# To use this key for S3 encryption:
#   resource "aws_s3_bucket_server_side_encryption_configuration" "example" {
#     bucket = aws_s3_bucket.example.id
#     rule {
#       apply_server_side_encryption_by_default {
#         sse_algorithm     = "aws:kms"
#         kms_master_key_id = aws_kms_key.personal_data.arn
#       }
#     }
#   }
