fivetran / terraform-provider-fivetran

Terraform Provider for Fivetran
https://fivetran.com
Apache License 2.0
40 stars 23 forks source link

fivetran_destination output fivetran_destination.name.config.public_key is blank for redshift #274

Closed ann8ty closed 6 months ago

ann8ty commented 6 months ago

Describe the bug The fivetran_destination output public_key is now blank. Can confirm in the fivetran web UI there is a public key for this destination (and the value matches what is currently stored in the secret version).

attempting to upgrade to v1.1.16 but cannot due to this blocker

Doc: https://registry.terraform.io/providers/fivetran/fivetran/latest/docs/resources/destination

To Reproduce Provide an example .tf configuration

snippet creates fivetran destination (it is already existing)

resource "fivetran_destination" "destination_redshift" {
  group_id           = fivetran_group.group_for_everything.id
  service            = "redshift"
  time_zone_offset   = "0"            
  region             = "GCP_US_EAST4" 
  trust_certificates = "true"
  trust_fingerprints = "true"
  run_setup_tests    = "true"

  config {
    tunnel_host     = data.aws_cloudformation_export.bastion_elastic_ip_export.value
    tunnel_port     = 22
    tunnel_user     = "fivetran"
    host            = local.redshift_host
    port            = 5439
    auth_type       = "PASSWORD"
    user            = jsondecode(data.aws_secretsmanager_secret_version.fivetran_database_user_secret.secret_string)["username"]
    password        = jsondecode(data.aws_secretsmanager_secret_version.fivetran_database_user_secret.secret_string)["password"]
    database        = var.redshift_database
    connection_type = "SshTunnel"
    cluster_region  = "us-east-2"
  }

}

snippet saves public key to aws secrets manager for use with bastion automation this code previously worked, but with v1.1.16 the config.public_key is empty

# write the public key to a secret
resource "aws_secretsmanager_secret" "fivetran_public_key_secret" {
  name        = "${local.app_env}-fivetran-${var.environment}-${local.schema_name}" 
  description = "${local.app_env} public key for fivetran ssh bastion"
  tags        = var.tags
}

resource "aws_secretsmanager_secret_version" "fivetran_public_key" {
  secret_id     = aws_secretsmanager_secret.fivetran_public_key_secret.id
  secret_string = fivetran_destination.destination_redshift_datainfra_v2.config.public_key
}

output "fivetran_public_key" {
  description = "fivetran_public_key"
  value = nonsensitive(fivetran_destination.destination_redshift_datainfra_v2.config.public_key)
  sensitive = true
}

run terraform output fivetran_public_key after plan, apply to see that public_key is empty

in v1.1.10 the code for config was indexed like this:

resource "aws_secretsmanager_secret_version" "fivetran_public_key" {
  secret_id     = aws_secretsmanager_secret.fivetran_public_key_secret.id
  secret_string = fivetran_destination.destination_redshift_datainfra_v2.config[0].public_key
}

Expected behavior public_key should have value

Logs & Output Provide terraform CLI output on plan | apply. If it is possible, please, refer to this guide to enable debug output.

sanitized plan output

tf-fivetran-group $ AWS_PROFILE="xxx" terraform plan -var-file="./$ENVIROMENT_LONG_NAME/$CDK_PREFIX.tfvars" -out=.terraform/$CDK_PREFIX.out

