Terraform level 4, task 5 - validation failed

Was able to complete, Were nat be able without your hints. Thanks again.

p.s. Had to use literally your choices for resources names. Also passed without to implement fully the described in the task requirements (dig out the specific permission policy in my attempts to narrow down the root cause for failures). Share this, just for the case if improving task description / validation is relevant.

It doesn’t work for me. Is the code complete?

cat > variables.tf << ‘EOF’

variable “KKE_SNS_TOPIC_NAME” {
description = “Name of the SNS topic”
type = string
default = “”
}

variable “KKE_SSM_PARAM_NAME” {
description = “SSM parameter name”
type = string
default = “”
}

variable “KKE_STEP_FUNCTION_NAME” {
description = “Step Function name”
type = string
default = “”
}
EOF

cat > terraform.tfvars << ‘EOF’
KKE_SNS_TOPIC_NAME = “nautilus-sns-topic”
KKE_SSM_PARAM_NAME = “nautilus-param”
KKE_STEP_FUNCTION_NAME = “nautilus-stepfunction”
EOF

mkdir -p modules/sns modules/ssm modules/stepfunctions

cat > modules/sns/main.tf << ‘EOF’
resource “aws_sns_topic” “this” {
name = var.KKE_SNS_TOPIC_NAME
}
EOF

cat > modules/sns/outputs.tf << ‘EOF’
output “topic_name” {
value = aws_sns_topic.this.name
}

output “topic_arn” {
value = aws_sns_topic.this.arn
}
EOF

cat > modules/ssm/module_vars.tf << ‘EOF’
variable “sns_topic_arn” {
type = string
description = “SNS Topic ARN from SNS module”
}
EOF

cat > modules/ssm/main.tf << ‘EOF’
resource “aws_ssm_parameter” “this” {
name = var.KKE_SSM_PARAM_NAME
type = “String”
value = var.sns_topic_arn
}
EOF

cat > modules/ssm/outputs.tf << ‘EOF’
output “parameter_name” {
value = aws_ssm_parameter.this.name
}

output “parameter_arn” {
value = aws_ssm_parameter.this.arn
}
EOF

cat > modules/stepfunctions/module_vars.tf << ‘EOF’
variable “ssm_parameter_arn” {
type = string
description = “ARN of SSM parameter from data source in root”
}

variable “ssm_parameter_value” {
type = string
description = “Value of SSM parameter from data source in root”
}
EOF

