

# PostgreSQL에 대한 Amazon Aurora 위임 확장 지원 사용
<a name="Aurora_delegated_ext"></a>

PostgreSQL에 대한 Amazon Aurora 위임 확장 지원을 사용하면 `rds_superuser` 역할이 아닌 사용자에게도 확장 관리를 위임할 수 있습니다. 이 위임 확장 지원을 통해 `rds_extension`이라는 새 역할이 생성되며, 이 역할이 할당되어야 해당 사용자가 다른 확장을 관리할 수 있습니다. 이 역할은 확장을 생성하고, 업데이트하고, 삭제할 수 있습니다.

Aurora PostgreSQL DB 인스턴스에 설치할 수 있는 확장을 `rds.allowed_extensions` 파라미터에 등록하여 지정할 수 있습니다. 자세한 내용은 [Amazon RDS for PostgreSQL로 PostgreSQL 확장 사용](https://docs.aws.amazon.com//AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.Extensions.html)을 참조하세요.

`rds.allowed_delegated_extensions` 파라미터를 사용하여 `rds_extension` 역할이 있는 사용자가 관리할 수 있는 가용 확장 목록을 제한할 수 있습니다.

위임 확장 지원은 다음 버전에서 사용할 수 있습니다.
+ 모든 상위 버전
+ 15.5 이상의 15 버전
+ 14.10 이상의 14 버전
+ 13.13 이상의 13 버전
+ 12.17 이상의 12 버전

**Topics**
+ [사용자에게 위임 확장 지원 활성화](#AuroraPostgreSQL.delegated_ext_mgmt)
+ [Aurora 위임 확장 지원에서 PostgreSQL에 대해 사용되는 구성](#AuroraPostgreSQL.delegated_ext_config)
+ [위임 확장에 대한 지원 비활성화](#AuroraPostgreSQL.delegated_ext_disable)
+ [Amazon Aurora 위임 확장 지원 사용의 이점](#AuroraPostgreSQL.delegated_ext_benefits)
+ [PostgreSQL에 대한 Aurora 위임 확장 지원 제한](#AuroraPostgreSQL.delegated_ext_limit)
+ [특정 확장에 필요한 권한](#AuroraPostgreSQL.delegated_ext_perm)
+ [보안 고려 사항](#AuroraPostgreSQL.delegated_ext_sec)
+ [확장 삭제 캐스케이드 비활성화](#AuroraPostgreSQL.delegated_ext_drop)
+ [위임 확장 지원을 사용하여 추가할 수 있는 확장의 예](#AuroraPostgreSQL.delegated_ext_support)

## 사용자에게 위임 확장 지원 활성화
<a name="AuroraPostgreSQL.delegated_ext_mgmt"></a>

사용자에게 위임 확장 지원을 활성화하려면 다음을 수행해야 합니다.

1. **사용자에게 `rds_extension` 역할 부여** - `rds_superuser` 권한으로 데이터베이스에 연결하고 다음 명령을 실행합니다.

   ```
   Postgres => grant rds_extension to user_name;
   ```

1. **위임된 사용자가 관리할 수 있는 확장 목록 설정** - `rds.allowed_delegated_extensions`를 통해 DB 클러스터 파라미터에서 `rds.allowed_extensions`를 사용하여 가용 확장의 하위 집합을 지정할 수 있습니다. 다음 수준 중 하나에서 이 작업을 수행할 수 있습니다.
   + 클러스터 또는 인스턴스 파라미터 그룹에서 AWS Management Console 또는 API를 통해 가능합니다. 자세한 내용은 [Amazon Aurora의 파라미터 그룹](USER_WorkingWithParamGroups.md) 섹션을 참조하세요.
   + 데이터베이스 수준에서 다음 명령을 사용하세요.

     ```
     alter database database_name set rds.allowed_delegated_extensions = 'extension_name_1,
                         extension_name_2,...extension_name_n';
     ```
   + 사용자 수준에서 다음 명령을 사용하세요.

     ```
     alter user user_name set rds.allowed_delegated_extensions = 'extension_name_1,
                         extension_name_2,...extension_name_n';
     ```
**참고**  
`rds.allowed_delegated_extensions` 동적 파라미터를 변경한 후에는 데이터베이스를 다시 시작할 필요가 없습니다.

1. **확장 생성 프로세스 중에 생성된 객체에 대한 위임된 사용자 액세스 허용** - 특정 확장에서는 추가 권한을 부여해야 `rds_extension` 역할을 가진 사용자가 해당 개체에 액세스할 수 있는 개체를 만들 수 있습니다. `rds_superuser`는 위임된 사용자에게 해당 객체에 대한 액세스 권한을 부여해야 합니다. 이벤트 트리거를 사용하여 위임된 사용자에게 권한을 자동으로 부여하는 것도 한 가지 방법입니다.

   **이벤트 트리거 예제**

   확장 생성 시 만들어진 객체에 대한 권한 설정이 필요한 확장을 `rds_extension` 권한이 있는 위임된 사용자가 사용할 수 있도록 하려면, 아래 이벤트 트리거 예제를 사용자 지정하고 위임된 사용자가 전체 기능에 액세스할 수 있도록 하려는 확장만 추가하면 됩니다. 이 이벤트 트리거는 template1(기본 템플릿)에서 만들 수 있으므로, template1에서 만든 모든 데이터베이스에는 해당 이벤트 트리거가 있습니다. 위임된 사용자가 확장을 설치하면 이 트리거는 확장에서 생성된 객체에 대한 소유권을 자동으로 부여합니다.

   ```
   CREATE OR REPLACE FUNCTION create_ext()
   
     RETURNS event_trigger AS $$
   
   DECLARE
   
     schemaname TEXT;
     databaseowner TEXT;
   
     r RECORD;
   
   BEGIN
   
     IF tg_tag = 'CREATE EXTENSION' and current_user != 'rds_superuser' THEN
       RAISE NOTICE 'SECURITY INVOKER';
       RAISE NOTICE 'user: %', current_user;
       FOR r IN SELECT * FROM pg_catalog.pg_event_trigger_ddl_commands()
       LOOP
           CONTINUE WHEN r.command_tag != 'CREATE EXTENSION' OR r.object_type != 'extension';
   
           schemaname = (
               SELECT n.nspname
               FROM pg_catalog.pg_extension AS e
               INNER JOIN pg_catalog.pg_namespace AS n
               ON e.extnamespace = n.oid
               WHERE e.oid = r.objid
           );
   
           databaseowner = (
               SELECT pg_catalog.pg_get_userbyid(d.datdba)
               FROM pg_catalog.pg_database d
               WHERE d.datname = current_database()
           );
           RAISE NOTICE 'Record for event trigger %, objid: %,tag: %, current_user: %, schema: %, database_owenr: %', r.object_identity, r.objid, tg_tag, current_user, schemaname, databaseowner;
           IF r.object_identity = 'address_standardizer_data_us' THEN
               EXECUTE pg_catalog.format('GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE %I.us_gaz TO %I WITH GRANT OPTION;', schemaname, databaseowner);
               EXECUTE pg_catalog.format('GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE %I.us_lex TO %I WITH GRANT OPTION;', schemaname, databaseowner);
               EXECUTE pg_catalog.format('GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE %I.us_rules TO %I WITH GRANT OPTION;', schemaname, databaseowner);
           ELSIF r.object_identity = 'dict_int' THEN
               EXECUTE pg_catalog.format('ALTER TEXT SEARCH DICTIONARY %I.intdict OWNER TO %I;', schemaname, databaseowner);
           ELSIF r.object_identity = 'pg_partman' THEN
               EXECUTE pg_catalog.format('GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE %I.part_config TO %I WITH GRANT OPTION;', schemaname, databaseowner);
               EXECUTE pg_catalog.format('GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE %I.part_config_sub TO %I WITH GRANT OPTION;', schemaname, databaseowner);
               EXECUTE pg_catalog.format('GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE %I.custom_time_partitions TO %I WITH GRANT OPTION;', schemaname, databaseowner);
           ELSIF r.object_identity = 'postgis_topology' THEN
               EXECUTE pg_catalog.format('GRANT SELECT, UPDATE, INSERT, DELETE ON ALL TABLES IN SCHEMA topology TO %I WITH GRANT OPTION;', databaseowner);
               EXECUTE pg_catalog.format('GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA topology TO %I WITH GRANT OPTION;', databaseowner);
               EXECUTE pg_catalog.format('GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA topology TO %I WITH GRANT OPTION;', databaseowner);
               EXECUTE pg_catalog.format('GRANT USAGE ON SCHEMA topology TO %I WITH GRANT OPTION;', databaseowner);
           END IF;
       END LOOP;
     END IF;
   END;
   $$ LANGUAGE plpgsql SECURITY DEFINER;
   
   CREATE EVENT TRIGGER log_create_ext ON ddl_command_end EXECUTE PROCEDURE create_ext();
   ```

## Aurora 위임 확장 지원에서 PostgreSQL에 대해 사용되는 구성
<a name="AuroraPostgreSQL.delegated_ext_config"></a>


| 구성 이름 | 설명 | 기본값 | 참고 | 권한을 수정하거나 부여할 수 있는 사람 | 
| --- | --- | --- | --- | --- | 
| `rds.allowed_delegated_extensions` | 이 파라미터는 rds\$1extension 역할이 데이터베이스에서 관리할 수 있는 확장을 제한합니다. rds.allowed\$1extensions의 하위 집합이어야 합니다. | 빈 문자열 | [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/AmazonRDS/latest/AuroraUserGuide/Aurora_delegated_ext.html) 이 파라미터 설정에 대한 자세한 내용은 [사용자에게 위임 확장 지원 활성화](#AuroraPostgreSQL.delegated_ext_mgmt) 섹션을 참조하세요. | rds\$1superuser | 
| `rds.allowed_extensions` | 이 파라미터를 사용하면 고객이 Aurora PostgreSQL DB 인스턴스에 설치할 수 있는 확장을 제한할 수 있습니다. 자세한 내용은 [PostgreSQL 확장 설치 제한](https://docs.aws.amazon.com//AmazonRDS/latest/UserGuide/CHAP_PostgreSQL.html#PostgreSQL.Concepts.General.FeatureSupport.Extensions.Restriction)을 참조하세요. | "\$1" | 기본적으로 이 파라미터는 ‘\$1’로 설정되어 있습니다. 즉, RDS for PostgreSQL과 Aurora PostgreSQL에서 지원되는 모든 확장은 필요한 권한이 있는 사용자가 만들 수 있습니다. 이 값이 비어 있으면 Aurora PostgreSQL DB 인스턴스에 확장을 설치할 수 없습니다. | 관리자 | 
| `rds-delegated_extension_allow_drop_cascade` | 이 파라미터는 `rds_extension` 권한이 있는 사용자가 캐스케이드 옵션을 사용하여 확장을 삭제할 수 있는 기능을 제어합니다. | 끄기 | 기본적으로 `rds-delegated_extension_allow_drop_cascade`는 `off`로 설정됩니다. 즉, `rds_extension` 사용자는 캐스케이드 옵션을 사용하여 확장 프로그램을 삭제할 수 없습니다. 이 기능을 부여하려면 `rds.delegated_extension_allow_drop_cascade` 파라미터를 `on`으로 설정해야 합니다. | rds\$1superuser | 

## 위임 확장에 대한 지원 비활성화
<a name="AuroraPostgreSQL.delegated_ext_disable"></a>

**부분적으로 비활성화**  
위임된 사용자는 새 확장을 만들 수는 없지만 기존 확장을 계속 업데이트할 수는 있습니다.
+ DB 클러스터 파라미터 그룹에서 `rds.allowed_delegated_extensions`를 기본값으로 재설정합니다.
+ 데이터베이스 수준에서 다음 명령을 사용하세요.

  ```
  alter database database_name reset rds.allowed_delegated_extensions;
  ```
+ 사용자 수준에서 다음 명령을 사용하세요.

  ```
  alter user user_name reset rds.allowed_delegated_extensions;
  ```

**전체적으로 비활성화**  
사용자로부터 `rds_extension` 역할을 취소하면 사용자는 표준 권한으로 되돌아갑니다. 해당 사용자는 더 이상 확장을 생성, 업데이트 또는 삭제할 수 없습니다.

```
postgres => revoke rds_extension from user_name;
```

## Amazon Aurora 위임 확장 지원 사용의 이점
<a name="AuroraPostgreSQL.delegated_ext_benefits"></a>

PostgreSQL에 대한 Amazon Aurora 위임 확장 지원을 사용하면 `rds_superuser` 역할이 아닌 사용자에게도 확장 관리를 안전하게 위임할 수 있습니다. 이 기능에는 다음과 같은 이점이 있습니다.
+ 원하는 사용자에게 확장 관리를 쉽게 위임할 수 있습니다.
+ 이 작업에는 `rds_superuser` 역할이 필요하지 않습니다.
+ 동일한 DB 클러스터의 여러 데이터베이스에 대해 서로 다른 확장 세트를 지원하는 기능을 제공합니다.

## PostgreSQL에 대한 Aurora 위임 확장 지원 제한
<a name="AuroraPostgreSQL.delegated_ext_limit"></a>
+ 확장 생성 프로세스 중에 생성되는 객체에서 확장이 제대로 작동하려면 추가 권한이 필요할 수 있습니다.

## 특정 확장에 필요한 권한
<a name="AuroraPostgreSQL.delegated_ext_perm"></a>

다음과 같은 확장을 생성, 사용 또는 업데이트하려면 위임된 사용자에게 다음과 같은 함수, 테이블 및 스키마에 대해 필요한 권한이 있어야 합니다.


| 소유권이나 권한이 필요한 확장 | 함수 | 테이블 | 스키마 | 텍스트 검색 사전 | 설명 | 
| --- | --- | --- | --- | --- | --- | 
| address\$1standardizer\$1data\$1us |  | us\$1gaz, us\$1lex, us\$1lex, I.us\$1rules |   |  |  | 
| amcheck | bt\$1index\$1check, bt\$1index\$1parent\$1check |  |   |  |  | 
| dict\$1int |  |  |  | intdict |  | 
| pg\$1partman |  | custom\$1time\$1partitions, part\$1config, part\$1config\$1sub |  |  |  | 
| pg\$1stat\$1statements |  |  |  |  |  | 
| PostGIS | st\$1tileenvelope | spatial\$1ref\$1sys |  |  |  | 
| postgis\$1raster |  |  |  |  |  | 
| postgis\$1topology |  | topology, layer | topology |  | 위임된 사용자는 데이터베이스 소유자여야 함 | 
| log\$1fdw | create\$1foreign\$1table\$1for\$1log\$1file |  |  |  |  | 
| rds\$1tools | role\$1password\$1encryption\$1type |  |  |  |  | 
| postgis\$1tiger\$1geocoder |  | geocode\$1settings\$1default, geocode\$1settings | tiger |  |  | 
| pg\$1freespacemap | pg\$1freespace |  |  |  |  | 
| pg\$1visibility | pg\$1visibility |  |  |  |  | 

## 보안 고려 사항
<a name="AuroraPostgreSQL.delegated_ext_sec"></a>

 `rds_extension` 역할이 있는 사용자는 접속 권한이 있는 모든 데이터베이스의 확장을 관리할 수 있다는 점을 기억하세요. 위임된 사용자가 단일 데이터베이스의 확장을 관리하도록 하려는 경우, 각 데이터베이스의 모든 공개 권한을 취소한 다음 해당 특정 데이터베이스의 연결 권한을 위임 사용자에게 명시적으로 부여하는 것이 좋습니다.

 사용자가 여러 데이터베이스의 정보에 액세스할 수 있도록 하는 확장에는 여러 가지가 있습니다. 이러한 확장을 `rds.allowed_delegated_extensions`에 추가하기 전에 `rds_extension` 권한을 부여한 사용자가 데이터베이스 간 기능을 사용할 수 있는지 확인하세요. 예를 들어, `postgres_fdw` 및 `dblink`는 동일한 인스턴스 또는 원격 인스턴스의 여러 데이터베이스를 쿼리할 수 있는 기능을 제공합니다. `log_fdw`는 인스턴스의 모든 데이터베이스에 대한 postgres 엔진 로그 파일을 읽습니다. 이 로그 파일에는 여러 데이터베이스의 느린 쿼리나 오류 메시지가 포함될 수 있습니다. `pg_cron`은 예약된 백그라운드 작업을 DB 인스턴스에서 실행할 수 있도록 하고 작업이 다른 데이터베이스에서 실행되도록 구성할 수 있습니다.

## 확장 삭제 캐스케이드 비활성화
<a name="AuroraPostgreSQL.delegated_ext_drop"></a>

 `rds_extension` 역할의 사용자가 캐스케이드 옵션을 사용하여 확장을 삭제하는 기능은 `rds.delegated_extension_allow_drop_cascade` 파라미터에 의해 제어됩니다. 기본적으로 `rds-delegated_extension_allow_drop_cascade`는 `off`로 설정됩니다. 즉, `rds_extension` 역할의 사용자는 아래 쿼리에 나와 있는 캐스케이드 옵션으로 확장을 삭제할 수 없습니다.

```
DROP EXTENSION CASCADE;
```

이렇게 하면 확장에 종속된 객체와 해당 객체에 종속된 모든 객체가 자동으로 삭제되기 때문입니다. 캐스케이드 옵션을 사용하려고 시도하면 오류가 발생합니다.

 이 기능을 부여하려면 `rds.delegated_extension_allow_drop_cascade` 파라미터를 `on`으로 설정해야 합니다.

 `rds.delegated_extension_allow_drop_cascade` 동적 파라미터를 변경하기 위해 데이터베이스를 다시 시작할 필요가 없습니다. 다음 수준 중 하나에서 이 작업을 수행할 수 있습니다.
+ 클러스터 또는 인스턴스 파라미터 그룹에서 AWS Management Console 또는 API를 통해 가능합니다.
+ 데이터베이스 수준에서 다음 명령을 사용하세요.

  ```
  alter database database_name set rds.delegated_extension_allow_drop_cascade = 'on';
  ```
+ 사용자 수준에서 다음 명령을 사용하세요.

  ```
  alter role tenant_user set rds.delegated_extension_allow_drop_cascade = 'on';
  ```

## 위임 확장 지원을 사용하여 추가할 수 있는 확장의 예
<a name="AuroraPostgreSQL.delegated_ext_support"></a>
+ `rds_tools`

  ```
  extension_test_db=> create extension rds_tools;
  CREATE EXTENSION
  extension_test_db=> SELECT * from rds_tools.role_password_encryption_type() where rolname = 'pg_read_server_files';
  ERROR: permission denied for function role_password_encryption_type
  ```
+ `amcheck`

  ```
  extension_test_db=> CREATE TABLE amcheck_test (id int);
  CREATE TABLE
  extension_test_db=> INSERT INTO amcheck_test VALUES (generate_series(1,100000));
  INSERT 0 100000
  extension_test_db=> CREATE INDEX amcheck_test_btree_idx ON amcheck_test USING btree (id);
  CREATE INDEX
  extension_test_db=> create extension amcheck;
  CREATE EXTENSION
  extension_test_db=> SELECT bt_index_check('amcheck_test_btree_idx'::regclass);
  ERROR: permission denied for function bt_index_check
  extension_test_db=> SELECT bt_index_parent_check('amcheck_test_btree_idx'::regclass);
  ERROR: permission denied for function bt_index_parent_check
  ```
+ `pg_freespacemap`

  ```
  extension_test_db=> create extension pg_freespacemap;
  CREATE EXTENSION
  extension_test_db=> SELECT * FROM pg_freespace('pg_authid');
  ERROR: permission denied for function pg_freespace
  extension_test_db=> SELECT * FROM pg_freespace('pg_authid',0);
  ERROR: permission denied for function pg_freespace
  ```
+ `pg_visibility`

  ```
  extension_test_db=> create extension pg_visibility;
  CREATE EXTENSION
  extension_test_db=> select * from pg_visibility('pg_database'::regclass);
  ERROR: permission denied for function pg_visibility
  ```
+ `postgres_fdw`

  ```
  extension_test_db=> create extension postgres_fdw;
  CREATE EXTENSION
  extension_test_db=> create server myserver foreign data wrapper postgres_fdw options (host 'foo', dbname 'foodb', port '5432');
  ERROR: permission denied for foreign-data wrapper postgres_fdw
  ```