

# 适用于 MariaDB、MySQL 和 PostgreSQL 的IAM 数据库身份验证
<a name="UsingWithRDS.IAMDBAuth"></a>

您可以使用 AWS Identity and Access Management（IAM）数据库身份验证对数据库实例进行身份验证。IAM 数据库身份验证适用于 MariaDB、MySQL 和 PostgreSQL。利用此身份验证方法，您在连接到数据库实例时将无需使用密码。而是使用身份验证令牌。

*身份验证令牌* 是 Amazon RDS 根据请求生成的唯一字符串。身份验证令牌是使用 AWS 签名版本 4 生成的。每个令牌的使用期限为 15 分钟。您无需将用户凭证存储在数据库中，因为身份验证是使用 IAM 进行外部管理的。此外，您仍可使用标准数据库身份验证。令牌仅用于身份验证，建立后不会影响会话。

IAM 数据库身份验证具有以下优势：
+ 数据库的出站和进站网络流量是使用安全套接字层 (SSL) 或传输层安全性 (TLS) 加密的。有关将 SSL/TLS 与 Amazon RDS 一起使用的更多信息，请参阅[使用 SSL/TLS 加密与数据库实例或集群的连接](UsingWithRDS.SSL.md)。
+ 您可以使用 IAM 集中管理对数据库资源的访问，而不是单独管理对每个数据库实例的访问。
+ 对于在 Amazon EC2 上运行的应用程序，您可以使用 EC2 实例特定的配置文件凭证访问数据库以提高安全性，而不是使用密码。

一般来说，如果应用程序每秒创建的连接少于 200 个，而且您不想直接在应用程序代码中管理用户名和密码，请考虑使用 IAM 数据库身份验证。

