【问题标题】:Unable to access RDS Database via IAM Authentication无法通过 IAM 身份验证访问 RDS 数据库
【发布时间】:2018-06-16 17:19:30
【问题描述】:

我无法使用 IAM 用户连接到我的 RDS 数据库。

数据库用户名:master
IAM 用户:api-user

我已为用户分配了编程访问权限并向用户添加了以下策略:

自定义的rds-permission定义为:https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.IAMPolicy.html

    {
   "Version": "2012-10-17",
   "Statement": [
      {
         "Effect": "Allow",
         "Action": [
             "rds-db:connect"
         ],
         "Resource": [
             "arn:aws:rds-db:REGION:ACCOUNT-ID:USER:dbi-resource-id/DB_ACCOUNT_NAME"
         ]
      }
   ]
}

奇怪的是,即使我已经完全按照文档中的要求定义了我的自定义权限,它也无法识别:

当我尝试使用身份验证令牌(通过 golang)进行连接时,出现以下错误:

error: ERROR: Error 1045: Access denied for user 'master'@'x.x.x.189' (using password: YES)

我的政策似乎不起作用!

尽管这无关紧要,但这是我通过 IAM 用户进行连接的方式:

//Yes Env vars are available
//creating new credentials from environment variables
//AWS_ACCESS_KEY_ID  and  AWS_SECRET_ACCESS_KEY
awsCreds := credentials.NewEnvCredentials()

//creating authentication token for the database connection
authToken, err := rdsutils.BuildAuthToken(dbEndpoint, awsRegion, dbUser, awsCreds)
if err != nil {
    Logger.LogFatal("Unable to build Authentication Token")
    log.Fatal("Unable to build Authentication Token")  //todo remove
}

//setting up TLS
mysql.RegisterTLSConfig("custom", &tls.Config{
    InsecureSkipVerify: true,
})

// Creating the MySQL DNS string for the DB connection
// user:password@protocol(endpoint)/dbname?<params>
dnsStr := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s allowCleartextPasswords=true&tls=custom",
    dbUser, authToken, dbEndpoint,dbPort, dbName,
)
rootCertPool := x509.NewCertPool() //NewCertPool returns a new, empty CertPool.

pem, err := ioutil.ReadFile("rds-ca-bundle.pem") //reading the provided pem
if err != nil {
    log.Fatal("! Could not read certificates")
}
fmt.Println("Loading certificate seems to work")
//AppendCertsFromPEM attempts to parse a series of PEM encoded certificates.
//pushing in the pem
if ok := rootCertPool.AppendCertsFromPEM(pem); !ok {
    log.Fatal("Failed to append PEM.")
}
fmt.Println("Appending certificate seems to work too")

//setting up TLS
//we dont need a client ca?
mysql.RegisterTLSConfig("custom", &tls.Config{
    RootCAs: rootCertPool,
    InsecureSkipVerify: true,
})
database, err = sql.Open("mysql", dnsStr)

【问题讨论】:

  • 想必您已将RDS实例配置为允许IAM DB Authentication (docs.aws.amazon.com/AmazonRDS/latest/UserGuide/…)?
  • 您好!是的,我做到了。 - 我没有人可以帮助我,我已经坐了 4 天了。求你帮忙
  • @JulieNoobie 政策声明的资源显示您使用的是“us-west-2c”,它是 AZ。您能否将其修改为“us-east-2”,即您的 RDS 资源所在的区域,然后重试?
  • 您是否为您的 RDS 实例启用 IAM 身份验证?
  • @abigperson 这些标志可用于 CLI 而不是编程访问。

标签: amazon-web-services go amazon-rds


【解决方案1】:

根据适用于 Go 编程语言的 AWS Github 存储库中的示例,您需要创建如下凭证:

IAM ARN

参考:IAM authentication go example

import (
    "database/sql"
    "fmt"
    "log"
    "os"

    "github.com/go-sql-driver/mysql"

    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/credentials/stscreds"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/rds/rdsutils"
)

awsCreds := stscreds.NewCredentials(session.New(&aws.Config{Region: &awsRegion}), iamArn) 

// iamArn: arn:aws:rds-db:region:account-id:dbuser:dbi-resource-id/data‌​base-user-name

authToken, err := rdsutils.BuildAuthToken(dbEndpoint, awsRegion, dbUser, awsCreds)

