DontShaveTheYak / cf2tf

Convert Cloudformation templates to Terraform.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ValueError: Fn::Split not allowed to be nested in None.

mcrowley-axcess opened this issue · comments

Template: https://s3.amazonaws.com/aws-transfer-resources/custom-idp-templates/aws-transfer-custom-idp-secrets-manager-sourceip-protocol-support-apig.zip

Environment:
Python 3.10.12

Traceback (most recent call last):
File "/home/localuser1/.local/bin/cf2tf", line 8, in
sys.exit(cli())
File "/usr/local/lib/python3.10/dist-packages/click/core.py", line 1157, in call
return self.main(*args, **kwargs)
File "/usr/local/lib/python3.10/dist-packages/click/core.py", line 1078, in main
rv = self.invoke(ctx)
File "/usr/local/lib/python3.10/dist-packages/click/core.py", line 1434, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/usr/local/lib/python3.10/dist-packages/click/core.py", line 783, in invoke
return __callback(*args, **kwargs)
File "/home/localuser1/.local/lib/python3.10/site-packages/cf2tf/app.py", line 44, in cli
config = TemplateConverter(tmpl_path.stem, cf_template, search_manger).convert()
File "/home/localuser1/.local/lib/python3.10/site-packages/cf2tf/convert.py", line 97, in convert
tf_resources = self.convert_to_tf(self.manifest)
File "/home/localuser1/.local/lib/python3.10/site-packages/cf2tf/convert.py", line 144, in convert_to_tf
tf_resources.extend(converter(resources))
File "/home/localuser1/.local/lib/python3.10/site-packages/cf2tf/convert.py", line 344, in convert_resources
resolved_values = self.resolve_values(
File "/home/localuser1/.local/lib/python3.10/site-packages/cf2tf/convert.py", line 176, in resolve_values
data[key] = self.resolve_values(
File "/home/localuser1/.local/lib/python3.10/site-packages/cf2tf/convert.py", line 206, in resolve_values
value = self.resolve_values(
File "/home/localuser1/.local/lib/python3.10/site-packages/cf2tf/convert.py", line 217, in resolve_values
resolved_list_values = [
File "/home/localuser1/.local/lib/python3.10/site-packages/cf2tf/convert.py", line 218, in
self.resolve_values(item, allowed_func, prev_func) for item in data
File "/home/localuser1/.local/lib/python3.10/site-packages/cf2tf/convert.py", line 176, in resolve_values
data[key] = self.resolve_values(
File "/home/localuser1/.local/lib/python3.10/site-packages/cf2tf/convert.py", line 204, in resolve_values
raise ValueError(f"{key} not allowed to be nested in {prev_func}.")
ValueError: Fn::Split not allowed to be nested in None.

commented

This has been fixed in release v0.7.0. You can upgrade with pip install -U cf2tf

Here is your converted template:

data "aws_caller_identity" "current" {}

data "aws_partition" "current" {}

data "aws_region" "current" {}

locals {
  CreateServer = var.create_server == "true"
  NotCreateServer = !local.CreateServer
  SecretsManagerRegionProvided = !var.secrets_manager_region == ""
  TransferVPCEndpoint = var.transfer_endpoint_type == "VPC"
  stack_id = uuidv5("dns", "testing")
}

variable create_server {
  description = "Whether this stack creates an AWS Transfer endpoint or not. If the endpoint is created as part of the stack, the custom identity provider is automatically associated with it."
  type = string
  default = "true"
}

variable secrets_manager_region {
  description = "(Optional) The region the secrets are stored in. If this value is not provided, the region this stack is deployed in will be used. Use this field if you are deploying this stack in a region where SecretsManager is not available."
  type = string
}

variable transfer_endpoint_type {
  description = "Select PUBLIC if you want a public facing AWS Transfer endpoint or VPC if you want a VPC based endpoint. Note that only SFTP and FTPS are supported on public endpoints."
  type = string
  default = "PUBLIC"
}

variable transfer_subnet_i_ds {
  description = "Required if launching a VPC endpoint. Comma-separated list of subnets that you would like the AWS Transfer endpoint to be provisioned into."
  type = string
}

variable transfer_vpcid {
  description = "Required if launching a VPC endpoint. The VPC ID that you would like the AWS Transfer endpoint to be provisioned into."
  type = string
}

resource "aws_transfer_server" "transfer_server" {
  count = local.CreateServer ? 1 : 0
  endpoint_type = var.transfer_endpoint_type
  endpoint_details {
    // CF Property(InvocationRole) = aws_iam_role.transfer_identity_provider_role.arn
    // CF Property(Url) = join("", ["https://", aws_api_gateway_rest_api.custom_identity_provider_api.arn, ".execute-api.", data.aws_region.current.name, ".", data.aws_partition.current.dns_suffix, "/", aws_api_gateway_stage.api_stage.arn])
  }
  identity_provider_type = "API_GATEWAY"
  logging_role = aws_iam_role.transfer_cw_logging_role.arn
}

resource "aws_iam_role" "transfer_cw_logging_role" {
  count = local.CreateServer ? 1 : 0
  assume_role_policy = {
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Principal = {
          Service = [
            "transfer.amazonaws.com"
          ]
        }
        Action = [
          "sts:AssumeRole"
        ]
      }
    ]
  }
  managed_policy_arns = [
    "arn:${data.aws_partition.current.partition}:iam::aws:policy/service-role/AWSTransferLoggingAccess"
  ]
}

resource "aws_api_gateway_rest_api" "custom_identity_provider_api" {
  name = "Transfer Family Secrets Manager Integration API"
  description = "API used for Transfer Family to access user information in Secrets Manager"
  fail_on_warnings = true
  endpoint_configuration {
    types = [
      "REGIONAL"
    ]
  }
}

resource "aws_iam_role" "lambda_execution_role" {
  assume_role_policy = {
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Principal = {
          Service = [
            "lambda.amazonaws.com"
          ]
        }
        Action = [
          "sts:AssumeRole"
        ]
      }
    ]
  }
  managed_policy_arns = [
    "arn:${data.aws_partition.current.partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
  ]
  force_detach_policies = [
    {
      PolicyName = "LambdaSecretsPolicy"
      PolicyDocument = {
        Version = "2012-10-17"
        Statement = [
          {
            Effect = "Allow"
            Action = [
              "secretsmanager:GetSecretValue"
            ]
            Resource = "arn:${data.aws_partition.current.partition}:secretsmanager:${local.SecretsManagerRegionProvided ? var.secrets_manager_region : data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:secret:aws/transfer/*"
          }
        ]
      }
    }
  ]
}

resource "aws_iam_role" "api_cloud_watch_logs_role" {
  assume_role_policy = {
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Principal = {
          Service = [
            "apigateway.amazonaws.com"
          ]
        }
        Action = [
          "sts:AssumeRole"
        ]
      }
    ]
  }
  force_detach_policies = [
    {
      PolicyName = "ApiGatewayLogsPolicy"
      PolicyDocument = {
        Version = "2012-10-17"
        Statement = [
          {
            Effect = "Allow"
            Action = [
              "logs:CreateLogGroup",
              "logs:CreateLogStream",
              "logs:DescribeLogGroups",
              "logs:DescribeLogStreams",
              "logs:DescribeQueries",
              "logs:FilterLogEvents",
              "logs:GetLogEvents",
              "logs:GetLogGroupFields",
              "logs:GetLogRecord",
              "logs:GetQueryResults",
              "logs:PutLogEvents",
              "logs:StartQuery",
              "logs:StopQuery"
            ]
            Resource = "*"
          }
        ]
      }
    }
  ]
}