Amazon Web Services（AWS）JDBC 驱动程序支持 IAM 数据库身份验证。有关更多信息，请参阅 [Amazon Web Services（AWS）JDBC 驱动程序 GitHub 存储库](https://github.com/aws/aws-advanced-jdbc-wrapper)中的 [AWS IAM 身份验证插件](https://github.com/aws/aws-advanced-jdbc-wrapper/blob/main/docs/using-the-jdbc-driver/using-plugins/UsingTheIamAuthenticationPlugin.md)。

Amazon Web Services（AWS）Python 驱动程序支持 IAM 数据库身份验证。有关更多信息，请参阅 [Amazon Web Services（AWS）Python 驱动程序 GitHub 存储库](https://github.com/aws/aws-advanced-python-wrapper)中的 [AWS IAM 身份验证插件](https://github.com/aws/aws-advanced-python-wrapper/blob/main/docs/using-the-python-driver/using-plugins/UsingTheIamAuthenticationPlugin.md)。

浏览以下主题，学习设置 IAM 用于数据库身份验证的过程：
+ [启用和禁用 IAM 数据库身份验证](UsingWithRDS.IAMDBAuth.Enabling.md)
+ [创建和使用适用于 IAM 数据库访问的 IAM 策略](UsingWithRDS.IAMDBAuth.IAMPolicy.md)
+ [使用 IAM 身份验证创建数据库账户](UsingWithRDS.IAMDBAuth.DBAccounts.md)
+ [使用 IAM 身份验证连接到数据库实例](UsingWithRDS.IAMDBAuth.Connecting.md) 

## 区域和版本可用性
<a name="UsingWithRDS.IAMDBAuth.Availability"></a>

功能可用性和支持因每个数据库引擎的特定版本而异。有关适用于 Amazon RDS 和 IAM 数据库身份验证的引擎、版本和区域可用性的更多信息，请参阅[支持 Amazon RDS 中 IAM 数据库身份验证功能的区域和数据库引擎](Concepts.RDS_Fea_Regions_DB-eng.Feature.IamDatabaseAuthentication.md)。

## CLI 和开发工具包支持
<a name="UsingWithRDS.IAMDBAuth.cli-sdk"></a>

IAM 数据库身份验证可用于 [AWS CLI](https://docs.aws.amazon.com/cli/latest/reference/rds/generate-db-auth-token.html) 以及以下特定于语言的 AWS 软件开发工具包：
+ [适用于 .NET 的 AWS SDK](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/RDS/TRDSAuthTokenGenerator.html)
+ [适用于 C\$1\$1 的 AWS SDK](https://docs.aws.amazon.com/sdk-for-cpp/latest/api/class_aws_1_1_r_d_s_1_1_r_d_s_client.html#ae134ffffed5d7672f6156d324e7bd392)
+ [适用于 Go 的 AWS SDK](https://docs.aws.amazon.com/sdk-for-go/api/service/rds/#pkg-overview)
+ [适用于 Java 的 AWS SDK](https://docs.aws.amazon.com/sdk-for-java/latest/reference/software/amazon/awssdk/services/rds/RdsUtilities.html)
+ [适用于 JavaScript 的 AWS SDK](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/modules/_aws_sdk_rds_signer.html)
+ [适用于 PHP 的 AWS SDK](https://docs.aws.amazon.com/aws-sdk-php/v3/api/class-Aws.Rds.AuthTokenGenerator.html)
+ [适用于 Python (Boto3) 的 AWS SDK](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/rds.html#RDS.Client.generate_db_auth_token)
+ [适用于 Ruby 的 AWS SDK](https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/RDS/AuthTokenGenerator.html)

## IAM 数据库身份验证的限制
<a name="UsingWithRDS.IAMDBAuth.Limitations"></a>

使用 IAM 数据库身份验证时，以下限制适用：
+ 目前，IAM 数据库身份验证并不支持所有的全局条件上下文键。

  有关全局条件上下文键的更多信息，请参阅《IAM 用户指南**》中的 [AWS 全局条件上下文键](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_condition-keys.html)。
+ 对于 PostgreSQL，如果将 IAM 角色（`rds_iam`）添加到某个用户（包括 RDS 主用户），IAM 身份验证将优先于密码身份验证，因此该用户必须以 IAM 用户身份登录。
+ 对于 PostgreSQL，Amazon RDS 不支持同时启用 IAM 和 Kerberos 身份验证方法。
+ 对于 PostgreSQL，您不能使用 IAM 身份验证来建立复制连接。
+ 不能使用自定义 Route 53 DNS 记录代替数据库实例端点来生成身份验证令牌。
+ CloudWatch 和 CloudTrail 不记录 IAM 身份验证。这些服务不会跟踪授权 IAM 角色启用数据库连接的 `generate-db-auth-token` API 调用。
+ IAM 数据库身份验证需要数据库实例上的计算资源。您的数据库上必须有 300 到 1000 MiB 的额外内存，才能实现可靠的连接。要查看工作负载所需的内存，请在启用 IAM 数据库身份验证之前和之后，比较增强型监控进程列表中 RDS 进程的 RES 列。请参阅[在 RDS 控制台中查看操作系统指标](USER_Monitoring.OS.Viewing.md)。

  如果您使用的是可突增类实例，请通过将其它参数使用的内存（如缓冲区和缓存）减少相同的量，从而避免内存耗尽。
+ 对于任何引擎，RDS on Outposts 不支持 IAM 数据库身份验证。

## IAM 数据库身份验证建议
<a name="UsingWithRDS.IAMDBAuth.ConnectionsPerSecond"></a>

在使用 IAM 数据库身份验证时，建议使用以下方法：
+ 当您的应用程序每秒需要少于 200 个新的 IAM 数据库身份验证连接时，请使用 IAM 数据库身份验证。

  使用 Amazon RDS 的数据库引擎不会对每秒的身份验证尝试次数施加任何限制。不过，在使用 IAM 数据库身份验证时，您的应用程序必须生成身份验证令牌。之后，您的应用程序将使用该令牌连接到数据库实例。如果超出每秒的最大新连接数限制，则 IAM 数据库身份验证的额外开销可能会导致连接受到限制。

  考虑在应用程序中使用连接池来减少持续的连接创建。这可以减少 IAM 数据库身份验证的开销，并允许应用程序重用现有连接。或者，考虑对这些使用案例使用 RDS 代理。RDS 代理有额外费用。请参阅 [RDS 代理定价](https://aws.amazon.com/rds/proxy/pricing/)。
+ IAM 数据库身份验证令牌的大小取决于许多因素，包括 IAM 标签的数量、IAM 服务策略、ARN 长度以及其他 IAM 和数据库属性。此令牌的最小大小通常约为 1KB，但可以更大。由于使用 IAM 身份验证将此令牌用作数据库的连接字符串中的密码，因此，您应确保您的数据库驱动程序（例如 ODBC）和/或任何工具不会因其大小而限制或以其他方式截断该令牌。截断的令牌将导致数据库和 IAM 执行的身份验证失败。
+ 如果您在创建 IAM 数据库身份验证令牌时使用临时凭证，则在使用 IAM 数据库身份验证令牌发出连接请求时，临时凭证必须仍然有效。

## 不支持的 AWS 全局条件上下文键
<a name="UsingWithRDS.IAMDBAuth.GlobalContextKeys"></a>

 IAM 数据库身份验证不支持 AWS 全局条件上下文键的以下子集。
+ `aws:Referer`
+ `aws:SourceIp`
+ `aws:SourceVpc`
+ `aws:SourceVpce`
+ `aws:UserAgent`
+ `aws:VpcSourceIp`

有关更多信息，请参阅《IAM 用户指南》**中的 [AWS 全局条件上下文键](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_condition-keys.html)。

# 启用和禁用 IAM 数据库身份验证
<a name="UsingWithRDS.IAMDBAuth.Enabling"></a>

默认情况下，已对数据库实例禁用 IAM 数据库身份验证。您可以使用 AWS 管理控制台、AWS CLI 或 API 启用或禁用 IAM 数据库身份验证。

您可以在执行以下操作之一时启用 IAM 数据库身份验证：
+ 要创建启用 IAM 数据库身份验证的新数据库实例，请参阅 [创建 Amazon RDS 数据库实例](USER_CreateDBInstance.md)。
+ 要修改数据库实例以启用 IAM 数据库身份验证，请参阅 [修改 Amazon RDS 数据库实例](Overview.DBInstance.Modifying.md)。
+ 要从启用了 IAM 数据库身份验证的快照还原数据库实例，请参阅[还原到数据库实例](USER_RestoreFromSnapshot.md)。
+ 要将数据库实例还原到已启用 IAM 数据库身份验证的某个时间点，请参阅 [将 Amazon RDS 的数据库实例还原到指定时间](USER_PIT.md)。

## 控制台
<a name="UsingWithRDS.IAMDBAuth.Enabling.Console"></a>

每个创建或修改工作流程都有一个**数据库身份验证**部分，您可以在其中启用或禁用 IAM 数据库身份验证。在该部分中，选择**密码和 IAM 数据库身份验证**以启用 IAM 数据库身份验证。

**为现有数据库实例启用或禁用 IAM 数据库身份验证**

1. 通过以下网址打开 Amazon RDS 控制台：[https://console.aws.amazon.com/rds/](https://console.aws.amazon.com/rds/)。

1. 在导航窗格中，选择 **Databases (数据库)**。

1. 选择要修改的数据库实例。
**注意**  
 确保数据库实例与 IAM 身份验证兼容。在[区域和版本可用性](UsingWithRDS.IAMDBAuth.md#UsingWithRDS.IAMDBAuth.Availability)中检查兼容性要求。

1. 选择**修改**。

1. 在**数据库身份验证**部分中，选择**密码和 IAM 数据库身份验证** ，启用 IAM 数据库身份验证。选择**密码身份验证**或**密码和 Kerberos 身份验证**以禁用 IAM 身份验证。

1. 也可以选择启用向 CloudWatch Logs 发布 IAM 数据库身份验证日志。在**日志导出**下，选择 **iam-db-auth-error log** 选项。将您的日志发布到 CloudWatch Logs 会消耗存储空间，并且您需要为该存储空间支付费用。请务必删除所有不再需要的 CloudWatch Logs。

1. 选择 **Continue (继续)**。

1. 要立即应用更改，请在**修改计划**部分中选择**立即**。

1. 选择**修改数据库实例** 。

## AWS CLI
<a name="UsingWithRDS.IAMDBAuth.Enabling.CLI"></a>

要使用 AWS CLI 创建采用 IAM 身份验证的新数据库实例，请使用 [https://docs.aws.amazon.com/cli/latest/reference/rds/create-db-instance.html](https://docs.aws.amazon.com/cli/latest/reference/rds/create-db-instance.html) 命令。指定 `--enable-iam-database-authentication` 选项，如以下示例中所示。

```
aws rds create-db-instance \
    --db-instance-identifier mydbinstance \
    --db-instance-class db.m3.medium \
    --engine MySQL \
    --allocated-storage 20 \
    --master-username masterawsuser \
    --manage-master-user-password \
    --enable-iam-database-authentication
```

要更新现有的数据库实例以使用或不使用 IAM 身份验证，请使用 AWS CLI 命令 [https://docs.aws.amazon.com/cli/latest/reference/rds/modify-db-instance.html](https://docs.aws.amazon.com/cli/latest/reference/rds/modify-db-instance.html)。根据需要指定 `--enable-iam-database-authentication` 或 `--no-enable-iam-database-authentication` 选项。

**注意**  
 确保数据库实例与 IAM 身份验证兼容。在[区域和版本可用性](UsingWithRDS.IAMDBAuth.md#UsingWithRDS.IAMDBAuth.Availability)中检查兼容性要求。

默认情况下，Amazon RDS 在下一个维护时段执行修改。如果您要覆盖该选项并尽快启用 IAM 数据库身份验证，请使用 `--apply-immediately` 参数。

以下示例说明了如何立即为现有数据库实例启用 IAM 身份验证。

```
aws rds modify-db-instance \
    --db-instance-identifier mydbinstance \
    --apply-immediately \
    --enable-iam-database-authentication
```

如果您将还原数据库实例，请使用下列 AWS CLI 命令之一：
+ `[restore-db-instance-to-point-in-time](https://docs.aws.amazon.com/cli/latest/reference/rds/restore-db-instance-to-point-in-time.html)`
+ `[restore-db-instance-from-db-snapshot](https://docs.aws.amazon.com/cli/latest/reference/rds/restore-db-instance-from-db-snapshot.html)`

IAM 数据库身份验证设置默认为源快照的设置。要更改此设置，请根据需要设置 `--enable-iam-database-authentication` 或 `--no-enable-iam-database-authentication` 选项。

## RDS API
<a name="UsingWithRDS.IAMDBAuth.Enabling.API"></a>

要使用 API 创建采用 IAM 身份验证的新数据库实例，请使用 API 操作 [https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateDBInstance.html](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateDBInstance.html)。将 `EnableIAMDatabaseAuthentication` 参数设置为 `true`。

要更新现有的数据库实例以采用 IAM 身份验证，请使用 API 操作 [https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_ModifyDBInstance.html](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_ModifyDBInstance.html)。将 `EnableIAMDatabaseAuthentication` 参数设置为 `true` 可启用 IAM 身份验证，将其设置为 `false` 可禁用 IAM 身份验证。

**注意**  
 确保数据库实例与 IAM 身份验证兼容。在[区域和版本可用性](UsingWithRDS.IAMDBAuth.md#UsingWithRDS.IAMDBAuth.Availability)中检查兼容性要求。

如果您将还原数据库实例，请使用以下 API 操作之一：
+ [https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_RestoreDBInstanceFromDBSnapshot.html](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_RestoreDBInstanceFromDBSnapshot.html)
+  [https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_RestoreDBInstanceToPointInTime.html](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_RestoreDBInstanceToPointInTime.html)

IAM 数据库身份验证设置默认为源快照的设置。要更改此设置，请将 `EnableIAMDatabaseAuthentication` 参数设置为 `true` 以启用 IAM 身份验证，或将其设置为 `false` 以禁用 IAM 身份验证。

# 创建和使用适用于 IAM 数据库访问的 IAM 策略
<a name="UsingWithRDS.IAMDBAuth.IAMPolicy"></a>

要允许用户或角色连接到数据库实例，您必须创建 IAM policy。之后，将策略附加到权限集或角色。

**注意**  
要了解有关 IAM 策略的更多信息，请参阅 [Amazon RDS 的 Identity and Access Management](UsingWithRDS.IAM.md)。

以下示例策略允许用户使用 IAM 数据库身份验证连接到数据库实例。

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "rds-db:connect"
            ],
            "Resource": [
                "arn:aws:rds-db:us-east-2:111122223333:dbuser:db-ABCDEFGHIJKL01234/db_user"
            ]
        }
    ]
}
```

------

**重要**  
具有管理员权限的用户即使在 IAM policy 中没有显式权限，也可以访问数据库实例。如果您希望限制管理员访问数据库实例，您可以创建具有合适的较低权限的 IAM 角色，并将其分配给管理员。

**注意**  
请不要将 `rds-db:` 前缀与以 `rds:` 开头的其他 RDS API 操作前缀混淆。仅在 IAM 数据库身份验证使用 `rds-db:` 前缀和 `rds-db:connect` 操作。它们在任何其他上下文中无效。

示例策略包含带以下元素的单个语句：
+ `Effect` – 指定 `Allow` 以授予数据库实例的访问权限。如果您没有显式允许访问，则默认情况下将拒绝访问。
+ `Action` – 指定 `rds-db:connect` 以允许连接到数据库实例。
+ `Resource` – 指定 Amazon Resource Name (ARN) 以描述一个数据库实例中的一个数据库账户。ARN 格式如下所示。

  ```
  arn:aws:rds-db:region:account-id:dbuser:DbiResourceId/db-user-name
  ```

  在此格式中，替换以下内容：
  + `region` 是数据库实例所在的 AWS 区域。在示例策略中，AWS 区域为 `us-east-2`。
  + `account-id` 是数据库实例的 AWS 账号。在示例策略中，账号为 `1234567890`。该用户必须位于与数据库实例的账户相同的账户中。

    要执行跨账户存取，请在数据库实例的账户中使用上面显示的策略创建 IAM 角色，并允许其他账户代入该角色。
  + `DbiResourceId` 是数据库实例的标识符。此标识符对 AWS 区域是唯一的，并且绝不会更改。在示例策略中，标识符为 `db-ABCDEFGHIJKL01234`。

    要在适用于 Amazon RDS 的 AWS 管理控制台中查找数据库实例资源 ID，请选择数据库实例来查看其详细信息。然后，选择**配置**选项卡。**Resource ID (资源 ID)** 将显示在 **Configuration (配置)** 部分中。

    或者，您可以使用 AWS CLI 命令列出当前 AWS 区域中所有数据库实例的标识符和资源 ID，如下所示。

    ```
    aws rds describe-db-instances --query "DBInstances[*].[DBInstanceIdentifier,DbiResourceId]"
    ```

    如果您使用的是 Amazon Aurora，请指定 `DbClusterResourceId` 而不是 `DbiResourceId`。有关更多信息，请参阅 *Amazon Aurora 用户指南*中的[创建和使用适用于 IAM 数据库访问的 IAM 策略](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/UsingWithRDS.IAMDBAuth.IAMPolicy.html)。
**注意**  
如果要通过 RDS 代理连接到数据库，请指定代理资源 ID，如 `prx-ABCDEFGHIJKL01234`。有关将 IAM 数据库身份验证与 RDS 代理结合使用的信息，请参阅 [使用 IAM 身份验证连接到数据库](rds-proxy-connecting.md#rds-proxy-connecting-iam)。
  + `db-user-name` 是与 IAM 身份验证关联的数据库账户的名称。在示例策略中，数据库账户为 `db_user`。

您可以构造其他 ARN 以支持多种访问模式。以下策略允许访问一个数据库实例中的两个不同的数据库账户。

------
#### [ JSON ]

****  

```
{
   "Version":"2012-10-17",		 	 	 
   "Statement": [
      {
         "Effect": "Allow",
         "Action": [
             "rds-db:connect"
         ],
         "Resource": [
             "arn:aws:rds-db:us-east-2:123456789012:dbuser:db-ABCDEFGHIJKL01234/jane_doe",
             "arn:aws:rds-db:us-east-2:123456789012:dbuser:db-ABCDEFGHIJKL01234/mary_roe"
         ]
      }
   ]
}
```

------

以下策略使用“\$1”字符匹配特定 AWS 账户和 AWS 区域的所有数据库实例和数据库账户。

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "rds-db:connect"
            ],
            "Resource": [
                "arn:aws:rds-db:us-east-2:111122223333:dbuser:*/*"
            ]
        }
    ]
}
```

------

以下策略匹配特定 AWS 账户和 AWS 区域的所有数据库实例。不过，该策略仅允许访问具有 `jane_doe` 数据库账户的数据库实例。

------
#### [ JSON ]

****  

```
{
   "Version":"2012-10-17",		 	 	 
   "Statement": [
      {
         "Effect": "Allow",
         "Action": [
             "rds-db:connect"
         ],
         "Resource": [
             "arn:aws:rds-db:us-east-2:123456789012:dbuser:*/jane_doe"
         ]
      }
   ]
}
```

------

用户或角色只能访问数据库用户有权访问的那些数据库。例如，假设数据库实例具有一个名为 *dev* 的数据库，以及另一个名为 *test* 的数据库。如果数据库用户 `jane_doe` 只能访问 *dev*，则与 `jane_doe` 用户一起访问数据库实例的任何用户或角色也只能访问 *dev*。此访问限制还适用于其他数据库对象 (如表、视图等)。

管理员必须创建 IAM policy，以便为实体授予权限，从而对其所需的指定资源执行特定的 API 操作。然后，管理员必须将这些策略附加到需要这些权限的权限集或角色。有关策略示例，请参阅“[Amazon RDS 的基于身份的策略示例](security_iam_id-based-policy-examples.md)”。

## 将 IAM policy 附加到权限集或角色
<a name="UsingWithRDS.IAMDBAuth.IAMPolicy.Attaching"></a>

在创建允许数据库身份验证的 IAM policy 之后，您需要将该策略附加到权限集或角色。有关此主题的教程，请参阅 *IAM 用户指南* 中的[创建和附加您的第一个客户托管策略](https://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_managed-policies.html)。

在演练此教程时，您可以使用此部分中显示的策略示例之一作为起点并根据您的需求进行定制。在教程结束时，您将有一个权限集，该权限集附加了一个可利用 `rds-db:connect` 操作的策略。

**注意**  
您可以将多个权限集或角色映射到同一数据库用户账户。例如，假设您的 IAM 策略指定了以下资源 ARN。  

```
arn:aws:rds-db:us-east-2:123456789012:dbuser:db-12ABC34DEFG5HIJ6KLMNOP78QR/jane_doe
```
如果将该策略附加到 *Jane*、*Bob* 和 *Diego*，则其中的每个用户都可以使用 `jane_doe` 数据库账户连接到指定的数据库实例。

# 使用 IAM 身份验证创建数据库账户
<a name="UsingWithRDS.IAMDBAuth.DBAccounts"></a>

在使用 IAM 数据库身份验证时，您不需要为创建的用户账户分配数据库密码。如果删除映射到某个数据库账户的用户，则还应使用 `DROP USER` 语句删除该数据库账户。

**注意**  
用于 IAM 身份验证的用户名必须与数据库中用户名的大小写相匹配。

**Topics**
+ [对 MariaDB 和 MySQL 使用 IAM 身份验证](#UsingWithRDS.IAMDBAuth.DBAccounts.MySQL)
+ [对 PostgreSQL 使用 IAM 身份验证](#UsingWithRDS.IAMDBAuth.DBAccounts.PostgreSQL)

## 对 MariaDB 和 MySQL 使用 IAM 身份验证
<a name="UsingWithRDS.IAMDBAuth.DBAccounts.MySQL"></a>

对于 MariaDB 和 MySQL，身份验证由 `AWSAuthenticationPlugin` 处理，这是 AWS 提供的一个插件，可以与 IAM 无缝协作以验证您的用户的身份。以主用户或其他可以创建用户和授予权限的用户身份连接到数据库实例。连接后，发出 `CREATE USER` 语句，如以下示例中所示。

```
CREATE USER 'jane_doe' IDENTIFIED WITH AWSAuthenticationPlugin AS 'RDS'; 
```

`IDENTIFIED WITH` 子句允许 MariaDB 和 MySQL 使用 `AWSAuthenticationPlugin` 对数据库账户 (`jane_doe`) 进行身份验证。`AS 'RDS'` 子句是指身份验证方法。确保指定的数据库用户名与 IAM 数据库访问策略中的资源相同。有关更多信息，请参阅“[创建和使用适用于 IAM 数据库访问的 IAM 策略](UsingWithRDS.IAMDBAuth.IAMPolicy.md)”。

**注意**  
如果看到以下消息，则意味着 AWS 提供的插件对当前的数据库实例不可用。  
`ERROR 1524 (HY000): Plugin 'AWSAuthenticationPlugin' is not loaded`  
要纠正该错误，请确认您使用支持的配置，并且在数据库实例上启用了 IAM 数据库身份验证。有关更多信息，请参阅“[区域和版本可用性](UsingWithRDS.IAMDBAuth.md#UsingWithRDS.IAMDBAuth.Availability)”和“[启用和禁用 IAM 数据库身份验证](UsingWithRDS.IAMDBAuth.Enabling.md)”。

在使用 `AWSAuthenticationPlugin` 创建一个账户后，可以像管理其他数据库账户一样管理此账户。例如，您可以使用 `GRANT` 语句和 `REVOKE` 语句修改账户权限，或使用 `ALTER USER` 语句修改各种账户属性。

使用 IAM 时，数据库网络流量使用 SSL/TLS 进行加密。要允许 SSL 连接，请使用以下命令修改用户账户。

```
ALTER USER 'jane_doe'@'%' REQUIRE SSL;     
```

 

## 对 PostgreSQL 使用 IAM 身份验证
<a name="UsingWithRDS.IAMDBAuth.DBAccounts.PostgreSQL"></a>

要在 PostgreSQL 中使用 IAM 身份验证，请以主用户或其他可以创建用户和授予权限的用户身份连接到数据库实例。连接后，创建数据库用户，然后向其授予 `rds_iam` 角色，如以下示例中所示。

```
CREATE USER db_userx; 
GRANT rds_iam TO db_userx;
```

确保指定的数据库用户名与 IAM 数据库访问策略中的资源相同。有关更多信息，请参阅 [创建和使用适用于 IAM 数据库访问的 IAM 策略](UsingWithRDS.IAMDBAuth.IAMPolicy.md)。您必须授予 `rds_iam` 角色才能使用 IAM 身份验证。也可以使用该角色的嵌套成员资格或间接授权。

# 使用 IAM 身份验证连接到数据库实例
<a name="UsingWithRDS.IAMDBAuth.Connecting"></a>

对于 IAM 数据库身份验证，您可以在连接到数据库实例时使用身份验证令牌。*身份验证令牌* 是您使用的一个字符串而不是密码。在生成身份验证令牌后，将在 15 分钟后失效。如果您尝试使用过期的令牌进行连接，则连接请求将被拒绝。

必须使用 AWS 签名版本 4 为每个身份验证令牌附带一个有效签名。（有关更多信息，请参阅《AWS 一般参考》**中的[签名版本 4 签名流程](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html)。） AWS CLI 和 AWS 软件开发工具包（例如 适用于 Java 的 AWS SDK 或者 适用于 Python (Boto3) 的 AWS SDK）可以自动对您创建的每个令牌进行签名。

从其他AWS服务（如 AWS Lambda）连接到 Amazon RDS 时，您可以使用身份验证令牌。通过使用令牌，可以避免在代码中放置密码。或者，您可以使用 AWS 开发工具包以编程方式创建身份验证令牌并为其签名。

在获得签名的 IAM 身份验证令牌后，您可以连接到 Amazon RDS 数据库实例。在下文中，您可以了解如何使用命令行工具或 AWS 开发工具包（例如 适用于 Java 的 AWS SDK 或 适用于 Python (Boto3) 的 AWS SDK）执行该操作。

有关更多信息，请参阅以下博客文章：
+ [使用 IAM 身份验证通过 SQL Workbench/J 连接到 Aurora MySQL 或 Amazon RDS for MySQL](https://aws.amazon.com/blogs/database/use-iam-authentication-to-connect-with-sql-workbenchj-to-amazon-aurora-mysql-or-amazon-rds-for-mysql/)
+ [使用 IAM 身份验证通过 pgAdmin Amazon Aurora PostgreSQL 或 Amazon RDS for PostgreSQL 进行连接](https://aws.amazon.com/blogs/database/using-iam-authentication-to-connect-with-pgadmin-amazon-aurora-postgresql-or-amazon-rds-for-postgresql/)

**先决条件**  
以下是使用 IAM 身份验证连接到数据库实例的先决条件：
+ [启用和禁用 IAM 数据库身份验证](UsingWithRDS.IAMDBAuth.Enabling.md)
+ [创建和使用适用于 IAM 数据库访问的 IAM 策略](UsingWithRDS.IAMDBAuth.IAMPolicy.md)
+ [使用 IAM 身份验证创建数据库账户](UsingWithRDS.IAMDBAuth.DBAccounts.md)

**Topics**
+ [使用 IAM 身份验证和 AWS 驱动程序连接到数据库实例](IAMDBAuth.Connecting.Drivers.md)
+ [通过命令行 AWS CLI 和 mysql 客户端，使用 IAM 身份验证连接到数据库实例](UsingWithRDS.IAMDBAuth.Connecting.AWSCLI.md)
+ [通过命令行使用 IAM 身份验证连接到数据库实例：AWS CLI 和 psql 客户端](UsingWithRDS.IAMDBAuth.Connecting.AWSCLI.PostgreSQL.md)
+ [使用 IAM 身份验证和 适用于 .NET 的 AWS SDK 连接到数据库实例](UsingWithRDS.IAMDBAuth.Connecting.NET.md)
+ [使用 IAM 身份验证和 适用于 Go 的 AWS SDK 连接到数据库实例](UsingWithRDS.IAMDBAuth.Connecting.Go.md)
+ [使用 IAM 身份验证和 适用于 Java 的 AWS SDK 连接到数据库实例](UsingWithRDS.IAMDBAuth.Connecting.Java.md)
+ [使用 IAM 身份验证和 适用于 Python (Boto3) 的 AWS SDK 连接到数据库实例](UsingWithRDS.IAMDBAuth.Connecting.Python.md)

# 使用 IAM 身份验证和 AWS 驱动程序连接到数据库实例
<a name="IAMDBAuth.Connecting.Drivers"></a>

借助 AWS 驱动程序套件，可显著缩短切换和故障转移时间，并支持使用 AWS Secrets Manager、AWS Identity and Access Management（IAM）和联合身份进行身份验证。AWS 驱动程序依靠监控数据库实例状态以及了解实例拓扑，来确定新的写入器。这种方法将切换和故障转移时间缩短到几秒钟，而开源驱动程序的切换和故障转移时间则为几十秒。

有关 AWS 驱动程序的更多信息，请参阅 [RDS for MariaDB](MariaDB.Connecting.Drivers.md#MariaDB.Connecting.JDBCDriver)、[RDS for MySQL](MySQL.Connecting.Drivers.md#MySQL.Connecting.JDBCDriver) 或 [RDS for PostgreSQL](PostgreSQL.Connecting.JDBCDriver.md) 数据库实例的相应语言驱动程序。

**注意**  
RDS for MariaDB 支持的唯一功能是使用 AWS Secrets Manager、AWS Identity and Access Management（IAM）和联合身份进行身份验证。

# 通过命令行 AWS CLI 和 mysql 客户端，使用 IAM 身份验证连接到数据库实例
<a name="UsingWithRDS.IAMDBAuth.Connecting.AWSCLI"></a>

可以使用 AWS CLI 和 `mysql` 命令行工具从命令行连接到 Amazon RDS 数据库实例，如下所述。

**先决条件**  
以下是使用 IAM 身份验证连接到数据库实例的先决条件：
+ [启用和禁用 IAM 数据库身份验证](UsingWithRDS.IAMDBAuth.Enabling.md)
+ [创建和使用适用于 IAM 数据库访问的 IAM 策略](UsingWithRDS.IAMDBAuth.IAMPolicy.md)
+ [使用 IAM 身份验证创建数据库账户](UsingWithRDS.IAMDBAuth.DBAccounts.md)

**注意**  
有关使用具有 IAM 身份验证的 SQL WorkBench/J 连接到数据库的信息，请参阅博客文章[使用 IAM 身份验证通过 SQL WorkBench/J 连接到 Aurora MySQL 或 Amazon RDS for MySQL](https://aws.amazon.com/blogs/database/use-iam-authentication-to-connect-with-sql-workbenchj-to-amazon-aurora-mysql-or-amazon-rds-for-mysql/)。

**Topics**
+ [生成 IAM 身份验证令牌](#UsingWithRDS.IAMDBAuth.Connecting.AWSCLI.AuthToken)
+ [连接到数据库实例](#UsingWithRDS.IAMDBAuth.Connecting.AWSCLI.Connect)

## 生成 IAM 身份验证令牌
<a name="UsingWithRDS.IAMDBAuth.Connecting.AWSCLI.AuthToken"></a>

以下示例说明了如何使用 AWS CLI 获取签名的身份验证令牌。

```
aws rds generate-db-auth-token \
   --hostname rdsmysql.123456789012.us-west-2.rds.amazonaws.com \
   --port 3306 \
   --region us-west-2 \
   --username jane_doe
```

在该示例中，参数如下所示：
+ `--hostname` – 要访问的数据库实例的主机名
+ `--port` – 用于连接到数据库实例的端口号
+ `--region` – 在其中运行数据库实例的 AWS 区域
+ `--username` – 要访问的数据库账户

令牌的前几个字符与以下内容类似。

```
rdsmysql.123456789012.us-west-2.rds.amazonaws.com:3306/?Action=connect&DBUser=jane_doe&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=900...
```

**注意**  
不能使用自定义 Route 53 DNS 记录代替数据库实例端点来生成身份验证令牌。

## 连接到数据库实例
<a name="UsingWithRDS.IAMDBAuth.Connecting.AWSCLI.Connect"></a>

通用连接格式如下所示。

```
mysql --host=hostName --port=portNumber --ssl-ca=full_path_to_ssl_certificate --enable-cleartext-plugin --user=userName --password=authToken
```

参数如下所示：
+ `--host` – 要访问的数据库实例的主机名
+ `--port` – 用于连接到数据库实例的端口号
+ `--ssl-ca` – 包含公有密钥的 SSL 证书文件的完整路径

  有关 MariaDB 的 SSL/TLS 支持的更多信息，请参阅 [Amazon RDS 上 MariaDB 数据库实例的 SSL/TLS 支持](MariaDB.Concepts.SSLSupport.md)。

  有关 MySQL 的 SSL/TLS 支持的更多信息，请参阅 [Amazon RDS 上 MySQL 数据库实例的 SSL/TLS 支持](MySQL.Concepts.SSLSupport.md)。

  要下载 SSL 证书，请参阅 [使用 SSL/TLS 加密与数据库实例或集群的连接](UsingWithRDS.SSL.md)。
+ `--enable-cleartext-plugin` – 一个指定 `AWSAuthenticationPlugin` 必须用于此连接的值

  如果您使用 MariaDB 客户端，则无需 `--enable-cleartext-plugin` 选项。
+ `--user` – 要访问的数据库账户
+ `--password` – 已签名的 IAM 身份验证令牌

身份验证令牌包含几百个字符。很难使用命令行对其进行处理。该问题的解决方式是，将令牌保存到一个环境变量中，然后在连接时使用此变量。以下示例说明了一种执行此解决方法的方式。在该示例中，*/sample\$1dir/* 是包含公有密钥的 SSL 证书文件的完整路径。

```
RDSHOST="mysqldb.123456789012.us-east-1.rds.amazonaws.com"
TOKEN="$(aws rds generate-db-auth-token --hostname $RDSHOST --port 3306 --region us-west-2 --username jane_doe )"

mysql --host=$RDSHOST --port=3306 --ssl-ca=/sample_dir/global-bundle.pem --enable-cleartext-plugin --user=jane_doe --password=$TOKEN
```

在使用 `AWSAuthenticationPlugin` 进行连接时，将使用 SSL 保护连接。要进行验证，请在 `mysql>` 命令提示符处键入以下内容。

```
show status like 'Ssl%';
```

输出中的以下行显示了更多详细信息。

```
+---------------+-------------+
| Variable_name | Value                                                                                                                                                                                                                                |
+---------------+-------------+
| ...           | ...
| Ssl_cipher    | AES256-SHA                                                                                                                                                                                                                           |
| ...           | ...
| Ssl_version   | TLSv1.1                                                                                                                                                                                                                              |
| ...           | ...
+-----------------------------+
```

如果您想通过代理连接到数据库实例，请参阅[使用 IAM 身份验证连接到数据库](rds-proxy-connecting.md#rds-proxy-connecting-iam)。

# 通过命令行使用 IAM 身份验证连接到数据库实例：AWS CLI 和 psql 客户端
<a name="UsingWithRDS.IAMDBAuth.Connecting.AWSCLI.PostgreSQL"></a>

可以使用 AWS CLI 和 psql 命令行工具从命令行连接到 Amazon RDS for PostgreSQL 数据库实例，如下所述。

**先决条件**  
以下是使用 IAM 身份验证连接到数据库实例的先决条件：
+ [启用和禁用 IAM 数据库身份验证](UsingWithRDS.IAMDBAuth.Enabling.md)
+ [创建和使用适用于 IAM 数据库访问的 IAM 策略](UsingWithRDS.IAMDBAuth.IAMPolicy.md)
+ [使用 IAM 身份验证创建数据库账户](UsingWithRDS.IAMDBAuth.DBAccounts.md)

**注意**  
有关使用具有 IAM 身份验证的 pgAdmin 连接到数据库的信息，请参阅博客文章[使用 IAM 身份验证通过 pgAdmin Amazon Aurora PostgreSQL 或 Amazon RDS for PostgreSQL 进行连接](https://aws.amazon.com/blogs/database/using-iam-authentication-to-connect-with-pgadmin-amazon-aurora-postgresql-or-amazon-rds-for-postgresql/)。

**Topics**
+ [生成 IAM 身份验证令牌](#UsingWithRDS.IAMDBAuth.Connecting.AWSCLI.AuthToken.PostgreSQL)
+ [连接到 Amazon RDS PostgreSQL 实例](#UsingWithRDS.IAMDBAuth.Connecting.AWSCLI.Connect.PostgreSQL)

## 生成 IAM 身份验证令牌
<a name="UsingWithRDS.IAMDBAuth.Connecting.AWSCLI.AuthToken.PostgreSQL"></a>

身份验证令牌包含几百个字符，因此，很难使用命令行对其进行处理。该问题的解决方式是，将令牌保存到一个环境变量中，然后在连接时使用此变量。以下示例说明了如何使用 AWS CLI 通过 `generate-db-auth-token` 命令获取签名的身份验证令牌，并将其存储在 `PGPASSWORD` 环境变量中。

```
export RDSHOST="rdspostgres.123456789012.us-west-2.rds.amazonaws.com"
export PGPASSWORD="$(aws rds generate-db-auth-token --hostname $RDSHOST --port 5432 --region us-west-2 --username jane_doe )"
```

在该示例中，`generate-db-auth-token` 命令的参数如下所示：
+ `--hostname` – 要访问的数据库实例（集群终端节点）的主机名。
+ `--port` – 用于连接到数据库实例的端口号
+ `--region` – 在其中运行数据库实例的 AWS 区域
+ `--username` – 要访问的数据库账户

生成的令牌的前几个字符与以下内容类似。

```
rdspostgres.123456789012.us-west-2.rds.amazonaws.com:5432/?Action=connect&DBUser=jane_doe&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=900...
```

**注意**  
不能使用自定义 Route 53 DNS 记录代替数据库实例端点来生成身份验证令牌。

## 连接到 Amazon RDS PostgreSQL 实例
<a name="UsingWithRDS.IAMDBAuth.Connecting.AWSCLI.Connect.PostgreSQL"></a>

使用 psql 进行连接的一般格式如下所示。

```
psql "host=hostName port=portNumber sslmode=verify-full sslrootcert=full_path_to_ssl_certificate dbname=DBName user=userName password=authToken"
```

参数如下所示：
+ `host` – 要访问的数据库实例（集群终端节点）的主机名。
+ `port` – 用于连接到数据库实例的端口号
+ `sslmode` – 要使用的 SSL 模式

  当您使用 `sslmode=verify-full` 时，SSL 连接将针对 SSL 证书中的终端节点验证数据库实例终端节点。
+ `sslrootcert` – 包含公有密钥的 SSL 证书文件的完整路径

  有关更多信息，请参阅 [将 SSL 与 PostgreSQL 数据库实例结合使用](PostgreSQL.Concepts.General.SSL.md)。

  要下载 SSL 证书，请参阅 [使用 SSL/TLS 加密与数据库实例或集群的连接](UsingWithRDS.SSL.md)。
+ `dbname` – 要访问的数据库
+ `user` – 要访问的数据库账户
+ `password` – 已签名的 IAM 身份验证令牌

**注意**  
不能使用自定义 Route 53 DNS 记录代替数据库实例端点来生成身份验证令牌。

以下示例演示了使用 psql 进行连接。在该示例中，psql 将环境变量 `RDSHOST` 用于主机，将环境变量 `PGPASSWORD` 用于生产的令牌。*/sample\$1dir/* 则是包含公有密钥的 SSL 证书文件的完整路径。

```
export RDSHOST="rdspostgres.123456789012.us-west-2.rds.amazonaws.com"
export PGPASSWORD="$(aws rds generate-db-auth-token --hostname $RDSHOST --port 5432 --region us-west-2 --username jane_doe )"
                    
psql "host=$RDSHOST port=5432 sslmode=verify-full sslrootcert=/sample_dir/global-bundle.pem dbname=DBName user=jane_doe password=$PGPASSWORD"
```

如果您想通过代理连接到数据库实例，请参阅[使用 IAM 身份验证连接到数据库](rds-proxy-connecting.md#rds-proxy-connecting-iam)。

# 使用 IAM 身份验证和 适用于 .NET 的 AWS SDK 连接到数据库实例
<a name="UsingWithRDS.IAMDBAuth.Connecting.NET"></a>

您可以使用 适用于 .NET 的 AWS SDK 连接到 RRDS for MariaDB、MySQL 或 PostgreSQL 数据库实例 ，如下所述。

**先决条件**  
以下是使用 IAM 身份验证连接到数据库实例的先决条件：
+ [启用和禁用 IAM 数据库身份验证](UsingWithRDS.IAMDBAuth.Enabling.md)
+ [创建和使用适用于 IAM 数据库访问的 IAM 策略](UsingWithRDS.IAMDBAuth.IAMPolicy.md)
+ [使用 IAM 身份验证创建数据库账户](UsingWithRDS.IAMDBAuth.DBAccounts.md)

**示例**  
以下代码示例演示如何生成身份验证令牌，然后使用该令牌连接到数据库实例。

要运行该代码示例，您需要使用 适用于 .NET 的 AWS SDK 网站上提供的 [AWS](https://aws.amazon.com/sdk-for-net/)。`AWSSDK.CORE` 和 `AWSSDK.RDS` 程序包是必需的。要连接到数据库实例，请使用用于数据库引擎的 .NET 数据库连接器，例如 MySqlConnector for MariaDB 或 MySQL，或 Npgsql for PostgreSQL。

此代码连接到 MariaDB 或 MySQL 数据库实例。根据需要修改以下变量的值：
+ `server` – 要访问的数据库实例的终端节点。
+ `user` – 要访问的数据库账户
+ `database` – 要访问的数据库
+ `port` – 用于连接到数据库实例的端口号
+ `SslMode` – 要使用的 SSL 模式

  当您使用 `SslMode=Required` 时，SSL 连接将针对 SSL 证书中的终端节点验证数据库实例终端节点。
+ `SslCa` – Amazon RDS 的 SSL 证书的完整路径

  要下载证书，请参阅 [使用 SSL/TLS 加密与数据库实例或集群的连接](UsingWithRDS.SSL.md)。

**注意**  
不能使用自定义 Route 53 DNS 记录代替数据库实例端点来生成身份验证令牌。

```
using System;
using System.Data;
using MySql.Data;
using MySql.Data.MySqlClient;
using Amazon;

namespace ubuntu
{
  class Program
  {
    static void Main(string[] args)
    {
      var pwd = Amazon.RDS.Util.RDSAuthTokenGenerator.GenerateAuthToken(RegionEndpoint.USEast1, "mysqldb.123456789012.us-east-1.rds.amazonaws.com", 3306, "jane_doe");
      // for debug only Console.Write("{0}\n", pwd);  //this verifies the token is generated

      MySqlConnection conn = new MySqlConnection($"server=mysqldb.123456789012.us-east-1.rds.amazonaws.com;user=jane_doe;database=mydB;port=3306;password={pwd};SslMode=Required;SslCa=full_path_to_ssl_certificate");
      conn.Open();

      // Define a query
      MySqlCommand sampleCommand = new MySqlCommand("SHOW DATABASES;", conn);

      // Execute a query
      MySqlDataReader mysqlDataRdr = sampleCommand.ExecuteReader();

      // Read all rows and output the first column in each row
      while (mysqlDataRdr.Read())
        Console.WriteLine(mysqlDataRdr[0]);

      mysqlDataRdr.Close();
      // Close connection
      conn.Close();
    }
  }
}
```

此代码连接到 PostgreSQL 数据库实例。

根据需要修改以下变量的值：
+ `Server` – 要访问的数据库实例的终端节点。
+ `User ID` – 要访问的数据库账户
+ `Database` – 要访问的数据库
+ `Port` – 用于连接到数据库实例的端口号
+ `SSL Mode` – 要使用的 SSL 模式

  当您使用 `SSL Mode=Required` 时，SSL 连接将针对 SSL 证书中的终端节点验证数据库实例终端节点。
+ `Root Certificate` – Amazon RDS 的 SSL 证书的完整路径

  要下载证书，请参阅 [使用 SSL/TLS 加密与数据库实例或集群的连接](UsingWithRDS.SSL.md)。

**注意**  
不能使用自定义 Route 53 DNS 记录代替数据库实例端点来生成身份验证令牌。

```
using System;
using Npgsql;
using Amazon.RDS.Util;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            var pwd = RDSAuthTokenGenerator.GenerateAuthToken("postgresmydb.123456789012.us-east-1.rds.amazonaws.com", 5432, "jane_doe");
// for debug only Console.Write("{0}\n", pwd);  //this verifies the token is generated

            NpgsqlConnection conn = new NpgsqlConnection($"Server=postgresmydb.123456789012.us-east-1.rds.amazonaws.com;User Id=jane_doe;Password={pwd};Database=mydb;SSL Mode=Require;Root Certificate=full_path_to_ssl_certificate");
            conn.Open();

            // Define a query
                   NpgsqlCommand cmd = new NpgsqlCommand("select count(*) FROM pg_user", conn);

            // Execute a query
            NpgsqlDataReader dr = cmd.ExecuteReader();

            // Read all rows and output the first column in each row
            while (dr.Read())
                Console.Write("{0}\n", dr[0]);

            // Close connection
            conn.Close();
        }
    }
}
```

如果您想通过代理连接到数据库实例，请参阅[使用 IAM 身份验证连接到数据库](rds-proxy-connecting.md#rds-proxy-connecting-iam)。

# 使用 IAM 身份验证和 适用于 Go 的 AWS SDK 连接到数据库实例
<a name="UsingWithRDS.IAMDBAuth.Connecting.Go"></a>

您可以使用 适用于 Go 的 AWS SDK 连接到 RRDS for MariaDB、MySQL 或 PostgreSQL 数据库实例 ，如下所述。

**先决条件**  
以下是使用 IAM 身份验证连接到数据库实例的先决条件：
+ [启用和禁用 IAM 数据库身份验证](UsingWithRDS.IAMDBAuth.Enabling.md)
+ [创建和使用适用于 IAM 数据库访问的 IAM 策略](UsingWithRDS.IAMDBAuth.IAMPolicy.md)
+ [使用 IAM 身份验证创建数据库账户](UsingWithRDS.IAMDBAuth.DBAccounts.md)

**示例**  
要运行上述代码示例，您需要使用 适用于 Go 的 AWS SDK 网站上提供的 [AWS](https://aws.amazon.com/sdk-for-go/)。

根据需要修改以下变量的值：
+ `dbName` – 要访问的数据库
+ `dbUser` – 要访问的数据库账户
+ `dbHost` – 要访问的数据库实例的终端节点。
**注意**  
不能使用自定义 Route 53 DNS 记录代替数据库实例端点来生成身份验证令牌。
+ `dbPort` – 用于连接到数据库实例的端口号
+ `region` – 在其中运行数据库实例的 AWS 区域

此外，请确保示例代码中的导入库存在于您的系统中。

**重要**  
本节中的示例使用以下代码提供从本地环境访问数据库的凭证：  
`creds := credentials.NewEnvCredentials()`  
如果要从AWS服务（如 Amazon EC2 或 Amazon ECS）访问数据库，则可以用以下代码替换：  
`sess := session.Must(session.NewSession())`  
`creds := sess.Config.Credentials`  
如果您进行此更改，请确保添加以下导入：  
`"github.com/aws/aws-sdk-go/aws/session"`

**Topics**
+ [使用 IAM 身份验证和 适用于 Go 的 AWS SDK V2 进行连接](#UsingWithRDS.IAMDBAuth.Connecting.GoV2)
+ [使用 IAM 身份验证和 适用于 Go 的 AWS SDK V1 进行连接](#UsingWithRDS.IAMDBAuth.Connecting.GoV1)

## 使用 IAM 身份验证和 适用于 Go 的 AWS SDK V2 进行连接
<a name="UsingWithRDS.IAMDBAuth.Connecting.GoV2"></a>

您可以使用 IAM 身份验证和 适用于 Go 的 AWS SDK V2 连接到数据库实例

以下代码示例演示如何生成身份验证令牌，然后使用该令牌连接到数据库实例。

此代码连接到 MariaDB 或 MySQL 数据库实例。

```
package main
                
import (
     "context"
     "database/sql"
     "fmt"

     "github.com/aws/aws-sdk-go-v2/config"
     "github.com/aws/aws-sdk-go-v2/feature/rds/auth"
     _ "github.com/go-sql-driver/mysql"
)

func main() {

     var dbName string = "DatabaseName"
     var dbUser string = "DatabaseUser"
     var dbHost string = "mysqldb.123456789012.us-east-1.rds.amazonaws.com"
     var dbPort int = 3306
     var dbEndpoint string = fmt.Sprintf("%s:%d", dbHost, dbPort)
     var region string = "us-east-1"

    cfg, err := config.LoadDefaultConfig(context.TODO())
    if err != nil {
    	panic("configuration error: " + err.Error())
    }

    authenticationToken, err := auth.BuildAuthToken(
    	context.TODO(), dbEndpoint, region, dbUser, cfg.Credentials)
    if err != nil {
	    panic("failed to create authentication token: " + err.Error())
    }

    dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?tls=true&allowCleartextPasswords=true",
        dbUser, authenticationToken, dbEndpoint, dbName,
    )

    db, err := sql.Open("mysql", dsn)
    if err != nil {
        panic(err)
    }

    err = db.Ping()
    if err != nil {
        panic(err)
    }
}
```

此代码连接到 PostgreSQL 数据库实例。

```
package main

import (
     "context"
     "database/sql"
     "fmt"

     "github.com/aws/aws-sdk-go-v2/config"
     "github.com/aws/aws-sdk-go-v2/feature/rds/auth"
     _ "github.com/lib/pq"
)

func main() {

     var dbName string = "DatabaseName"
     var dbUser string = "DatabaseUser"
     var dbHost string = "postgresmydb.123456789012.us-east-1.rds.amazonaws.com"
     var dbPort int = 5432
     var dbEndpoint string = fmt.Sprintf("%s:%d", dbHost, dbPort)
     var region string = "us-east-1"

    cfg, err := config.LoadDefaultConfig(context.TODO())
    if err != nil {
    	panic("configuration error: " + err.Error())
    }

    authenticationToken, err := auth.BuildAuthToken(
    	context.TODO(), dbEndpoint, region, dbUser, cfg.Credentials)
    if err != nil {
	    panic("failed to create authentication token: " + err.Error())
    }

    dsn := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s",
        dbHost, dbPort, dbUser, authenticationToken, dbName,
    )

    db, err := sql.Open("postgres", dsn)
    if err != nil {
        panic(err)
    }

    err = db.Ping()
    if err != nil {
        panic(err)
    }
}
```

如果您想通过代理连接到数据库实例，请参阅[使用 IAM 身份验证连接到数据库](rds-proxy-connecting.md#rds-proxy-connecting-iam)。

## 使用 IAM 身份验证和 适用于 Go 的 AWS SDK V1 进行连接
<a name="UsingWithRDS.IAMDBAuth.Connecting.GoV1"></a>

使用 IAM 身份验证和 适用于 Go 的 AWS SDK V1 连接到数据库实例

以下代码示例演示如何生成身份验证令牌，然后使用该令牌连接到数据库实例。

此代码连接到 MariaDB 或 MySQL 数据库实例。

```
package main
         
import (
    "database/sql"
    "fmt"
    "log"

    "github.com/aws/aws-sdk-go/aws/credentials"
    "github.com/aws/aws-sdk-go/service/rds/rdsutils"
    _ "github.com/go-sql-driver/mysql"
)

func main() {
    dbName := "app"
    dbUser := "jane_doe"
    dbHost := "mysqldb.123456789012.us-east-1.rds.amazonaws.com"
    dbPort := 3306
    dbEndpoint := fmt.Sprintf("%s:%d", dbHost, dbPort)
    region := "us-east-1"

    creds := credentials.NewEnvCredentials()
    authToken, err := rdsutils.BuildAuthToken(dbEndpoint, region, dbUser, creds)
    if err != nil {
        panic(err)
    }

    dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?tls=true&allowCleartextPasswords=true",
        dbUser, authToken, dbEndpoint, dbName,
    )

    db, err := sql.Open("mysql", dsn)
    if err != nil {
        panic(err)
    }

    err = db.Ping()
    if err != nil {
        panic(err)
    }
}
```

此代码连接到 PostgreSQL 数据库实例。

```
package main

import (
	"database/sql"
	"fmt"

	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/service/rds/rdsutils"
	_ "github.com/lib/pq"
)

func main() {
    dbName := "app"
    dbUser := "jane_doe"
    dbHost := "postgresmydb.123456789012.us-east-1.rds.amazonaws.com"
    dbPort := 5432
    dbEndpoint := fmt.Sprintf("%s:%d", dbHost, dbPort)
    region := "us-east-1"

    creds := credentials.NewEnvCredentials()
    authToken, err := rdsutils.BuildAuthToken(dbEndpoint, region, dbUser, creds)
    if err != nil {
        panic(err)
    }

    dsn := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s",
        dbHost, dbPort, dbUser, authToken, dbName,
    )

    db, err := sql.Open("postgres", dsn)
    if err != nil {
        panic(err)
    }

    err = db.Ping()
    if err != nil {
        panic(err)
    }
}
```

如果您想通过代理连接到数据库实例，请参阅[使用 IAM 身份验证连接到数据库](rds-proxy-connecting.md#rds-proxy-connecting-iam)。

# 使用 IAM 身份验证和 适用于 Java 的 AWS SDK 连接到数据库实例
<a name="UsingWithRDS.IAMDBAuth.Connecting.Java"></a>

您可以使用 适用于 Java 的 AWS SDK 连接到 RRDS for MariaDB、MySQL 或 PostgreSQL 数据库实例 ，如下所述。

**先决条件**  
以下是使用 IAM 身份验证连接到数据库实例的先决条件：
+ [启用和禁用 IAM 数据库身份验证](UsingWithRDS.IAMDBAuth.Enabling.md)
+ [创建和使用适用于 IAM 数据库访问的 IAM 策略](UsingWithRDS.IAMDBAuth.IAMPolicy.md)
+ [使用 IAM 身份验证创建数据库账户](UsingWithRDS.IAMDBAuth.DBAccounts.md)
+ [设置适用于 Java 的AWS开发工具包](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/setup-install.html)

有关如何使用 SDK for Java 2.x 的示例，请参阅 [Amazon RDS examples using SDK for Java 2.x](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/java_rds_code_examples.html)。也可以使用 AWS 高级 JDBC 包装器，请参阅 [AWS Advanced JDBC Wrapper documentation](https://github.com/aws/aws-advanced-jdbc-wrapper/blob/main/docs/Documentation.md)。

**Topics**
+ [生成 IAM 身份验证令牌](#UsingWithRDS.IAMDBAuth.Connecting.Java.AuthToken)
+ [手动构造 IAM 身份验证令牌](#UsingWithRDS.IAMDBAuth.Connecting.Java.AuthToken2)
+ [连接到数据库实例](#UsingWithRDS.IAMDBAuth.Connecting.Java.AuthToken.Connect)

## 生成 IAM 身份验证令牌
<a name="UsingWithRDS.IAMDBAuth.Connecting.Java.AuthToken"></a>

如果您使用适用于 Java 的 AWS SDK编写程序，则可使用 `RdsIamAuthTokenGenerator` 类获取已签名的身份验证令牌。使用此类需要提供 AWS 凭证。为此，创建 `DefaultAWSCredentialsProviderChain` 类的实例。`DefaultAWSCredentialsProviderChain` 使用它在[默认凭证提供程序链](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/credentials.html#credentials-default)中找到的第一个 AWS 访问密钥和私有密钥。有关 AWS 访问密钥的更多信息，请参阅[管理用户的访问密钥](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html)。

**注意**  
不能使用自定义 Route 53 DNS 记录代替数据库实例端点来生成身份验证令牌。

在创建一个 `RdsIamAuthTokenGenerator` 实例后，您可调用 `getAuthToken` 方法以获取已签名的令牌。提供 AWS 区域、主机名、端口号和用户名。以下代码示例说明了如何执行该操作。

```
package com.amazonaws.codesamples;

import com.amazonaws.auth.DefaultAWSCredentialsProviderChain;
import com.amazonaws.services.rds.auth.GetIamAuthTokenRequest;
import com.amazonaws.services.rds.auth.RdsIamAuthTokenGenerator;

public class GenerateRDSAuthToken {

    public static void main(String[] args) {

	    String region = "us-west-2";
	    String hostname = "rdsmysql.123456789012.us-west-2.rds.amazonaws.com";
	    String port = "3306";
	    String username = "jane_doe";
	
	    System.out.println(generateAuthToken(region, hostname, port, username));
    }

    static String generateAuthToken(String region, String hostName, String port, String username) {

	    RdsIamAuthTokenGenerator generator = RdsIamAuthTokenGenerator.builder()
		    .credentials(new DefaultAWSCredentialsProviderChain())
		    .region(region)
		    .build();

	    String authToken = generator.getAuthToken(
		    GetIamAuthTokenRequest.builder()
		    .hostname(hostName)
		    .port(Integer.parseInt(port))
		    .userName(username)
		    .build());
	    
	    return authToken;
    }

}
```

## 手动构造 IAM 身份验证令牌
<a name="UsingWithRDS.IAMDBAuth.Connecting.Java.AuthToken2"></a>

在 Java 中，生成身份验证令牌的最简单方式是使用 `RdsIamAuthTokenGenerator`。此类将为您创建一个身份验证令牌，然后使用 AWS 签名版本 4 为该令牌签名。有关更多信息，请参阅《AWS 一般参考》**中的[签名版本 4 签名流程](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html)。

不过，您也可以手动构造身份验证令牌并为之签名，如以下代码示例中所示。

```
package com.amazonaws.codesamples;

import com.amazonaws.SdkClientException;
import com.amazonaws.auth.DefaultAWSCredentialsProviderChain;
import com.amazonaws.auth.SigningAlgorithm;
import com.amazonaws.util.BinaryUtils;
import org.apache.commons.lang3.StringUtils;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.SortedMap;
import java.util.TreeMap;

import static com.amazonaws.auth.internal.SignerConstants.AWS4_TERMINATOR;
import static com.amazonaws.util.StringUtils.UTF8;

public class CreateRDSAuthTokenManually {
    public static String httpMethod = "GET";
    public static String action = "connect";
    public static String canonicalURIParameter = "/";
    public static SortedMap<String, String> canonicalQueryParameters = new TreeMap();
    public static String payload = StringUtils.EMPTY;
    public static String signedHeader = "host";
    public static String algorithm = "AWS4-HMAC-SHA256";
    public static String serviceName = "rds-db";
    public static String requestWithoutSignature;

    public static void main(String[] args) throws Exception {

        String region = "us-west-2";
        String instanceName = "rdsmysql.123456789012.us-west-2.rds.amazonaws.com";
        String port = "3306";
        String username = "jane_doe";
	
        Date now = new Date();
        String date = new SimpleDateFormat("yyyyMMdd").format(now);
        String dateTimeStamp = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'").format(now);
        DefaultAWSCredentialsProviderChain creds = new DefaultAWSCredentialsProviderChain();
	    String awsAccessKey = creds.getCredentials().getAWSAccessKeyId();
	    String awsSecretKey = creds.getCredentials().getAWSSecretKey();
        String expiryMinutes = "900";
        
        System.out.println("Step 1:  Create a canonical request:");
        String canonicalString = createCanonicalString(username, awsAccessKey, date, dateTimeStamp, region, expiryMinutes, instanceName, port);
        System.out.println(canonicalString);
        System.out.println();

        System.out.println("Step 2:  Create a string to sign:");        
        String stringToSign = createStringToSign(dateTimeStamp, canonicalString, awsAccessKey, date, region);
        System.out.println(stringToSign);
        System.out.println();

        System.out.println("Step 3:  Calculate the signature:");        
        String signature = BinaryUtils.toHex(calculateSignature(stringToSign, newSigningKey(awsSecretKey, date, region, serviceName)));
        System.out.println(signature);
        System.out.println();

        System.out.println("Step 4:  Add the signing info to the request");                
        System.out.println(appendSignature(signature));
        System.out.println();
        
    }

    //Step 1: Create a canonical request date should be in format YYYYMMDD and dateTime should be in format YYYYMMDDTHHMMSSZ
    public static String createCanonicalString(String user, String accessKey, String date, String dateTime, String region, String expiryPeriod, String hostName, String port) throws Exception {
        canonicalQueryParameters.put("Action", action);
        canonicalQueryParameters.put("DBUser", user);
        canonicalQueryParameters.put("X-Amz-Algorithm", "AWS4-HMAC-SHA256");
        canonicalQueryParameters.put("X-Amz-Credential", accessKey + "%2F" + date + "%2F" + region + "%2F" + serviceName + "%2Faws4_request");
        canonicalQueryParameters.put("X-Amz-Date", dateTime);
        canonicalQueryParameters.put("X-Amz-Expires", expiryPeriod);
        canonicalQueryParameters.put("X-Amz-SignedHeaders", signedHeader);
        String canonicalQueryString = "";
        while(!canonicalQueryParameters.isEmpty()) {
            String currentQueryParameter = canonicalQueryParameters.firstKey();
            String currentQueryParameterValue = canonicalQueryParameters.remove(currentQueryParameter);
            canonicalQueryString = canonicalQueryString + currentQueryParameter + "=" + currentQueryParameterValue;
            if (!currentQueryParameter.equals("X-Amz-SignedHeaders")) {
                canonicalQueryString += "&";
            }
        }
        String canonicalHeaders = "host:" + hostName + ":" + port + '\n';
        requestWithoutSignature = hostName + ":" + port + "/?" + canonicalQueryString;

        String hashedPayload = BinaryUtils.toHex(hash(payload));
        return httpMethod + '\n' + canonicalURIParameter + '\n' + canonicalQueryString + '\n' + canonicalHeaders + '\n' + signedHeader + '\n' + hashedPayload;

    }

    //Step 2: Create a string to sign using sig v4
    public static String createStringToSign(String dateTime, String canonicalRequest, String accessKey, String date, String region) throws Exception {
        String credentialScope = date + "/" + region + "/" + serviceName + "/aws4_request";
        return algorithm + '\n' + dateTime + '\n' + credentialScope + '\n' + BinaryUtils.toHex(hash(canonicalRequest));

    }

    //Step 3: Calculate signature
    /**
     * Step 3 of the &AWS; Signature version 4 calculation. It involves deriving
     * the signing key and computing the signature. Refer to
     * http://docs.aws.amazon
     * .com/general/latest/gr/sigv4-calculate-signature.html
     */
    public static byte[] calculateSignature(String stringToSign,
                                            byte[] signingKey) {
        return sign(stringToSign.getBytes(Charset.forName("UTF-8")), signingKey,
                SigningAlgorithm.HmacSHA256);
    }

    public static byte[] sign(byte[] data, byte[] key,
                          SigningAlgorithm algorithm) throws SdkClientException {
        try {
            Mac mac = algorithm.getMac();
            mac.init(new SecretKeySpec(key, algorithm.toString()));
            return mac.doFinal(data);
        } catch (Exception e) {
            throw new SdkClientException(
                    "Unable to calculate a request signature: "
                            + e.getMessage(), e);
        }
    }

    public static byte[] newSigningKey(String secretKey,
                                   String dateStamp, String regionName, String serviceName) {
        byte[] kSecret = ("AWS4" + secretKey).getBytes(Charset.forName("UTF-8"));
        byte[] kDate = sign(dateStamp, kSecret, SigningAlgorithm.HmacSHA256);
        byte[] kRegion = sign(regionName, kDate, SigningAlgorithm.HmacSHA256);
        byte[] kService = sign(serviceName, kRegion,
                SigningAlgorithm.HmacSHA256);
        return sign(AWS4_TERMINATOR, kService, SigningAlgorithm.HmacSHA256);
    }

    public static byte[] sign(String stringData, byte[] key,
                       SigningAlgorithm algorithm) throws SdkClientException {
        try {
            byte[] data = stringData.getBytes(UTF8);
            return sign(data, key, algorithm);
        } catch (Exception e) {
            throw new SdkClientException(
                    "Unable to calculate a request signature: "
                            + e.getMessage(), e);
        }
    }

    //Step 4: append the signature
    public static String appendSignature(String signature) {
        return requestWithoutSignature + "&X-Amz-Signature=" + signature;
    }

    public static byte[] hash(String s) throws Exception {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            md.update(s.getBytes(UTF8));
            return md.digest();
        } catch (Exception e) {
            throw new SdkClientException(
                    "Unable to compute hash while signing request: "
                            + e.getMessage(), e);
        }
    }
}
```

## 连接到数据库实例
<a name="UsingWithRDS.IAMDBAuth.Connecting.Java.AuthToken.Connect"></a>

以下代码示例演示如何生成一个身份验证令牌，然后使用该令牌连接到运行 MariaDB 或 MySQL 的实例。

要运行该代码示例，您需要使用 适用于 Java 的 AWS SDK 网站上提供的 [AWS](https://aws.amazon.com/sdk-for-java/)。此外，您需要：
+ MySQL Connector/J。此代码示例已使用 `mysql-connector-java-5.1.33-bin.jar` 进行测试。
+ 特定于AWS区域的 Amazon RDS 的中间证书。（有关更多信息，请参阅 [使用 SSL/TLS 加密与数据库实例或集群的连接](UsingWithRDS.SSL.md)。） 在运行时，类加载程序会在与此 Java 代码示例相同的目录中查找证书以便可以找到它。
+ 根据需要修改以下变量的值：
  + `RDS_INSTANCE_HOSTNAME` – 要访问的数据库实例的主机名。
  + `RDS_INSTANCE_PORT` – 用于连接到 PostgreSQL 数据库实例的端口号。
  + `REGION_NAME` – 在其中运行数据库实例的AWS区域。
  + `DB_USER` – 要访问的数据库账户
  + `SSL_CERTIFICATE` – 特定于AWS区域的 Amazon RDS 的中间证书。

    要为AWS区域下载证书，请参阅[使用 SSL/TLS 加密与数据库实例或集群的连接](UsingWithRDS.SSL.md)。将 SSL 证书放置在此 Java 程序文件所在的同一目录中，以便类加载程序可在运行时找到此证书。

此代码示例将从[默认凭证提供程序链](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/credentials.html#credentials-default)获取 AWS 凭证。

**注意**  
作为安全最佳实践，请为 `DEFAULT_KEY_STORE_PASSWORD` 指定除此处所示提示以外的密码。

```
package com.amazonaws.samples;

import com.amazonaws.services.rds.auth.RdsIamAuthTokenGenerator;
import com.amazonaws.services.rds.auth.GetIamAuthTokenRequest;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.auth.DefaultAWSCredentialsProviderChain;
import com.amazonaws.auth.AWSStaticCredentialsProvider;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;

import java.net.URL;

public class IAMDatabaseAuthenticationTester {
    //&AWS; Credentials of the IAM user with policy enabling IAM Database Authenticated access to the db by the db user.
    private static final DefaultAWSCredentialsProviderChain creds = new DefaultAWSCredentialsProviderChain();
    private static final String AWS_ACCESS_KEY = creds.getCredentials().getAWSAccessKeyId();
    private static final String AWS_SECRET_KEY = creds.getCredentials().getAWSSecretKey();

    //Configuration parameters for the generation of the IAM Database Authentication token
    private static final String RDS_INSTANCE_HOSTNAME = "rdsmysql.123456789012.us-west-2.rds.amazonaws.com";
    private static final int RDS_INSTANCE_PORT = 3306;
    private static final String REGION_NAME = "us-west-2";
    private static final String DB_USER = "jane_doe";
    private static final String JDBC_URL = "jdbc:mysql://" + RDS_INSTANCE_HOSTNAME + ":" + RDS_INSTANCE_PORT;

    private static final String SSL_CERTIFICATE = "rds-ca-2019-us-west-2.pem";

    private static final String KEY_STORE_TYPE = "JKS";
    private static final String KEY_STORE_PROVIDER = "SUN";
    private static final String KEY_STORE_FILE_PREFIX = "sys-connect-via-ssl-test-cacerts";
    private static final String KEY_STORE_FILE_SUFFIX = ".jks";
    private static final String DEFAULT_KEY_STORE_PASSWORD = "changeit";

    public static void main(String[] args) throws Exception {
        //get the connection
        Connection connection = getDBConnectionUsingIam();

        //verify the connection is successful
        Statement stmt= connection.createStatement();
        ResultSet rs=stmt.executeQuery("SELECT 'Success!' FROM DUAL;");
        while (rs.next()) {
        	    String id = rs.getString(1);
            System.out.println(id); //Should print "Success!"
        }

        //close the connection
        stmt.close();
        connection.close();
        
        clearSslProperties();
        
    }

    /**
     * This method returns a connection to the db instance authenticated using IAM Database Authentication
     * @return
     * @throws Exception
     */
    private static Connection getDBConnectionUsingIam() throws Exception {
        setSslProperties();
        return DriverManager.getConnection(JDBC_URL, setMySqlConnectionProperties());
    }

    /**
     * This method sets the mysql connection properties which includes the IAM Database Authentication token
     * as the password. It also specifies that SSL verification is required.
     * @return
     */
    private static Properties setMySqlConnectionProperties() {
        Properties mysqlConnectionProperties = new Properties();
        mysqlConnectionProperties.setProperty("verifyServerCertificate","true");
        mysqlConnectionProperties.setProperty("useSSL", "true");
        mysqlConnectionProperties.setProperty("user",DB_USER);
        mysqlConnectionProperties.setProperty("password",generateAuthToken());
        return mysqlConnectionProperties;
    }

    /**
     * This method generates the IAM Auth Token.
     * An example IAM Auth Token would look like follows:
     * btusi123---cmz7kenwo2ye---rds---cn-north-1.amazonaws.com.rproxy.goskope.com.cn:3306/?Action=connect&DBUser=iamtestuser&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20171003T010726Z&X-Amz-SignedHeaders=host&X-Amz-Expires=899&X-Amz-Credential=AKIAPFXHGVDI5RNFO4AQ%2F20171003%2Fcn-north-1%2Frds-db%2Faws4_request&X-Amz-Signature=f9f45ef96c1f770cdad11a53e33ffa4c3730bc03fdee820cfdf1322eed15483b
     * @return
     */
    private static String generateAuthToken() {
        BasicAWSCredentials awsCredentials = new BasicAWSCredentials(AWS_ACCESS_KEY, AWS_SECRET_KEY);

        RdsIamAuthTokenGenerator generator = RdsIamAuthTokenGenerator.builder()
                .credentials(new AWSStaticCredentialsProvider(awsCredentials)).region(REGION_NAME).build();
        return generator.getAuthToken(GetIamAuthTokenRequest.builder()
                .hostname(RDS_INSTANCE_HOSTNAME).port(RDS_INSTANCE_PORT).userName(DB_USER).build());
    }

    /**
     * This method sets the SSL properties which specify the key store file, its type and password:
     * @throws Exception
     */
    private static void setSslProperties() throws Exception {
        System.setProperty("javax.net.ssl.trustStore", createKeyStoreFile());
        System.setProperty("javax.net.ssl.trustStoreType", KEY_STORE_TYPE);
        System.setProperty("javax.net.ssl.trustStorePassword", DEFAULT_KEY_STORE_PASSWORD);
    }

    /**
     * This method returns the path of the Key Store File needed for the SSL verification during the IAM Database Authentication to
     * the db instance.
     * @return
     * @throws Exception
     */
    private static String createKeyStoreFile() throws Exception {
        return createKeyStoreFile(createCertificate()).getPath();
    }

    /**
     *  This method generates the SSL certificate
     * @return
     * @throws Exception
     */
    private static X509Certificate createCertificate() throws Exception {
        CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
        URL url = new File(SSL_CERTIFICATE).toURI().toURL();
        if (url == null) {
            throw new Exception();
        }
        try (InputStream certInputStream = url.openStream()) {
            return (X509Certificate) certFactory.generateCertificate(certInputStream);
        }
    }

    /**
     * This method creates the Key Store File
     * @param rootX509Certificate - the SSL certificate to be stored in the KeyStore
     * @return
     * @throws Exception
     */
    private static File createKeyStoreFile(X509Certificate rootX509Certificate) throws Exception {
        File keyStoreFile = File.createTempFile(KEY_STORE_FILE_PREFIX, KEY_STORE_FILE_SUFFIX);
        try (FileOutputStream fos = new FileOutputStream(keyStoreFile.getPath())) {
            KeyStore ks = KeyStore.getInstance(KEY_STORE_TYPE, KEY_STORE_PROVIDER);
            ks.load(null);
            ks.setCertificateEntry("rootCaCertificate", rootX509Certificate);
            ks.store(fos, DEFAULT_KEY_STORE_PASSWORD.toCharArray());
        }
        return keyStoreFile;
    }
    
    /**
     * This method clears the SSL properties.
     * @throws Exception
     */
    private static void clearSslProperties() throws Exception {
           System.clearProperty("javax.net.ssl.trustStore");
           System.clearProperty("javax.net.ssl.trustStoreType");
           System.clearProperty("javax.net.ssl.trustStorePassword"); 
    }
    
}
```

如果您想通过代理连接到数据库实例，请参阅[使用 IAM 身份验证连接到数据库](rds-proxy-connecting.md#rds-proxy-connecting-iam)。

# 使用 IAM 身份验证和 适用于 Python (Boto3) 的 AWS SDK 连接到数据库实例
<a name="UsingWithRDS.IAMDBAuth.Connecting.Python"></a>

您可以使用 适用于 Python (Boto3) 的 AWS SDK 连接到 RRDS for MariaDB、MySQL 或 PostgreSQL 数据库实例 ，如下所述。

**先决条件**  
以下是使用 IAM 身份验证连接到数据库实例的先决条件：
+ [启用和禁用 IAM 数据库身份验证](UsingWithRDS.IAMDBAuth.Enabling.md)
+ [创建和使用适用于 IAM 数据库访问的 IAM 策略](UsingWithRDS.IAMDBAuth.IAMPolicy.md)
+ [使用 IAM 身份验证创建数据库账户](UsingWithRDS.IAMDBAuth.DBAccounts.md)

此外，请确保示例代码中的导入库存在于您的系统中。

**示例**  
该代码示例将配置文件用于共享凭证。有关指定凭证的信息，请参阅 适用于 Python (Boto3) 的 AWS SDK 文档中的[凭证](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html)。

以下代码示例演示如何生成身份验证令牌，然后使用该令牌连接到数据库实例。

要运行该代码示例，您需要使用 适用于 Python (Boto3) 的 AWS SDK 网站上提供的 [AWS](https://aws.amazon.com/sdk-for-python/)。

根据需要修改以下变量的值：
+ `ENDPOINT` – 要访问的数据库实例的终端节点。
+ `PORT` – 用于连接到数据库实例的端口号
+ `USER` – 要访问的数据库账户
+ `REGION` – 在其中运行数据库实例的 AWS 区域
+ `DBNAME` – 要访问的数据库
+ `SSLCERTIFICATE` – Amazon RDS 的 SSL 证书的完整路径

  对于 `ssl_ca`，请指定 SSL 证书。要下载 SSL 证书，请参阅 [使用 SSL/TLS 加密与数据库实例或集群的连接](UsingWithRDS.SSL.md)。

**注意**  
不能使用自定义 Route 53 DNS 记录代替数据库实例端点来生成身份验证令牌。

此代码连接到 MariaDB 或 MySQL 数据库实例。

在运行此代码之前，请按照 [Python 包索引](https://pypi.org/project/PyMySQL/)中的说明安装 PyMySQL 驱动程序。

```
import pymysql
import sys
import boto3
import os

ENDPOINT="mysqldb.123456789012.us-east-1.rds.amazonaws.com"
PORT="3306"
USER="jane_doe"
REGION="us-east-1"
DBNAME="mydb"
os.environ['LIBMYSQL_ENABLE_CLEARTEXT_PLUGIN'] = '1'

#gets the credentials from .aws/credentials
session = boto3.Session(profile_name='default')
client = session.client('rds')

token = client.generate_db_auth_token(DBHostname=ENDPOINT, Port=PORT, DBUsername=USER, Region=REGION)

try:
    conn =  pymysql.connect(auth_plugin_map={'mysql_clear_password':None},host=ENDPOINT, user=USER, password=token, port=PORT, database=DBNAME, ssl_ca='SSLCERTIFICATE', ssl_verify_identity=True, ssl_verify_cert=True)
    cur = conn.cursor()
    cur.execute("""SELECT now()""")
    query_results = cur.fetchall()
    print(query_results)
except Exception as e:
    print("Database connection failed due to {}".format(e))
```

此代码连接到 PostgreSQL 数据库实例。

在运行此代码之前，请按照 [Psycopg 文档](https://pypi.org/project/psycopg2/)中的说明安装 `psycopg2`。

```
import psycopg2
import sys
import boto3
import os

ENDPOINT="postgresmydb.123456789012.us-east-1.rds.amazonaws.com"
PORT="5432"
USER="jane_doe"
REGION="us-east-1"
DBNAME="mydb"

#gets the credentials from .aws/credentials
session = boto3.Session(profile_name='RDSCreds')
client = session.client('rds')

token = client.generate_db_auth_token(DBHostname=ENDPOINT, Port=PORT, DBUsername=USER, Region=REGION)

try:
    conn = psycopg2.connect(host=ENDPOINT, port=PORT, database=DBNAME, user=USER, password=token, sslrootcert="SSLCERTIFICATE")
    cur = conn.cursor()
    cur.execute("""SELECT now()""")
    query_results = cur.fetchall()
    print(query_results)
except Exception as e:
    print("Database connection failed due to {}".format(e))
```

如果您想通过代理连接到数据库实例，请参阅[使用 IAM 身份验证连接到数据库](rds-proxy-connecting.md#rds-proxy-connecting-iam)。

# IAM 数据库身份验证故障排除
<a name="UsingWithRDS.IAMDBAuth.Troubleshooting"></a>

下面，您可以找到一些常见 IAM 数据库身份验证问题的故障排除思路，以及有关 IAM 数据库身份验证的 CloudWatch 日志和指标的信息。

## 将 IAM 数据库身份验证错误日志导出到 CloudWatch Logs
<a name="UsingWithRDS.IAMDBAuth.Troubleshooting.ErrorLogs"></a>

IAM 数据库身份验证错误日志存储在数据库主机上，您可以将这些日志导出到您的 CloudWatch Logs 账户。使用本页中的日志和补救方法来解决 IAM 数据库身份验证问题。

可以通过控制台、AWS CLI 和 RDS API 启用向 CloudWatch Logs 导出日志。有关控制台说明，请参阅 [将数据库日志发布到 Amazon CloudWatch Logs](USER_LogAccess.Procedural.UploadtoCloudWatch.md)。

要在从 AWS CLI 中创建数据库实例时将 IAM 数据库身份验证错误日志导出到 CloudWatch Logs，请使用以下命令：

```
aws rds create-db-instance --db-instance-identifier mydbinstance \
--region us-east-1 \
--db-instance-class db.t3.large \
--allocated-storage 50 \
--engine postgres \
--engine-version 16 \
--port 5432 \
--master-username master \
--master-user-password password \
--publicly-accessible \
--enable-iam-database-authentication \
--enable-cloudwatch-logs-exports=iam-db-auth-error
```

要在从 AWS CLI 中修改数据库实例时将 IAM 数据库身份验证错误日志导出到 CloudWatch Logs，请使用以下命令：

```
aws rds modify-db-instance --db-instance-identifier mydbinstance \
--region us-east-1 \
--cloudwatch-logs-export-configuration '{"EnableLogTypes":["iam-db-auth-error"]}'
```

要验证数据库实例是否正在将 IAM 数据库身份验证日志导出到 CloudWatch Logs，请检查 `describe-db-instances` 命令输出中的 `EnabledCloudwatchLogsExports` 参数是否设置为 `iam-db-auth-error`。

```
aws rds describe-db-instances --region us-east-1 --db-instance-identifier mydbinstance
            ...
            
             "EnabledCloudwatchLogsExports": [
                "iam-db-auth-error"
            ],
            ...
```

## IAM 数据库身份验证 CloudWatch 指标
<a name="UsingWithRDS.IAMDBAuth.Troubleshooting.CWMetrics"></a>

Amazon RDS 向您的 Amazon CloudWatch 账户提供有关 IAM 数据库身份验证的近乎实时的指标。下表列出了使用 CloudWatch 时可用的 IAM 数据库身份验证指标：


| 指标 | 描述 | 
| --- | --- | 
|  `IamDbAuthConnectionRequests`  |  使用 IAM 数据库身份验证发出的连接请求总数。  | 
|  `IamDbAuthConnectionSuccess`  |  成功的 IAM 数据库身份验证请求总数。  | 
|  `IamDbAuthConnectionFailure`  |  失败的 IAM 数据库身份验证请求总数。  | 
|  `IamDbAuthConnectionFailureInvalidToken`  | 由于令牌无效而失败的 IAM 数据库身份验证请求总数。 | 
|  `IamDbAuthConnectionFailureInsufficientPermissions`  |  由于策略或权限不正确而失败的 IAM 数据库身份验证请求总数。  | 
|  `IamDbAuthConnectionFailureThrottling`  |  由于 IAM 数据库身份验证节流而失败的 IAM 数据库身份验证请求总数。  | 
|  `IamDbAuthConnectionFailureServerError`  |  由于 IAM 数据库身份验证功能中的内部服务器错误而失败的 IAM 数据库身份验证请求总数。  | 

## 常见问题和解决方案
<a name="UsingWithRDS.IAMDBAuth.Troubleshooting.IssuesSolutions"></a>

 使用 IAM 数据库身份验证时可能会遇到以下问题。使用表中的修复步骤来解决问题：


| 错误 | 指标 | 原因 | 解决方案 | 
| --- | --- | --- | --- | 
|  `[ERROR] Failed to authenticate the connection request for user db_user because the provided token is malformed or otherwise invalid. (Status Code: 400, Error Code: InvalidToken)`  |  `IamDbAuthConnectionFailure` `IamDbAuthConnectionFailureInvalidToken`  |  连接请求中的 IAM 数据库身份验证令牌要么不是有效的 SigV4a 令牌，要么格式不正确。  |  在应用程序中检查令牌生成策略。在某些情况下，请确保使用有效的格式传递令牌。截断令牌（或字符串格式不正确）将使令牌失效。  | 
|  `[ERROR] Failed to authenticate the connection request for user db_user because the token age is longer than 15 minutes. (Status Code: 400, Error Code:ExpiredToken)`  |  `IamDbAuthConnectionFailure` `IamDbAuthConnectionFailureInvalidToken`  |  IAM 数据库身份验证令牌已到期。令牌仅在 15 分钟内有效。  |  检查应用程序中的令牌缓存和/或令牌重用逻辑。您不应重用超过 15 分钟的令牌。  | 
|  `[ERROR] Failed to authorize the connection request for user db_user because the IAM policy assumed by the caller 'arn:aws:sts::123456789012:assumed-role/ <RoleName>/ <RoleSession>' is not authorized to perform `rds-db:connect` on the DB instance. (Status Code: 403, Error Code:NotAuthorized)`  |  `IamDbAuthConnectionFailure` `IamDbAuthConnectionFailureInsufficientPermissions`  |  该错误可能是由于以下原因引起的： [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.Troubleshooting.html)  |  验证您在应用程序中采用的 IAM 角色和/或策略。请务必采用与连接到数据库相同的策略来生成令牌。  | 
|  `[ERROR] Failed to authorize the connection request for user db_user due to IAM DB authentication throttling. (Status Code: 429, Error Code: ThrottlingException)`  |  `IamDbAuthConnectionFailure` `IamDbAuthConnectionFailureThrottling`  | 您在短时间内向数据库发出的连接请求过多。IAM 数据库身份验证节流限制为每秒 200 个连接。 |  降低使用 IAM 身份验证建立新连接的速率。考虑使用 RDS 代理来实现连接池，以便在应用程序中重用已建立的连接。  | 
|  `[ERROR] Failed to authorize the connection request for user db_user due to an internal IAM DB authentication error. (Status Code: 500, Error Code: InternalError)`  |  `IamDbAuthConnectionFailure` `IamDbAuthConnectionFailureThrottling` |  使用 IAM 数据库身份验证授权数据库连接时出现内部错误。  |  请联系 https://aws.amazon.com/premiumsupport/ 以便调查此问题。  | 