无法通过 IAM 身份验证访问 RDS 数据库

Unable to access RDS Database via IAM Authentication

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

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

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

自定义 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)

根据 AWS Github Go 编程语言存储库中的示例,您需要按如下方式创建凭据:

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

You need to connect to your database and create a user using the AWS authentication plugin.

The following SQL statement creates a database user named lambda. Instead of specifying a password, the AWSAuthenticationPlugin is used for identifying the user. Replace with the name of the database you want to grant the user access to.

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 文档中的以下内容很重要:

Limitations for IAM Database Authentication

With IAM database authentication, you are limited to a maximum of 20 new connections per second. If you are using a db.t2.micro instance class, the limit is 10 connections per second.

The Amazon RDS for MySQL and Aurora MySQL database engines do not impose any limits on authentication attempts per second. However, when you use IAM database authentication, your application must generate an authentication token. Your application then uses that token to connect to the DB instance or cluster. If you exceed the maximum new-connection-per-second limit, then the extra overhead of IAM database authentication can cause connection throttling. The extra overhead can even cause existing connections to drop.

We recommend the following:

  • Use IAM database authentication as a mechanism for temporary, personal access to databases.

  • Don't use IAM database authentication if your application requires more than 20 new connections per second.

  • Use IAM database authentication only for workloads that can be easily retried.

Note

For information about the maximum total connections for MySQL, see see Maximum MySQL connections. For information about the maximum total connections for Aurora MySQL, see Maximum Connections to an Aurora MySQL DB Instance.

我遇到了同样的问题。在(大量在线查找)我添加了用于构建 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

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

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

因此 arn 不是 iam 数据库用户之一,而是分配给您的资源(EC2、ECS、Fargate)的角色的 arn

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