

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 使用 Active Directory 安全群組為 Babelfish 設定 Kerberos 驗證
<a name="babelfish-kerberos-securityad"></a>

從 Babelfish 4.2.0 版開始，您可以使用 Active Directory 安全群組為 Babelfish 設定 Kerberos 身分驗證。若要使用 Active Directory 設定 Kerberos 身分驗證，以下是要完成的先決條件：
+  您必須遵循[使用 Babelfish 進行 Kerberos 身分驗證](babelfish-active-directory.md)中提到的所有步驟。
+ 確保資料庫執行個體與 Active Directory 相關聯。若要驗證，您可以在 主控台中或透過執行 [https://docs.aws.amazon.com/cli/latest/reference/rds/describe-db-instances.html](https://docs.aws.amazon.com/cli/latest/reference/rds/describe-db-instances.html) AWS CLI 命令來檢視網域成員資格的狀態。

  資料庫執行個體的狀態應為啟用 kerberos 的狀態。如需了解網域成員資格的詳細資訊，請參閱[了解網域成員資格](postgresql-kerberos-managing.md#postgresql-kerberos-managing.understanding)。
+ 使用以下查詢驗證 NetBIOS 網域名稱與 DNS 網域名稱之間的對應：

  ```
  SELECT netbios_domain_name, fq_domain_name FROM babelfish_domain_mapping;
  ```
+ 繼續進行之前，請先驗證使用個別登入的 Kerberos 身分驗證是否如預期運作。以 Active Directory 使用者身分使用 Kerberos 身分驗證的連線應會成功。如果您遇到任何問題，請參閱[常見錯誤](babelfish-active-directory.md#babelfish-active-directory-errors)。

## 設定 pg\$1ad\$1mapping 延伸模組
<a name="babelfish-kerberos-securityad-setpgextn"></a>

 您必須遵循[設定 pg\$1ad\$1mapping 延伸模組](AD.Security.Groups.md#AD.Security.Groups.Setup)中提到的所有步驟。若要驗證是否已安裝延伸模組，請從 TDS 端點執行下列查詢：

```
1> SELECT extname, extversion FROM pg_extension where extname like 'pg_ad_mapping';
2> GO
extname       extversion
------------- ----------
pg_ad_mapping 0.1

(1 rows affected)
```

## 管理群組登入
<a name="babelfish-kerberos-securityad-managing"></a>

 依照[管理登入](babelfish-active-directory.md#babelfish-active-directory-login-managing)中所述步驟建立群組登入。我們建議登入名稱與 Active Directory (AD) 安全群組名稱應相同，以便輕鬆維護，但這不是強制性的。例如：

```
CREATE LOGIN [corp\accounts-group] FROM WINDOWS [WITH DEFAULT_DATABASE=database]
```

# 使用 AD 安全群組對應 T-SQL 群組登入
<a name="babelfish-kerberos-securityad-maptsql"></a>

 您需要為每個需要存取資料庫伺服器的 AD 安全群組明確佈建 T-SQL Windows 群組登入。屬於至少一個佈建 AD 安全群組的 AD 使用者將可存取資料庫伺服器。

**注意**  
此 T-SQL 登入無法再使用密碼型身分驗證進行身分驗證。

 例如，accounts-group 是 AD 中的安全群組，如果您想要在 Babelfish 中佈建此安全群組，則必須使用格式 [corp\$1accounts-group]。
+ AD 安全群組：accounts-group
+ TSQL 登入：[corp\$1accounts-group]
+ 指定 TSQL 登入的同等 PG 角色：accounts-group@CORP.EXAMPLE.COM

 管理員現在可以繼續透過下列 psql 命令，從 PostgreSQL 端點建立 AD 安全群組和 T-SQL 登入之間的對應。如需函數使用的詳細資訊，請參閱[使用 `pg_ad_mapping` 延伸模組中的函數](AD.Security.Groups.md#AD.Security.Groups.functions)。

**注意**  
新增對應時，應以 login\$1name@FQDN 格式指定 T-SQL 登入。透過 TDS 端點進行連線時，會忽略權重。如需權重使用的詳細資訊，請參閱[透過 PostgreSQL 連接埠上的 PostgreSQL 端點連線至 Babelfish](babelfish-kerberos-securityad-connect-pgendpoint.md)。

```
postgres=>select pgadmap_set_mapping('accounts-group', 'accounts-group@CORP.EXAMPLE.COM', <SID>, <Weight>);
```

如需擷取 AD 安全群組 SID 的資訊，請參閱[在 PowerShell 中擷取 Active Directory 群組 SID](AD.Security.Groups.md#AD.Security.Groups.retrieving)。

下表顯示從 AD 安全群組到 T-SQL 登入的範例對應：


| AD 安全群組 | TSQL 登入 | 指定 TSQL 登入的同等 PG 角色 | Weight (粗細) | 
| --- | --- | --- | --- | 
| accounts-group | [corp\$1accounts-group] | accounts-group@CORP.EXAMPLE.COM | 7 | 
| sales-group | [corp\$1sales-group] | sales-group@CORP.EXAMPLE.COM | 10 | 
| dev-group | [corp\$1dev-group] | dev-group@CORP.EXAMPLE.COM | 7 | 

```
postgres=> select admap.ad_sid, admap.ad_grp, lgn.orig_loginname, lgn.rolname, admap.weight from pgadmap_read_mapping() as admap, sys.babelfish_authid_login_ext as lgn where admap.pg_role = lgn.rolname;
    ad_sid    |     ad_grp     |    orig_loginname   |             rolname             | weight
--------------+----------------+---------------------+---------------------------------+--------
 S-1-5-67-890 | accounts-group | corp\accounts-group  | accounts-group@CORP.EXAMPLE.COM |     7
 S-1-2-34-560 | sales-group    | corp\sales-group     | sales-group@CORP.EXAMPLE.COM    |     10
 S-1-8-43-612 | dev-group      | corp\dev-group       | dev-group@CORP.EXAMPLE.COM      |     7
 (7 rows)
```

# 透過 TDS 端點連線至 Babelfish
<a name="babelfish-kerberos-securityad-connect"></a>

 在下列範例中，user1 是 accounts-group 和 sales-group 的成員，user2 是 accounts-group 和 dev-group 的成員。


| 使用者名稱 | AD 安全群組成員資格 | 
| --- | --- | 
| user1 | accounts-group、sales-group | 
| user2 | accounts-group、dev-group | 

 使用 sqlcmd 公用程式連線至 Babelfish 資料庫伺服器。您可以依照下列範例，使用 Kerberos 驗證使用者 (此範例中的 user1)：

```
1> select principal, gss_authenticated from pg_stat_gssapi where pid = pg_backend_pid();
2>  GO
principal               gss_authenticated
----------------------  -----------------
user1@CORP.EXAMPLE.COM  1 

((1 rows affected))
1> select suser_name();
2>  GO
suser_name
----------
corp\user1 

(1 rows affected)
```

 在此範例中，user1 會繼承帳戶群組和銷售群組的權限。您可以使用 `sys.login_token` 系統檢視來驗證群組成員資格。

```
1> SELECT name, type FROM sys.login_token;
2>  GO
name                type
------------------- ----
corp\accounts-group WINDOWS GROUP
corp\sales-group    WINDOWS GROUP

(2 rows affected)
```

## 稽核和記錄
<a name="babelfish-kerberos-securityad-audit"></a>

 若要判斷 AD 安全主體身分，請使用下列命令：

```
1> select suser_name();
2> GO
suser_name
----------
corp\user1

(1 rows affected)
```

目前，日誌中看不到 AD 使用者身分。您可以開啟 `log_connections` 參數來記錄資料庫工作階段的建立。如需詳細資訊，請參閱 [log\$1connections](https://docs.aws.amazon.com/prescriptive-guidance/latest/tuning-postgresql-parameters/log-connections.html)。如下列範例所示，輸出包含作為主體的 AD 使用者身分。與此輸出相關聯的後端 PID 可以協助將動作追溯至實際 AD 使用者。

```
bbf_group_ad_login@babelfish_db:[615]:LOG: connection authorized: user=bbf_group_ad_login database=babelfish_db application_name=sqlcmd GSS (authenticated=yes, encrypted=yes, principal=user1@CORP.EXAMPLE.COM)
```

# AD 安全群組成員資格的使用權限
<a name="babelfish-kerberos-securityad-privileges"></a>

## 繼承伺服器層級權限
<a name="babelfish-kerberos-securityad-inheritpriv-server"></a>

 屬於指定 AD 安全群組成員的 AD 使用者會繼承伺服器層級權限，這些權限會授予至對應的 Windows 群組登入。例如，請考慮 `accounts-group` AD 安全群組，此群組會在 Babelfish 中獲授予 `sysadmin` 伺服器角色成員資格。您可以使用下列命令繼承伺服器層級權限：

```
1> ALTER SERVER ROLE sysadmin ADD MEMBER [corp\accounts-group];
```

 因此，身為 `accounts-group` AD 安全群組成員的任何 Active Directory 使用者，都會繼承與該 `sysadmin` 角色相關聯的伺服器層級權限。這表示像 `corp\user1` 這樣的使用者 (身為 `accounts-group` 的成員) 現在將能夠在 Babelfish 中執行伺服器層級操作。

**注意**  
 若要執行伺服器層級 DDL，個別 AD 使用者的 Windows 登入必須存在。如需詳細資訊，請參閱[限制](babelfish-kerberos-securityad-limitations.md)。

## 繼承資料庫層級權限
<a name="babelfish-kerberos-securityad-inheritpriv-database"></a>

 若要授予資料庫層級權限，必須使用 Windows 群組登入來建立和對應資料庫使用者。屬於指定 AD 安全群組成員的 AD 使用者會繼承資料庫層級權限，這些權限會授予至該資料庫使用者。在下列範例中，您可以查看如何指派 Windows 群組 [corp\$1accounts-group] 的資料庫層級權限。

```
1> CREATE DATABASE db1; 
2> GO
1> USE db1;
2> GO
Changed database context to 'db1'.
1> CREATE TABLE dbo.t1(a int);
2> GO
```

 為 Windows 群組登入 [corp\$1accounts-group] 建立資料庫使用者 [corp\$1sales-group]。若要執行此步驟，請使用身為 sysadmin 成員的登入透過 TDS 端點進行連線。

```
1> CREATE USER [corp\accounts-group] FOR LOGIN [corp\accounts-group];
2> GO
```

 現在，請以 AD 使用者 user1 身分進行連線，以檢查資料表 t1 的存取權。我們尚未授予資料庫層級權限，因此會導致許可遭拒錯誤。

```
1> SELECT * FROM dbo.t1;
2> GO
Msg 33557097, Level 16, State 1, Server db-inst, Line 1
permission denied for table t1
```

將資料表 t1 的 SELECT 授予資料庫使用者 [corp\$1accounts-group]。若要執行此步驟，請使用身為 sysadmin 成員的登入透過 TDS 端點進行連線。

```
1> GRANT SELECT ON dbo.t1 TO [corp\accounts-group];
2> GO
```

 以 AD 使用者 user1 身分進行連線以驗證存取權。

```
1> SELECT * FROM dbo.t1;
2> GO
a
-----------

(0 rows affected)
```

# 根據預設或明確結構描述處理 DDL 陳述式行為
<a name="babelfish-kerberos-securityad-ddl"></a>

 使用 AD 驗證工作階段時，目前工作階段的預設結構描述取決於下列條件：
+ 如果存在個別資料庫使用者，會將使用者的預設結構描述視為目前工作階段的預設結構描述。
+ 如果群組資料庫使用者的預設結構描述存在，則會將群組資料庫使用者的預設結構描述視為具有最小主體 ID 的目前工作階段預設結構描述。

## 了解 CREATE DDL 陳述式行為
<a name="babelfish-kerberos-securityad-ddlcreate"></a>

 如果 CREATE DDL 陳述式中未指定明確的結構描述，則會在目前工作階段的預設結構描述中建立物件。如果無法判斷結構描述是預設還是明確，則 DDL 陳述式會擲出下列錯誤：

```
"Babelfish Unsupported Command : Schema required for CREATE DDLs when connecting with Active Directory Group authentication. Assign default schema to group user or specify schema in command."
```

**Example ：Windows 群組使用者的預設結構描述不存在**  
Windows 群組使用者 [corp\$1accounts-group] 具有 NULL 預設結構描述，而 AD 使用者 user1 正嘗試執行 DDL，而不明確指定結構描述。由於 user1 不存在個別 Windows 登入和使用者，因此只會取得 Windows 群組使用者 [corp\$1accounts-group] 的資料庫層級權限。  

```
1> create TABLE t2(a int);
2> GO

Msg 33557097, Level 16, State 1, Server db-inst, Line 1
Babelfish Unsupported Command : Schema required for CREATE DDLs when connecting with Active Directory Group authentication. Assign default schema to group user or specify schema in command.
```
AD 使用者 user1 的個別 Windows 登入和使用者不存在

**Example ：Windows 群組使用者存在預設結構描述**  
使用 sysadmin 以預設結構描述建立 [corp\$1accounts-group] 登入的 Windows 群組使用者。  

```
1> CREATE USER [corp\accounts-group] FOR LOGIN [corp\accounts-group] WITH DEFAULT_SCHEMA = sch_acc;
2> GO
1> CREATE SCHEMA sch_acc AUTHORIZATION [gad\accounts-group];
2> GO
1> SELECT name, principal_id, default_schema_name FROM sys.database_principals WHERE name = 'corp\accounts-group';
2> GO
                
name               principal_id default_schema_name
------------------ ------------ -------------------
corp\accounts-group 24162        sch_acc

(1 rows affected)
```
 嘗試建立物件，而不使用 AD 使用者 user1 明確指定結構描述。系統將在 [corp\$1accounts-group] Windows 群組的預設結構描述中建立資料表 t2。此物件的擁有者將與結構描述 sch\$1acc 的擁有者相同。  

```
1> CREATE TABLE t_group(a int);
2> GO
1> SELECT name, schema_name(schema_id) FROM sys.objects WHERE name like 't_group';
2> GO

name    schema_name
------- -----------
t_group sch_acc

(1 rows affected)
```
AD 使用者 user1 的個別 Windows 登入和使用者不存在

**Example ：AD 使用者的個別資料庫使用者也存在**  
 如果 AD 使用者的個別資料庫使用者也存在，則一律會在與個別資料庫使用者相關聯的結構描述中建立物件。如果資料庫使用者不存在結構描述，則會使用 dbo 結構描述。為 AD 使用者 user1 建立個別 Windows 登入和資料庫使用者。使用 sysadmin 登入透過 TDS 端點進行連線   

```
1> CREATE LOGIN [corp\user1] FROM WINDOWS;
2> GO
1> CREATE USER [corp\user1] FOR LOGIN [corp\user1] WITH DEFAULT_SCHEMA = sch1;
2> GO
1> CREATE SCHEMA sch1 AUTHORIZATION [corp\user1];
2> GO
1> SELECT name, default_schema_name FROM sys.database_principals WHERE name = 'corp\user1';
2> GO

name      default_schema_name
--------- -------------------
corp\user1 sch1

(1 rows affected)
```
 使用 AD 使用者 user1 進行連線，並嘗試建立物件，而不明確指定結構描述。將在結構描述 sch1 中建立資料表 t2。另請注意，此物件的擁有者將與結構描述 sch1 的擁有者相同。  

```
1> CREATE TABLE t2(a int);
2> GO
1> SELECT name, schema_name(schema_id) FROM sys.objects WHERE name like 't2';
2> GO
            
name schema_name
---- -----------
t2   sch1

(1 rows affected)
```

# 限制
<a name="babelfish-kerberos-securityad-limitations"></a>
+ 傾印/還原公用程式不支援傾印 pg\$1ad\$1mapping 延伸模組對應。還原後，您將需要重新建立那些對應。
+ 針對使用 `pg_ad_mapping` 的 Babelfish 和 Aurora PostgreSQL 執行個體，不支援藍綠部署。
+ 不支援隱含結構描述的建立。不支援需要隱含結構描述建立的 DDL 陳述式。
+ 當個別 Windows 登入不存在時，群組 AD 驗證工作階段中不支援伺服器層級 DDL ALTER AUTHORIZATION ON DATABASE、CREATE DATABASE、CREATE LOGIN、ALTER LOGIN、ALTER SERVER ROLE、ALTER DATABASE，只有群組 Windows 登入存在。若要解決此限制，建議在密碼驗證工作階段中執行這些操作，或建立個別 Windows 登入。
+ 不支援隱含使用者建立。理想的 T-SQL 行為 [Babelfish 中尚不支援]；在某些情況下，例如 DDL 和 GRANT/REVOKE 之類存取控制陳述式，在命令中會指定 AD 使用者名稱，但資料庫中不存在該名稱時，則會隱含地建立名為 AD 使用者的資料庫使用者。
+ 對於從 PSQL 端點建立且從群組 AD 驗證工作階段中 TDS 端點執行的 PL/pgSQL 程序或函數中的 DDL：
  + 將支援 ALTER/DROP 陳述式。
  + CREATE TABLE、CREATE VIEW、CREATE INDEX、CREATE FUNCTION/PROC、CREATE TYPE、CREATE SEQUENCE、CREATE TRIGGER、SELECT INTO、CREATE FULLTEXT INDEX、CREATE UNIQUE INDEX 會在未明確提供結構描述且目前工作階段的預設結構描述為 null 時擲出錯誤。
  + CREATE DATABASE、CREATE EXTENSION 和所有其他 CREATE 陳述式 (適用於 PG(不在 T-SQL 中) 特定物件 CREATE 訂閱、CREATE 資料表空間、CREATE 政策、CREATE 轉換的 CREATE 陳述式將不受支援。
+ Group AD 驗證工作階段中不支援 PostgreSQL 端點的 DDL。作為解決方法，您可以隨時使用主要使用者或任何其他使用密碼型身分驗證機制的使用者進行連線。
+ SUSER\$1SID()、IS\$1SRVROLEMEMBER()、IS\$1MEMBER()、sys.dm\$1exec\$1sessions 等系統物件具有下列限制。
  + 提供 AD 使用者或 AD 安全群組時，SUSER\$1SID() 不會傳回 SID。
  + 如果目前的 AD 使用者從任何 Windows 群組登入的伺服器角色成員資格繼承伺服器角色成員資格，則 IS\$1SRVROLEMEMBER() 不會考慮角色成員資格。
  + IS\$1MEMBER() 會針對任何 Windows 群組相關查詢傳回 false。
  + sys.dm\$1exec\$1sessions 不會顯示預期值 login\$1name、nt\$1user\$1name 欄。

# 透過 PostgreSQL 連接埠上的 PostgreSQL 端點連線至 Babelfish
<a name="babelfish-kerberos-securityad-connect-pgendpoint"></a>

您也可以利用從 TDS 連接埠建立的群組登入，透過 PostgreSQL 連接埠進行連線。若要透過 PostgreSQL 連接埠進行連線，您需要從 PostgreSQL 用戶端應用程式以格式 `<ad_username@FQDN>` 指定 AD 使用者名稱。您不能使用 `<DNS domain name\ad_username>` 格式。

根據預設，PostgreSQL 會針對使用者名稱使用區分大小寫的比較。若要讓 Aurora PostgreSQL 將 Kerberos 使用者名稱解譯為不區分大小寫，您必須在自訂 Babelfish 叢集參數群組中，將 krb\$1caseins\$1users 參數設為 true。此參數預設為 false。如需詳細資訊，請參閱[針對不區分大小寫的使用者名稱設定 Aurora PostgreSQL 資料庫叢集](postgresql-kerberos-setting-up.md#postgresql-kerberos-setting-up.create-logins.set-case-insentive)。

## 當 AD 使用者屬於多個群組時，T-SQL 和 PostgreSQL 端點的行為差異
<a name="babelfish-kerberos-securityad-diff-tsql-pg"></a>

假設 AD 使用者 user1 是兩個 AD 安全群組 [corp\$1accounts-group] 和 [corp\$1sales-group] 的一部分，且資料庫管理員已透過下列方式設定使用者對應。

```
postgres=> select * from pgadmap_read_mapping();
            
ad_sid       | pg_role                         | weight | ad_grp 
-------------+---------------------------------+--------+---------------
S-1-5-67-980 | accounts-group@CORP.EXAMPLE.COM | 7      | accounts-group
S-1-2-34-560 | sales-group@CORP.EXAMPLE.COM    | 10     | sales-group
(2 rows)
```

如果使用者從 T-SQL 端點連線，則在授權期間，其會繼承所有相關聯 T-SQL 登入的權限。在此範例中，user1 將從 T-SQL 群組登入繼承權限聯集，且權重將遭到忽略。這符合標準 T-SQL 行為。

不過，如果相同的使用者從 PostgreSQL 端點進行連線，則只能從一個具有最高權重的相關聯 T-SQL 登入繼承權限。如果兩個 T-SQL 群組登入受指派相同的權重，則 AD 使用者將繼承與最近新增的對應相對應的 T-SQL 登入權限。對於 PostgreSQL，建議指定反映個別資料庫角色相對許可/權限的權重，以避免模棱兩可的情況。在下列範例中，user1 透過 PSQL 端點連線，並僅繼承銷售群組權限。

```
babelfish_db=> select session_user, current_user;

   session_user               |   current_user
------------------------------+---------------------------
 sales-group@CORP.EXAMPLE.COM | sales-group@CORP.EXAMPLE.COM
(1 row)


babelfish_db=> select principal, gss_authenticated from pg_stat_gssapi where pid = pg_backend_pid();

     principal          | gss_authenticated
------------------------+-------------------
 user1@CORP.EXAMPLE.COM | t
(1 row)
```