AWS RDS 代理不可用 - 如何调试?

AWS RDS Proxy unavailalbe - how to debug?

我已经使用 Terraform 创建了一个 RDS 代理。但是,它似乎没有用。

我的应用程序代码无法连接到代理(超时)并且 aws rds describe-db-proxy-targets 给出以下内容:

{
    "Targets": [
        {
            "Endpoint": "mydb.aaaaaaaaaaaa.eu-west-2.rds.amazonaws.com",
            "RdsResourceId": "mydb",
            "Port": 5432,
            "Type": "RDS_INSTANCE",
            "TargetHealth": {
                "State": "UNAVAILABLE",
                "Description": "DBProxy Target unavailable due to an internal error"
            }
        }
    ]
}

我该如何调试它?

这是代理的 Terraform 脚本。 RDS 实例在别处有描述,但正在运行。

data "aws_subnet" "mydb_rds" {
  filter {
    name   = "availability-zone"
    values = [ aws_db_instance.mydb.availability_zone ]
  }
}

resource "aws_secretsmanager_secret" "mydb_rds_proxy" {
  name = "mydb-rds-proxy"
}

resource "aws_secretsmanager_secret_version" "mydb_rds_proxy" {
  secret_id     = aws_secretsmanager_secret.mydb_rds_proxy.id
  secret_string = var.db_password
}

resource "aws_iam_role" "mydb_rds_proxy" {
  name = "mydb-rds-proxy"
  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Action": "sts:AssumeRole",
      "Effect": "Allow",
      "Principal": {
        "Service": "rds.amazonaws.com"
      }
    }
  ]
}
EOF
}

resource "aws_iam_policy" "mydb_rds_proxy_policy" {
  name = "mydb-rds-proxy"

  policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "GetSecretValue",
      "Action": [
        "secretsmanager:GetSecretValue"
      ],
      "Effect": "Allow",
      "Resource": [
        "${aws_secretsmanager_secret.mydb_rds_proxy.arn}"
      ]
    },
    {
      "Sid": "DecryptSecretValue",
      "Action": [
        "kms:Decrypt"
      ],
      "Effect": "Allow",
      "Resource": [
        "${aws_secretsmanager_secret.mydb_rds_proxy.arn}"
      ]
    }
  ]
}
EOF
}

resource "aws_iam_role_policy_attachment" "mydb_rds_proxy_policy_attachment" {
  role       = aws_iam_role.mydb_rds_proxy.name
  policy_arn = aws_iam_policy.mydb_rds_proxy_policy.arn
}

resource "aws_db_proxy" "mydb" {
  name                   = "mydb-rds-proxy"
  debug_logging          = false
  engine_family          = "POSTGRESQL"
  idle_client_timeout    = 1800
  require_tls            = true
  role_arn               = aws_iam_role.mydb_rds_proxy.arn
  vpc_security_group_ids = [ aws_security_group.mydb_rds.id ]
  vpc_subnet_ids         = [
    data.aws_subnet.mydb_rds.id,
    aws_default_subnet.subnet_a.id,
    aws_default_subnet.subnet_b.id
  ]

  auth {
    auth_scheme = "SECRETS"
    iam_auth    = "DISABLED"
    secret_arn  = aws_secretsmanager_secret.mydb_rds_proxy.arn
  }
}

resource "aws_db_proxy_default_target_group" "mydb" {
  db_proxy_name = aws_db_proxy.mydb.name

  connection_pool_config {
    connection_borrow_timeout    = 120
    max_connections_percent      = 100
    max_idle_connections_percent = 50
  }
}

resource "aws_db_proxy_target" "mydb" {
  db_instance_identifier = aws_db_instance.mydb.id
  db_proxy_name          = aws_db_proxy.mydb.name
  target_group_name      = aws_db_proxy_default_target_group.mydb.name
}

locals {
  proxied_pg_connection_string = "postgres://${aws_db_instance.mydb.username}:${var.db_password}@${aws_db_proxy.mydb.endpoint}:5432/postgres?client_encoding=UTF8"
}

您需要做几件事才能使其正常工作:

  • secret中存储的用户名/密码
  • 来自 Lambda 的安全组规则 -> RDS 代理
  • 来自 RDS 代理的安全组规则 -> RDS
  • RDS Proxy、Lambda 和 RDS 在同一个 VPC 中
  • RDS 代理角色可以访问机密

一个有用的调试查询是:

aws rds describe-db-proxy-targets --db-proxy-name <proxy-name>

要了解它返回的错误消息,请参阅 this page

用户名/密码是最难发现的,因为 Terraform 还不支持它。您需要做的是在 Terraform 中构造一个匹配 RDS Proxy 可以理解的内容的 JSON 字符串:

resource "aws_secretsmanager_secret_version" "my_db_proxy" {
  secret_id     = aws_secretsmanager_secret.my_db_proxy.id
  secret_string = jsonencode({
    "username"             = aws_db_instance.my_db.username
    "password"             = var.db_password
    "engine"               = "postgres"
    "host"                 = aws_db_instance.my_db.address
    "port"                 = 5432
    "dbInstanceIdentifier" = aws_db_instance.my_db.id
  })
}

然后您需要确保这些安全组规则允许端口 5432(对于 Postgres)上的 TCP 流量存在:

  • ingress Lambda 到 RDS 代理
  • ingress RDS 代理到 RDS
  • egress RDS 代理到 "0.0.0.0/0"

RDS 代理角色应具有如下策略:

resource "aws_iam_policy" "my_rds_proxy_policy" {
  name = "my-rds-proxy"

  policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Action": [
        "rds:*"
      ],
      "Effect": "Allow",
      "Resource": [
        "${aws_db_instance.my_db.arn}"
      ]
    },
    {
      "Sid": "GetSecretValue",
      "Action": [
        "secretsmanager:GetSecretValue"
      ],
      "Effect": "Allow",
      "Resource": [
        "${aws_secretsmanager_secret.my_rds_proxy.arn}"
      ]
    },
    {
      "Sid": "DecryptSecretValue",
      "Action": [
        "kms:Decrypt"
      ],
      "Effect": "Allow",
      "Resource": [
        "*"
      ]
    },
    {
      "Sid": "DecryptKms",
      "Effect": "Allow",
      "Action": "kms:Decrypt",
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "kms:ViaService": "secretsmanager.${var.aws_region}.amazonaws.com"
        }
      }
    }
  ]
}
EOF
}

祝你好运!