resource "aws_api_gateway_account" "api_logging_account" {
  cloudwatch_role_arn = aws_iam_role.api_cloud_watch_logs_role.arn
}

resource "aws_api_gateway_stage" "api_stage" {
  deployment_id = aws_api_gateway_deployment.api_deployment202008.id
  // CF Property(MethodSettings) = [
  //   {
  //     DataTraceEnabled = false
  //     HttpMethod = "*"
  //     LoggingLevel = "INFO"
  //     ResourcePath = "/*"
  //   }
  // ]
  rest_api_id = aws_api_gateway_rest_api.custom_identity_provider_api.arn
  stage_name = "prod"
}

resource "aws_api_gateway_deployment" "api_deployment202008" {
  rest_api_id = aws_api_gateway_rest_api.custom_identity_provider_api.arn
}

resource "aws_iam_role" "transfer_identity_provider_role" {
  assume_role_policy = {
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Principal = {
          Service = "transfer.amazonaws.com"
        }
        Action = [
          "sts:AssumeRole"
        ]
      }
    ]
  }
  force_detach_policies = [
    {
      PolicyName = "TransferCanInvokeThisApi"
      PolicyDocument = {
        Version = "2012-10-17"
        Statement = [
          {
            Effect = "Allow"
            Action = [
              "execute-api:Invoke"
            ]
            Resource = "arn:${data.aws_partition.current.partition}:execute-api:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:${aws_api_gateway_rest_api.custom_identity_provider_api.arn}/prod/GET/*"
          }
        ]
      }
    },
    {
      PolicyName = "TransferCanReadThisApi"
      PolicyDocument = {
        Version = "2012-10-17"
        Statement = [
          {
            Effect = "Allow"
            Action = [
              "apigateway:GET"
            ]
            Resource = "*"
          }
        ]
      }
    }
  ]
}

resource "aws_emrserverless_application" "get_user_config_lambda" {
  // CF Property(CodeUri) = "src/"
  // CF Property(Description) = "A function to lookup and return user data from AWS Secrets Manager."
  // CF Property(Handler) = "index.lambda_handler"
  // CF Property(Role) = aws_iam_role.lambda_execution_role.arn
  // CF Property(Runtime) = "python3.11"
  // CF Property(Environment) = {
  //   Variables = {
  //     SecretsManagerRegion = local.SecretsManagerRegionProvided ? var.secrets_manager_region : data.aws_region.current.name
  //   }
  // }
}

