

# 使用 AD 安全组进行 Aurora PostgreSQL 访问控制
<a name="AD.Security.Groups"></a>

从 Aurora PostgreSQL 14.10 和 15.5 版本起，可以使用 AWS Directory Service for Microsoft Active Directory（AD）安全组来管理 Aurora PostgreSQL 访问控制。早期版本的 Aurora PostgreSQL 仅支持单个用户使用 AD 进行基于 Kerberos 的身份验证。每个 AD 用户都必须显式预调配到数据库集群，才能获得访问权限。

您可以按如下所述利用 AD 安全组，而不是根据业务需求将每个 AD 用户显式预调配到数据库集群：
+ AD 用户是 Active Directory 中不同 AD 安全组的成员。这些不是由数据库集群管理员决定，而是基于业务要求，并由 AD 管理员处理。
+ 数据库集群管理员根据业务需求在数据库实例中创建数据库角色。这些数据库角色可能具有不同的权限或特权。
+ 数据库集群管理员根据每个数据库集群配置从 AD 安全组到数据库角色的映射。
+ 数据库用户可以使用其 AD 凭证访问数据库集群。访问权限基于 AD 安全组成员资格。AD 用户根据其 AD 组成员资格自动获得或失去访问权限。

## 先决条件
<a name="AD.Security.Groups.Prereq"></a>

在为 AD 安全组设置扩展之前，请确保您具备以下条件：
+ 为 PostgreSQL 数据库集群设置 Kerberos 身份验证。有关更多信息，请参阅[为 PostgreSQL 数据库集群设置 Kerberos 身份验证](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/postgresql-kerberos-setting-up.html)。
**注意**  
对于 AD 安全组，请跳过此设置过程中的“步骤 7：为 Kerberos 主体创建 PostgreSQL 用户”。
**重要**  
如果在已经启用 Kerberos 身份验证的 Aurora PostgreSQL 集群上启用 AD 安全组，则可能会遇到身份验证问题。当您向 `shared_preload_libraries` 参数添加 `pg_ad_mapping` 并重新启动数据库时，就会发生这种情况。使用集群端点时，如果尝试登录时使用的 AD 用户不是具有 `rds_ad` 角色的数据库用户，则登录可能会失败。这还可能导致引擎崩溃。要解决此问题，请在集群上禁用 Kerberos 身份验证，然后重新启用它。现有实例需要使用此变通方案，但不会影响在 2025 年 4 月之后创建的实例。
+ 在域中管理数据库集群。有关更多信息，请参阅[在域中管理数据库集群](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/postgresql-kerberos-managing.html)。

## 设置 pg\$1ad\$1mapping 扩展
<a name="AD.Security.Groups.Setup"></a>

