Kodekloud Terraform level 4, task 2 - task validation failed

I’ve prepared such code, and all resources were created successfully -

main.tf

locals {
  project_name    = "xfusion"
  environment     = "dev"
  common_name     = "${local.project_name}-${local.environment}"
  
  default_tags = {
    Project    = local.project_name
    Environment = local.environment
    Owner      = "iptcp"
    Team       = "IT"
  }
}

# SNS topic
resource "aws_sns_topic" "sns_topic" {
  name = "${local.common_name}-topic"
  tags = local.default_tags
}

# SQS queue
resource "aws_sqs_queue" "sqs_queue" {
  name = "${local.common_name}-queue"
  tags = local.default_tags
}

# SNS topic subscription to the SQS queue
resource "aws_sns_topic_subscription" "queue_subscription" {
  endpoint             = aws_sqs_queue.sqs_queue.arn
  protocol             = "sqs"
  topic_arn            = aws_sns_topic.sns_topic.arn
  raw_message_delivery = true

  depends_on = [
    aws_sns_topic.sns_topic,
    aws_sqs_queue.sqs_queue
  ]
}


# SQS queue policy to allow SNS to send messages
resource "aws_sqs_queue_policy" "sqs_queue_policy" {
  queue_url = aws_sqs_queue.sqs_queue.url
  policy    = data.aws_iam_policy_document.sqs_policy.json
}

data "aws_iam_policy_document" "sqs_policy" {
  statement {
    actions   = ["SQS:SendMessage"]
    resources = [aws_sqs_queue.sqs_queue.arn]
    principals {
      type        = "Service"
      identifiers = ["sns.amazonaws.com"]
    }
  }
}

# DynamoDB table
resource "aws_dynamodb_table" "dynamo_table" {
  name           = "${local.common_name}-events"
  hash_key       = "event_id"
  billing_mode   = "PROVISIONED"
  read_capacity  = 5
  write_capacity = 5

  attribute {
    name = "event_id"
    type = "S"
  }

  tags = local.default_tags
}

# IAM role for SNS to assume
resource "aws_iam_role" "iam_role" {
  name = "${local.common_name}-role"
  
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "sns.amazonaws.com"
        }
      }
    ]
  })

  tags = local.default_tags
}

# IAM policy for specific actions
resource "aws_iam_policy" "iam_policy" {
  name        = "${local.common_name}-policy"
  description = "IAM policy for allowing specific actions"
  policy      = jsonencode({
    Version = "2012-10-17"
    Statement = [
      for action in var.KKE_IAM_ACTIONS : {
        Effect   = "Allow"
        Action   = action
        Resource = "*"
      }
    ]
  })
}

# Attach IAM policy to IAM role
resource "aws_iam_role_policy_attachment" "policy_attachment" {
  role       = aws_iam_role.iam_role.name
  policy_arn = aws_iam_policy.iam_policy.arn
}

# CloudWatch alarm for queue depth
resource "aws_cloudwatch_metric_alarm" "queue_depth_alarm" {
  alarm_name                = "${local.common_name}-alarm"
  comparison_operator       = "GreaterThanOrEqualToThreshold"
  evaluation_periods        = "1"
  metric_name               = "ApproximateNumberOfMessagesVisible"
  namespace                 = "AWS/SQS"
  period                    = "60"
  statistic                 = "Maximum"
  threshold                 = var.KKE_QUEUE_DEPTH_THRESHOLD
  alarm_description         = "Alarm for when the SQS queue depth exceeds the threshold"
  insufficient_data_actions = []

  dimensions = {
    QueueName = aws_sqs_queue.sqs_queue.name
  }
}

variables.tf

locals {
  valid_regions = ["us-east-1"]
}

variable "KKE_AWS_REGION" {
  description = "AWS region to be used"
  type        = string
  default     = "us-east-1"

  validation {
    condition     = contains(local.valid_regions, var.KKE_AWS_REGION)
    error_message = "The AWS region must be one of the following: us-east-1."
  }
}

# Validation for queue depth threshold
variable "KKE_QUEUE_DEPTH_THRESHOLD" {
  description = "CloudWatch alarm threshold for queue depth"
  type        = number
  default     = 50

  validation {
    condition     = var.KKE_QUEUE_DEPTH_THRESHOLD >= 1 && var.KKE_QUEUE_DEPTH_THRESHOLD <= 1000
    error_message = "The queue depth threshold must be between 1 and 1000."
  }
}

variable "KKE_IAM_ACTIONS" {
  description = "List of IAM actions to allow in dynamic policy"
  type        = list(string)
  default     = ["sqs:ReceiveMessage", "dynamodb:PutItem", "sns:Publish"]
}

outputs.tf

output "kke_cloudwatch_alarm_name" {
  value = aws_cloudwatch_metric_alarm.queue_depth_alarm.alarm_name
}

output "kke_dynamodb_table_name" {
  value = aws_dynamodb_table.dynamo_table.name
}

output "kke_iam_role_arn" {
  value = aws_iam_role.iam_role.arn
}

output "kke_sns_topic_arn" {
  value = aws_sns_topic.sns_topic.arn
}

output "kke_sqs_queue_url" {
  value = aws_sqs_queue.sqs_queue.url
}

Task validation is failing on such error -

No worries!!

Uh oh! Looks like the task was not completed successfully. But it’s Ok. You can try again next time this task is assigned to you.

You may check your work again to see what went wrong. The environment expires in 5 minutes.

If you think you did your work correctly and is marked failed, you may request for a review from your task dashboard. Or alternatively please submit outputs/screenshot(s) of your work and post to community.kodekloud.com

You can also view your results in your dashboard under the “Active Practice” page.

@raymond.baoly Could you please advise how can I complete this lab?

Hi @petya.bogdan

Thanks for your detailed feedback. Could you please share the validation message? It seems to be missing from your post. Was the message “SNS topic is not ensured to be created before subscription”?

Actually now I don’t see any SNS topic image, I only see this -

Thank you for your feedback. I’m trying to reproduce it to find the root cause.

I second this, having the same issues.

@Mederbek @petya.bogdan

This is a valid issue. The team is working on updating the task, and I’ll keep you updated.

Hi guys,

The task has been updated, and I was able to complete it. Please try again.

not sure, what’s happening to the lab, it’s giving weird errors.

Hi @Mederbek

The task requires using an inline policy, so we need to create an IAM role and attach the policy as inline, for example:

resource "aws_iam_role" "iam_role" {
  name = "${local.common_name}-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect = "Allow"
      Principal = {
        Service = "sns.amazonaws.com"
      }
      Action = "sts:AssumeRole"
    }]
  })

  tags = local.default_tags
}

resource "aws_iam_role_policy" "inline_policy" {
  name = "${local.common_name}-policy"
  role = aws_iam_role.iam_role.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      for action in var.KKE_IAM_ACTIONS : {
        Effect   = "Allow"
        Action   = action
        Resource = "*"
      }
    ]
  })
}```