cat > modules/stepfunctions/main.tf << ‘EOF’
resource “aws_iam_role” “step_function_role” {
name = “${var.KKE_STEP_FUNCTION_NAME}-role”

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

resource “aws_iam_role_policy” “step_function_policy” {
name = “${var.KKE_STEP_FUNCTION_NAME}-policy”
role = aws_iam_role.step_function_role.id

policy = jsonencode({
Version = “2012-10-17”
Statement = [{
Effect = “Allow”
Action = [“ssm:GetParameter”]
Resource = var.ssm_parameter_arn
}]
})
}

resource “aws_sfn_state_machine” “this” {
name = var.KKE_STEP_FUNCTION_NAME
role_arn = aws_iam_role.step_function_role.arn

definition = jsonencode({
Comment = “Step Function using SSM parameter”
StartAt = “PassState”
States = {
PassState = {
Type = “Pass”
Result = {
SSMParameterARN = var.ssm_parameter_arn
SSMParameterValue = var.ssm_parameter_value
}
End = true
}
}
})
}
EOF

cat > modules/stepfunctions/outputs.tf << ‘EOF’
output “state_machine_name” {
value = aws_sfn_state_machine.this.name
}
EOF

echo “Checking module files…”
for module in sns ssm stepfunctions; do
if [ ! -f “modules/$module/main.tf” ]; then
echo " ERROR: modules/$module/main.tf not found!"
exit 1
fi
if [ ! -f “modules/$module/outputs.tf” ]; then
echo " ERROR: modules/$module/outputs.tf not found!"
exit 1
fi
done
echo “All module files created”

echo “Creating symlinks…”
rm -f modules/sns/variables.tf modules/ssm/variables.tf modules/stepfunctions/variables.tf
ln -s /home/bob/terraform/variables.tf modules/sns/variables.tf
ln -s /home/bob/terraform/variables.tf modules/ssm/variables.tf
ln -s /home/bob/terraform/variables.tf modules/stepfunctions/variables.tf

echo “Verifying symlinks:”
ls -la modules/*/variables.tf

cat > main.tf << ‘EOF’
module “sns” {
source = “./modules/sns”

KKE_SNS_TOPIC_NAME = var.KKE_SNS_TOPIC_NAME
KKE_SSM_PARAM_NAME = var.KKE_SSM_PARAM_NAME
KKE_STEP_FUNCTION_NAME = var.KKE_STEP_FUNCTION_NAME
}

module “ssm” {
source = “./modules/ssm”

KKE_SNS_TOPIC_NAME = var.KKE_SNS_TOPIC_NAME
KKE_SSM_PARAM_NAME = var.KKE_SSM_PARAM_NAME
KKE_STEP_FUNCTION_NAME = var.KKE_STEP_FUNCTION_NAME

sns_topic_arn = module.sns.topic_arn

depends_on = [module.sns]
}

data “aws_ssm_parameter” “this” {
name = module.ssm.parameter_name

depends_on = [module.ssm]
}

module “stepfunctions” {
source = “./modules/stepfunctions”

KKE_SNS_TOPIC_NAME = var.KKE_SNS_TOPIC_NAME
KKE_SSM_PARAM_NAME = var.KKE_SSM_PARAM_NAME
KKE_STEP_FUNCTION_NAME = var.KKE_STEP_FUNCTION_NAME

ssm_parameter_arn = data.aws_ssm_parameter.this.arn
ssm_parameter_value = data.aws_ssm_parameter.this.value

depends_on = [data.aws_ssm_parameter.this]
}
EOF

============================================================================

7. outputs.tf

============================================================================

cat > outputs.tf << ‘EOF’
output “kke_sns_topic_name” {
value = module.sns.topic_name
}

output “kke_ssm_parameter_name” {
value = module.ssm.parameter_name
}

output “kke_step_function_name” {
value = module.stepfunctions.state_machine_name
}
EOF

1 Like

I’m getting this error: SSM parameter does not have a visible Terraform graph dependency on SNS.

Here’s my code:

mkdir -p modules/sns modules/ssm modules/stepfunctions

cat << EOF > variables.tf
variable "KKE_SNS_TOPIC_NAME" {
  type = string
}

variable "KKE_SSM_PARAM_NAME" {
  type = string
}

variable "KKE_STEP_FUNCTION_NAME" {
  type = string
}
EOF

ln -s /home/bob/terraform/variables.tf modules/sns/variables.tf
ln -s /home/bob/terraform/variables.tf modules/ssm/variables.tf
ln -s /home/bob/terraform/variables.tf modules/stepfunctions/variables.tf

cat << EOF > terraform.tfvars
KKE_SNS_TOPIC_NAME = "nautilus-sns-topic"
KKE_SSM_PARAM_NAME = "nautilus-param"
KKE_STEP_FUNCTION_NAME = "nautilus-stepfunction"
EOF

cat << EOF > outputs.tf
output "kke_sns_topic_name" {
  value = module.sns.kke_sns_topic_name
}

output "kke_ssm_parameter_name" {
  value = module.ssm.kke_ssm_parameter_name
}

output "kke_step_function_name" {
  value = module.stepfunctions.kke_step_function_name
}
EOF

cat << EOF > main.tf
module "sns" {
  source = "./modules/sns"

  KKE_SNS_TOPIC_NAME = var.KKE_SNS_TOPIC_NAME
  KKE_SSM_PARAM_NAME = var.KKE_SSM_PARAM_NAME
  KKE_STEP_FUNCTION_NAME = var.KKE_STEP_FUNCTION_NAME
}

module "ssm" {
  source = "./modules/ssm"

  KKE_SNS_TOPIC_NAME = var.KKE_SNS_TOPIC_NAME
  KKE_SSM_PARAM_NAME = var.KKE_SSM_PARAM_NAME
  KKE_STEP_FUNCTION_NAME = var.KKE_STEP_FUNCTION_NAME
  sns_topic_arn = module.sns.topic_arn

  depends_on = [module.sns]
}

module "stepfunctions" {
  source = "./modules/stepfunctions"

  KKE_SNS_TOPIC_NAME = var.KKE_SNS_TOPIC_NAME
  KKE_SSM_PARAM_NAME = var.KKE_SSM_PARAM_NAME
  KKE_STEP_FUNCTION_NAME = var.KKE_STEP_FUNCTION_NAME
  ssm_parameter_arn = module.ssm.parameter_arn
  ssm_parameter_value = module.sns.topic_arn

  depends_on = [module.ssm]
}
EOF

cat << EOF > modules/sns/outputs.tf
output "kke_sns_topic_name" {
  value = aws_sns_topic.KKE_SNS_TOPIC_NAME.name
}

output "topic_arn" {
  value = aws_sns_topic.KKE_SNS_TOPIC_NAME.arn
}
EOF

cat << EOF > modules/ssm/outputs.tf
output "kke_ssm_parameter_name" {
  value = aws_ssm_parameter.KKE_SSM_PARAM_NAME.name
}

output "parameter_arn" {
  value = aws_ssm_parameter.KKE_SSM_PARAM_NAME.arn
}
EOF

cat << EOF > modules/stepfunctions/outputs.tf
output "kke_step_function_name" {
  value = aws_sfn_state_machine.KKE_STEP_FUNCTION_NAME.name
}
EOF

cat << EOF > modules/ssm/module_vars.tf
variable "sns_topic_arn" {
  type = string
}
EOF

cat << EOF > modules/stepfunctions/module_vars.tf
variable "ssm_parameter_arn" {
  type = string
}

variable "ssm_parameter_value" {
  type = string
}
EOF

cat << EOF > modules/sns/main.tf
resource "aws_sns_topic" "KKE_SNS_TOPIC_NAME" {
  name = var.KKE_SNS_TOPIC_NAME
}
EOF

cat << EOF > modules/ssm/main.tf
resource "aws_ssm_parameter" "KKE_SSM_PARAM_NAME" {
  name  = var.KKE_SSM_PARAM_NAME
  type  = "String"
  value = "arn:aws:sns:us-east-1:000000000000:${var.KKE_SNS_TOPIC_NAME}"
}
EOF

cat << EOF > modules/stepfunctions/main.tf
resource "aws_iam_role" "KKE_STEP_FUNCTION_NAME" {
  name = var.KKE_STEP_FUNCTION_NAME

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

resource "aws_iam_policy" "KKE_STEP_FUNCTION_NAME" {
  name = var.KKE_STEP_FUNCTION_NAME
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "ssm:GetParameter"
        Effect = "Allow"
        Resource = var.ssm_parameter_arn
      },
    ]
  })
}

resource "aws_iam_role_policy_attachment" "KKE_STEP_FUNCTION_NAME" {
  role       = aws_iam_role.KKE_STEP_FUNCTION_NAME.name
  policy_arn = aws_iam_policy.KKE_STEP_FUNCTION_NAME.arn
}

resource "aws_sfn_state_machine" "KKE_STEP_FUNCTION_NAME" {
  name     = var.KKE_STEP_FUNCTION_NAME
  role_arn = aws_iam_role.KKE_STEP_FUNCTION_NAME.arn

  definition = jsonencode({
    Comment = "Step Function using SSM parameter"
    StartAt = "Start"
    States = {
      Start = {
        Type = "Task"
        Resource = "arn:aws:states:::aws-sdk:ssm:getParameter"
        Parameters = {
          Name = var.KKE_SSM_PARAM_NAME
        }
        End = true
      }
    }
  })
}
EOF

Hi @edsfocci

Please try the solution from Danielyan

@raymond.baoly is @Danielyan 's code confirmed to work for this task? My code is almost similar. I wonder what exactly is wrong with my code that is causing the error?

Hi @edsfocci

Yes, it’s confirmed, he was able to pass the task. I reviewed your answer and noticed that you created modules/ssm/module_vars.tf and modules/stepfunctions/module_vars.tf, which aren’t needed. The variables for these modules are already linked from /home/bob/terraform/variables.tf

@raymond.baoly I’m confused by your reply, because I originally attempted this task without modules/ssm/module_vars.tf and modules/stepfunctions/module_vars.tf, and I got the error that time, so I looked at Danielyan’s version, assuming that his code works, and it had the two module_vars.tf files, so I thought it might help my solution. Unfortunately, it didn’t.

You can see Danielyan’s module_vars.tf below:

cat > modules/ssm/module_vars.tf << ‘EOF’
variable “sns_topic_arn” {
type = string
description = “SNS Topic ARN from SNS module”
}
EOF

cat > modules/stepfunctions/module_vars.tf << ‘EOF’
variable “ssm_parameter_arn” {
type = string
description = “ARN of SSM parameter from data source in root”
}

variable “ssm_parameter_value” {
type = string
description = “Value of SSM parameter from data source in root”
}
EOF

same failed too, following Danielyan’s solution.

Hi everyone,

It’s more that 5 days I’m with this task. I tried all way and still I’m getting “Step Functions data source does not depend on the SSM parameter.”
I did complete “@Danielyan” solution and still I’m getting “Step Functions data source does not depend on the SSM parameter.” No way for me to skip this task

How can we validate ?

Hi everyone, Danielyan has confirmed that he was able to pass the task. Not sure why the wrong solution was shared earlier, please refer to the solution here and try again.

main.tf

module "sns" {
  source = "./modules/sns"
  KKE_SSM_PARAM_NAME = var.KKE_SSM_PARAM_NAME
  KKE_SNS_TOPIC_NAME = var.KKE_SNS_TOPIC_NAME
  KKE_STEP_FUNCTION_NAME = var.KKE_STEP_FUNCTION_NAME
}

module "ssm" {
  source     = "./modules/ssm"
  KKE_SSM_PARAM_NAME = var.KKE_SSM_PARAM_NAME
  KKE_SNS_TOPIC_NAME = var.KKE_SNS_TOPIC_NAME
  KKE_STEP_FUNCTION_NAME = var.KKE_STEP_FUNCTION_NAME
  depends_on = [module.sns]
}

module "stepfunctions" {
  source     = "./modules/stepfunctions"
  KKE_SSM_PARAM_NAME = var.KKE_SSM_PARAM_NAME
  KKE_SNS_TOPIC_NAME = var.KKE_SNS_TOPIC_NAME
  KKE_STEP_FUNCTION_NAME = var.KKE_STEP_FUNCTION_NAME
  depends_on = [module.ssm]
}

outputs.tf

output "kke_sns_topic_name" {
  value = module.sns.kke_sns_topic
}

output "kke_ssm_parameter_name" {
  value = module.ssm.kke_sns_parameter_name
}

output "kke_step_function_name" {
  value = module.stepfunctions.kke_step_function_name
}

terraform.tfvars

KKE_SNS_TOPIC_NAME       = "datacenter-sns-topic"
KKE_SSM_PARAM_NAME       = "datacenter-param"
KKE_STEP_FUNCTION_NAME   = "datacenter-stepfunction"

variables.tf

variable "KKE_SNS_TOPIC_NAME" {
  description = "Name of the SNS topic"
  type        = string
}

variable "KKE_SSM_PARAM_NAME" {
  description = "Name of the SSM parameter"
  type        = string
}

variable "KKE_STEP_FUNCTION_NAME" {
  description = "Name of the Step Function"
  type        = string
}

modules/sns/main.tf

resource "aws_sns_topic" "this" {
  name = var.KKE_SNS_TOPIC_NAME
}

modules/sns/outputs.tf

output "kke_sns_topic" {
  value = aws_sns_topic.this.name
}

modules/ssm/main.tf

resource "aws_ssm_parameter" "this" {
  name  = var.KKE_SSM_PARAM_NAME
  type  = "String"
  value = "arn:aws:sns:us-east-1:000000000000:${var.KKE_SNS_TOPIC_NAME}"
}

modules/ssm/outputs.tf

output "kke_sns_parameter_name" {
  value = aws_ssm_parameter.this.name
}

modules/stepfunctions/main.tf

data "aws_ssm_parameter" "sns_param" {
  name = var.KKE_SSM_PARAM_NAME
}

resource "aws_iam_role" "sfn_role" {
  name = "${var.KKE_STEP_FUNCTION_NAME}-role"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect    = "Allow"
      Principal = { Service = "states.amazonaws.com" }
      Action    = "sts:AssumeRole"
    }]
  })
}

resource "aws_sfn_state_machine" "this" {
  name     = var.KKE_STEP_FUNCTION_NAME
  role_arn = aws_iam_role.sfn_role.arn
  definition = jsonencode({
    StartAt = "ReadSSM"
    States = {
      ReadSSM = {
        Type   = "Pass"
        Result = {
          SnsArn = data.aws_ssm_parameter.sns_param.value
        }
        End = true
      }
    }
  })
}

modules/stepfunctions/outputs.tf

output "kke_step_function_name" {
  value = aws_sfn_state_machine.this.name
}

Then run this script:

cd modules/sns
ln -s /home/bob/terraform/variables.tf variables.tf
cd ../ssm/
ln -s /home/bob/terraform/variables.tf variables.tf
cd ../stepfunctions/
ln -s /home/bob/terraform/variables.tf variables.tf
1 Like

I tried it and it works. Thank you @raymond.baoly

1 Like

I’m still getting the same error, and my code is almost the same as from @raymond.baoly . I want to learn, I don’t want to just copy. Can anyone figure out what is wrong with my code?

I wonder if the tests are too strict. The task text says nothing about a specific role name. The text says to make both role and policy, but @raymond.baoly 's code has nothing about a policy. I even found a good alternate aws_sfn_state_machine code that seems to give the same output.

I used this AWS CLI:

aws stepfunctions start-exectution --state-machine-arn arn:aws:states:us-east-1:000000000000:stateMachine:xfusion-stepfunction
aws stepfunctions describe-execution --execution-arn arn:aws:states:us-east-1:000000000000:execution:xfusion-stepfunction:<random_hex_numbers>

My output from execution through AWS CLI:

    "output": "{\"SnsArn\":\"arn:aws:sns:us-east-1:000000000000:devops-sns-topic\"}",

@raymond.baoly 's output from execution through AWS CLI:

    "output": "{\"SnsArn\":\"arn:aws:sns:us-east-1:000000000000:xfusion-sns-topic\"}",

The current version of my code:

#!/bin/bash

mkdir -p modules/sns modules/ssm modules/stepfunctions

cat << EOF > variables.tf
variable "KKE_SNS_TOPIC_NAME" {
  type = string
}

variable "KKE_SSM_PARAM_NAME" {
  type = string
}

variable "KKE_STEP_FUNCTION_NAME" {
  type = string
}
EOF

ln -s /home/bob/terraform/variables.tf modules/sns/variables.tf
ln -s /home/bob/terraform/variables.tf modules/ssm/variables.tf
ln -s /home/bob/terraform/variables.tf modules/stepfunctions/variables.tf

cat << EOF > terraform.tfvars
KKE_SNS_TOPIC_NAME = "xfusion-sns-topic"
KKE_SSM_PARAM_NAME = "xfusion-param"
KKE_STEP_FUNCTION_NAME = "xfusion-stepfunction"
EOF

cat << EOF > outputs.tf
output "kke_sns_topic_name" {
  value = module.sns.kke_sns_topic_name
}

output "kke_ssm_parameter_name" {
  value = module.ssm.kke_ssm_parameter_name
}

output "kke_step_function_name" {
  value = module.stepfunctions.kke_step_function_name
}
EOF

cat << EOF > main.tf
module "sns" {
  source = "./modules/sns"

  KKE_SNS_TOPIC_NAME = var.KKE_SNS_TOPIC_NAME
  KKE_SSM_PARAM_NAME = var.KKE_SSM_PARAM_NAME
  KKE_STEP_FUNCTION_NAME = var.KKE_STEP_FUNCTION_NAME
}

module "ssm" {
  source = "./modules/ssm"

  KKE_SNS_TOPIC_NAME = var.KKE_SNS_TOPIC_NAME
  KKE_SSM_PARAM_NAME = var.KKE_SSM_PARAM_NAME
  KKE_STEP_FUNCTION_NAME = var.KKE_STEP_FUNCTION_NAME

  depends_on = [module.sns]
}

module "stepfunctions" {
  source = "./modules/stepfunctions"

  KKE_SNS_TOPIC_NAME = var.KKE_SNS_TOPIC_NAME
  KKE_SSM_PARAM_NAME = var.KKE_SSM_PARAM_NAME
  KKE_STEP_FUNCTION_NAME = var.KKE_STEP_FUNCTION_NAME

  depends_on = [module.ssm]
}
EOF

cat << EOF > modules/sns/outputs.tf
output "kke_sns_topic_name" {
  value = aws_sns_topic.KKE_SNS_TOPIC_NAME.name
}
EOF

cat << EOF > modules/ssm/outputs.tf
output "kke_ssm_parameter_name" {
  value = aws_ssm_parameter.KKE_SSM_PARAM_NAME.name
}
EOF

cat << EOF > modules/stepfunctions/outputs.tf
output "kke_step_function_name" {
  value = aws_sfn_state_machine.KKE_STEP_FUNCTION_NAME.name
}
EOF

cat << EOF > modules/sns/main.tf
resource "aws_sns_topic" "KKE_SNS_TOPIC_NAME" {
  name = var.KKE_SNS_TOPIC_NAME
}
EOF

cat << EOF > modules/ssm/main.tf
resource "aws_ssm_parameter" "KKE_SSM_PARAM_NAME" {
  name  = var.KKE_SSM_PARAM_NAME
  type  = "String"
  value = "arn:aws:sns:us-east-1:000000000000:\${var.KKE_SNS_TOPIC_NAME}"
}
EOF

cat << EOF > modules/stepfunctions/main.tf
data "aws_ssm_parameter" "sns_param" {
  name = var.KKE_SSM_PARAM_NAME
}

resource "aws_iam_role" "KKE_STEP_FUNCTION_NAME" {
  name = "\${var.KKE_STEP_FUNCTION_NAME}-role"

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

# resource "aws_iam_policy" "KKE_STEP_FUNCTION_NAME" {
#   name = var.KKE_STEP_FUNCTION_NAME
#   policy = jsonencode({
#     Version = "2012-10-17"
#     Statement = [
#       {
#         Action = "ssm:GetParameter"
#         Effect = "Allow"
#         Resource = "*"
#       },
#     ]
#   })
# }

# resource "aws_iam_role_policy_attachment" "KKE_STEP_FUNCTION_NAME" {
#   role       = aws_iam_role.KKE_STEP_FUNCTION_NAME.name
#   policy_arn = aws_iam_policy.KKE_STEP_FUNCTION_NAME.arn
# }

resource "aws_sfn_state_machine" "KKE_STEP_FUNCTION_NAME" {
  name     = var.KKE_STEP_FUNCTION_NAME
  role_arn = aws_iam_role.KKE_STEP_FUNCTION_NAME.arn

  definition = jsonencode({
    StartAt = "ReadSSM"
    States = {
      ReadSSM = {
        Type   = "Pass"
        Result = {
          SnsArn = data.aws_ssm_parameter.sns_param.value
        }
        End = true
      }
    }
  })
}
EOF