resource "aws_lambda_permission" "get_user_config_lambda_permission" {
  action = "lambda:invokeFunction"
  function_name = aws_emrserverless_application.get_user_config_lambda.arn
  principal = "apigateway.amazonaws.com"
  source_arn = "arn:${data.aws_partition.current.partition}:execute-api:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:${aws_api_gateway_rest_api.custom_identity_provider_api.arn}/*"
}

resource "aws_api_gateway_resource" "servers_resource" {
  rest_api_id = aws_api_gateway_rest_api.custom_identity_provider_api.arn
  parent_id = aws_api_gateway_rest_api.custom_identity_provider_api.root_resource_id
  path_part = "servers"
}

resource "aws_api_gateway_resource" "server_id_resource" {
  rest_api_id = aws_api_gateway_rest_api.custom_identity_provider_api.arn
  parent_id = aws_api_gateway_resource.servers_resource.id
  path_part = "{serverId}"
}

resource "aws_api_gateway_resource" "users_resource" {
  rest_api_id = aws_api_gateway_rest_api.custom_identity_provider_api.arn
  parent_id = aws_api_gateway_resource.server_id_resource.id
  path_part = "users"
}

resource "aws_api_gateway_resource" "user_name_resource" {
  rest_api_id = aws_api_gateway_rest_api.custom_identity_provider_api.arn
  parent_id = aws_api_gateway_resource.users_resource.id
  path_part = "{username}"
}

resource "aws_api_gateway_resource" "get_user_config_resource" {
  rest_api_id = aws_api_gateway_rest_api.custom_identity_provider_api.arn
  parent_id = aws_api_gateway_resource.user_name_resource.id
  path_part = "config"
}

resource "aws_api_gateway_method" "get_user_config_request" {
  authorization = "AWS_IAM"
  http_method = "GET"
  // CF Property(Integration) = {
  //   Type = "AWS"
  //   IntegrationHttpMethod = "POST"
  //   Uri = join("", ["arn:", data.aws_partition.current.partition, ":apigateway:", data.aws_region.current.name, ":lambda:path/2015-03-31/functions/", aws_emrserverless_application.get_user_config_lambda.arn, "/invocations"])
  //   IntegrationResponses = [
  //     {
  //       StatusCode = 200
  //     }
  //   ]
  //   RequestTemplates = {
  //     application/json = "{
  //   "username": "$util.urlDecode($input.params('username'))",
  //   "password": "$util.escapeJavaScript($input.params('Password')).replaceAll("\\'","'")",
  //   "protocol": "$input.params('protocol')",
  //   "serverId": "$input.params('serverId')",
  //   "sourceIp": "$input.params('sourceIp')"
  // }
  // "
  //   }
  // }
  request_parameters = {
    method.request.header.Password = false
  }
  resource_id = aws_api_gateway_resource.get_user_config_resource.id
  rest_api_id = aws_api_gateway_rest_api.custom_identity_provider_api.arn
  // CF Property(MethodResponses) = [
  //   {
  //     StatusCode = 200
  //     ResponseModels = {
  //       application/json = "UserConfigResponseModel"
  //     }
  //   }
  // ]
}

resource "aws_api_gateway_model" "get_user_config_response_model" {
  rest_api_id = aws_api_gateway_rest_api.custom_identity_provider_api.arn
  content_type = "application/json"
  description = "API response for GetUserConfig"
  name = "UserConfigResponseModel"
  schema = {
    $schema = "http://json-schema.org/draft-04/schema#"
    title = "UserUserConfig"
    type = "object"
    properties = {
      HomeDirectory = {
        type = "string"
      }
      Role = {
        type = "string"
      }
      Policy = {
        type = "string"
      }
      PublicKeys = {
        type = "array"
        items = {
          type = "string"
        }
      }
    }
  }
}

output "server_id" {
  value = aws_transfer_server.transfer_server.id
}

output "stack_arn" {
  value = local.stack_id
}

output "transfer_identity_provider_url" {
  description = "URL to pass to AWS Transfer CreateServer call as part of optional IdentityProviderDetails"
  value = join("", ["https://", aws_api_gateway_rest_api.custom_identity_provider_api.arn, ".execute-api.", data.aws_region.current.name, ".", data.aws_partition.current.dns_suffix, "/", aws_api_gateway_stage.api_stage.arn])
}

output "transfer_identity_provider_invocation_role" {
  description = "IAM Role to pass to AWS Transfer CreateServer call as part of optional IdentityProviderDetails"
  value = aws_iam_role.transfer_identity_provider_role.arn
}

Thank you! :) I manually rewrote the cf to tf for this one, but I will definitely keep this in my back pocket for the next one.