

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

# Amazon Aurora PostgreSQL 的安全性
<a name="AuroraPostgreSQL.Security"></a>

如需有關 Aurora 安全性的一般概觀，請參閱 [ Amazon Aurora 的安全性](UsingWithRDS.md)。您可在幾個不同的層級管理 Amazon Aurora PostgreSQL 的安全性：
+ 若要控制誰可以在 Aurora PostgreSQL 資料庫叢集和資料庫執行個體上執行 Amazon RDS 管理動作，請使用 AWS Identity and Access Management (IAM)。IAM 在使用者可存取服務之前處理使用者身分的身分驗證。其還會處理授權，亦即，是否允許使用者去做其想做的事情。IAM 資料庫身分驗證是一種額外的身分驗證方法，您可在建立 Aurora PostgreSQL 資料庫叢集時選擇該方法。如需詳細資訊，請參閱[Amazon Aurora 的 Identity and access management](UsingWithRDS.IAM.md)。

  若您是將 IAM 與 Aurora PostgreSQL 資料庫叢集搭配使用，請先使用您的 IAM 憑證登入 AWS 管理主控台 ，然後才於 [https://console.aws.amazon.com/rds/](https://console.aws.amazon.com/rds/) 開啟 Amazon RDS 主控台。
+ Aurora 資料庫叢集必須在以 Amazon VPC 服務為基礎的虛擬私有雲端 (VPC) 中建立。若要控制哪些裝置和 Amazon EC2 執行個體可以開放對 VPC 中 Aurora 資料庫叢集的資料庫執行個體端點和連接埠的連線，可以使用 VPC 安全群組。您可使用 Secure Sockets Layer (SSL) 對這些端點和連接埠建立連線。此外，貴公司的防火牆規則可控管在公司內執行的裝置是否可開啟與資料庫執行個體的連線。如需 VPC 的詳細資訊，請參閱[Amazon VPC 和 Amazon Aurora](USER_VPC.md)。

  支援的 VPC 租用取決於您的 Aurora PostgreSQL 資料庫叢集所使用的資料庫執行個體類別。使用 `default` VPC 租用時，資料庫叢集在共用硬體上執行。使用 `dedicated` VPC 租用時，資料庫叢集會在專用硬體執行個體上執行。爆量效能資料庫執行個體類別僅支援預設的 VPC 租用。爆量效能資料庫執行個體類別包括 db.t3 和 db.t4g 資料庫執行個體類別。其他所有 Aurora PostgreSQL 資料庫執行個體類別都支援預設和專用的 VPC 租用。

  如需執行個體類別的詳細資訊，請參閱[Amazon Aurora 資料庫執行個體類別](Concepts.DBInstanceClass.md)。如需 `default` 和 `dedicated` VPC 租用的詳細資訊，請參閱《Amazon Elastic Compute Cloud 使用者指南》**中的[專用執行個體](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/dedicated-instance.html)。
+ 如要對 Amazon Aurora 資料庫叢集上執行的 PostgreSQL 資料庫授予權限，您可採取與 PostgreSQL 獨立執行個體相同的通用方法。`CREATE ROLE`、`ALTER ROLE`、`GRANT` 和 `REVOKE` 等命令的運作方式與內部部署資料庫所使用的命令相同，會直接修改資料庫、結構描述，和資料表。

  PostgreSQL 會使用*角色*來管理權限。`rds_superuser` 角色是 Aurora PostgreSQL 資料庫叢集上權限最高的角色。此角色會自動建立，並授予建立資料庫叢集的使用者 (主要使用者帳户，依預設為 `postgres`)。如需進一步了解，請參閱 [了解 PostgreSQL 角色和許可](Appendix.PostgreSQL.CommonDBATasks.Roles.md)。

所有可用的 Aurora PostgreSQL 版本 (包括第 10、11、12、13、14 版及更高版本) 支援密碼的 Salted Challenge Response Authentication Mechanism (SCRAM) 功能，作為訊息摘要 (MD5) 的替代方案。建議您使用 SCRAM，因為它比 MD5 更安全。如需詳細資訊，包括如何將資料庫使用者密碼從 MD5 遷移到 SCRAM，請參閱 [使用 SCRAM 進行 PostgreSQL 密碼加密](PostgreSQL_Password_Encryption_configuration.md)。

# 了解 PostgreSQL 角色和許可
<a name="Appendix.PostgreSQL.CommonDBATasks.Roles"></a>

當您使用 建立 Aurora PostgreSQL 資料庫叢集 時 AWS 管理主控台，會同時建立管理員帳戶。依預設，其名稱為 `postgres`，如下列螢幕擷取畫面所示：

![\[Create database (建立資料庫) 頁面中的憑證預設登入身分為 postgres。\]](http://docs.aws.amazon.com/zh_tw/AmazonRDS/latest/AuroraUserGuide/images/default-login-identity-apg-rpg.png)


您可以選擇其他名稱，而不是接受預設值 (`postgres`)。若是如此，則選擇的名稱必須以字母開頭，且介於 1 到 16 個英數字元之間。為簡單起見，我們在本指南中使用主要使用者帳戶的預設值 (`postgres`)，來指稱主要使用者帳戶。

如果您使用 `create-db-cluster` AWS CLI 而非 AWS 管理主控台，您可以透過使用 `master-username` 參數傳遞使用者名稱來建立使用者名稱。如需詳細資訊，請參閱 [步驟 2：建立 Aurora PostgreSQL 資料庫叢集](CHAP_GettingStartedAurora.AuroraPostgreSQL.FullConfig.md#CHAP_GettingStarted.AuroraPostgreSQL.CreateDBCluster)。

無論您是使用 AWS 管理主控台、 AWS CLI或 Amazon RDS API，還是使用預設`postgres`名稱或選擇不同的名稱，這個第一個資料庫使用者帳戶都是 `rds_superuser`群組的成員，並且具有 `rds_superuser` 權限。

**Topics**
+ [了解 rds\$1superuser 角色](Appendix.PostgreSQL.CommonDBATasks.Roles.rds_superuser.md)
+ [控制使用者對 PostgreSQL 資料庫的存取](Appendix.PostgreSQL.CommonDBATasks.Access.md)
+ [委派和控制使用者密碼管理](Appendix.PostgreSQL.CommonDBATasks.RestrictPasswordMgmt.md)
+ [使用 SCRAM 進行 PostgreSQL 密碼加密](PostgreSQL_Password_Encryption_configuration.md)

# 了解 rds\$1superuser 角色
<a name="Appendix.PostgreSQL.CommonDBATasks.Roles.rds_superuser"></a>

於 PostgreSQL 中，*角色*可定義使用者、群組或授予群組或使用者對資料庫中各種物件的一組特定權限。`CREATE USER` 和 `CREATE GROUP` 的 PostgreSQL 命令已為更為通用的 `CREATE ROLE` 所取代，其具有可區分資料庫使用者的特定屬性。資料庫使用者可視為具有 LOGIN 權限的角色。

**注意**  
`CREATE USER` 和 `CREATE GROUP` 命令仍可使用。如需詳細資訊，請參閱 PostgreSQL 文件中的[資料庫角色](https://www.postgresql.org/docs/current/user-manag.html)。

`postgres` 使用者是 Aurora PostgreSQL 資料庫叢集上具最高權限的資料庫使用者。其具有下列 `CREATE ROLE` 陳述式所定義的特性。

```
CREATE ROLE postgres WITH LOGIN NOSUPERUSER INHERIT CREATEDB CREATEROLE NOREPLICATION VALID UNTIL 'infinity'
```

屬性 `NOSUPERUSER`、`NOREPLICATION`、`INHERIT`，和 `VALID UNTIL 'infinity'` 為 CREATE ROLE 的預設選項，除非另有指定。

根據預設，`postgres` 具有授與 `rds_superuser` 角色的權限，以及建立角色和資料庫的許可。`rds_superuser` 角色可讓 `postgres` 使用者執行下列動作：
+ 新增可與 Aurora PostgreSQL。如需詳細資訊，請參閱 [使用擴充功能和外部資料包裝函式](Appendix.PostgreSQL.CommonDBATasks.md)。
+ 建立使用者的角色，並授予使用者權限。如需詳細資訊，請參閱 PostgreSQL 文件中的 [CREATE ROLE](https://www.postgresql.org/docs/current/sql-createrole.html) 和 [GRANT](https://www.postgresql.org/docs/14/sql-grant.html)。
+ 建立資料庫。如需詳細資訊，請參閱 PostgreSQL 文件中的 [CREATE DATABASE](https://www.postgresql.org/docs/14/sql-createdatabase.html)。
+ 將 `rds_superuser` 權限授予並無這些權限的使用者角色，並視需要撤銷這些權限。建議您僅將此角色授予執行超級使用者任務的使用者。換句話說，您可以將此角色授予資料庫管理員 (DBA) 或系統管理員。
+ 對不具 `rds_replication` 角色的資料庫使用者授予 (和撤銷) `rds_superuser` 角色。
+ 對不具 `rds_password` 角色的資料庫使用者授予 (和撤銷) `rds_superuser` 角色。
+ 使用 `pg_stat_activity` 檢視，取得有關所有資料庫連線的狀態資訊。如有需要，`rds_superuser` 可使用 `pg_terminate_backend` 或 `pg_cancel_backend` 停止任何連線。

於 `CREATE ROLE postgres...` 陳述式中，您可看到 `postgres` 使用者角色明確禁止 PostgreSQL `superuser` 權限。Aurora PostgreSQL 為受管服務，因此您無法存取主機作業系統，也無法使用 PostgreSQL `superuser` 帳户進行連線。許多需要在獨立 PostgreSQL 上進行 `superuser` 存取的任務是由 Aurora 自動管理。

如需有關授予權限的詳細資訊，請參閱 PostgreSQL 文件中的 [GRANT](http://www.postgresql.org/docs/current/sql-grant.html)。

`rds_superuser` 角色是 Aurora PostgreSQL 資料庫叢集中數個*預先定義*角色的其中一個。

**注意**  
在 PostgreSQL 13 和更早版本中，*預先定義*角色稱為*預設*角色。

於下列清單中，您可以找到為新的 Aurora PostgreSQL 資料庫叢集自動建立的一些其他預先定義角色。預先定義的角色及其權限無法進行變更。您無法為這些預先定義角色停止、重新命名或修改權限。嘗試這麼做會造成錯誤。
+ **rds\$1password** – 可變更密碼並為資料庫使用者設定密碼約束的角色。依預設授予此角色 `rds_superuser` 角色，並可授予資料庫使用者該角色。如需詳細資訊，請參閱[控制使用者對 PostgreSQL 資料庫的存取控制使用者對 PostgreSQL 的存取](Appendix.PostgreSQL.CommonDBATasks.Access.md)。
  + 對於 14 之前的 RDS for PostgreSQL 版本，`rds_password` 角色可以變更密碼，並為資料庫使用者和具有 `rds_superuser` 角色的使用者設定密碼限制。從 RDS for PostgreSQL 第 14 版及更新版本，`rds_password` 角色可以變更密碼，並僅為資料庫使用者設定密碼限制。只有具有 `rds_superuser` 角色的使用者才能對具有 `rds_superuser` 角色的其他使用者執行這些動作。
+ **rdsadmin** – 為處理具有 `superuser` 權限的管理員將在獨立 PostgreSQL 資料庫上執行的許多管理任務而建立的角色。此角色由 Aurora PostgreSQL 在內部用於許多管理任務。

# 檢視角色及其權限
<a name="Appendix.PostgreSQL.CommonDBATasks.Roles.View"></a>

您可以根據 PostgreSQL 版本，使用不同的命令在 RDS for PostgreSQL 資料庫執行個體中檢視預先定義的角色及其權限。若要查看所有預先定義的角色，您可以連線至 RDS for PostgreSQL 資料庫執行個體，並使用 `psql` 執行下列命令。

**對於 `psql` 第 15 版和更早版本**

連線至 RDS for PostgreSQL 資料庫執行個體，並在 psql 中使用 `\du` 命令：

```
postgres=> \du
                                                               List of roles
    Role name    |                         Attributes                         |                          Member of
-----------------+------------------------------------------------------------+------------------------------------------------------
 postgres        | Create role, Create DB                                    +| {rds_superuser}
                 | Password valid until infinity                              |
 rds_ad          | Cannot login                                               | {}
 rds_iam         | Cannot login                                               | {}
 rds_password    | Cannot login                                               | {}
 rds_replication | Cannot login                                               | {}
 rds_superuser   | Cannot login                                               | {pg_monitor,pg_signal_backend,rds_password,rds_replication}
 rdsadmin        | Superuser, Create role, Create DB, Replication, Bypass RLS+| {}
                 | Password valid until infinity                              |
```

**對於 `psql` 第 16 版和更新版本**

```
postgres=> \drg+
                             List of role grants
   Role name   |          Member of          |       Options       | Grantor
---------------+-----------------------------+---------------------+----------
 postgres      | rds_superuser               | INHERIT, SET        | rdsadmin
 rds_superuser | pg_checkpoint               | ADMIN, INHERIT, SET | rdsadmin
 rds_superuser | pg_monitor                  | ADMIN, INHERIT, SET | rdsadmin
 rds_superuser | pg_signal_backend           | ADMIN, INHERIT, SET | rdsadmin
 rds_superuser | pg_use_reserved_connections | ADMIN, INHERIT, SET | rdsadmin
 rds_superuser | rds_password                | ADMIN, INHERIT, SET | rdsadmin
 rds_superuser | rds_replication             | ADMIN, INHERIT, SET | rdsadmin
```

若要在沒有版本相依性的情況下檢查角色成員資格，您可以使用下列 SQL 查詢：

```
SELECT m.rolname AS "Role name", r.rolname AS "Member of"
FROM pg_catalog.pg_roles m
JOIN pg_catalog.pg_auth_members pam ON (pam.member = m.oid)
LEFT JOIN pg_catalog.pg_roles r ON (pam.roleid = r.oid)
LEFT JOIN pg_catalog.pg_roles g ON (pam.grantor = g.oid)
WHERE m.rolname !~ '^pg_'
ORDER BY 1, 2;
```

於輸出中，您可看到 `rds_superuser` 並非資料庫使用者角色 (無法登入)，但其具有許多其他角色的權限。您還可以看到資料庫使用者 `postgres` 是 `rds_superuser` 角色的成員。如前所述，`postgres` 是 Amazon RDS 主控台 **Create database (建立資料庫)** 頁面中的預設值。若選擇其他名稱，則該名稱將顯示於角色清單中。

**注意**  
 Aurora PostgreSQL 15.2 和 14.7 版導入了限制性的 `rds_superuser` 角色行為。即使已將 `rds_superuser` 角色授予 Aurora PostgreSQL 使用者，使用者仍需被授予對應資料庫的 `CONNECT` 權限才能連線。在 Aurora PostgreSQL 14.7 和 15.2 版之前，只要已將 `rds_superuser` 角色授予使用者，該使用者就能夠連線到任何資料庫和系統資料表。這種限制行為符合 AWS 和 Amazon Aurora 對持續改善安全性的承諾。  
如果您的應用程式受到上述增強功能的影響，請更新應用程式中的個別邏輯。

# 控制使用者對 PostgreSQL 資料庫的存取
<a name="Appendix.PostgreSQL.CommonDBATasks.Access"></a>

PostgreSQL 中的新資料庫會永遠使用資料庫 `public` 結構描述中的一組預設權限建立，允許所有資料庫使用者和角色建立物件。例如，這些權限可讓資料庫使用者連接至資料庫，並在連線時建立暫存資料表。

為了對您 Aurora PostgreSQL 資料庫叢集主節點上建立之資料庫執行個體的使用者存取進行更好地控制，我們建議您撤消這些預設的 `public` 權限。完成此作業後，您可更精細地為資料庫使用者授予特定權限，如下列程序所示。

**如要設定新資料庫執行個體的角色和權限**

假設您正在一個剛建立的 Aurora PostgreSQL 資料庫叢集上設定資料庫，以供多位研究人員使用，其皆需要資料庫的讀寫存取權。

1. 使用 `psql` (或 pgAdmin) 連接至您 Aurora PostgreSQL 資料庫叢集上的主資料庫執行個體： 

   ```
   psql --host=your-cluster-instance-1.666666666666.aws-region.rds.amazonaws.com --port=5432 --username=postgres --password
   ```

   出現提示時，輸入您的密碼。`psql` 用戶端連接並顯示預設管理連接資料庫 `postgres=>` 作為提示。

1. 如要防止資料庫使用者在 `public` 結構描述中建立物件，請執行下列動作：

   ```
   postgres=> REVOKE CREATE ON SCHEMA public FROM PUBLIC;
   REVOKE
   ```

1. 接下來，您會建立新的資料庫執行個體：

   ```
   postgres=> CREATE DATABASE lab_db;
   CREATE DATABASE
   ```

1. 從此新資料庫上 `PUBLIC` 結構描述撤消所有權限。

   ```
   postgres=> REVOKE ALL ON DATABASE lab_db FROM public;
   REVOKE
   ```

1. 建立一個資料庫使用者的角色。

   ```
   postgres=> CREATE ROLE lab_tech;
   CREATE ROLE
   ```

1. 使具有此角色的資料庫使用者可連接至資料庫。

   ```
   postgres=> GRANT CONNECT ON DATABASE lab_db TO lab_tech;
   GRANT
   ```

1. 授予具 `lab_tech` 角色的所有使用者此資料庫的所有權限。

   ```
   postgres=> GRANT ALL PRIVILEGES ON DATABASE lab_db TO lab_tech;
   GRANT
   ```

1. 建立資料庫使用者，如下所示：

   ```
   postgres=> CREATE ROLE lab_user1 LOGIN PASSWORD 'change_me';
   CREATE ROLE
   postgres=> CREATE ROLE lab_user2 LOGIN PASSWORD 'change_me';
   CREATE ROLE
   ```

1. 授予這兩個使用者與 lab\$1tech 角色關聯的權限：

   ```
   postgres=> GRANT lab_tech TO lab_user1;
   GRANT ROLE
   postgres=> GRANT lab_tech TO lab_user2;
   GRANT ROLE
   ```

至此，`lab_user1` 和 `lab_user2` 便可連接 `lab_db` 資料庫。此範例並未遵循企業使用的最佳實務，其中可能包括建立多個資料庫執行個體、不同的結構描述，及授予有限的權限。如需更多完整資訊和其他方案，請參閱[管理 PostgreSQL 使用者和角色](https://aws.amazon.com/blogs//database/managing-postgresql-users-and-roles/)。

如需有關 PostgreSQL 資料庫中權限的詳細資訊，請參閱 PostgreSQL 文件中的 [GRANT](https://www.postgresql.org/docs/current/static/sql-grant.html) 命令。

# 委派和控制使用者密碼管理
<a name="Appendix.PostgreSQL.CommonDBATasks.RestrictPasswordMgmt"></a>

作為 DBA，您可能想要委派管理使用者密碼。或者，您可能想要防止資料庫使用者變更其密碼或重新設定密碼約束 (例如密碼生命週期)。如要確保只有您選擇的資料庫使用者才可變更密碼設定，您可開啟受限制的密碼管理功能。啟動此功能時，只有那些已被授予 `rds_password` 角色的資料庫使用者才可管理密碼。

**注意**  
如要使用受限制的密碼管理，您的 Aurora PostgreSQL 資料庫叢集必須執行 Amazon Aurora PostgreSQL 10.6 或更新版本。

依預設，此功能為 `off`，如下列所示：

```
postgres=> SHOW rds.restrict_password_commands;
  rds.restrict_password_commands
--------------------------------
 off
(1 row)
```

如要開啟此功能，請使用自訂參數群組，並將 `rds.restrict_password_commands` 的設定變更為 1。請務必重新啟動您的 Aurora PostgreSQL 的主資料庫執行個體 ，以使設定生效。

啟用此功能後，下列 SQL 命令需要 `rds_password` 權限：

```
CREATE ROLE myrole WITH PASSWORD 'mypassword';
CREATE ROLE myrole WITH PASSWORD 'mypassword' VALID UNTIL '2023-01-01';
ALTER ROLE myrole WITH PASSWORD 'mypassword' VALID UNTIL '2023-01-01';
ALTER ROLE myrole WITH PASSWORD 'mypassword';
ALTER ROLE myrole VALID UNTIL '2023-01-01';
ALTER ROLE myrole RENAME TO myrole2;
```

若密碼使用 MD5 雜湊演算法，則重新命名角色 (`ALTER ROLE myrole RENAME TO newname`) 也會受到限制。

啟用此功能後，嘗試使用任何這些 SQL 命令，而不使用 `rds_password` 角色權限會產生下列錯誤：

```
ERROR: must be a member of rds_password to alter passwords
```

建議您僅對專用於密碼管理的一些角色授予 `rds_password`。若您授予不具 `rds_superuser` 權限之資料庫使用者 `rds_password` 權限，則還需要授予其 `CREATEROLE` 屬性。

確定您驗證用戶端上的密碼需求，例如到期時間和需要的複雜度。若您使用自己的用戶端公用程式進行與密碼相關的變更，則該公用程式必須為 `rds_password` 的成員並具有 `CREATE ROLE` 權限。

# 使用 SCRAM 進行 PostgreSQL 密碼加密
<a name="PostgreSQL_Password_Encryption_configuration"></a>

*Salted Challenge Response Authentication Mechanism (SCRAM)* 是 PostgreSQL 預設訊息摘要 (MD5) 演算法的替代選項，用於加密密碼。SCRAM 身分驗證機制被認為比 MD5 更安全。若要進一步了解這兩種不同的密碼保護方法，請參閱 PostgreSQL 文件中的 [Password Authentication](https://www.postgresql.org/docs/14/auth-password.html) (密碼身分驗證)。

建議您使用 SCRAM 作為 Aurora PostgreSQL 資料庫叢集的密碼加密配置，而不是使用 MD5。Aurora PostgreSQL 第 10 版和所有更新的主要和次要版本都支援 SCRAM。這是一種加密的挑戰回應機制，使用 scram-sha-256 演算法進行密碼身分驗證和加密。

您可能需要更新程式庫，用戶端應用程式才會支援 SCRAM。例如，42.2.0 之前的 JDBC 版本不支援 SCRAM。如需詳細資訊，請參閱 PostgreSQL JDBC 驅動程式文件中的 [PostgreSQL JDBC Driver](https://jdbc.postgresql.org/changelogs/2018-01-17-42.2.0-release/) (PostgreSQL JDBC 驅動程式)。如需其他 PostgreSQL 驅動程式和 SCRAM 支援的清單，請參閱 PostgreSQL 文件中的 [List of drivers](https://wiki.postgresql.org/wiki/List_of_drivers) (驅動程式清單)。

Aurora PostgreSQL 14 版和更新版本預設支援 scram-sha-256 用於新資料庫叢集的密碼加密。對於這些版本，預設資料庫叢集參數群組 (`default.aurora-postgresql14`) 將其 `password_encryption` 值設定為 scram-sha-256。Aurora Serverless v1 不支援 SCRAM。

## 設定 Aurora PostgreSQL 資料庫叢集 以要求 SCRAM
<a name="PostgreSQL_Password_Encryption_configuration.preliminary"></a>

對於 Aurora PostgreSQL 14.3 和更新版本，您可以要求 Aurora PostgreSQL 資料庫叢集僅接受使用 scram-sha-256 演算法的密碼。

**重要**  
對於 PostgreSQL 資料庫的現有 RDS 代理，如果您將資料庫驗證修改為僅使用 `SCRAM`，則該代理會變成無法使用，最多持續 60 秒。若要避免發生此問題，請執行下列其中一項：  
確定資料庫同時允許 `SCRAM` 和 `MD5` 身分驗證。
若只要使用 `SCRAM` 身分驗證，請建立新代理、將應用程式流量遷移至新代理，然後刪除先前與資料庫相關聯的代理。

在對系統進行變更之前，請確保您了解完整過程，如下所示：
+ 獲得所有資料庫使用者的所有角色與密碼加密相關資訊。
+ 針對控制密碼加密的參數，再次檢查 Aurora PostgreSQL 資料庫叢集的參數設定。
+ 如果您的 Aurora PostgreSQL 資料庫叢集使用預設參數群組，則需要建立自訂資料庫叢集參數群組，並將其套用到 Aurora PostgreSQL 資料庫叢集，讓您可以在需要時修改參數。如果您的 Aurora PostgreSQL 資料庫叢集使用自訂參數群組，則您稍後可以視需要在過程中修改必要參數。
+ 將 `password_encryption` 參數變更為 `scram-sha-256`。
+ 通知所有資料庫使用者他們必須更新密碼。針對您的 `postgres` 帳戶進行相同的動作。系統會使用 scram-sha-256 演算法加密與儲存新密碼。
+ 驗證確認使用加密類型將所有密碼加密。
+ 如果所有密碼都使用 scram-sha-256，您可以將 `rds.accepted_password_auth_method` 參數從 `md5+scram` 變更為 `scram-sha-256`。

**警告**  
在您僅將 `rds.accepted_password_auth_method` 變更為 scram-sha-256 後，則任何具有 `md5` 加密密碼的使用者 (角色) 將無法連線。

### 準備好為您的 Aurora PostgreSQL 資料庫叢集 要求 SCRAM
<a name="PostgreSQL_Password_Encryption_configuration.getting-ready"></a>

對 Aurora PostgreSQL 資料庫叢集進行任何變更之前，請檢查所有現有的資料庫使用者帳戶。另外，請檢查用於密碼的加密類型。您可以使用 `rds_tools` 擴充功能執行這些任務。若要查看哪些 PostgreSQL 版本支援 `rds_tools`，請參閱 [Amazon RDS for PostgreSQL 的延伸版本](https://docs.aws.amazon.com/AmazonRDS/latest/PostgreSQLReleaseNotes/postgresql-extensions.html)。

**獲得資料庫使用者 (角色) 與密碼加密方法清單**

1. 使用 `psql` 連線至 Aurora PostgreSQL 資料庫叢集上的主要執行個體 ，如下所示。

   ```
   psql --host=cluster-name-instance-1.111122223333.aws-region.rds.amazonaws.com --port=5432 --username=postgres --password
   ```

1. 安裝 `rds_tools` 擴充功能。

   ```
   postgres=> CREATE EXTENSION rds_tools;
   CREATE EXTENSION
   ```

1. 取得角色和加密清單。

   ```
   postgres=> SELECT * FROM 
         rds_tools.role_password_encryption_type();
   ```

   您會看到類似下列的輸出。

   ```
          rolname        | encryption_type
   ----------------------+-----------------
    pg_monitor           |
    pg_read_all_settings |
    pg_read_all_stats    |
    pg_stat_scan_tables  |
    pg_signal_backend    |
    lab_tester           | md5
    user_465             | md5
    postgres             | md5
   (8 rows)
   ```

### 建立自訂資料庫叢集參數群組
<a name="PostgreSQL_Password_Encryption_configuration.custom-parameter-group"></a>

**注意**  
如果您的 Aurora PostgreSQL 資料庫叢集已使用自訂參數群組，則不需要建立新的群組。

如需 Aurora 的參數群組概觀，請參閱 [在 Amazon Aurora 中建立資料庫叢集參數群組](USER_WorkingWithParamGroups.CreatingCluster.md)。

用於密碼的密碼加密類型是在某一個參數 (亦即 `password_encryption`) 中設定的。Aurora PostgreSQL 資料庫叢集允許的加密則是在另一個參數 (亦即 `rds.accepted_password_auth_method`) 中設定的。若要從這些預設值變更，則需要您建立自訂資料庫叢集參數群組，並套用到您的叢集。

您也可以使用 AWS 管理主控台 或 RDS API 來建立自訂資料庫叢集參數群組。如需詳細資訊，請參閱 [在 Amazon Aurora 中建立資料庫叢集參數群組](USER_WorkingWithParamGroups.CreatingCluster.md)。

您可以使用資料庫執行個體與自訂參數群組建立關聯。

**建立自訂資料庫叢集參數群組**

1. 使用 `[create-db-cluster-parameter-group](https://docs.aws.amazon.com/cli/latest/reference/rds/create-db-cluster-parameter-group.html)` CLI 命令以建立叢集的自訂參數群組。以下範例使用 `aurora-postgresql13` 作為此自訂參數群組的來源。

   對於 Linux、macOS 或 Unix：

   ```
   aws rds create-db-cluster-parameter-group --db-cluster-parameter-group-name 'docs-lab-scram-passwords' \
     --db-parameter-group-family aurora-postgresql13  --description 'Custom DB cluster parameter group for SCRAM'
   ```

   在 Windows 中：

   ```
   aws rds create-db-cluster-parameter-group --db-cluster-parameter-group-name "docs-lab-scram-passwords" ^
     --db-parameter-group-family aurora-postgresql13  --description "Custom DB cluster parameter group for SCRAM"
   ```

   現在您可以將自訂參數群組與叢集建立關聯。

1. 使用 `[modify-db-cluster](https://docs.aws.amazon.com/cli/latest/reference/rds/modify-db-cluster.html)` CLI 命令將此自訂參數群組套用至您的 Aurora PostgreSQL 資料庫叢集。

   對於 Linux、macOS 或 Unix：

   ```
   aws rds modify-db-cluster --db-cluster-identifier 'your-instance-name' \
           --db-cluster-parameter-group-name "docs-lab-scram-passwords
   ```

   在 Windows 中：

   ```
   aws rds modify-db-cluster --db-cluster-identifier "your-instance-name" ^
           --db-cluster-parameter-group-name "docs-lab-scram-passwords
   ```

   若要重新同步 Aurora PostgreSQL 資料庫叢集與自訂資料庫叢集參數群組，以及 ，請重新啟動叢集的主要與所有其他執行個體。

### 設定密碼加密以使用 SCRAM
<a name="PostgreSQL_Password_Encryption_configuration.configure-password-encryption"></a>

Aurora PostgreSQL 資料庫叢集使用的密碼加密機制是在資料庫叢集參數群組的 `password_encryption` 參數中設定的。允許的值為未設定、`md5` 或 `scram-sha-256`。預設值視 Aurora PostgreSQL 版本而定，如下所示：
+ Aurora PostgreSQL 14 – 預設值為 `scram-sha-256`
+ Aurora PostgreSQL 13 – 預設值為 `md5`

透過將自訂資料庫叢集參數群組連接至 Aurora PostgreSQL 資料庫叢集，您可以修改密碼加密參數的值。

![\[接著，RDS 主控台顯示 Aurora PostgreSQL 其 password_encryption 參數的預設值。\]](http://docs.aws.amazon.com/zh_tw/AmazonRDS/latest/AuroraUserGuide/images/apg-pwd-encryption-md5-scram-1.png)


**將密碼加密設定變更為 scram-sha-256**
+ 將密碼加密的值變更為 scram-sha-256，如下所示。變更會立即套用，因為參數是動態的，因此不需要重新啟動即可使變更生效。

  對於 Linux、macOS 或 Unix：

  ```
  aws rds modify-db-cluster-parameter-group --db-cluster-parameter-group-name \
    'docs-lab-scram-passwords' --parameters 'ParameterName=password_encryption,ParameterValue=scram-sha-256,ApplyMethod=immediate'
  ```

  在 Windows 中：

  ```
  aws rds modify-db-parameter-group --db-parameter-group-name ^
    "docs-lab-scram-passwords" --parameters "ParameterName=password_encryption,ParameterValue=scram-sha-256,ApplyMethod=immediate"
  ```

### 將使用者角色的密碼遷移至 SCRAM
<a name="PostgreSQL_Password_Encryption_configuration.migrating-users"></a>

您可以將使用者角色的密碼遷移至 SCRAM，如下說明：

**將資料庫使用者 (角色) 密碼從 MD5 遷移至 SCRAM**

1. 以管理員使用者身分 (預設使用者名稱 `postgres`) 登入，如下所示。

   ```
   psql --host=cluster-name-instance-1.111122223333.aws-region.rds.amazonaws.com --port=5432 --username=postgres --password
   ```

1. 使用下列命令檢查 RDS for PostgreSQL 資料庫執行個體上 `password_encryption` 參數的設定。

   ```
   postgres=> SHOW password_encryption;
    password_encryption
   ---------------------
    md5
    (1 row)
   ```

1. 將此參數的值變更為 scram-sha-256。如需詳細資訊，請參閱[設定密碼加密以使用 SCRAM](#PostgreSQL_Password_Encryption_configuration.configure-password-encryption)。

1.  再次檢查該值以確定它現在已設定為 `scram-sha-256`，如下所示。

   ```
   postgres=> SHOW password_encryption;
    password_encryption
   ---------------------
    scram-sha-256
    (1 row)
   ```

1. 通知所有資料庫使用者變更自己的密碼。務必亦為帳戶 `postgres` (具有 `rds_superuser` 權限的資料庫使用者) 變更您自己的密碼。

   ```
   labdb=> ALTER ROLE postgres WITH LOGIN PASSWORD 'change_me';
   ALTER ROLE
   ```

1. 對 Aurora PostgreSQL 資料庫叢集上所有的資料庫重複此程序。

### 變更參數為需要 SCRAM
<a name="PostgreSQL_Password_Encryption_configuration.require-scram"></a>

這是程序中的最後一個步驟。在以下程序中進行變更後，仍然使用 `md5` 將密碼加密的任何使用者帳戶 (角色) 將無法登入 Aurora PostgreSQL 資料庫叢集。

`rds.accepted_password_auth_method` 指定 Aurora PostgreSQL 資料庫叢集在登入程序期間接受的使用者密碼加密方法。預設值為 `md5+scram`，這意味著任何一種方法都接受。在下圖中，您可以找到此參數的預設設定。

![\[顯示 rds.accepted_password_auth_method 參數其預設值與允許值的 RDS 主控台。\]](http://docs.aws.amazon.com/zh_tw/AmazonRDS/latest/AuroraUserGuide/images/pwd-encryption-md5-scram-2.png)


此參數的允許值為 `md5+scram` 或僅 `scram`。將此參數值變更為 `scram` 會使此成為一個需求。

**將參數值變更為需要對密碼進行 SCRAM 身分驗證**

1. 確認 Aurora PostgreSQL 資料庫叢集上所有資料庫的所有資料庫使用者密碼使用 `scram-sha-256` 進行密碼加密。若要這麼做，請向 `rds_tools` 查詢角色 (使用者) 和加密類型，如下所示。

   ```
   postgres=> SELECT * FROM rds_tools.role_password_encryption_type();
     rolname        | encryption_type
     ----------------------+-----------------
     pg_monitor           |
     pg_read_all_settings |
     pg_read_all_stats    |
     pg_stat_scan_tables  |
     pg_signal_backend    |
     lab_tester           | scram-sha-256
     user_465             | scram-sha-256
     postgres             | scram-sha-256
     ( rows)
   ```

1. 針對您的 Aurora PostgreSQL 資料庫叢集中所有的資料庫執行個體重複此查詢。

   如果所有密碼都使用 scram-sha-256，您可以繼續進行。

1. 將接受的密碼身分驗證值變更為 scram-sha-256，如下所示。

   對於 Linux、macOS 或 Unix：

   ```
   aws rds modify-db-cluster-parameter-group --db-cluster-parameter-group-name 'docs-lab-scram-passwords' \
     --parameters 'ParameterName=rds.accepted_password_auth_method,ParameterValue=scram,ApplyMethod=immediate'
   ```

   在 Windows 中：

   ```
   aws rds modify-db-cluster-parameter-group --db-cluster-parameter-group-name "docs-lab-scram-passwords" ^
     --parameters "ParameterName=rds.accepted_password_auth_method,ParameterValue=scram,ApplyMethod=immediate"
   ```

## 使用 SSL/TLS 保護 Aurora PostgreSQL 資料的安全
<a name="AuroraPostgreSQL.Security.SSL"></a>

對於 Aurora PostgreSQL 資料庫叢集，Amazon RDS 支援 Secure Sockets Layer (SSL) 和 Transport Layer Security (TLS) 加密。您可以使用 SSL/TLS，將應用程式與 Aurora PostgreSQL 資料庫叢集之間的連線加密。您也可以強制 Aurora PostgreSQL 資料庫叢集的所有連線都使用 SSL/TLS。Amazon Aurora PostgreSQL 現已支援 Transport Layer Security (TLS) 版本 1.1 和 1.2。建議使用 TLS 1.2 進行加密連線。我們從以下版本的 Aurora PostgreSQL 新增了對 TLSv1.3 的支援：
+ 15.3 版和所有更新版本
+ 14.8 版和更新的 14 版本
+ 13.11 版和更新的 13 版本
+ 12.15 版和更新的 12 版
+ 11.20 版和更新的 11 版本

如需 SSL/TLS 支援和 PostgreSQL 資料庫的一般資訊，請參閱 PostgreSQL 文件中的 [SSL 支援](https://www.postgresql.org/docs/current/libpq-ssl.html)。如需透過 JDBC 使用 SSL/TLS 連線的相關資訊，請參閱 PostgreSQL 文件中的[設定用戶端](https://jdbc.postgresql.org/documentation/head/ssl-client.html)。

**Topics**
+ [需要使用 SSL/TLS 連線至 Aurora PostgreSQL 資料庫叢集](#AuroraPostgreSQL.Security.SSL.Requiring)
+ [判斷 SSL/TLS 連線狀態](#AuroraPostgreSQL.Security.SSL.Status)
+ [為 Aurora PostgreSQL 資料庫叢集的連線設定密碼套件](#AuroraPostgreSQL.Security.SSL.ConfiguringCipherSuites)

Aurora PostgreSQL 的所有 AWS 區域都提供 SSL/TLS 支援。建立資料庫叢集時，Amazon RDS 會為您的 Aurora PostgreSQL 資料庫叢集建立 SSL/TLS 憑證。如果您啟用 SSL/TLS 憑證驗證，則 SSL/TLS 憑證會包含資料庫叢集端點，當作 SSL/TLS 憑證的通用名稱 (CN)，以防範詐騙攻擊。

**透過 SSL/TLS 連線至 Aurora PostgreSQL 資料庫叢集**

1. 下載憑證。

   如需有關下載憑證的詳細資訊，請參閱[使用 SSL/TLS 加密與資料庫叢集的連線](UsingWithRDS.SSL.md)。

1. 將憑證匯入作業系統。

1. 透過 SSL/TLS 連線至 Aurora PostgreSQL 資料庫叢集。

   當您使用 SSL/TLS 連線時，用戶端可以選擇是否驗證憑證鏈。如果您的連線參數指定 `sslmode=verify-ca` 或 `sslmode=verify-full`，則用戶端在信任存放區必須有 RDS CA 憑證，或在連線 URL 中必須參考這些憑證。此需求是為了驗證用於簽署資料庫憑證的憑證鏈。

   當用戶端 (例如 psql 或 JDBC) 設有 SSL/TLS 支援時，依預設，用戶端會先嘗試使用 SSL/TLS 連線至資料庫。如果用戶端無法使用 SSL/TLS 連線，則回復為不使用 SSL/TLS 連線。根據預設，JDBC 和 libpq 型用戶端的 `sslmode` 選項設定為 `prefer`。

   使用 `sslrootcert` 參數來參考憑證，例如 `sslrootcert=rds-ssl-ca-cert.pem`。

以下是使用 psql 連接至 Aurora PostgreSQL 資料庫叢集的範例。

```
$ psql -h testpg.cdhmuqifdpib.us-east-1.rds.amazonaws.com -p 5432 \
    "dbname=testpg user=testuser sslrootcert=rds-ca-2015-root.pem sslmode=verify-full"
```

### 需要使用 SSL/TLS 連線至 Aurora PostgreSQL 資料庫叢集
<a name="AuroraPostgreSQL.Security.SSL.Requiring"></a>

若需要連至 Aurora PostgreSQL 資料庫叢集的 SSL/TLS 連線，請使用 `rds.force_ssl` 參數。
+ 若需要 SSL/TLS 連線，請將 `rds.force_ssl` 參數值設為 1 (開啟)。
+ 若要關閉所需的 SSL/TLS 連線，請將 `rds.force_ssl` 參數值設為 0 (關閉)。

此參數的預設值取決於 Aurora PostgreSQL 版本：
+ 對於 Aurora PostgreSQL 第 17 版及更新版本：預設值為 1 (開啟)。
+ 對於 Aurora PostgreSQL 第 16 版及更舊版本：預設值為 0 (關閉)。

**注意**  
當您從 Aurora PostgreSQL 第 16 版或更舊版本執行升級至第 17 版或更新版本的主要版本升級時，參數的預設值會從 0 (關閉) 變更為 1 (開啟)。此變更可能會導致未針對 SSL 設定的應用程式連線能力失敗。您可以將此參數設定為 0 (關閉)，以還原至先前的預設行為。

如需處理參數的詳細資訊，請參閱 [Amazon Aurora 的參數群組](USER_WorkingWithParamGroups.md)。

更新 `rds.force_ssl` 參數也會將 PostgreSQL `ssl` 參數設為 1 (開啟)，並修改資料庫叢集的 `pg_hba.conf` 檔案，以支援新的 SSL/TLS 組態。

當資料庫叢集的 `rds.force_ssl` 參數設為 1 時，您在連線時會看到類似如下的輸出，表示現在需要使用 SSL/TLS：

```
$ psql postgres -h SOMEHOST.amazonaws.com -p 8192 -U someuser
psql (9.3.12, server 9.4.4)
WARNING: psql major version 9.3, server major version 9.4.
Some psql features might not work.
SSL connection (cipher: DHE-RSA-AES256-SHA, bits: 256)
Type "help" for help.

postgres=>
```

### 判斷 SSL/TLS 連線狀態
<a name="AuroraPostgreSQL.Security.SSL.Status"></a>

當您連接至資料庫叢集時，登入橫幅中會顯示連線的加密狀態。

```
Password for user master: 
psql (9.3.12) 
SSL connection (cipher: DHE-RSA-AES256-SHA, bits: 256) 
Type "help" for help.   

postgres=>
```

您也可以載入 `sslinfo` 擴充功能，然後呼叫 `ssl_is_used()` 函數，以判斷是否正在使用 SSL/TLS。如果連線正在使用 SSL/TLS，此函數會傳回 `t`，否則傳回 `f`。

```
postgres=> create extension sslinfo;
CREATE EXTENSION

postgres=> select ssl_is_used();
 ssl_is_used
---------
t
(1 row)
```

您可以使用 `select ssl_cipher()` 命令來決定 SSL/TLS 密碼：

```
postgres=> select ssl_cipher();
ssl_cipher
--------------------
DHE-RSA-AES256-SHA
(1 row)
```

 如果您啟用 `set rds.force_ssl` 並重新啟動資料庫叢集，則非 SSL 連線會遭到拒絕並傳回下列訊息：

```
$ export PGSSLMODE=disable
$ psql postgres -h SOMEHOST.amazonaws.com -p 8192 -U someuser
psql: FATAL: no pg_hba.conf entry for host "host.ip", user "someuser", database "postgres", SSL off
$
```

如需 `sslmode` 選項的資訊，請參閱 PostgreSQL 文件中的[資料庫連線控制函數](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNECT-SSLMODE)。

### 為 Aurora PostgreSQL 資料庫叢集的連線設定密碼套件
<a name="AuroraPostgreSQL.Security.SSL.ConfiguringCipherSuites"></a>

透過使用可設定的密碼套件，您可以更進一步控制資料庫連線的安全性。您可以指定要允許的密碼套件清單，用以保護用戶端與資料庫之間的 SSL/TLS 連線的安全。您可以使用可設定的密碼套件來控制資料庫伺服器接受的連線加密。這樣做有助於避免使用不安全或已作廢的密碼。

Aurora PostgreSQL 11.8 版及更高版本支援可設定的密碼套件。

要指定用於加密連線的許可密碼列表，請修改 `ssl_ciphers` 叢集參數。使用 AWS CLI、 或 RDS API AWS 管理主控台，將 `ssl_ciphers` 參數設定為叢集參數群組中逗號分隔密碼值的字串。要設定叢集參數，請參閱 [在 Amazon Aurora 中修改資料庫叢集參數群組中的參數](USER_WorkingWithParamGroups.ModifyingCluster.md)。

下表顯示有效 Aurora PostgreSQL 引擎版本支援的密碼。


| Aurora PostgreSQL 引擎版本 | 受支援的密碼 | TLS 1.1 | TLS 1.2 | TLS 1.3 | 
| --- | --- | --- | --- | --- | 
| 9.6、10.20 和更低版本，11.15 和更低版本，12.10 和更低版本，13.6 和更低版本 | DHE-RSA-AES128-SHA DHE-RSA-AES128-SHA256 DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES256-SHA DHE-RSA-AES256-SHA256 DHE-RSA-AES256-GCM-SHA384 ECDHE-ECDSA-AES256-SHA ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-RSA-AES256-SHA384 ECDHE-RSA-AES128-SHA ECDHE-RSA-AES128-SHA256 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-RSA-AES256-SHA ECDHE-RSA-AES256-GCM-SHA384 | 是 否 否 否 否 否 是 否 否 是 否 否 是 否 | 否 是 是 是 是 是 是 是 是 是 是 是 是 是 |  否 否 否 否 否 否 否 否 否 否 否 否 否 否  | 
| 10.21、11.16、12.11、13.7、14.3 和 14.4 |  ECDHE-RSA-AES128-SHATLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1GCM\$1SHA256 TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1CBC\$1SHA TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1GCM\$1SHA384 TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1GCM\$1SHA256 TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1CBC\$1SHA TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1GCM\$1SHA384 TLS\$1RSA\$1WITH\$1AES\$1256\$1GCM\$1SHA384 TLS\$1RSA\$1WITH\$1AES\$1256\$1CBC\$1SHA TLS\$1RSA\$1WITH\$1AES\$1128\$1GCM\$1SHA256 TLS\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA TLS\$1ECDHE\$1RSA\$1WITH\$1CHACHA20\$1POLY1305\$1SHA256 | 是 否 是 否 是 否 是 否 否 是 否 是 否 | 是 是 是 是 是 是 是 是 是 是 是 是 是 | 否 否 否 否 否 否 否 否 否 否 否 否 否 | 
| 10.22、11.17、12.12、13.8、14.5 和 15.2 |  TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA256 TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1GCM\$1SHA256 TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1CBC\$1SHA TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1GCM\$1SHA384 TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA256 TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1GCM\$1SHA256 TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1CBC\$1SHA TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1GCM\$1SHA384 TLS\$1RSA\$1WITH\$1AES\$1256\$1GCM\$1SHA384 TLS\$1RSA\$1WITH\$1AES\$1256\$1CBC\$1SHA TLS\$1RSA\$1WITH\$1AES\$1128\$1GCM\$1SHA256 TLS\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA256 TLS\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA TLS\$1ECDHE\$1RSA\$1WITH\$1CHACHA20\$1POLY1305\$1SHA256 |  是 否 否 是 否 是 否 否 是 否 否 是 否 是 是 否  | 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是 | 否 否 否 否 否 否 否 否 否 否 否 否 否 否 否 否 | 
| 11.20、12.15、13.11、14.8、15.3、16.1 及更新版本 | TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA256 TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1GCM\$1SHA256 TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1CBC\$1SHA TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1GCM\$1SHA384 TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA256 TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1GCM\$1SHA256 TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1CBC\$1SHA TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1GCM\$1SHA384 TLS\$1RSA\$1WITH\$1AES\$1256\$1GCM\$1SHA384 TLS\$1RSA\$1WITH\$1AES\$1256\$1CBC\$1SHA TLS\$1RSA\$1WITH\$1AES\$1128\$1GCM\$1SHA256 TLS\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA256 TLS\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA TLS\$1ECDHE\$1RSA\$1WITH\$1CHACHA20\$1POLY1305\$1SHA256 TLS\$1AES\$1128\$1GCM\$1SHA256 TLS\$1AES\$1256\$1GCM\$1SHA384  | 是 否 否 是 否 是 否 否 是 否 否 是 否 是 是 否 否 否 | 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是 否 否 |  否 否 否 否 否 否 否 否 否 否 否 否 否 否 否 否 是 是  | 

您也可以使用 [describe-engine-default-cluster-parameters](https://docs.aws.amazon.com/cli/latest/reference/rds/describe-engine-default-cluster-parameters.html) CLI 命令決定特定參數群組系列目前支援哪些密碼套件。下列範例顯示如何取得適用於 Aurora PostgreSQL 11 的 `ssl_cipher` 叢集參數的允許值。

```
aws rds describe-engine-default-cluster-parameters --db-parameter-group-family aurora-postgresql11
                
    ...some output truncated...
	{
		"ParameterName": "ssl_ciphers",
		"Description": "Sets the list of allowed TLS ciphers to be used on secure connections.",
		"Source": "engine-default",
		"ApplyType": "dynamic",
		"DataType": "list",
		"AllowedValues": "DHE-RSA-AES128-SHA,DHE-RSA-AES128-SHA256,DHE-RSA-AES128-GCM-SHA256,DHE-RSA-AES256-SHA,DHE-RSA-AES256-SHA256,DHE-RSA-AES256-GCM-SHA384,
		ECDHE-RSA-AES128-SHA,ECDHE-RSA-AES128-SHA256,ECDHE-RSA-AES128-GCM-SHA256,ECDHE-RSA-AES256-SHA,ECDHE-RSA-AES256-SHA384,ECDHE-RSA-AES256-GCM-SHA384,TLS_RSA_WITH_AES_256_GCM_SHA384,
		TLS_RSA_WITH_AES_256_CBC_SHA,TLS_RSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
		TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
		"IsModifiable": true,
		"MinimumEngineVersion": "11.8",
		"SupportedEngineModes": [
			"provisioned"
		]
	},
    ...some output truncated...
```

`ssl_ciphers` 參數預設為所有允許的密碼套件。如需有關密碼的詳細資訊，請參閱 PostgreSQL 文件中的 [ssl\$1cipher](https://www.postgresql.org/docs/current/runtime-config-connection.html#GUC-SSL-CIPHERS) 變數。

# 搭配 Aurora PostgreSQL 使用動態遮罩
<a name="AuroraPostgreSQL.Security.DynamicMasking"></a>

動態資料遮罩是一項安全功能，可透過控制資料在查詢時對使用者顯示的方式，保護 Aurora PostgreSQL 資料庫中的敏感資料。Aurora 透過 `pg_columnmask`延伸模組實作它。 `pg_columnmask`提供資料欄層級資料保護，以補充 PostgreSQL 的原生資料列層級安全性和精細存取控制機制。

使用 `pg_columnmask`，您可以建立遮罩政策，根據使用者角色判斷資料可見性。當使用者使用遮罩政策查詢資料表時，Aurora PostgreSQL 會根據使用者的角色和政策權重，在查詢時間套用適當的遮罩函數。基礎資料在儲存中保持不變。

`pg_columnmask` 支援下列功能：
+ **內建和自訂遮罩函數** – 針對電子郵件和文字遮罩等常見模式使用預先建置的函數，或建立您自己的自訂函數，透過 SQL 型遮罩政策保護敏感資料 (PII)。
+ **多個遮罩策略** – 完全隱藏資訊、以萬用字元取代部分值，或定義自訂遮罩方法。
+ **政策優先順序** – 為單一資料欄定義多個政策。使用權重來判斷在將多個政策套用至資料欄時應使用哪些遮罩政策。Aurora PostgreSQL 會根據權重和使用者角色成員資格套用政策。

`pg_columnmask` 適用於 Aurora PostgreSQL 16.10 版和更新版本，以及 17.6 版和更新版本。可免費使用。

# 開始使用動態遮罩
<a name="AuroraPostgreSQL.Security.DynamicMasking.GetStarted"></a>

若要動態遮罩資料，您可以在資料庫中安裝 `pg_columnmask` 擴充功能，並為資料表建立遮罩政策。設定程序包含先決條件驗證、延伸安裝、角色組態、政策建立和驗證測試。

## 延伸模組安裝和組態
<a name="AuroraPostgreSQL.Security.DynamicMasking.GetStarted.Installation"></a>

使用 RDS 主控台查詢編輯器或 PostgreSQL 用戶端連線至 Aurora PostgreSQL 叢集，例如具有 rds\$1superuser （主要使用者） 憑證的 psql。

執行延伸項目建立命令以啟用 `pg_columnmask` 功能：

```
CREATE EXTENSION pg_columnmask;
```

此命令會安裝 `pg_columnmask` 延伸模組、建立必要的目錄資料表，並註冊內建遮罩函數。延伸模組安裝是資料庫特定的，這表示您必須在需要 功能的每個資料庫中分別安裝。

**注意**  
在安裝此延伸模組之前進行的連線仍會顯示未遮罩的資料。關閉並重新連線以修正此問題。

檢查可用的遮罩函數來驗證延伸模組安裝：

```
SELECT proname FROM pg_proc
    WHERE pronamespace = 'pgcolumnmask'::regnamespace AND proname LIKE 'mask_%';
    proname     
--------Output --------
 mask_email
 mask_text
 mask_timestamp
(3 rows)
```

# 管理資料遮罩政策的程序
<a name="AuroraPostgreSQL.Security.DynamicMasking.Procedures"></a>

您可以使用 `pg_columnmask` 擴充功能提供的程序來管理遮罩政策。若要建立、修改或捨棄遮罩政策，您必須具有下列其中一個權限：
+ 您要建立`pg_columnmask`政策之資料表的擁有者。
+ 的成員`rds_superuser`。
+ `pgcolumnmask.policy_admin_rolname` 參數設定`pg_columnmask`的政策管理員角色成員。

下列命令會建立用於後續區段的資料表：

```
CREATE TABLE public.customers (
    id SERIAL PRIMARY KEY,
    name TEXT,
    phone TEXT,
    address TEXT,
    email TEXT
);
```

## CREATE\$1MASKING\$1POLICY
<a name="AuroraPostgreSQL.Security.DynamicMasking.Procedures.CreateMaskingPolicy"></a>

下列程序會為使用者資料表建立新的遮罩政策：

**語法**

```
create_masking_policy(
    policy_name,
    table_name,
    masking_expressions,
    roles,
    weight)
```

**Arguments (引數)**


| 參數 | Datatype | Description | 
| --- | --- | --- | 
| policy\$1name | NAME |  遮罩政策的名稱。每個資料表必須是唯一的。  | 
| table\$1name | REGCLASS |  要套用遮罩政策之資料表的合格/不合格名稱或 oid。  | 
| masking\$1expressions | JSONB |  包含資料欄名稱和遮罩函數對的 JSON 物件。每個索引鍵都是資料欄名稱，其值是要套用至該資料欄的遮罩表達式。  | 
| roles | NAME【】 |  此遮罩政策套用的角色。預設為 PUBLIC。  | 
| weight | INT |  遮罩政策的權重。當多個政策適用於指定使用者的查詢時，具有最高權重 （較高的整數） 的政策將套用至每個遮罩的資料欄。 預設值為 0。資料表上沒有任何兩個遮罩政策可以具有相同的 Wight。  | 

**傳回類型**

無

**Example 建立遮罩政策以遮罩`test_user`角色的電子郵件欄：**  

```
CALL pgcolumnmask.create_masking_policy(
    'customer_mask',
    'public.customers',
    JSON_OBJECT('{
        "email", "pgcolumnmask.mask_email(email)"
    }')::JSONB,
    ARRAY['test_user'],
    100
);
```

## ALTER\$1MASKING\$1POLICY
<a name="AuroraPostgreSQL.Security.DynamicMasking.Procedures.AlterMaskingPolicy"></a>

此程序會修改現有的遮罩政策。 `ALTER_MASKING_POLICY`可以修改政策遮罩表達式、政策套用的一組角色，以及遮罩政策的權重。省略其中一個參數時，政策的對應部分保持不變。

**語法**

```
alter_masking_policy(
    policy_name,
    table_name,
    masking_expressions,
    roles,
    weight)
```

**Arguments (引數)**


| 參數 | Datatype | Description | 
| --- | --- | --- | 
| policy\$1name | NAME |  遮罩政策的現有名稱。  | 
| table\$1name | REGCLASS |  包含遮罩政策之資料表的合格/不合格名稱 oid。  | 
| masking\$1expressions | JSONB |  包含資料欄名稱和遮罩函數對或 NULL 的新 JSON 物件。  | 
| roles | NAME【】 |  套用此遮罩政策的新角色清單，否則為 NULL。  | 
| weight | INT |  遮罩政策或 NULL 的新權重。  | 

**傳回類型**

無

**Example 將分析師角色新增至現有遮罩政策，而不變更其他政策屬性。**  

```
CALL pgcolumnmask.alter_masking_policy(
    'customer_mask',
    'public.customers',
    NULL,
    ARRAY['test_user', 'analyst'],
    NULL 
);

-- Alter the weight of the policy without altering other details
CALL pgcolumnmask.alter_masking_policy(
    'customer_mask',
    'customers',
    NULL,
    NULL,
    4
);
```

## DROP\$1MASKING\$1POLICY
<a name="AuroraPostgreSQL.Security.DynamicMasking.Procedures.DropMaskingPolicy"></a>

此程序會移除現有的遮罩政策。

**語法**

```
drop_masking_policy(
        policy_name,
        table_name)
```

**Arguments (引數)**


| 參數 | Datatype | Description | 
| --- | --- | --- | 
| policy\$1name | NAME |  遮罩政策的現有名稱。  | 
| table\$1name | REGCLASS |  包含遮罩政策之資料表的合格/不合格名稱 oid。  | 

**傳回類型**

無

**Example 捨棄遮罩政策 customer\$1mask**  

```
-- Drop a masking policy
    CALL pgcolumnmask.drop_masking_policy(
        'customer_mask',
        'public.customers',
    );
```

# 遮罩政策 DDL 程序中的逸出識別符
<a name="AuroraPostgreSQL.Security.DynamicMasking.EscapeIdentifiers"></a>

使用引號識別符建立資料遮罩政策時，需要適當的逸出，以確保正確的物件參考和政策應用程式。若要在`pg_columnmask`遮罩政策管理程序中使用引號識別符：
+ **政策名稱** – 必須以雙引號括住。
+ **資料表名稱** – 結構描述名稱和資料表名稱都必須視需要個別以雙引號括住。
+ **遮罩表達**式 – 遮罩表達式中的資料欄和函數名稱必須以雙引號括住，且必須使用反斜線逸出引號本身。
+ **角色** – 會自動引用角色名稱的陣列。角色名稱應該完全符合 中顯示的名稱，`pg_roles`包括區分大小寫。

**Example 逸出和引號語法的**  
此範例顯示為使用混合大小寫名稱或在 Aurora PostgreSQL 中需要引用識別符的資料表、資料欄、函數和角色建立遮罩政策時，適當的逸出和引用語法。  

```
-- Create a table and columns with mixed case name 
CREATE TABLE public."Employees" (
    "Name" TEXT,
    "Email" TEXT,
    ssn VARCHAR(20)
);

-- Create a role with mixed case name
CREATE ROLE "Masked_user";

-- Create a function with mixed case name
CREATE OR REPLACE FUNCTION public."MaskEmail"(text)
    RETURNS character varying
    LANGUAGE plpgsql
    IMMUTABLE PARALLEL SAFE
    AS $$ BEGIN
        RETURN 'XXXXXXXX'::text;
    END $$;

-- Now use these objects with mixed case names in
-- masking policy management procedures
CALL pgcolumnmask.create_masking_policy(
    '"Policy1"',  -- policy name should be surrounded with double quotes for quoting
    'public."Employees"', -- table and schema name should be individually 
                          -- surrounded with double quotes for quoting
    JSON_OBJECT('{
        "\"Email\"", "\"MaskEmail\"(\"Email\")"
    }')::JSONB, -- masking expression should have double quotes around function names
                -- and columns names etc when needed. Also the double quotes itself
                -- should be escaped using \ (backslash) since this is a JSON string
    ARRAY['Masked_user'], -- Rolename do not need quoting
                          -- (this behaviour may change in future release)
    100
);

SELECT * FROM pgcolumnmask.pg_columnmask_policies
    WHERE tablename = 'Employees';
-[ RECORD 1 ]-----+-------------------------------------
schemaname        | public
tablename         | Employees
policyname        | Policy1
roles             | {Masked_user}
masked_columns    | {Email}
masking_functions | {"(\"MaskEmail\"(\"Email\"))::text"}
weight            | 100
```

## 管理檢視
<a name="AuroraPostgreSQL.Security.DynamicMasking.AdminViews"></a>

您可以使用可公開存取的`pgcolumnmask.pg_columnmask_policies`管理檢視來檢閱所有`pg_columnmask`政策。下列資訊可透過此檢視取得。檢視只會傳回目前使用者擁有的遮罩政策。


| 欄名稱 | 資料類型 | Description | 
| --- | --- | --- | 
|  結構描述名稱  | NAME |  政策所連接關係的結構描述  | 
|  資料表名稱  | NAME |  政策所連接關係的名稱  | 
|  policyname  | NAME |  遮罩政策的名稱，所有遮罩政策都有唯一的名稱  | 
|  roles  | TEXT【】 |  政策適用的角色。  | 
|  masked\$1columns  | TEXT【】 |  遮罩的資料欄  | 
|  masking\$1functions  | TEXT【】 |  遮罩函數  | 
| Weight | INT |  附加政策的權重  | 

# 預先定義的資料遮罩函數
<a name="AuroraPostgreSQL.Security.DynamicMasking.PredefinedMaskingFunctions"></a>

`pg_columnmask` extension 提供以 C 語言寫入的內建公用程式函數 （以加快執行速度），可用於`pg_columnmask`政策的遮罩表達式。

**mask\$1text**

使用可設定的可見性選項遮罩文字資料的 函數。

**Arguments (引數)**


| 參數 | Datatype | Description | 
| --- | --- | --- | 
| input | TEXT |  要遮罩的原始文字字串  | 
| mask\$1char | CHAR(1) |  用於遮罩的字元 （預設：'X')  | 
| visible\$1prefix | INT |  在輸入文字開頭的字元數將保持非遮罩 （預設值：0)  | 
| visible\$1suffix | INT |  輸入文字結尾的字元數將保持非遮罩 （預設值：0)  | 
| use\$1hash\$1mask | BOOLEAN |  若為 TRUE， 會使用以雜湊為基礎的遮罩，而非 mask\$1char （預設值：FALSE)  | 

**Example 使用不同的遮罩選項**  
使用預設的「X」字元遮罩整個輸入字串  

```
postgres=> SELECT pgcolumnmask.mask_text('Hello World');
  mask_text  
-------------
 XXXXXXXXXXX
```
使用 `mask_char` 引數來遮罩使用不同字元的文字輸入  

```
postgres=> SELECT pgcolumnmask.mask_text('Hello World', '*');
  mask_text  
-------------
 ***********
```
使用 `visible_prefix`和 `visible_suffix` 參數控制在文字的開頭和結尾保持未遮罩的字元數量  

```
postgres=> SELECT pgcolumnmask.mask_text('Hello World', '*', 5, 1);
  mask_text  
-------------
 Hello*****d
```
當 `use_hash_mask` 為 true 時，系統會忽略使用隨機字元`mask_char`引數遮罩輸入字串，`visible_prefix`但仍會`visible_suffix`接受  

```
postgres=> SELECT pgcolumnmask.mask_text('Hello World', '*', 2, 2, true);
  mask_text  
-------------
 Hex36dOHild
```

**mask\$1timestamp**


| 參數 | Datatype | Description | 
| --- | --- | --- | 
| ts\$1to\$1mask | TIMESTAMP |  要遮罩的原始時間戳記  | 
| mask\$1part | TEXT |  指定要遮罩的時間戳記部分 （預設值：'all') 有效值：'year'、'month'、'day'、'hour'、'minute'、'second'、'all'  | 
| mask\$1value | TIMESTAMP |  用於遮罩的時間戳記值 （預設值：'1900-01-01 00：00：00')  | 

**Example 使用 `mask_timestamps`**  
這些範例示範對預設值的完整時間戳記遮罩、特定時間戳記元件的部分遮罩 （僅限年份），以及使用自訂取代值遮罩。  
完全遮罩預設時間戳記的輸入值  

```
postgres=> SELECT pgcolumnmask.mask_timestamp('2023-06-15 14:30:00');
   mask_timestamp    
---------------------
 1900-01-01 00:00:00
```
僅遮罩範例中的某個部分時間戳記，僅限年份  

```
postgres=> SELECT pgcolumnmask.mask_timestamp('2023-06-15 14:30:00', 'year');
   mask_timestamp    
---------------------
 1900-06-15 14:30:00
```
若要變更時間戳記的遮罩值，請使用 `mask_value`引數  

```
postgres=> SELECT pgcolumnmask.mask_timestamp('2023-06-15 14:30:00', 'all', '2012-12-12 12:12:12');
   mask_timestamp    
---------------------
 2012-12-12 12:12:12
```

**mask\$1timestamp**

在保留電子郵件結構時遮罩電子郵件地址的 函數。


| 參數 | Datatype | Description | 
| --- | --- | --- | 
| input | TEXT |  要遮罩的原始電子郵件地址  | 
| mask\$1char | CHAR(1) |  用於遮罩的字元 （預設：'X')  | 
| mask\$1local | BOOLEAN |  如果是 TRUE， 會遮罩電子郵件的本機部分 (@ 之前） （預設值：TRUE)  | 
| mask\$1domain | BOOLEAN |  如果為 TRUE， 會遮罩電子郵件的網域部分 (@ 之後） （預設：TRUE)  | 

**Example 使用 `mask_email`**  
這些範例示範完整的電子郵件遮罩、自訂遮罩字元，以及電子郵件地址的本機部分或網域部分的選擇性遮罩。  
完成遮罩  

```
postgres=> SELECT pgcolumnmask.mask_email('user@example.com');
    mask_email    
------------------
 XXXX@XXXXXXX.com
```
使用 `mask_char` 變更用於遮罩的字元  

```
postgres=> SELECT pgcolumnmask.mask_email('user@example.com', '*');
    mask_email    
------------------
 ****@*******.com
```
使用 `mask_local`和 `mask_domain` 控制本機和網域上的遮罩  

```
postgres=> SELECT pgcolumnmask.mask_email('user@example.com', '*', true, false);
    mask_email    
------------------
 ****@example.com

postgres=> SELECT pgcolumnmask.mask_email('user@example.com', '*', false, true);
    mask_email    
------------------
 user@*******.com
```

# 在end-to-end工作流程中實作 pg\$1columnmask
<a name="AuroraPostgreSQL.Security.DynamicMasking.WorkflowExample"></a>

本節示範`pg_columnmask`將範例員工資料表與敏感資料搭配使用的完整實作。您將了解如何建立自訂遮罩函數、為各種角色 （互動、支援、分析師） 定義具有不同權重層級的多個遮罩政策，以及觀察具有單一或多個角色成員資格的使用者如何看到不同層級的遮罩資料。這些範例也涵蓋具有 RETURNING 子句的 DML 陳述式中的遮罩行為、資料表與檢視的觸發，以及政策管理操作，包括重新命名、變更權重和清除。

1. 使用一些敏感資料建立範例資料表：

   ```
   CREATE SCHEMA hr;
   
   CREATE TABLE hr.employees (
       id INT PRIMARY KEY,
       name TEXT NOT NULL,
       email TEXT,
       ssn TEXT,
       salary NUMERIC(10,2)
    );
   
   INSERT INTO hr.employees VALUES
       (1, 'John Doe', 'john.doe@example.com', '123-45-6789', 50000.00),
       (2, 'Jane Smith', 'jane.smith@example.com', '987-65-4321', 60000.00);
   ```

1. 建立自訂遮罩函數：

   ```
   CREATE OR REPLACE FUNCTION public.mask_ssn(ssn TEXT)
       RETURNS TEXT AS $$
       BEGIN
           RETURN 'XXX-XX-' || RIGHT(ssn, 4);
       END;
       $$ LANGUAGE plpgsql;
   
   CREATE OR REPLACE FUNCTION public.mask_salary(salary NUMERIC, multiplier NUMERIC DEFAULT 0.0)
       RETURNS NUMERIC AS $$
       BEGIN
           RETURN salary * multiplier;
       END;
       $$ LANGUAGE plpgsql;
   ```

1. 根據使用者角色建立具有不同遮罩層級的多個政策：

   ```
   -- Create different roles
   CREATE ROLE analyst_role;
   CREATE ROLE support_role;
   CREATE ROLE intern_role;
   
   GRANT USAGE ON SCHEMA hr TO analyst_role, support_role, intern_role;
   GRANT SELECT ON hr.employees TO analyst_role, support_role, intern_role;
   ----------------------------------------------------------------------
   
   -- Low-Weight Policy (Intern)
   CALL pgcolumnmask.create_masking_policy(
       'employee_mask_strict',
       'hr.employees',
       JSON_BUILD_OBJECT('name', 'pgcolumnmask.mask_text(name, ''*'')',
                         'email', 'pgcolumnmask.mask_email(email)',
                         'ssn', 'pgcolumnmask.mask_text(ssn, ''*'')',
                         'salary', 'public.mask_salary(salary)')::JSONB,
       ARRAY['intern_role'],
       10  -- Lowest weight
   );
   
   ----------------------------------------------------------------------
   -- Medium-Weight Policy (Support)
   CALL pgcolumnmask.create_masking_policy(
       'employee_mask_moderate',
       'hr.employees',
       JSON_BUILD_OBJECT('email', 'pgcolumnmask.mask_email(email, ''#'')',
                         'ssn', 'public.mask_ssn(ssn)',
                         'salary', 'public.mask_salary(salary)')::JSONB,
       ARRAY['support_role'],
       50   -- Medium weight
   );
   
   ----------------------------------------------------------------------
   -- High-Weight Policy (Analyst)
   CALL pgcolumnmask.create_masking_policy(
       'employee_mask_light',
       'hr.employees',
       JSON_BUILD_OBJECT('ssn', 'public.mask_ssn(ssn)',
                         'salary', 'public.mask_salary(salary, 0.9)')::JSONB,
       ARRAY['analyst_role'],
       100   -- Highest weight
   );
   ```

1. 下列範例示範不同使用者如何根據其角色成員資格和政策權重來查看資料。

   ```
   -- Create users
   CREATE USER sarah_intern;
   GRANT intern_role TO sarah_intern;
   
   CREATE USER lisa_support;
   GRANT support_role TO lisa_support;
   
   CREATE USER mike_analyst;
   GRANT analyst_role TO mike_analyst;
   
   CREATE USER ethan_support_intern;
   GRANT support_role, intern_role TO ethan_support_intern;
   
   CREATE USER john_analyst_intern;
   GRANT analyst_role, intern_role TO john_analyst_intern;
   ```

   作為內部 （最嚴格的遮罩）：

   ```
   SET ROLE sarah_intern;
   
   SELECT * FROM hr.employees;
    id |    name    |         email          |     ssn     | salary 
   ----+------------+------------------------+-------------+--------
     1 | ********   | XXXXXXXX@XXXXXXX.com   | *********** |   0.00
     2 | ********** | XXXXXXXXXX@XXXXXXX.com | *********** |   0.00
   ```

   身為支援使用者 （中度遮罩）：

   ```
   SET ROLE lisa_support;
   
   SELECT * FROM hr.employees;
    id |    name    |         email          |     ssn     | salary 
   ----+------------+------------------------+-------------+--------
     1 | John Doe   | ########@#######.com   | XXX-XX-6789 |   0.00
     2 | Jane Smith | ##########@#######.com | XXX-XX-4321 |   0.00
   ```

   身為分析師 （最輕量的遮罩）：

   ```
   SET ROLE mike_analyst;
   
   SELECT * FROM hr.employees;
    id |    name    |         email          |     ssn     |  salary  
   ----+------------+------------------------+-------------+----------
     1 | John Doe   | john.doe@example.com   | XXX-XX-6789 | 45000.00
     2 | Jane Smith | jane.smith@example.com | XXX-XX-4321 | 54000.00
   ```

   作為 ethan\$1support\$1intern 使用者，該使用者同時是 intern 和支援使用者：

   ```
   SET ROLE ethan_support_intern;
   
   -- masking policies appliable to this user: employee_mask_strict and employee_mask_moderate
   -- id : unmasked because no masking policy appliable on ethan_support_intern
   --            masks these columns
   -- name : masked because of employee_mask_strict policy
   -- email, ssn, salary : both employee_mask_strict and employee_mask_moderate mask these columns
   --                      but employee_mask_moderate will be use because of higher weight 
   
   SELECT * FROM hr.employees;
    id |    name    |         email          |     ssn     | salary 
   ----+------------+------------------------+-------------+--------
     1 | ********   | ########@#######.com   | XXX-XX-6789 |   0.00
     2 | ********** | ##########@#######.com | XXX-XX-4321 |   0.00
   ```

   作為 john\$1analyst\$1intern，它是 intern 和分析師：

   ```
   SET ROLE john_analyst_intern;
   
   -- masking policies appliable to this user: employee_mask_strict and employee_mask_light
   -- id : unmasked because no masking policy appliable on john_analyst_intern
   --            masks these columns
   -- name, email : masked because of employee_mask_strict
   -- ssn, salary : both employee_mask_strict and employee_mask_light mask these columns
   --               but employee_mask_light will be use because of higher weight 
   
   SELECT * FROM hr.employees;
    id |    name    |         email          |     ssn     |  salary  
   ----+------------+------------------------+-------------+----------
     1 | ********   | XXXXXXXX@XXXXXXX.com   | XXX-XX-6789 | 45000.00
     2 | ********** | XXXXXXXXXX@XXXXXXX.com | XXX-XX-4321 | 54000.00
   ```

# 了解 DML 操作中的遮罩行為
<a name="AuroraPostgreSQL.Security.DynamicMasking.DMLMasking"></a>

`pg_columnmask` 會一致地套用至所有 DML 操作，包括 INSERT、UPDATE、DELETE 和 MERGE 陳述式。當您執行這些操作時，Aurora PostgreSQL 會根據核心原則遮罩資料 – 從儲存體讀取的任何資料都會根據目前使用者的適用政策遮罩。

遮罩會影響下列一些查詢元件，例如：
+ WHERE 子句
+ JOIN 條件
+ 子查詢
+ RETURNING 子句

所有這些元件都以遮罩值運作，而不是原始資料。當資料寫入儲存體時未遮罩，使用者只會在回讀時看到其遮罩檢視。

Aurora PostgreSQL 會對實際儲存的值強制執行所有資料庫限制 （非 NULL、UNIQUE、 CHECK、FOREIGN KEY)，而非遮罩的值。如果未仔細設計遮罩函數，這有時可能會產生明顯的不一致。

遮罩可與資料欄層級許可搭配使用：
+ 沒有 SELECT 權限的使用者無法讀取資料欄
+ 具有 SELECT 權限的使用者會根據其適用的政策查看遮罩的值

# 了解觸發函數中的遮罩行為
<a name="AuroraPostgreSQL.Security.DynamicMasking.TriggerFunctionMasking"></a>

將`pg_columnmask`政策套用至資料表時，請務必了解遮罩如何與觸發函數互動。觸發條件是自動執行的資料庫函數，以回應資料表上的某些事件，例如 INSERT、UPDATE 或 DELETE 操作。

根據預設，DDM 會根據觸發類型套用不同的遮罩規則：

資料表觸發條件  
**未遮罩轉換資料表** – 資料表上的觸發函數可以存取其轉換資料表中舊資料列和新資料列版本的未遮罩資料  
資料表擁有者會建立觸發條件並擁有資料，因此他們具有有效管理資料表的完整存取權

檢視觸發 (INSTEAD OF Triggers)  
**轉換資料表已遮罩** – 檢視上的觸發函數會根據目前使用者的許可查看遮罩的資料  
檢視擁有者可能與基礎資料表擁有者不同，因此應遵守基礎資料表上的遮罩政策

兩個伺服器層級組態參數會使用遮罩資料表控制觸發行為。這些只能由 設定`rds_superuser`：
+ **限制遮罩資料表的觸發** – 當遮罩使用者對具有適用遮罩政策的資料表執行 DML 操作時，防止觸發執行。
+ **使用遮罩資料表限制檢視的觸發：** – 當檢視定義包含適用於目前使用者的遮罩政策的資料表時，防止在檢視上觸發執行。

**Example 函數應用程式與資料表和檢視之間的差異**  
下列範例會建立觸發函數來列印舊資料列值和新資料列值，然後示範相同的函數在連接到資料表時與檢視時的行為有何不同。  

```
-- Create trigger function
CREATE OR REPLACE FUNCTION print_changes()
    RETURNS TRIGGER AS
    $$
        BEGIN
        RAISE NOTICE 'Old row: name=%, email=%, ssn=%, salary=%',
            OLD.name, OLD.email, OLD.ssn, OLD.salary;
        
        RAISE NOTICE 'New row: name=%, email=%, ssn=%, salary=%',
            NEW.name, NEW.email, NEW.ssn, NEW.salary;
        
        RETURN NEW;
        END;
    $$ LANGUAGE plpgsql;

-- Create trigger
CREATE TRIGGER print_changes_trigger
    BEFORE UPDATE ON hr.employees
    FOR EACH ROW
    EXECUTE FUNCTION print_changes();

-- Grant update to analyst role
GRANT UPDATE ON hr.employees TO analyst_role;

-- Unmasked data must be seen inside trigger even for masked user for the OLD and NEW
-- row passed to trigger function
BEGIN;
SET ROLE mike_analyst;
UPDATE hr.employees SET id = id + 10 RETURNING *;
NOTICE:  Old row: name=John Doe, email=john.doe@example.com, ssn=123-45-6789, salary=50000.00
NOTICE:  New row: name=John Doe, email=john.doe@example.com, ssn=123-45-6789, salary=50000.00
NOTICE:  Old row: name=Jane Smith, email=jane.smith@example.com, ssn=987-65-4321, salary=60000.00
NOTICE:  New row: name=Jane Smith, email=jane.smith@example.com, ssn=987-65-4321, salary=60000.00
 id |    name    |         email          |     ssn     |  salary  
----+------------+------------------------+-------------+----------
 11 | John Doe   | john.doe@example.com   | XXX-XX-6789 | 45000.00
 12 | Jane Smith | jane.smith@example.com | XXX-XX-4321 | 54000.00
(2 rows)

ROLLBACK;


-- Triggers on views (which are supposed to see masked data for new/old row)
CREATE VIEW hr.view_over_employees AS SELECT * FROM hr.employees;
GRANT UPDATE, SELECT ON hr.view_over_employees TO analyst_role;

-- Create trigger for this view
CREATE TRIGGER print_changes_trigger
    INSTEAD OF UPDATE ON hr.view_over_employees
    FOR EACH ROW
    EXECUTE FUNCTION print_changes();

-- Masked new and old rows should be passed to trigger if trigger is on view
BEGIN;
SET ROLE mike_analyst;
UPDATE hr.view_over_employees SET id = id + 10 RETURNING *;
NOTICE:  Old row: name=John Doe, email=john.doe@example.com, ssn=XXX-XX-6789, salary=45000.00
NOTICE:  New row: name=John Doe, email=john.doe@example.com, ssn=XXX-XX-6789, salary=45000.00
NOTICE:  Old row: name=Jane Smith, email=jane.smith@example.com, ssn=XXX-XX-4321, salary=54000.00
NOTICE:  New row: name=Jane Smith, email=jane.smith@example.com, ssn=XXX-XX-4321, salary=54000.00
 id |    name    |         email          |     ssn     |  salary  
----+------------+------------------------+-------------+----------
 11 | John Doe   | john.doe@example.com   | XXX-XX-6789 | 45000.00
 12 | Jane Smith | jane.smith@example.com | XXX-XX-4321 | 54000.00
(2 rows)
ROLLBACK;
```
建議您先檢閱觸發行為，再對遮罩的資料表實作觸發。資料表觸發程序可存取轉換資料表中的未遮罩資料，而檢視觸發程序則會看到遮罩的資料。

**Example 重新命名遮罩政策**  
下列範例示範如何使用 `rename_masking_policy` 程序重新命名現有政策。  

```
-- Rename the strict policy
CALL pgcolumnmask.rename_masking_policy(
    'employee_mask_strict',
    'hr.employees',
    'intern_protection_policy'
);

-- Verify the rename
SELECT policyname, roles, weight
    FROM pgcolumnmask.pg_columnmask_policies
    WHERE tablename = 'employees'
    ORDER BY weight DESC;

        policyname        |     roles      | weight 
--------------------------+----------------+--------
 employee_mask_light      | {analyst_role} |    100
 employee_mask_moderate   | {support_role} |     50
 intern_protection_policy | {intern_role}  |     10
```

**Example 更改政策權重**  
下列範例示範如何變更政策權重以變更其權重。  

```
-- Change weight of moderate policy
CALL pgcolumnmask.alter_masking_policy(
    'employee_mask_moderate'::NAME,
    'hr.employees'::REGCLASS,
    NULL,    -- Keep existing masking expressions
    NULL,    -- Keep existing roles
    75       -- New weight
);

-- Verify the changes
SELECT policyname, roles, weight
    FROM pgcolumnmask.pg_columnmask_policies
    WHERE tablename = 'employees'
    ORDER BY weight DESC;
        policyname        |     roles      | weight 
--------------------------+----------------+--------
 employee_mask_light      | {analyst_role} |    100
 employee_mask_moderate   | {support_role} |     75
 intern_protection_policy | {intern_role}  |     10
```

**Example 清除**  
下列範例示範如何捨棄所有政策、資料表和使用者。  

```
-- Drop policies
CALL pgcolumnmask.drop_masking_policy(
    'intern_protection_policy',
    'hr.employees'
);

CALL pgcolumnmask.drop_masking_policy(
    'employee_mask_moderate',
    'hr.employees'
);

CALL pgcolumnmask.drop_masking_policy(
    'employee_mask_light',
    'hr.employees'
);

-- Drop table and functions
DROP VIEW IF EXISTS hr.view_over_employees;
DROP TABLE IF EXISTS hr.employees;
DROP SCHEMA IF EXISTS hr;
DROP FUNCTION IF EXISTS public.mask_ssn(text);
DROP FUNCTION IF EXISTS public.mask_salary(numeric, numeric);

-- Drop users
DROP USER sarah_intern, lisa_support, mike_analyst,
    ethan_support_intern, john_analyst_intern;
DROP ROLE intern_role, support_role, analyst_role;
```

# 設定遮罩政策管理角色
<a name="AuroraPostgreSQL.Security.DynamicMasking.PolicyManagementRole"></a>

PostgreSQL 資料欄遮罩延伸模組 `pg_columnmask`可讓您將遮罩政策的管理委派給特定角色，而不是要求 `rds_superuser`或 資料表擁有者權限。這可以更精細地控制誰可以建立、更改和捨棄遮罩政策。

若要設定具有遮罩政策管理權限的角色，請遵循下列步驟：

1. 建立政策管理員角色 – 建立負責管理遮罩政策`rds_superuser`的新角色：

   ```
   CREATE ROLE mask_admin NOLOGIN;
   ```

1. 設定 PostgreSQL 參數 – 在自訂資料庫叢集參數群組中，將`pgcolumnmask.policy_admin_rolname`引擎組態參數設定為您建立的角色名稱：

   ```
   pgcolumnmask.policy_admin_rolname = mask_admin
   ```

   此引擎組態參數可以在資料庫叢集參數群組中設定，而且不需要重新啟動執行個體。如需更新參數的詳細資訊，請參閱 [在 Amazon Aurora 中修改資料庫叢集參數群組中的參數](USER_WorkingWithParamGroups.ModifyingCluster.md)。

1. 將角色授予使用者 作為 `rds_superuser`，將`mask_admin`角色授予應能夠管理遮罩政策的使用者：

   ```
   CREATE USER alice LOGIN;
   CREATE USER bob LOGIN;
   GRANT mask_admin TO alice, bob;
   ```

   此外，請確保使用者在管理遮罩政策的結構描述上具有 USAGE 權限：

   ```
   GRANT USAGE ON SCHEMA hr TO alice, bob;
   ```

現在，當使用者`alice`和 `bob` 連線到資料庫時，他們可以使用標準`pg_columnmask`延伸函數，在所有結構描述具有`USAGE`權限的結構描述中的所有資料表上建立、更改和捨棄遮罩政策。

# 安全 pg\$1columnmask 實作的最佳實務
<a name="AuroraPostgreSQL.Security.DynamicMasking.BestPractices"></a>

下一節提供`pg_columnmask`在 Aurora PostgreSQL 環境中實作 的安全最佳實務。請遵循這些建議：
+ 建立安全的角色型存取控制架構
+ 開發防止安全漏洞的遮罩函數
+ 使用遮罩資料了解和控制觸發行為

## 角色型安全架構
<a name="AuroraPostgreSQL.Security.DynamicMasking.BestPractices.architecture"></a>

定義角色階層以在資料庫中實作存取控制。Aurora PostgreSQL 透過為這些角色中的精細資料遮罩提供額外的圖層來`pg_columnmask`增強這些控制。

建立符合組織函數的專用角色，而不是將許可授予個別使用者。此方法可提供更好的可稽核性，並簡化組織結構演進時的許可管理。

**Example 建立組織角色階層**  
下列範例會建立具有不同 函數專用角色的組織角色階層，然後將個別使用者指派給適當的角色。在此範例中，會先建立組織角色 (analyst\$1role、support\$1role)，然後授與個別使用者這些角色的成員資格。此結構可讓您在角色層級管理許可，而不是針對每個個別使用者。  

```
-- Create organizational role hierarchy
CREATE ROLE data_admin_role;
CREATE ROLE security_admin_role;
CREATE ROLE analyst_role;
CREATE ROLE support_role;
CREATE ROLE developer_role;

-- Specify security_admin_role as masking policy manager in the DB cluster parameter
-- group pgcolumnmask.policy_admin_rolname = 'security_admin_role'

-- Create specific users and assign to appropriate roles
CREATE USER security_manager;
CREATE USER data_analyst1, data_analyst2;
CREATE USER support_agent1, support_agent2;

GRANT security_admin_role TO security_manager;
GRANT analyst_role TO data_analyst1, data_analyst2;
GRANT support_role TO support_agent1, support_agent2;
```
僅授予每個角色所需的最低許可，以實作最低權限原則。避免授予在登入資料洩露時可能遭到利用的廣泛許可。  

```
-- Grant specific table permissions rather than schema-wide access
GRANT SELECT ON sensitive_data.customers TO analyst_role;
GRANT SELECT ON sensitive_data.transactions TO analyst_role;
-- Do not grant: GRANT ALL ON SCHEMA sensitive_data TO analyst_role;
```
政策管理員需要管理遮罩政策之結構描述`USAGE`的權限。遵循最低權限原則，選擇性地授予這些權限。定期審查結構描述存取許可，以確保只有獲得授權的人員才能維護政策管理功能。  
政策管理員角色參數組態僅限於資料庫管理員。此參數無法在資料庫或工作階段層級修改，防止無權限使用者覆寫政策管理員指派。此限制可確保遮罩政策控制保持集中且安全。  
將政策管理員角色指派給特定個人，而非群組。此目標方法可確保選擇性存取遮罩政策管理，因為政策管理員能夠遮罩資料庫中的所有資料表。

## 安全遮罩函數開發
<a name="AuroraPostgreSQL.Security.DynamicMasking.BestPractices.MaskingDevelopment"></a>

使用早期繫結語意開發遮罩函數，以確保適當的相依性追蹤，並防止延遲繫結漏洞，例如在執行期修改搜尋路徑。建議使用 SQL `BEGIN ATOMIC` 函數的語法來啟用編譯時間驗證 （即早期繫結） 和相依性管理。

```
-- Example - Secure masking function with early binding
CREATE OR REPLACE FUNCTION secure_mask_ssn(input_ssn TEXT)
    RETURNS TEXT
    LANGUAGE SQL
    IMMUTABLE PARALLEL SAFE STRICT
    BEGIN ATOMIC
        SELECT CASE
            WHEN input_ssn IS NULL THEN NULL
            WHEN length(input_ssn) < 4 THEN repeat('X', length(input_ssn))
            ELSE repeat('X', length(input_ssn) - 4) || right(input_ssn, 4)
        END;
    END;
```

或者，透過明確建構符合所有物件參考的結構描述，建立可避免搜尋路徑變更的函數，確保不同使用者工作階段的行為一致。

```
-- Function immune to search path changes
CREATE OR REPLACE FUNCTION data_masking.secure_phone_mask(phone_number TEXT)
    RETURNS TEXT
    LANGUAGE SQL
    IMMUTABLE PARALLEL SAFE STRICT
    AS $$
    SELECT CASE
        WHEN phone_number IS NULL THEN NULL
        WHEN public.length(public.regexp_replace(phone_number, '[^0-9]', '', 'g')) < 10 THEN 'XXX-XXX-XXXX'
        ELSE public.regexp_replace(
            phone_number,
            '([0-9]{3})[0-9]{3}([0-9]{4})',
            public.concat('\1-XXX-\2')
        )
    END;
    $$;
```

在遮罩函數中實作輸入驗證，以處理邊緣案例並防止意外行為。一律包含 NULL 處理和驗證輸入格式，以確保一致的遮罩行為。

```
-- Robust masking function with comprehensive input validation
CREATE OR REPLACE FUNCTION secure_mask_phone(phone_number TEXT)
    RETURNS TEXT
    LANGUAGE SQL
    IMMUTABLE PARALLEL SAFE STRICT
    BEGIN ATOMIC
        SELECT CASE
            WHEN phone_number IS NULL THEN NULL
            WHEN length(trim(phone_number)) = 0 THEN phone_number
            WHEN length(regexp_replace(phone_number, '[^0-9]', '', 'g')) < 10 THEN 'XXX-XXX-XXXX'
            ELSE regexp_replace(phone_number, '([0-9]{3})[0-9]{3}([0-9]{4})', '\1-XXX-\2')
        END;
    END;
```

## DML 使用 pg\$1columnmask 觸發行為
<a name="AuroraPostgreSQL.Security.DynamicMasking.BestPractices.DMLTriggerBehavior"></a>

對於資料表觸發，轉換資料表將完全取消遮罩。對於檢視觸發 (IOT)，將根據目前使用者的檢視許可遮罩轉換資料表。

使用 pg\$1columnmask 的資料表觸發  
觸發程序會傳遞轉換表，其中包含由觸發 DML 查詢修改的舊版和新版本資料列。根據觸發時間，Aurora PostgreSQL 會填入新舊資料列。例如，`BEFORE INSERT`觸發條件只有新版本的資料列和空白的舊版本，因為沒有要參考的舊版本。  
`pg_columnmask` 不會遮罩資料表上觸發條件內的轉換資料表。觸發程序可以在其內文中使用遮罩的資料欄，並查看未遮罩的資料。觸發器建立者應確保如何為使用者執行觸發器。在此情況下，下列範例可正常運作。  

```
-- Example for table trigger uses masked column in its definition
-- Create a table and insert some rows
CREATE TABLE public.credit_card_table (
    name TEXT,
    credit_card_no VARCHAR(16),
    is_fraud BOOL
);

INSERT INTO public.credit_card_table (name, credit_card_no, is_fraud)
    VALUES
    ('John Doe', '4532015112830366', false),
    ('Jane Smith', '5410000000000000', true),
    ('Brad Smith', '1234567891234567', true);

-- Create a role which will see masked data and grant it privileges
CREATE ROLE intern_user;
GRANT SELECT, DELETE ON public.credit_card_table TO intern_user;

-- Trigger which will silenty skip delete of non fraudelent credit cards
CREATE OR REPLACE FUNCTION prevent_non_fraud_delete()
    RETURNS TRIGGER AS
    $$
    BEGIN
        IF OLD.is_fraud = false THEN
            RETURN NULL;
        END IF;
        RETURN OLD;
    END;
    $$ LANGUAGE plpgsql;

CREATE TRIGGER prevent_non_fraud_delete
    BEFORE DELETE ON credit_card_table
    FOR EACH ROW
    EXECUTE FUNCTION prevent_non_fraud_delete();

CREATE OR REPLACE FUNCTION public.return_false()
    RETURNS BOOLEAN
    LANGUAGE SQL
    IMMUTABLE PARALLEL SAFE STRICT
    BEGIN ATOMIC
      SELECT false;
    END;

-- A masking policy that masks both credit card number and is_fraud column.
-- If we apply masking inside trigger then prevent_non_fraud_delete trigger will
-- allow deleting more rows to masked user (even non fraud ones).
CALL pgcolumnmask.create_masking_policy(
    'mask_credit_card_no_&_is_fraud'::NAME,
    'public.credit_card_table'::REGCLASS,
    JSON_BUILD_OBJECT('credit_card_no', 'pgcolumnmask.mask_text(credit_card_no)',
                      'is_fraud', 'public.return_false()')::JSONB,
    ARRAY['intern_user']::NAME[],
    10::INT
);

-- Test trigger behaviour using intern_user
BEGIN;
SET ROLE intern_user;
-- credit card number & is_fraud is completely masked from intern_user
SELECT * FROM public.credit_card_table;
    name    |  credit_card_no  | is_fraud 
------------+------------------+----------
 John Doe   | XXXXXXXXXXXXXXXX | f
 Jane Smith | XXXXXXXXXXXXXXXX | f
 Brad Smith | XXXXXXXXXXXXXXXX | f
(3 rows)

-- The delete trigger lets the intern user delete rows for Jane and Brad even though
-- intern_user sees their is_fraud = false, but the table trigger works with original
-- unmasked value
DELETE FROM public.credit_card_table RETURNING *;
    name    |  credit_card_no  | is_fraud 
------------+------------------+----------
 Jane Smith | XXXXXXXXXXXXXXXX | f
 Brad Smith | XXXXXXXXXXXXXXXX | f
(2 rows)

COMMIT;
```
如果使用者對其在觸發內文中使用的陳述式不小心，觸發建立者會將未遮罩的資料洩漏給使用者。例如，使用 會將資料欄`RAISE NOTICE ‘%’, masked_column;`列印到目前使用者。  

```
-- Example showing table trigger leaking column value to current user
CREATE OR REPLACE FUNCTION leaky_trigger_func()
    RETURNS TRIGGER AS
    $$
    BEGIN
        RAISE NOTICE 'Old credit card number was: %', OLD.credit_card_no;
        RAISE NOTICE 'New credit card number is %', NEW.credit_card_no;
        RETURN NEW;
    END;
    $$ LANGUAGE plpgsql;

CREATE TRIGGER leaky_trigger
    AFTER UPDATE ON public.credit_card_table
    FOR EACH ROW
    EXECUTE FUNCTION leaky_trigger_func();

-- Grant update on column is_fraud to auditor role
-- auditor will NOT HAVE PERMISSION TO READ DATA
CREATE ROLE auditor;
GRANT UPDATE (is_fraud) ON public.credit_card_table TO auditor;

-- Also add auditor role to existing masking policy on credit card table
CALL pgcolumnmask.alter_masking_policy(
    'mask_credit_card_no_&_is_fraud'::NAME,
    'public.credit_card_table'::REGCLASS,
    NULL::JSONB,
    ARRAY['intern_user', 'auditor']::NAME[],
    NULL::INT
);

-- Log in as auditor
-- [auditor]
-- Update will fail if trying to read data from the table
UPDATE public.credit_card_table
    SET is_fraud = true
    WHERE credit_card_no = '4532015112830366';
ERROR:  permission denied for table cc_table

-- [auditor]
-- But leaky update trigger will still print the entire row even though
-- current user does not have permission to select from public.credit_card_table
UPDATE public.credit_card_table SET is_fraud = true;
NOTICE:  Old credit_card_no was: 4532015112830366
NOTICE:  New credit_card_no is 4532015112830366
```

使用 pg\$1columnmask 的檢視觸發 （而非觸發）  
觸發條件只能在 PostgreSQL 的檢視上建立。它們用於在無法更新的檢視上執行 DML 陳述式。傳輸資料表一律會在內部遮罩，而非觸發 (IOT)，因為檢視和檢視查詢中使用的基底資料表可能會有不同的擁有者。在這種情況下，基礎資料表可能會有一些適用於檢視擁有者的遮罩政策，而且檢視擁有者必須在其觸發條件內查看基礎資料表的遮罩資料。這與資料表上的觸發不同，因為在這種情況下，觸發建立者和資料表內的資料是由同一使用者所擁有，而不是這裡的情況。  

```
-- Create a view over credit card table
CREATE OR REPLACE VIEW public.credit_card_view
    AS
    SELECT * FROM public.credit_card_table;

-- Truncate credit card table and insert fresh data
TRUNCATE TABLE public.credit_card_table;
INSERT INTO public.credit_card_table (name, credit_card_no, is_fraud)
    VALUES
    ('John Doe', '4532015112830366', false),
    ('Jane Smith', '5410000000000000', true),
    ('Brad Smith', '1234567891234567', true);

CREATE OR REPLACE FUNCTION public.print_changes()
    RETURNS TRIGGER AS
    $$
    BEGIN
        RAISE NOTICE 'Old row: name=%, credit card number=%, is fraud=%',
            OLD.name, OLD.credit_card_no, OLD.is_fraud;
    
        RAISE NOTICE 'New row: name=%, credit card number=%, is fraud=%',
            NEW.name, NEW.credit_card_no, NEW.is_fraud;
    
    RETURN NEW;
   END;
   $$ LANGUAGE plpgsql;

CREATE TRIGGER print_changes_trigger
    INSTEAD OF UPDATE ON public.credit_card_view
    FOR EACH ROW
    EXECUTE FUNCTION public.print_changes();

GRANT SELECT, UPDATE ON public.credit_card_view TO auditor;

-- [auditor]
-- Login as auditor role
BEGIN;

-- Any data coming out from the table will be masked in instead of triggers
-- according to masking policies applicable to current user
UPDATE public.credit_card_view
    SET name = CONCAT(name, '_new_name')
    RETURNING *;
NOTICE:  Old row: name=John Doe, credit card number=XXXXXXXXXXXXXXXX, is fraud=f
NOTICE:  New row: name=John Doe_new_name, credit card number=XXXXXXXXXXXXXXXX, is fraud=f
NOTICE:  Old row: name=Jane Smith, credit card number=XXXXXXXXXXXXXXXX, is fraud=f
NOTICE:  New row: name=Jane Smith_new_name, credit card number=XXXXXXXXXXXXXXXX, is fraud=f
NOTICE:  Old row: name=Brad Smith, credit card number=XXXXXXXXXXXXXXXX, is fraud=f
NOTICE:  New row: name=Brad Smith_new_name, credit card number=XXXXXXXXXXXXXXXX, is fraud=f
        name         |  credit_card_no  | is_fraud 
---------------------+------------------+----------
 John Doe_new_name   | XXXXXXXXXXXXXXXX | f
 Jane Smith_new_name | XXXXXXXXXXXXXXXX | f
 Brad Smith_new_name | XXXXXXXXXXXXXXXX | f
 
 -- Any new data going into the table using INSERT or UPDATE command will be unmasked
 UPDATE public.credit_card_view
    SET credit_card_no = '9876987698769876'
    RETURNING *;
NOTICE:  Old row: name=John Doe, credit card number=XXXXXXXXXXXXXXXX, is fraud=f
NOTICE:  New row: name=John Doe, credit card number=9876987698769876, is fraud=f
NOTICE:  Old row: name=Jane Smith, credit card number=XXXXXXXXXXXXXXXX, is fraud=f
NOTICE:  New row: name=Jane Smith, credit card number=9876987698769876, is fraud=f
NOTICE:  Old row: name=Brad Smith, credit card number=XXXXXXXXXXXXXXXX, is fraud=f
NOTICE:  New row: name=Brad Smith, credit card number=9876987698769876, is fraud=f
    name    |  credit_card_no  | is_fraud 
------------+------------------+----------
 John Doe   | 9876987698769876 | f
 Jane Smith | 9876987698769876 | f
 Brad Smith | 9876987698769876 | f
 
 COMMIT;
```

控制觸發行為的資料庫/使用者層級 GuCs   
兩個組態參數控制具有適用遮罩政策之使用者的觸發執行行為。當需要額外的安全限制時，請使用這些參數來防止觸發程序在遮罩的資料表或檢視上執行。預設會停用這兩個參數，允許觸發程序正常執行。  
**第一個 GUC：遮罩資料表的觸發條件限制**  
規格：  
+ 名稱：`pgcolumnmask.restrict_dml_triggers_for_masked_users`
+ 類型：`boolean`
+ 預設：`false`（允許執行觸發）
設為 TRUE 時，防止遮罩使用者在遮罩資料表上觸發執行。 `pg_columnmask`會執行錯誤。  
**第二個 GUC：對具有遮罩資料表的檢視觸發觸發限制**  
規格：  
+ 名稱：`pgcolumnmask.restrict_iot_triggers_for_masked_users`
+ 類型：`boolean`
+ 預設：`false`（允許執行觸發）
設為 TRUE 時，防止對遮罩使用者在其定義中包含遮罩資料表的檢視觸發執行。

這些參數可獨立運作，並可像標準資料庫組態參數一樣進行設定。

# Aurora PostgreSQL pg\$1columnmask 資料移動案例
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement"></a>

`pg_columnmask` 根據操作是發生在儲存體、邏輯或應用程式層，行為會因不同的資料移動操作而有所不同。儲存層級操作 （例如複製） 的行為與邏輯操作 （例如 `pg_dump`) 和應用程式層級操作 （例如 FDW 查詢） 不同。本節說明複寫、備份、匯出和遷移等常見案例的遮罩行為，並說明每個案例的安全影響。

**Topics**
+ [Aurora 全域資料庫和僅供讀取複本](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.RR)
+ [資料庫複製和快照還原](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.Clones)
+ [邏輯複寫](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.LogRep)
+ [藍/綠部署](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.BlueGreen)
+ [零 ETL 和 CDC 串流](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.ZETL)
+ [AWS Database Migration Service](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.DMS)
+ [資料匯出](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.DataExport)
+ [檢視和具體化檢視](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.Views)
+ [資料傾印和還原](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.DDR)
+ [外部資料包裝函式](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.FDQ)

## Aurora 全域資料庫和僅供讀取複本
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.RR"></a>

Aurora `pg_columnmask`政策存放在叢集磁碟區的資料庫系統資料表中。所有複本都會存取相同的政策，並傳回一致的遮罩結果。對於 Aurora Global Database 部署，`pg_columnmask`政策 AWS 區域 會與其他資料庫系統資料表一起複寫到次要 ，以確保跨區域的一致資料保護。在容錯移轉案例期間，所有`pg_columnmask`政策都保持不變且正常運作。

## 資料庫複製和快照還原
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.Clones"></a>

Aurora Fast Clone 和快照還原操作會保留所有`pg_columnmask`政策、角色和組態，做為資料庫系統資料表的一部分。複製或還原的資料庫會從來源叢集繼承所有現有的政策。複製或還原之後，每個資料庫叢集都會維護獨立的`pg_columnmask`政策。

## 邏輯複寫
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.LogRep"></a>

在初始同步期間，邏輯複寫會使用標準 SQL COPY 操作，並根據複寫使用者的許可強制執行`pg_columnmask`政策。在進行中的 CDC （變更資料擷取） 期間，不會套用遮罩政策，並透過 WAL 記錄複寫未遮罩的資料。具有 `pg_create_subscription`權限的使用者可以透過將複寫設定到他們控制的系統，潛在地洩漏未遮罩的資料。

## 藍/綠部署
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.BlueGreen"></a>

在快照還原期間，會自動包含`pg_columnmask`政策。綠色環境從藍色環境中所有政策的相同副本開始。從藍色複寫到綠色期間，不會遮罩資料。藍色叢集上的後續遮罩政策變更 (DDL 命令） 不會複寫到綠色叢集，並使 RDS 藍/綠部署失效。

## 零 ETL 和 CDC 串流
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.ZETL"></a>

資料複寫不受`pg_columnmask`政策影響。零 ETL 支援 DDL 複寫，但不複寫 `pg_columnmask`或 RLS 政策。不會將遮罩政策套用至 Zero-ETL 中的複寫資料。

## AWS Database Migration Service
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.DMS"></a>

初始資料同步會根據為 DMS 任務選取的使用者進行遮罩或取消遮罩。CDC 資料一律會取消遮罩。雖然`pg_columnmask`相關的內部 RLS 政策可能會遷移，但它們無法在啟用非 pg\$1columnmask 的目標上運作。

## 資料匯出
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.DataExport"></a>

`pg_columnmask` 將匯出視為任何其他查詢操作，會根據執行使用者的許可套用遮罩。這適用於 SQL 命令，例如 COPY、SELECT INTO、CREATE TABLE AS 和 Aurora PostgreSQL 的 S3 匯出功能。

**注意**  
當遮罩使用者匯出資料時，產生的檔案包含遮罩值，這些值可能會在還原時違反資料庫限制。

## 檢視和具體化檢視
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.Views"></a>

使用檢視時，請記住下列考量事項：
+ **一般檢視** – `INVOKER` 一律使用語意。無論誰建立檢視，目前使用者的遮罩政策都會在查詢檢視時套用。
+ **具體化視**觀表 – 重新整理時，套用具體化視觀表擁有者的遮罩政策，而非執行重新整理的使用者政策。如果擁有者有遮罩政策，具體化視觀表一律包含遮罩資料。

## 資料傾印和還原
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.DDR"></a>

`pg_dump` 以一般資料庫使用者身分運作，並根據連線使用者的許可套用遮罩政策。如果遮罩的使用者執行傾印，備份檔案會包含遮罩的資料。 `pg_columnmask` 政策會包含在傾印中，做為資料庫結構描述的一部分。成功還原需要目標資料庫中存在所有參考的角色，且目標已安裝`pg_columnmask`延伸模組。

**注意**  
從 PostgreSQL 18 開始， `pg_dump`支援從資料庫傾印中排除資料列層級安全性 (RLS) 和`pg_columnmask`遮罩政策`—no-policies`的選項。如需詳細資訊，請參閱 [pg\$1dump](https://www.postgresql.org/docs/current/app-pgdump.html)。

## 外部資料包裝函式
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.FDQ"></a>

使用外部資料包裝函式時，遠端資料表上的遮罩政策會根據映射的使用者在來源伺服器上的許可套用，而不是本機查詢使用者的許可，而且雖然您可以透過 FDW 存取遮罩的遠端資料，但您無法直接在本機資料庫中的外部資料表上建立 DDM 或 RLS 政策。