fivetran_group.group_for_everything: Refreshing state... [id=xxx]
data.aws_cloudformation_export.fivetran_redshift_user_export_secret_arn: Reading...
data.aws_cloudformation_export.bastion_elastic_ip_export: Reading...
aws_ssm_parameter.ssm_fivetran_group_id_external_id_data_account: Refreshing state... [id=/xxx-xxx-v2/schema-v2/fivetranGroupId]
aws_secretsmanager_secret.fivetran_public_key_secret: Refreshing state... [id=arn:aws:secretsmanager:xxx:xxx:secret:xxx-xxx-v2-fivetran-sandbox-schema-v2-xxx]
data.aws_cloudformation_export.fivetran_redshift_user_export_secret_arn: Read complete after 0s [id=cloudformation-exports-xxx-xxx-xxx-v2-tf-fivetran-secret-arn]
data.aws_secretsmanager_secret.fivetran_database_user_secret_by_arn: Reading...
data.aws_cloudformation_export.bastion_elastic_ip_export: Read complete after 0s [id=cloudformation-exports-xxx-xxx-bastions-v2-tf-fivetran-group-elastic-ip]
aws_ssm_parameter.ssm_fivetran_group_id_external_id_app_account: Refreshing state... [id=/xxx-xxx-v2/schema-v2/appenvironment/fivetranGroupId]
data.aws_secretsmanager_secret.fivetran_database_user_secret_by_arn: Read complete after 0s [id=arn:aws:secretsmanager:xxx:xxx:secret:xxxxxxv2fivetranserv-xxx-xxx]
data.aws_secretsmanager_secret_version.fivetran_database_user_secret: Reading...
data.aws_secretsmanager_secret_version.fivetran_database_user_secret: Read complete after 0s [id=arn:aws:secretsmanager:xxx:xxx:secret:xxxxxxv2fivetranserv-xxx-xxx|AWSCURRENT]
fivetran_destination.destination_redshift_xxx_v2: Refreshing state... [id=xxx]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_secretsmanager_secret_version.fivetran_public_key will be created
  + resource "aws_secretsmanager_secret_version" "fivetran_public_key" {
      + arn            = (known after apply)
      + id             = (known after apply)
      + secret_id      = "arn:aws:secretsmanager:xxx:xxx:secret:xxx-xxx-v2-fivetran-sandbox-schema-v2-xxx"
      + version_id     = (known after apply)
      + version_stages = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Saved the plan to: .terraform/xxx.out

To perform exactly these actions, run the following command to apply:
    terraform apply ".terraform/xxx.out"

shows that terraform thinks the public key. has changed (it has, it is now blank, which is not good!)

then apply fails because... its blank

~/tf-fivetran-group $ AWS_PROFILE="xxx" terraform apply .terraform/$CDK_PREFIX.out                                                           

aws_secretsmanager_secret_version.fivetran_public_key: Creating...
╷
│ Error: putting Secrets Manager Secret value: InvalidRequestException: You must provide either SecretString or SecretBinary.
│ 
│   with aws_secretsmanager_secret_version.fivetran_public_key,
│   on bastion.tf line 26, in resource "aws_secretsmanager_secret_version" "fivetran_public_key":
│   26: resource "aws_secretsmanager_secret_version" "fivetran_public_key" {
│ 
╵

Plugin version: v1.1.16

Additional context

I wanted to see if this public_key was blank for a new redshift destination as well, and it is. So this problem exists both for an existing destination, and a new destination. You can ignore the bastion complaining about auth failures, the important bit is │ Error: putting Secrets Manager Secret value: InvalidRequestException: You must provide either SecretString or SecretBinary. indicating the public key is empty.

(.venv) ~/tf-fivetran-group $ AWS_PROFILE="xxx" terraform plan -var-file="./$ENVIROMENT_LONG_NAME/$CDK_PREFIX.tfvars" -out=.terraform/$CDK_PREFIX.out

fivetran_group.group_for_everything: Refreshing state... [id=xxx]
data.aws_cloudformation_export.bastion_elastic_ip_export: Reading...
data.aws_cloudformation_export.fivetran_redshift_user_export_secret_arn: Reading...
aws_secretsmanager_secret.fivetran_public_key_secret: Refreshing state... [id=arn:aws:secretsmanager:xxx:xxx:secret:xxx-xxx-v2-fivetran-sandbox-schema-v2-xxx]
aws_ssm_parameter.ssm_fivetran_group_id_external_id_data_account: Refreshing state... [id=/xxx-xxx-v2/schema-v2/fivetranGroupId]
data.aws_cloudformation_export.bastion_elastic_ip_export: Read complete after 1s [id=cloudformation-exports-xxx-xxx-bastions-v2-tf-fivetran-group-elastic-ip]
data.aws_cloudformation_export.fivetran_redshift_user_export_secret_arn: Read complete after 1s [id=cloudformation-exports-xxx-xxx-xxx-v2-tf-fivetran-secret-arn]
data.aws_secretsmanager_secret.fivetran_database_user_secret_by_arn: Reading...
aws_ssm_parameter.ssm_fivetran_group_id_external_id_app_account: Refreshing state... [id=/xxx-xxx-v2/schema-v2/appenvironment/fivetranGroupId]
data.aws_secretsmanager_secret.fivetran_database_user_secret_by_arn: Read complete after 0s [id=arn:aws:secretsmanager:xxx:xxx:secret:xxxxxxv2fivetranserv-xxx-xxx]
data.aws_secretsmanager_secret_version.fivetran_database_user_secret: Reading...
data.aws_secretsmanager_secret_version.fivetran_database_user_secret: Read complete after 0s [id=arn:aws:secretsmanager:xxx:xxx:secret:xxxxxxv2fivetranserv-xxx-xxx|AWSCURRENT]
fivetran_destination.destination_redshift_xxx_v2: Refreshing state... [id=xxx]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_secretsmanager_secret.fivetran_public_key_secret_16 will be created
  + resource "aws_secretsmanager_secret" "fivetran_public_key_secret_16" {
      + arn                            = (known after apply)
      + description                    = "xxx-xxx-v2 public key for fivetran ssh bastion"
      + force_overwrite_replica_secret = false
      + id                             = (known after apply)
      + name                           = "xxx-xxx-v2-fivetran-sandbox-schema-v2_16"
      + name_prefix                    = (known after apply)
      + policy                         = (known after apply)
      + recovery_window_in_days        = 30
      + tags                           = {
          + "Billing"      = "data"
          + "Component"    = "tf-fivetran-group"
          + "Environment"  = "sandbox"
          + "Orchestrator" = "Terraform"
        }
      + tags_all                       = {
          + "Billing"      = "data"
          + "Component"    = "tf-fivetran-group"
          + "Environment"  = "sandbox"
          + "Orchestrator" = "Terraform"
        }
    }

  # aws_secretsmanager_secret_version.fivetran_public_key will be created
  + resource "aws_secretsmanager_secret_version" "fivetran_public_key" {
      + arn            = (known after apply)
      + id             = (known after apply)
      + secret_id      = "arn:aws:secretsmanager:xxx:xxx:secret:xxx-xxx-v2-fivetran-sandbox-schema-v2-xxx"
      + version_id     = (known after apply)
      + version_stages = (known after apply)
    }

  # aws_secretsmanager_secret_version.fivetran_public_key_16 will be created
  + resource "aws_secretsmanager_secret_version" "fivetran_public_key_16" {
      + arn            = (known after apply)
      + id             = (known after apply)
      + secret_id      = (known after apply)
      + secret_string  = (sensitive value)
      + version_id     = (known after apply)
      + version_stages = (known after apply)
    }

  # fivetran_destination.destination_redshift_xxx_v2_16 will be created
  + resource "fivetran_destination" "destination_redshift_xxx_v2_16" {
      + group_id           = (known after apply)
      + id                 = (known after apply)
      + region             = "GCP_US_EAST4"
      + run_setup_tests    = true
      + service            = "redshift"
      + setup_status       = (known after apply)
      + time_zone_offset   = "0"
      + trust_certificates = true
      + trust_fingerprints = true

      + config {
          + always_encrypted         = (known after apply)
          + auth                     = (known after apply)
          + auth_type                = "PASSWORD"
          + cloud_provider           = (known after apply)
          + cluster_region           = "xxx"
          + connection_method        = (known after apply)
          + connection_type          = "SshTunnel"
          + create_external_tables   = (known after apply)
          + data_format              = (known after apply)
          + database                 = "dbname"
          + enable_remote_execution  = (known after apply)
          + external_id              = (known after apply)
          + host                     = "xxx-redshift.sandbox.xxx"
          + is_private_key_encrypted = (known after apply)
          + is_private_link_required = (known after apply)
          + is_redshift_serverless   = (known after apply)
          + num_of_partitions        = (known after apply)
          + password                 = (sensitive value)
          + port                     = 5439
          + public_key               = (known after apply)
          + replication_factor       = (known after apply)
          + sasl_mechanism           = (known after apply)
          + schema_compatibility     = (known after apply)
          + schema_registry          = (known after apply)
          + security_protocol        = (known after apply)
          + snowflake_cloud          = (known after apply)
          + tunnel_host              = "xxx"
          + tunnel_port              = 22
          + tunnel_user              = "user"
          + user                     = (sensitive value)
        }
    }

  # fivetran_group.group_for_everything_16 will be created
  + resource "fivetran_group" "group_for_everything_16" {
      + created_at   = (known after apply)
      + id           = (known after apply)
      + last_updated = (known after apply)
      + name         = "xxx_xxx_v2_redshift_schema_v2_16"
    }

Plan: 5 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + fivetran_public_key = (sensitive value)

───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Saved the plan to: .terraform/xxx.out

To perform exactly these actions, run the following command to apply:
    terraform apply ".terraform/xxx.out"
(.venv) ~tf-fivetran-group $ AWS_PROFILE="xxx" terraform apply .terraform/$CDK_PREFIX.out                                                           

fivetran_group.group_for_everything_16: Creating...
aws_secretsmanager_secret_version.fivetran_public_key: Creating...
aws_secretsmanager_secret.fivetran_public_key_secret_16: Creating...
fivetran_group.group_for_everything_16: Creation complete after 1s [id=region_propensity]
fivetran_destination.destination_redshift_xxx_v2_16: Creating...
aws_secretsmanager_secret.fivetran_public_key_secret_16: Creation complete after 0s [id=arn:aws:secretsmanager:xxx:xxx:secret:xxx-xxx-v2-fivetran-sandbox-schema-v2_16-zV1tXZ]
fivetran_destination.destination_redshift_xxx_v2_16: Still creating... [10s elapsed]
fivetran_destination.destination_redshift_xxx_v2_16: Still creating... [20s elapsed]
fivetran_destination.destination_redshift_xxx_v2_16: Still creating... [30s elapsed]
fivetran_destination.destination_redshift_xxx_v2_16: Creation complete after 39s [id=region_propensity]
aws_secretsmanager_secret_version.fivetran_public_key_16: Creating...
aws_secretsmanager_secret_version.fivetran_public_key_16: Creation complete after 0s [id=arn:aws:secretsmanager:xxx:xxx:secret:xxx-xxx-v2-fivetran-sandbox-schema-v2_16-zV1tXZ|terraform-20240314161413184500000003]
╷
│ Warning: Setup Tests for destination failed on creation. Running post-creation attempt.
│ 
│   with fivetran_destination.destination_redshift_xxx_v2_16,
│   on destination.tf line 35, in resource "fivetran_destination" "destination_redshift_xxx_v2_16":
│   35: resource "fivetran_destination" "destination_redshift_xxx_v2_16" {
│ 
│ [{Validating cluster region PASSED } {Verify Host/Cluster details SKIPPED } {Connecting to SSH tunnel FAILED SSH_MSG_DISCONNECT: 2 Too many authentication failures }]
╵
╷
│ Warning: Setup Tests for destination failed.
│ 
│   with fivetran_destination.destination_redshift_xxx_v2_16,
│   on destination.tf line 35, in resource "fivetran_destination" "destination_redshift_xxx_v2_16":
│   35: resource "fivetran_destination" "destination_redshift_xxx_v2_16" {
│ 
│ [{Connecting to SSH tunnel FAILED SSH_MSG_DISCONNECT: 2 Too many authentication failures } {Validating cluster region PASSED } {Verify Host/Cluster details SKIPPED }]
╵
╷
│ Error: putting Secrets Manager Secret value: InvalidRequestException: You must provide either SecretString or SecretBinary.
│ 
│   with aws_secretsmanager_secret_version.fivetran_public_key,
│   on bastion.tf line 26, in resource "aws_secretsmanager_secret_version" "fivetran_public_key":
│   26: resource "aws_secretsmanager_secret_version" "fivetran_public_key" {
│ 
╵
ann8ty commented 6 months ago

ok, my new theory is that this issue is actually caused by https://github.com/fivetran/terraform-provider-fivetran/issues/253 which between 1.1.10 and 1.1.16 i need to change SSHTunnel to SshTunnel. this worked for my dev and I am now testing on other environments:

yes, this resolved it.