我几乎可以肯定您缺少 IAM ARN 的那部分。


准备数据库用户

参考:Preparing a Database User

您需要连接到您的数据库并使用 AWS 身份验证插件创建用户。

以下 SQL 语句创建一个名为 lambda 的数据库用户。 AWSAuthenticationPlugin 不是指定密码,而是用于识别用户。替换为您要授予用户访问权限的数据库的名称。

CREATE USER 'master' IDENTIFIED WITH AWSAuthenticationPlugin as 'RDS';
GRANT ALL PRIVILEGES ON <DB_NAME>.* TO 'master'@'%';
FLUSH PRIVILEGES;

奖金推荐

参考:Limitations for IAM Database Authentication

我不知道在您的项目中使用 IAM 身份验证的目的是什么,但我认为 AWS 文档中的以下内容很重要:

IAM 数据库身份验证的限制

使用 IAM 数据库身份验证,您每秒最多只能有 20 个新连接。如果您使用的是 db.t2.micro 实例类,则限制为每秒 10 个连接。

Amazon RDS for MySQL 和 Aurora MySQL 数据库引擎对每秒的身份验证尝试没有任何限制。但是,当您使用 IAM 数据库身份验证时,您的应用程序必须生成身份验证令牌。然后,您的应用程序使用该令牌连接到数据库实例或集群。如果您超过每秒新连接的最大限制,那么 IAM 数据库身份验证的额外开销可能会导致连接限制。额外的开销甚至会导致现有连接断开。

我们建议如下:

  • 使用 IAM 数据库身份验证作为临时、个人访问数据库的机制。

  • 如果您的应用程序每秒需要超过 20 个新连接,请不要使用 IAM 数据库身份验证。

  • 仅对可以轻松重试的工作负载使用 IAM 数据库身份验证。

注意

有关 MySQL 的最大总连接数的信息,请参阅最大 MySQL 连接数。有关 Aurora MySQL 的最大总连接数的信息,请参阅 Aurora MySQL 数据库实例的最大连接数。

【讨论】:

  • 你好。我刚刚尝试了重制示例,但没有成功。我想我会选择一个替代方案。你能推荐我的任何身份验证方式吗?我应该硬编码密码吗?非常感谢你帮助我。
  • @JulieNoobie 你不需要硬编码密码。您可以使用通过环境变量传递主机名、端口、用户名和密码的常用方式进行身份验证。
  • 非常感谢。把你的比特币或以太坊钱包发给我。我会送你一份礼物。
  • 此时mysql限制为每秒256个新连接数(不是20个)。
  • @Ele 好的,经过一段时间的努力,我意识到他的回答部分错误!您提供的 iamArn 不正确,它应该是 您想假设的角色不是 iam 用户
【解决方案2】:

Ele 提供的答案部分错误这是正确的代码:

arn := "arn:aws:iam::00000000000:role/your-TaskRole"
awsCreds := stscreds.NewCredentials(session.New(&aws.Config{Region: aws.String(Region)}), arn)

所以arn 不是 iam db 用户之一,而是分配给您的资源(EC2、ECS、Fargate)的角色的 arn

请记住,您还必须使用 TLS 通过 IAM 身份验证连接到数据库

【讨论】:

    【解决方案3】:

    我遇到了同样的问题。在我添加了用于构建 Auth Token 的端口号(大量在线查找)之后得到了解决。

    之前是这样的:

    authToken, err := rdsutils.BuildAuthToken(host, region, username, sess.Config.Credentials)
    

    我必须更改为:

    authToken, err := rdsutils.BuildAuthToken(fmt.Sprintf("%s:%d", host, 3306), region, username, sess.Config.Credentials)
    

    这是针对 Golang 应用程序的。但同样可能适用于其他语言 SDK。 我从https://luktom.net/en/e1544-aws-lambda-and-mysql-iam-authentication-in-go得到这个答案

    来自 AWS 的人员需要更新他们的 official docs on this

    【讨论】:

    • 据我了解 credentials.NewEnvCredentials() 在 ECS 或 EC2 中不起作用
    猜你喜欢
    • 2017-12-08
    • 1970-01-01
    • 2020-09-03
    • 2018-11-23
    • 2021-05-14
    • 2020-12-21
    • 1970-01-01
    • 1970-01-01
    • 2017-10-31
    相关资源
    最近更新 更多