Aurora PostgreSQL 现在提供 `pg_ad_mapping` 扩展来管理 Aurora PostgreSQL 集群中 AD 安全组和数据库角色之间的映射。有关 `pg_ad_mapping` 提供的函数的更多信息，请参阅[使用 `pg_ad_mapping` 扩展中的函数](#AD.Security.Groups.functions)。

要在 Aurora PostgreSQL 数据库集群上设置 `pg_ad_mapping` 扩展，首先要将 `pg_ad_mapping` 添加到 Aurora PostgreSQL 数据库集群的自定义数据库集群参数组上的共享库中。有关创建自定义数据库集群参数组的信息，请参阅[Amazon Aurora 的参数组](USER_WorkingWithParamGroups.md)。接下来，安装 `pg_ad_mapping` 扩展。本部分中的过程向您展示如何操作。您可以使用AWS 管理控制台或 AWS CLI。

您必须拥有 `rds_superuser` 角色的权限才能执行所有这些任务。

以下步骤假设 Aurora PostgreSQL 数据库集群与自定义数据库集群参数组相关联。

### 控制台
<a name="AD.Security.Groups.basic-setup.CON"></a>

**设置 `pg_ad_mapping` 扩展**

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

1. 在导航窗格中，选择 Aurora PostgreSQL 数据库集群的写入器实例。

1. 打开 Aurora PostgreSQL 数据库集群写入器实例的**配置**选项卡。在实例详细信息中，找到 **Parameter group**（参数组）链接。

1. 选择此链接以打开与 Aurora PostgreSQL 数据库集群关联的自定义参数。

1. 在 **Parameters**（参数）搜索字段中，键入 `shared_pre` 以查找 `shared_preload_libraries` 参数。

1. 选择 **Edit parameters**（编辑参数）以访问属性值。

1. 将 `pg_ad_mapping` 添加到 **Values**（值）字段的列表中。使用逗号分隔值列表中的项目。  
![\[添加了 pgAudit 的 shared_preload_libaries 参数的图像。\]](http://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/AuroraUserGuide/images/apg_shared_preload_pgadmapping.png)

1. 重启 Aurora PostgreSQL 数据库集群的写入器实例，以使对 `shared_preload_libraries` 参数的更改生效。

1. 当实例可用时，验证 `pg_ad_mapping` 是否已初始化。使用 `psql` 连接到 Aurora PostgreSQL 数据库集群的写入器实例，然后运行以下命令。

   ```
   SHOW shared_preload_libraries;
   shared_preload_libraries 
   --------------------------
   rdsutils,pg_ad_mapping
   (1 row)
   ```

1. 初始化 `pg_ad_mapping` 后，您现在可以创建扩展了。您需要在初始化库之后创建扩展，才能开始使用此扩展提供的函数。

   ```
   CREATE EXTENSION pg_ad_mapping;
   ```

1. 关闭 `psql` 会话。

   ```
   labdb=> \q
   ```

### AWS CLI
<a name="Appendix.PostgreSQL.CommonDBATasks.pgaudit.basic-setup.CLI"></a>

**设置 pg\$1ad\$1mapping**

要使用 AWS CLI 设置 pg\$1ad\$1mapping，您可以调用 [modify-db-parameter-group](https://docs.aws.amazon.com/cli/latest/reference/rds/modify-db-parameter-group.html) 操作来在自定义参数组中添加此参数，如以下过程所示。

1. 使用以下 AWS CLI 命令向 `shared_preload_libraries` 参数中添加 `pg_ad_mapping`。

   ```
   aws rds modify-db-parameter-group \
      --db-parameter-group-name custom-param-group-name \
      --parameters "ParameterName=shared_preload_libraries,ParameterValue=pg_ad_mapping,ApplyMethod=pending-reboot" \
      --region aws-region
   ```

1. 使用以下 AWS CLI 命令重启 Aurora PostgreSQL 数据库集群的写入器实例，以便初始化 pg\$1ad\$1mapping。

   ```
   aws rds reboot-db-instance \
       --db-instance-identifier writer-instance \
       --region aws-region
   ```

1. 当实例可用时，您可以验证 `pg_ad_mapping` 是否已初始化。使用 `psql` 连接到 Aurora PostgreSQL 数据库集群的写入器实例，然后运行以下命令。

   ```
   SHOW shared_preload_libraries;
   shared_preload_libraries 
   --------------------------
   rdsutils,pg_ad_mapping
   (1 row)
   ```

   初始化 pg\$1ad\$1mapping 后，您现在可以创建扩展了。

   ```
   CREATE EXTENSION pg_ad_mapping;
   ```

1. 关闭 `psql` 会话以便您可以使用 AWS CLI。

   ```
   labdb=> \q
   ```

## 在 PowerShell 中检索 Active Directory 组 SID
<a name="AD.Security.Groups.retrieving"></a>

安全标识符（SID）用于唯一标识安全主体或安全组。每当在 Active Directory 中创建安全组或账户时，都会为其分配一个 SID。要从 Active Directory 获取 AD 安全组 SID，可以从加入该 Active Directory 域的 Windows 客户端计算机中使用 Get-ADGroup cmdlet。Identity 参数指定用于获取相应 SID 的 Active Directory 组名称。

以下示例返回 AD 组 *adgroup1* 的 SID。

```
C:\Users\Admin> Get-ADGroup -Identity adgroup1 | select SID
            
             SID
-----------------------------------------------
S-1-5-21-3168537779-1985441202-1799118680-1612
```

## 映射数据库角色与 AD 安全组
<a name="AD.Security.Groups.mapping"></a>

您需要将数据库中的 AD 安全组显式预调配为 PostgreSQL 数据库角色。属于至少一个预调配 AD 安全组的 AD 用户将获得数据库的访问权限。您不应该向基于 AD 组安全性的数据库角色授予 `rds_ad role`。安全组的 Kerberos 身份验证将通过使用域名后缀（例如 *user1@example.com*）来触发。此数据库角色无法使用密码或 IAM 身份验证来访问数据库。

**注意**  
在数据库中具有相应数据库角色并获得 `rds_ad` 角色的 AD 用户不能作为 AD 安全组的一部分登录。他们将以单个用户身份通过数据库角色获得访问权限。

例如，accounts-group 是 AD 中的一个安全组，您希望在 Aurora PostgreSQL 中将该安全组预调配为 accounts-role。


| AD 安全组 | PosgreSQL 数据库角色 | 
| --- | --- | 
| accounts-group | accounts-role  | 

将数据库角色与 AD 安全组映射时，必须确保该数据库角色设置了 LOGIN 属性并且具有访问所需登录数据库的 CONNECT 权限。

```
postgres => alter role accounts-role login;
        
ALTER ROLE
postgres => grant connect on database accounts-db to accounts-role;
```

管理员现在可以继续创建 AD 安全组和 PostgreSQL 数据库角色之间的映射。

```
admin=>select pgadmap_set_mapping('accounts-group', 'accounts-role', <SID>, <Weight>);
```

有关检索 AD 安全组的 SID 的信息，请参阅[在 PowerShell 中检索 Active Directory 组 SID](#AD.Security.Groups.retrieving)。

在某些情况下，AD 用户可能属于多个组，在这种情况下，AD 用户将继承预调配了最高权重的数据库角色的权限。如果两个角色的权重相同，则 AD 用户将继承与最近添加的映射相对应的数据库角色的权限。建议指定权重，以反映各个数据库角色的相对权限/特权。数据库角色的权限或特权越高，应与映射条目关联的权重就越高。这将避免两个具有相同权重的映射产生歧义。

下表显示了从 AD 安全组到 Aurora PostgreSQL 数据库角色的映射示例。


| AD 安全组 | PosgreSQL 数据库角色 | 权重 | 
| --- | --- | --- | 
| accounts-group | accounts-role | 7 | 
| sales-group | sales-role | 10 | 
| dev-group | dev-role | 7 | 

在以下示例中，`user1` 将继承 sales-role 的权限，因为它的权重更高；而 `user2` 将继承 `dev-role` 的权限，因为该角色的映射是在 `accounts-role` 后创建的，它们的权重与 `accounts-role` 相同。


| 用户名 | 安全组成员资格 | 
| --- | --- | 
| user1 | accounts-group sales-group | 
| user2 | accounts-group dev-group | 

用于建立、列出和清除映射的 psql 命令如下所示。目前，无法修改单个映射条目。需要删除现有条目并重新创建映射。

```
admin=>select pgadmap_set_mapping('accounts-group', 'accounts-role', 'S-1-5-67-890', 7);
admin=>select pgadmap_set_mapping('sales-group', 'sales-role', 'S-1-2-34-560', 10);
admin=>select pgadmap_set_mapping('dev-group', 'dev-role', 'S-1-8-43-612', 7);
            
admin=>select * from pgadmap_read_mapping();
            
ad_sid       | pg_role        | weight | ad_grp 
-------------+----------------+--------+---------------
S-1-5-67-890 | accounts-role | 7      | accounts-group
S-1-2-34-560 | sales-role    | 10     | sales-group
S-1-8-43-612 | dev-role      | 7      | dev-group
(3 rows)
```

## AD 用户身份日志记录/审计
<a name="AD.Security.Groups.useridentity"></a>

使用以下命令确定当前用户或会话用户继承的数据库角色：

```
postgres=>select session_user, current_user;
            
session_user | current_user
-------------+--------------
dev-role     | dev-role

(1 row)
```

要确定 AD 安全主体身份，请使用以下命令：

```
postgres=>select principal from pg_stat_gssapi where pid = pg_backend_pid();
            
 principal        
-------------------------
 user1@example.com

(1 row)
```

目前，AD 用户身份在审计日志中不可见。可以启用 `log_connections` 参数来记录数据库会话建立。有关更多信息，请参阅 [log\$1connections](https://docs.aws.amazon.com/prescriptive-guidance/latest/tuning-postgresql-parameters/log-connections.html)。其输出包括 AD 用户身份，如下所示。然后，与此输出关联的后端 PID 有助于将操作归因回实际 AD 用户。

```
pgrole1@postgres:[615]:LOG: connection authorized: user=pgrole1 database=postgres application_name=psql GSS (authenticated=yes, encrypted=yes, principal=Admin@EXAMPLE.COM)
```

## 限制
<a name="AD.Security.Groups.limitations"></a>
+ 不支持称为 Azure Active Directory 的 Microsoft Entra ID。

## 使用 `pg_ad_mapping` 扩展中的函数
<a name="AD.Security.Groups.functions"></a>

`pg_ad_mapping` 扩展为以下函数提供了支持：

### pgadmap\$1set\$1mapping
<a name="AD.Security.Groups.functions.setmapping"></a>

此函数在 AD 安全组与具有关联权重的数据库角色之间建立映射。

#### 语法
<a name="pgadmap_set_mapping-syntax"></a>

 

```
pgadmap_set_mapping(
ad_group, 
db_role, 
ad_group_sid, 
weight)
```

#### 参数
<a name="pgadmap_set_mapping-arguments"></a>


| 参数 | 说明 | 
| --- | --- | 
| ad\$1group | AD 组的名称。值不能为 null 或空字符串。 | 
| db\$1role | 要映射到指定 AD 组的数据库角色。值不能为 Null 或空字符串。 | 
| ad\$1group\$1sid | 用于唯一标识 AD 组的安全标识符。值以“S-1-”开头，不能为 null 或空字符串。有关更多信息，请参阅 [在 PowerShell 中检索 Active Directory 组 SID](#AD.Security.Groups.retrieving)。 | 
| weight | 与数据库角色关联的权重。当用户是多个组的成员时，权重最高的角色优先。权重的默认值为 1。 | 

#### 返回类型
<a name="pgadmap_set_mapping-return-type"></a>

`None`

#### 使用说明
<a name="pgadmap_set_mapping-usage-notes"></a>

此函数添加了从 AD 安全组到数据库角色的新映射。它只能由具有 rds\$1superuser 权限的用户在数据库集群的主数据库实例上执行。

#### 示例
<a name="pgadmap_set_mapping-examples"></a>

```
postgres=> select pgadmap_set_mapping('accounts-group','accounts-role','S-1-2-33-12345-67890-12345-678',10);
            
pgadmap_set_mapping 

(1 row)
```

### pgadmap\$1read\$1mapping
<a name="AD.Security.Groups.functions.readmapping"></a>

此函数列出使用 `pgadmap_set_mapping` 函数设置的 AD 安全组和数据库角色之间的映射。

#### 语法
<a name="pgadmap_read_mapping-syntax"></a>

 

```
pgadmap_read_mapping()
```

#### 参数
<a name="pgadmap_read_mapping-arguments"></a>

`None`

#### 返回类型
<a name="pgadmap_read_mapping-return-type"></a>


| 参数 | 说明 | 
| --- | --- | 
| ad\$1group\$1sid | 用于唯一标识 AD 组的安全标识符。值以“S-1-”开头，不能为 Null 或空字符串。有关更多信息，请参阅[在 PowerShell 中检索 Active Directory 组 SID](#AD.Security.Groups.retrieving)。accounts-role@example.com | 
| db\$1role | 要映射到指定 AD 组的数据库角色。值不能为 Null 或空字符串。 | 
| weight | 与数据库角色关联的权重。当用户是多个组的成员时，权重最高的角色优先。权重的默认值为 1。 | 
| ad\$1group | AD 组的名称。值不能为 Null 或空字符串。 | 

#### 使用说明
<a name="pgadmap_read_mapping-usage-notes"></a>

调用此函数以列出 AD 安全组和数据库角色之间的所有可用映射。

#### 示例
<a name="pgadmap_read_mapping-examples"></a>

```
postgres=> select * from pgadmap_read_mapping();
            
ad_sid                              | pg_role       | weight | ad_grp 
------------------------------------+---------------+--------+------------------
S-1-2-33-12345-67890-12345-678      | accounts-role | 10     | accounts-group
(1 row)

(1 row)
```

### pgadmap\$1reset\$1mapping
<a name="AD.Security.Groups.functions.resetmapping"></a>

此函数重置使用 `pgadmap_set_mapping` 函数设置的一个或所有映射。

#### 语法
<a name="pgadmap_reset_mapping-syntax"></a>

 

```
pgadmap_reset_mapping(
ad_group_sid, 
db_role, 
weight)
```

#### 参数
<a name="pgadmap_reset_mapping-arguments"></a>


| 参数 | 说明 | 
| --- | --- | 
| ad\$1group\$1sid | 用于唯一标识 AD 组的安全标识符。 | 
| db\$1role | 要映射到指定 AD 组的数据库角色。 | 
| weight | 与数据库角色关联的权重。 | 

如果未提供任何参数，则将重置 AD 组到数据库角色的所有映射。要么需要提供所有参数，要么不提供任何参数。

#### 返回类型
<a name="pgadmap_reset_mapping-return-type"></a>

`None`

#### 使用说明
<a name="pgadmap_reset_mapping-usage-notes"></a>

调用此函数以删除 AD 组到数据库角色的特定映射或重置所有映射。此函数只能由具有 `rds_superuser` 权限的用户在数据库集群的主数据库实例上执行。

#### 示例
<a name="pgadmap_reset_mapping-examples"></a>

```
postgres=> select * from pgadmap_read_mapping();
            
   ad_sid                       | pg_role      | weight      | ad_grp 
--------------------------------+--------------+-------------+-------------------
 S-1-2-33-12345-67890-12345-678 | accounts-role| 10          | accounts-group
 S-1-2-33-12345-67890-12345-666 | sales-role   | 10          | sales-group
 
(2 rows)
postgres=> select pgadmap_reset_mapping('S-1-2-33-12345-67890-12345-678', 'accounts-role', 10);
                
pgadmap_reset_mapping   
(1 row)
                
postgres=> select * from pgadmap_read_mapping();
            
   ad_sid                       | pg_role      | weight      | ad_grp 
--------------------------------+--------------+-------------+---------------
 S-1-2-33-12345-67890-12345-666 | sales-role   | 10          | sales-group
 
(1 row)
postgres=> select pgadmap_reset_mapping();

pgadmap_reset_mapping   
(1 row)
                
postgres=> select * from pgadmap_read_mapping();
            
   ad_sid                       | pg_role      | weight      | ad_grp 
--------------------------------+--------------+-------------+--------------
 (0 rows)
```