

 Amazon Redshift는 패치 198부터 새 Python UDF 생성을 더 이상 지원하지 않습니다. 기존 Python UDF는 2026년 6월 30일까지 계속 작동합니다. 자세한 내용은 [블로그 게시물](https://aws.amazon.com/blogs/big-data/amazon-redshift-python-user-defined-functions-will-reach-end-of-support-after-june-30-2026/)을 참조하세요.

# 동적 데이터 마스킹
<a name="t_ddm"></a>

**참고**  
Amazon Redshift는 민감한 메타데이터의 노출을 방지하기 위해 Data Catalog 뷰에 대한 쿼리 정보를 로깅할 때 특정 시스템 테이블 열을 자동으로 마스킹합니다. 자세한 내용은 *Amazon Redshift 관리 안내서*의 [보안 로깅](https://docs.aws.amazon.com/redshift/latest/mgmt/db-auditing-secure-logging.html)을 참조하세요.

Amazon Redshift에서 동적 데이터 마스킹(DDM)을 사용하면 데이터 웨어하우스의 민감한 데이터를 보호할 수 있습니다. Amazon Redshift가 데이터베이스에서 데이터를 변환하지 않고 쿼리 시 민감한 데이터를 사용자에게 표시하는 방식을 조작할 수 있습니다. 지정된 사용자 또는 역할에 사용자 지정 난독화 규칙을 적용하는 마스킹 정책을 통해 데이터에 대한 액세스를 제어합니다. 이렇게 하면 기본 데이터를 변경하거나 SQL 쿼리를 편집하지 않고도 변화하는 개인 정보 보호 요구 사항에 대응할 수 있습니다.

동적 데이터 마스킹 정책은 지정된 형식과 일치하는 데이터를 숨기거나 난독화하거나 익명화합니다. 테이블에 첨부하면 마스킹 표현식이 하나 이상의 해당 열에 적용됩니다. 마스킹 정책을 추가로 수정하여 특정 사용자 또는 [역할 기반 액세스 제어(RBAC)](t_Roles.md)로 생성할 수 있는 사용자 정의 역할에만 적용할 수 있습니다. 또한 마스킹 정책을 생성할 때 조건부 열을 사용하여 셀 수준에서 DDM을 적용할 수 있습니다. 조건부 마스킹에 대한 자세한 설명은 [조건부 동적 데이터 마스킹](t_ddm-conditional.md) 섹션을 참조하세요.

난독화 수준이 다른 여러 마스킹 정책을 테이블의 동일한 열에 적용하고 다른 역할에 할당할 수 있습니다. 하나의 열에 다른 정책을 적용하는 다른 역할이 있는 경우 충돌을 방지하기 위해 각 응용 프로그램에 대한 우선 순위를 설정할 수 있습니다. 이러한 방식으로 지정된 사용자 또는 역할이 액세스할 수 있는 데이터를 제어할 수 있습니다. DDM 정책은 데이터를 부분적으로 또는 완전히 수정하거나 SQL, Python 또는 AWS Lambda로 작성된 사용자 정의 함수를 사용하여 데이터를 해시할 수 있습니다. 해시를 사용하여 데이터를 마스킹하면 잠재적으로 민감한 정보에 액세스하지 않고도 이 데이터에 조인을 적용할 수 있습니다.

# 동적 데이터 마스킹 정책 관리용 SQL 명령
<a name="r_ddm-procedures"></a>

다음 작업을 수행하여 동적 데이터 마스킹 정책을 생성, 연결, 분리 및 삭제할 수 있습니다.
+ DDM 정책을 만들려면 [마스킹 정책 생성](r_CREATE_MASKING_POLICY.md) 명령을 사용합니다.

  다음은 SHA-2 해시함수를 이용하여 마스킹 정책을 생성한 예이다.

  ```
  CREATE MASKING POLICY hash_credit 
  WITH (credit_card varchar(256)) 
  USING (sha2(credit_card + 'testSalt', 256));
  ```
+ 기존 DDM 정책을 변경하려면 [마스킹 정책 변경](r_ALTER_MASKING_POLICY.md) 명령을 사용합니다.

  다음은 기존 마스킹 정책을 변경하는 예제입니다.

  ```
  ALTER MASKING POLICY hash_credit
  USING (sha2(credit_card + 'otherTestSalt', 256));
  ```
+ 테이블에 대한 DDM 정책을 하나 이상의 사용자 또는 역할에 연결하려면 [마스킹 정책 연결](r_ATTACH_MASKING_POLICY.md) 명령을 사용합니다.

  다음은 마스킹 정책을 열/역할 쌍에 연결하는 예제입니다.

  ```
   ATTACH MASKING POLICY hash_credit 
  ON credit_cards (credit_card) 
  TO ROLE science_role 
  PRIORITY 30;
  ```

  PRIORITY 절은 여러 정책이 동일한 열에 첨부될 때 사용자 세션에 적용되는 마스킹 정책을 결정합니다. 예를 들어 앞의 예에서 사용자가 동일한 신용 카드 열에 우선 순위가 20인 다른 마스킹 정책을 연결한 경우 science\$1role의 정책이 우선 순위가 30보다 높으므로 적용됩니다.
+ 하나 이상의 사용자 또는 역할에서 테이블의 DDM 정책을 분리하려면 DETACH [마스킹 정책 분리](r_DETACH_MASKING_POLICY.md) 명령을 사용합니다.

  다음은 마스킹 정책을 열/역할 쌍에서 분리하는 예제입니다.

  ```
  DETACH MASKING POLICY hash_credit 
  ON credit_cards(credit_card) 
  FROM ROLE science_role;
  ```
+ 모든 데이터베이스에서 DDM 정책을 삭제하려면 [마스킹 정책 삭제](r_DROP_MASKING_POLICY.md) 명령을 사용하세요.

  다음은 모든 데이터베이스에서 마스킹 정책을 삭제하는 예제입니다.

  ```
  DROP MASKING POLICY hash_credit;  
  ```

# 동적 데이터 마스킹 정책 계층 구조
<a name="t_ddm-hierarchy"></a>

마스킹 정책을 여러 개 연결할 때는 다음 사항을 고려하세요.
+ 여러 마스킹 정책을 단일 열에 연결할 수 있습니다.
+ 쿼리에 여러 마스킹 정책을 적용할 경우 각 열에 첨부된 가장 높은 우선 순위의 정책이 적용됩니다. 다음 예제를 살펴보세요.

  ```
  ATTACH MASKING POLICY partial_hash
  ON credit_cards(address, credit_card)
  TO ROLE analytics_role 
  PRIORITY 20;
  
  ATTACH MASKING POLICY full_hash
  ON credit_cards(credit_card, ssn)
  TO ROLE auditor_role 
  PRIORITY 30;
  
  SELECT address, credit_card, ssn
  FROM credit_cards;
  ```

  SELECT 문을 실행할 때 분석 및 감사자 역할을 모두 가진 사용자는 `partial_hash` 마스킹 정책이 적용된 주소 열을 보게 됩니다. 신용카드 열에서 `full_hash` 정책의 우선순위가 더 높기 때문에 `full_hash` 마스킹 정책이 적용된 신용카드 및 SSN 열이 표시됩니다.
+  마스킹 정책을 연결할 때 우선 순위를 지정하지 않으면 기본 우선 순위는 0입니다.
+ 우선 순위가 동일한 동일한 열에 두 개의 정책을 연결할 수 없습니다.
+ 사용자와 열 또는 역할과 열의 동일한 조합에 두 개의 정책을 연결할 수 없습니다.
+ 동일한 사용자 또는 역할에 연결된 상태에서 동일한 SUPER 경로를 따라 여러 마스킹 정책을 적용할 경우 우선순위가 가장 높은 첨부 파일만 적용됩니다. 다음 예제를 살펴보세요.

  첫 번째 예는 동일한 경로에 연결된 두 개의 마스킹 정책을 보여 주며 우선순위가 더 높은 정책이 적용됩니다.

  ```
  ATTACH MASKING POLICY hide_name
  ON employees(col_person.name)
  TO PUBLIC
  PRIORITY 20;
  
  ATTACH MASKING POLICY hide_last_name
  ON employees(col_person.name.last)
  TO PUBLIC
  PRIORITY 30;
  
  --Only the hide_last_name policy takes effect.
  SELECT employees.col_person.name FROM employees;
  ```

  두 번째 예에서는 정책 간 충돌 없이 동일한 SUPER 객체의 서로 다른 경로에 연결된 두 마스킹 정책을 보여줍니다. 두 첨부 파일이 동시에 적용됩니다.

  ```
  ATTACH MASKING POLICY hide_first_name
  ON employees(col_person.name.first)
  TO PUBLIC
  PRIORITY 20;
  
  ATTACH MASKING POLICY hide_last_name
  ON employees(col_person.name.last)
  TO PUBLIC
  PRIORITY 20;
  
  --Both col_person.name.first and col_person.name.last are masked.
  SELECT employees.col_person.name FROM employees;
  ```

주어진 사용자와 열 또는 역할과 열 조합에 적용되는 마스킹 정책을 확인하기 위해 [https://docs.aws.amazon.com/redshift/latest/dg/r_roles-default.html](https://docs.aws.amazon.com/redshift/latest/dg/r_roles-default.html) 역할이 있는 사용자는 [SVV\$1ATTACHED\$1MASKING\$1POLICY](r_SVV_ATTACHED_MASKING_POLICY.md) 시스템 뷰에서 열/역할 또는 열/사용자 쌍을 조회할 수 있습니다. 자세한 내용은 [동적 데이터 마스킹 시스템 뷰](r_ddm-svv.md) 섹션을 참조하세요.

# SUPER 데이터 유형 경로와 함께 동적 데이터 마스킹 사용
<a name="t_ddm-super"></a>

 Amazon Redshift는 동적 데이터 마스킹 정책을 SUPER 유형 열의 경로에 연결하는 것을 지원합니다. SUPER 데이터 형식에 대한 자세한 내용은 [Amazon Redshift의 반정형 데이터](super-overview.md) 섹션을 참조하세요.

SUPER 유형 열의 경로에 마스킹 정책을 연결할 때는 다음 사항을 고려하세요.
+ 마스킹 정책을 열의 경로에 연결하는 경우 해당 열을 SUPER 데이터 유형으로 정의해야 합니다. SUPER 경로의 **스칼라 값에만 마스킹 정책을 적용할 수 있습니다. 복잡한 구조나 배열에는 마스킹 정책을 적용할 수 없습니다.
+ SUPER 경로가 충돌하지 않는 한 단일 SUPER 열의 여러 스칼라 값에 서로 다른 마스킹 정책을 적용할 수 있습니다. 예를 들어 SUPER 경로 `a.b` 및 `a.b.c`는 `a.b`가 `a.b.c`의 상위 구조로 동일한 경로에 있기 때문에 충돌이 발생합니다. SUPER 경로 `a.b.c` 및 `a.b.d`는 충돌하지 않습니다.
+ Amazon Redshift는 사용자 쿼리 런타임 시 정책이 적용되기 전까지는 마스킹 정책이 연결된 경로가 데이터에 있고 예상 유형인지 확인할 수 없습니다. 예를 들어, INT 값이 포함된 SUPER 경로에 TEXT 값을 마스킹하는 마스킹 정책을 연결하면 Amazon Redshift는 해당 경로에 있는 값의 유형을 캐스팅하려고 시도합니다.

  이러한 상황에서 런타임 시 Amazon Redshift의 동작은 SUPER 객체를 쿼리하기 위한 구성 설정에 따라 달라집니다. 기본적으로 Amazon Redshift는 lax 모드이며 지정된 SUPER 경로에서 누락된 경로와 잘못된 캐스트를 `NULL`로 해석합니다. SUPER와 관련한 구성 설정에 대한 자세한 내용은 [SUPER 구성](super-configurations.md) 섹션을 참조하세요.
+ SUPER는 스키마가 없는 유형입니다. 즉, Amazon Redshift는 지정된 SUPER 경로에서 값의 존재를 확인할 수 없습니다. 존재하지 않는 SUPER 경로에 마스킹 정책을 연결하고 Amazon Redshift가 lax 모드인 경우 Amazon Redshift는 경로를 `NULL` 값으로 해석합니다. SUPER 열 경로에 마스킹 정책을 연결할 때는 SUPER 객체의 예상 형식과 이러한 객체에 예상치 못한 속성이 있을 가능성을 고려하는 것이 좋습니다. SUPER 열에 예상치 못한 스키마가 있다고 생각되면 마스킹 정책을 SUPER 열에 직접 연결하는 것을 고려해 보세요. SUPER 유형 정보 함수를 사용하여 속성 및 유형을 확인하고 값을 마스킹하는 데 `OBJECT_TRANSFORM`을 사용할 수 있습니다. SUPER 유형 정보 함수에 대한 자세한 내용은 [SUPER 형식 정보 함수](c_Type_Info_Functions.md) 섹션을 참조하세요.

## 예제
<a name="t_ddm-super-examples"></a>

**SUPER 경로에 마스킹 정책 연결**  
다음 예에서는 여러 마스킹 정책을 한 열의 여러 SUPER 유형 경로에 연결합니다.

```
CREATE TABLE employees (
    col_person SUPER
);

INSERT INTO employees
VALUES
    (
        json_parse('
            {
                "name": {
                    "first": "John",
                    "last": "Doe"
                },
                "age": 25,
                "ssn": "111-22-3333",
                "company": "Company Inc."
            }
        ')
    ),
    (
        json_parse('
            {
                "name": {
                    "first": "Jane",
                    "last": "Appleseed"
                },
                "age": 34,
                "ssn": "444-55-7777",
                "company": "Organization Org."
            }
        ')
    )
;
GRANT ALL ON ALL TABLES IN SCHEMA "public" TO PUBLIC;

-- Create the masking policies.

-- This policy converts the given name to all uppercase letters.
CREATE MASKING POLICY mask_first_name
WITH(first_name TEXT)
USING ( UPPER(first_name) );

-- This policy replaces the given name with the fixed string 'XXXX'.
CREATE MASKING POLICY mask_last_name
WITH(last_name TEXT)
USING ( 'XXXX'::TEXT );

-- This policy rounds down the given age to the nearest 10.
CREATE MASKING POLICY mask_age
WITH(age INT)
USING ( (FLOOR(age::FLOAT / 10) * 10)::INT );

-- This policy converts the first five digits of the given SSN to 'XXX-XX'.
CREATE MASKING POLICY mask_ssn
WITH(ssn TEXT)
USING ( 'XXX-XX-'::TEXT || SUBSTRING(ssn::TEXT FROM 8 FOR 4) );

-- Attach the masking policies to the employees table.
ATTACH MASKING POLICY mask_first_name
ON employees(col_person.name.first)
TO PUBLIC;

ATTACH MASKING POLICY mask_last_name
ON employees(col_person.name.last)
TO PUBLIC;

ATTACH MASKING POLICY mask_age
ON employees(col_person.age)
TO PUBLIC;

ATTACH MASKING POLICY mask_ssn
ON employees(col_person.ssn)
TO PUBLIC;

-- Verify that your masking policies are attached.
SELECT
    policy_name,
    TABLE_NAME,
    priority,
    input_columns,
    output_columns
FROM
    svv_attached_masking_policy;

   policy_name   | table_name | priority |           input_columns           |          output_columns
-----------------+------------+----------+-----------------------------------+-----------------------------------
 mask_age        | employees  |        0 | ["col_person.\"age\""]            | ["col_person.\"age\""]
 mask_first_name | employees  |        0 | ["col_person.\"name\".\"first\""] | ["col_person.\"name\".\"first\""]
 mask_last_name  | employees  |        0 | ["col_person.\"name\".\"last\""]  | ["col_person.\"name\".\"last\""]
 mask_ssn        | employees  |        0 | ["col_person.\"ssn\""]            | ["col_person.\"ssn\""]
(4 rows)

-- Observe the masking policies taking effect.
SELECT col_person FROM employees ORDER BY col_person.age;

-- This result is formatted for ease of reading.
         col_person
--------------------------------
{
    "name": {
        "first": "JOHN",
        "last": "XXXX"
    },
    "age": 20,
    "ssn": "XXX-XX-3333",
    "company": "Company Inc."
}
{
    "name": {
        "first": "JANE",
        "last": "XXXX"
    },
    "age": 30,
    "ssn": "XXX-XX-7777",
    "company": "Organization Org."
}
```

다음은 SUPER 경로에 잘못된 마스킹 정책을 첨부한 몇 가지 예입니다.

```
-- This attachment fails because there is already a policy
-- with equal priority attached to employees.name.last, which is
-- on the same SUPER path as employees.name.
ATTACH MASKING POLICY mask_ssn
ON employees(col_person.name)
TO PUBLIC;
ERROR:  DDM policy "mask_last_name" is already attached on relation "employees" column "col_person."name"."last"" with same priority
               
-- Create a masking policy that masks DATETIME objects.
CREATE MASKING POLICY mask_date
WITH(INPUT DATETIME)
USING ( INPUT );
               
-- This attachment fails because SUPER type columns can't contain DATETIME objects.
ATTACH MASKING POLICY mask_date
ON employees(col_person.company)
TO PUBLIC;
ERROR:  cannot attach masking policy for output of type "timestamp without time zone" to column "col_person."company"" of type "super
```

다음은 마스킹 정책을 존재하지 않는 SUPER 경로에 연결하는 예입니다. 기본적으로 Amazon Redshift는 경로를 `NULL`로 해석합니다.

```
ATTACH MASKING POLICY mask_first_name
ON employees(col_person.not_exists)
TO PUBLIC;

SELECT col_person FROM employees LIMIT 1;

-- This result is formatted for ease of reading.
         col_person
-----------------------------------
{
    "name": {
        "first": "JOHN",
        "last": "XXXX"
    },
    "age": 20,
    "ssn": "XXX-XX-3333",
    "company": "Company Inc.",
    "not_exists": null
}
```

# 조건부 동적 데이터 마스킹
<a name="t_ddm-conditional"></a>

마스킹 표현식에서 조건식을 사용하여 마스킹 정책을 생성하여 셀 수준에서 데이터를 마스킹할 수 있습니다. 예를 들어 해당 행에 있는 다른 열의 값에 따라 다른 마스크를 값에 적용하는 마스킹 정책을 만들 수 있습니다.

다음은 조건부 데이터 마스킹을 사용하여 사기와 관련된 신용 카드 번호를 부분적으로 수정하고 다른 모든 신용 카드 번호를 완전히 숨기는 마스킹 정책을 만들고 첨부하는 예입니다. 이 예제를 실행하려면 수퍼유저이거나 [https://docs.aws.amazon.com/redshift/latest/dg/r_roles-default.html](https://docs.aws.amazon.com/redshift/latest/dg/r_roles-default.html) 역할이 있어야 합니다.

```
--Create an analyst role.
CREATE ROLE analyst;

--Create a credit card table. The table contains an is_fraud boolean column,
--which is TRUE if the credit card number in that row was involved in a fraudulent transaction.
CREATE TABLE credit_cards (id INT, is_fraud BOOLEAN, credit_card_number VARCHAR(16));

--Create a function that partially redacts credit card numbers.
CREATE FUNCTION REDACT_CREDIT_CARD (credit_card VARCHAR(16))
RETURNS VARCHAR(16) IMMUTABLE
AS $$
    import re
    regexp = re.compile("^([0-9]{6})[0-9]{5,6}([0-9]{4})")
 
    match = regexp.search(credit_card)
    if match != None:
        first = match.group(1)
        last = match.group(2)
    else:
        first = "000000"
        last = "0000"
    
    return "{}XXXXX{}".format(first, last)
$$ LANGUAGE plpythonu;

--Create a masking policy that partially redacts credit card numbers if the is_fraud value for that row is TRUE,
--and otherwise blanks out the credit card number completely.
CREATE MASKING POLICY card_number_conditional_mask
    WITH (fraudulent BOOLEAN, pan varchar(16)) 
    USING (CASE WHEN fraudulent THEN REDACT_CREDIT_CARD(pan)
                ELSE Null
           END);

--Attach the masking policy to the credit_cards/analyst table/role pair. 
ATTACH MASKING POLICY card_number_conditional_mask ON credit_cards (credit_card_number)
 USING (is_fraud, credit_card_number)
 TO ROLE analyst PRIORITY 100;
```

# 동적 데이터 마스킹 시스템 뷰
<a name="r_ddm-svv"></a>

수퍼유저, `sys:operator` 역할이 있는 사용자, ACCESS SYSTEM TABLE 권한이 있는 사용자는 다음과 같은 DDM 관련 시스템 뷰에 액세스할 수 있습니다.
+  [SVV\$1MASKING\$1POLICY](r_SVV_MASKING_POLICY.md) 

   SVV\$1MASKING\$1POLICY를 사용하여 클러스터 또는 작업 그룹에 생성된 모든 마스킹 정책을 볼 수 있습니다.
+  [SVV\$1ATTACHED\$1MASKING\$1POLICY](r_SVV_ATTACHED_MASKING_POLICY.md) 

  SVV\$1ATTACHED\$1MASKING\$1POLICY를 사용하여 현재 연결된 데이터베이스에 정책이 연결된 모든 관계 및 사용자 또는 역할을 봅니다.
+  [SYS\$1APPLIED\$1MASKING\$1POLICY\$1LOG](SYS_APPLIED_MASKING_POLICY_LOG.md) 

  SYS\$1APPLIED\$1MASKING\$1POLICY\$1LOG를 사용하여 DDM로 보호되는 관계를 참조하는 쿼리에서 마스킹 정책의 적용을 추적합니다.

다음은 시스템 뷰를 사용하여 찾을 수 있는 정보의 몇 가지 예제입니다.

```
--Select all policies associated with specific users, as opposed to roles
SELECT policy_name,
       schema_name,
       table_name,
       grantee
FROM svv_attached_masking_policy
WHERE grantee_type = 'user';     

--Select all policies attached to a specific user
SELECT policy_name,
       schema_name,
       table_name,
       grantee
FROM svv_attached_masking_policy
WHERE grantee = 'target_grantee_name'            
            
--Select all policies attached to a given table
SELECT policy_name,
       schema_name,
       table_name,
       grantee
FROM svv_attached_masking_policy
WHERE table_name = 'target_table_name'
      AND schema_name = 'target_schema_name';            
            
--Select the highest priority policy attachment for a given role
SELECT samp.policy_name,
       samp.priority,
       samp.grantee,
       smp.policy_expression
FROM svv_masking_policy AS smp
JOIN svv_attached_masking_policy AS samp
    ON samp.policy_name = smp.policy_name
WHERE
    samp.grantee_type = 'role' AND
    samp.policy_name = mask_get_policy_for_role_on_column(
        'target_schema_name', 
        'target_table_name', 
        'target_column_name', 
        'target_role_name')
ORDER BY samp.priority desc
LIMIT 1;         

--See which policy a specific user will see on a specific column in a given relation
SELECT samp.policy_name,
       samp.priority,
       samp.grantee,
       smp.policy_expression
FROM svv_masking_policy AS smp
JOIN svv_attached_masking_policy AS samp
    ON samp.policy_name = smp.policy_name
WHERE
    samp.grantee_type = 'role' AND
    samp.policy_name = mask_get_policy_for_user_on_column(
        'target_schema_name',
        'target_table_name',
        'target_column_name',
        'target_user_name')
ORDER BY samp.priority desc; 
         
 --Select all policies attached to a given relation.
SELECT policy_name,
schema_name,
relation_name,
database_name
FROM sys_applied_masking_policy_log
WHERE relation_name = 'relation_name'
AND schema_name = 'schema_name';
```

# 동적 데이터 마스킹 사용 시 고려 사항
<a name="t_ddm-considerations"></a>

동적 데이터 마스킹을 사용할 때 다음 사항을 고려하세요.
+  뷰와 같은 테이블에서 생성된 객체를 쿼리할 때 사용자는 객체를 생성한 사용자의 정책이 아닌 자신의 마스킹 정책에 따라 결과를 보게 됩니다. 예를 들어 secadmin이 생성한 뷰를 쿼리하는 분석가 역할을 가진 사용자는 분석가 역할에 연결된 마스킹 정책이 있는 결과를 볼 수 있습니다.
+  EXPLAIN 명령이 잠재적으로 중요한 마스킹 정책 필터를 노출하지 않도록 하기 위해 SYS\$1EXPLAIN\$1DDM 권한이 있는 사용자만 EXPLAIN 출력에 적용된 마스킹 정책을 볼 수 있습니다. 사용자에게는 기본적으로 SYS\$1EXPLAIN\$1DDM 권한이 없습니다.

  다음은 역할에 권한을 부여할 때 사용하는 구문입니다.

  ```
  GRANT EXPLAIN MASKING TO ROLE rolename
  ```

   EXPLAIN 명령에 대한 자세한 내용은 [EXPLAIN](r_EXPLAIN.md) 섹션을 참조하세요.
+  역할이 다른 사용자는 사용된 필터 조건 또는 조인 조건에 따라 다른 결과를 볼 수 있습니다. 예를 들어 명령을 실행하는 사용자에게 해당 열을 난독화하는 마스킹 정책이 적용된 경우 특정 열 값을 사용하여 테이블에서 SELECT 명령을 실행하면 실패합니다.
+  DDM 정책은 조건자 작업 또는 예측보다 먼저 적용되어야 합니다. 마스킹 정책에는 다음이 포함될 수 있습니다.
  + 값을 null로 변환하는 것과 같은 저비용 상수 연산
  + HMAC 해싱과 같은 중간 비용 연산
  + 외부 Lambda 사용자 정의 함수 호출과 같은 고비용 연산

  따라서 가능하면 간단한 마스킹 표현식을 사용하는 것이 좋습니다.
+  행 수준 보안 정책이 있는 역할에 DDM 정책을 사용할 수 있지만 RLS 정책은 DDM보다 먼저 적용됩니다. 동적 데이터 마스킹 표현식은 RLS로 보호된 행을 읽을 수 없습니다. RLS에 대한 자세한 내용은 [행 수준 보안](t_rls.md) 섹션을 참조하세요.
+  [COPY](r_COPY.md) 명령을 사용하여 Parquet에서 보호된 대상 테이블로 복사할 때는 COPY 문에 열을 명시적으로 지정해야 합니다. COPY를 사용한 열 매핑에 대한 자세한 내용은 [열 매핑 옵션](copy-parameters-column-mapping.md) 섹션을 참조하세요.
+  DDM 정책은 다음 관계에 연결될 수 없습니다.
  +  시스템 테이블 및 카탈로그 
  +  외부 테이블 
  +  데이터 공유 테이블
  +  교차 데이터베이스 관계 
  +  임시 테이블 
  +  상관관계가 있는 쿼리 
+  DDM 정책에는 조회 테이블이 포함될 수 있습니다. 조회 테이블은 USING 절에 있을 수 있습니다. 다음 관계 유형은 조회 테이블로 사용할 수 없습니다.
  +  시스템 테이블 및 카탈로그 
  +  외부 테이블 
  +  데이터 공유 테이블 
  +  뷰, 구체화된 뷰 및 지연 바인딩 뷰 
  +  교차 데이터베이스 관계 
  +  임시 테이블 
  +  상관관계가 있는 쿼리 

  다음은 마스킹 정책을 조회 테이블에 연결하는 예제입니다.

  ```
  --Create a masking policy referencing a lookup table
  CREATE MASKING POLICY lookup_mask_credit_card WITH (credit_card TEXT) USING (
    CASE
      WHEN
        credit_card IN (SELECT credit_card_lookup FROM credit_cards_lookup)      
      THEN '000000XXXX0000'
      ELSE REDACT_CREDIT_CARD(credit_card)
      END
    ); 
    
  --Provides access to the lookup table via a policy attached to a role
  GRANT SELECT ON TABLE credit_cards_lookup TO MASKING POLICY lookup_mask_credit_card;
  ```
+  대상 열의 유형 및 크기와 호환되지 않는 출력을 생성하는 마스킹 정책을 연결할 수 없습니다. 예를 들어 12자 길이의 문자열을 VARCHAR(10) 열에 출력하는 마스킹 정책을 연결할 수 없습니다. Amazon Redshift Redshift는 다음 예외를 지원합니다.
  +  입력 유형이 INTN인 마스킹 정책은 M < N인 한 크기가 INTM인 정책에 연결할 수 있습니다. 예를 들어 BIGINT(INT8) 입력 정책은 smallint(INT4) 열에 연결할 수 있습니다.
  +  입력 유형이 NUMERIC 또는 DECIMAL인 마스킹 정책은 항상 FLOAT 열에 연결할 수 있습니다.
+ DDM 정책은 데이터 공유와 함께 사용할 수 없습니다. 데이터 공유의 데이터 생산자가 데이터 공유의 테이블에 DDM 정책을 연결하면, 테이블을 쿼리하려는 데이터 소비자의 사용자는 해당 테이블에 액세스할 수 없게 됩니다. 생산자측 클러스터 또는 네임스페이스에서 데이터 공유에 관계를 추가하려고 하면 다음 오류와 함께 작업이 실패합니다.

  ```
  <ddm_protected_relation> or a relation dependent on it is protected by a masking policy and cannot be added to a datashare
  ```

  마스킹 정책을 생산자측의 관계에 연결하고 해당 관계가 이미 데이터 공유에 포함된 경우 소비자측에서 관계를 쿼리하려고 하면 다음 오류와 함께 작업이 실패합니다.

  ```
  cross-cluster query of the masked relation <ddm_protected_relation> is not supported.
  ```

  MASKING OFF FOR DATASHARES 파라미터와 함께 ALTER TABLE 명령을 사용하여 데이터 공유에 대한 DDM을 끌 수 있습니다. 자세한 내용은 [ALTER TABLE](r_ALTER_TABLE.md) 섹션을 참조하세요.
+ 다음 구성 옵션의 값이 세션의 기본값과 일치하지 않으면 DDM 정책을 첨부한 관계를 쿼리할 수 없습니다.
  +  `enable_case_sensitive_super_attribute` 
  +  `enable_case_sensitive_identifier` 
  +  `downcase_delimited_identifier` 

  DDM 정책이 첨부된 관계를 쿼리하려고 할 때 "대/소문자 구분이 기본값과 다른 DDM 보호 관계에서 세션 수준 구성을 지원하지 않습니다."라는 메시지가 표시되면 세션의 구성 옵션을 재설정하는 것이 좋습니다.
+  프로비저닝된 클러스터 또는 서버리스 네임스페이스에 동적 데이터 마스킹 정책이 있는 경우 일반 사용자에게는 다음 명령이 차단됩니다.

  ```
  ALTER <current_user> SET enable_case_sensitive_super_attribute/enable_case_sensitive_identifier/downcase_delimited_identifier
  ```

  DDM 정책을 만들 때 일반 사용자의 기본 구성 옵션 설정을 정책을 만들 당시의 세션의 구성 옵션 설정과 일치하도록 변경하는 것이 좋습니다. 슈퍼유저 및 ALTER USER 권한이 있는 사용자는 파라미터 그룹 설정 또는 ALTER USER 명령을 사용하여 이 작업을 수행할 수 있습니다. 파라미터 그룹에 대한 자세한 내용은 **Amazon Redshift 관리 안내서의 [Amazon Redshift 파라미터 그룹](https://docs.aws.amazon.com/redshift/latest/mgmt/working-with-parameter-groups.html)을 참조하세요. ALTER USER 명령에 대한 자세한 내용은 [ALTER USER](r_ALTER_USER.md) 섹션을 참조하세요.
+ DDM 정책이 연결된 뷰와 지연 바인딩 뷰는 일반 사용자가 [CREATE VIEW](r_CREATE_VIEW.md) 명령을 사용하여 교체할 수 없습니다. DDM 정책이 연결된 뷰 또는 LBV를 바꾸려면 먼저 연결된 DDM 정책을 분리하고 뷰 또는 LBV를 교체한 다음, 정책을 다시 연결합니다. 슈퍼 사용자 및 `sys:secadmin` 권한이 있는 사용자는 정책을 분리하지 않고도 DDM 정책이 연결된 뷰 또는 LBV에 CREATE VIEW를 사용할 수 있습니다.
+ DDM 정책이 연결된 뷰는 시스템 테이블과 뷰를 참조할 수 없습니다. 지연 바인딩 뷰는 시스템 테이블 및 뷰를 참조할 수 있습니다.
+ DDM 정책이 연결된 지연 바인딩 뷰는 데이터 레이크의 중첩된 데이터(예: JSON 문서)를 참조할 수 없습니다.
+  지연 바인딩 뷰를 참조하는 뷰가 있는 경우 해당 지연 바인딩 뷰에는 DDM 정책을 연결할 수 없습니다.
+  지연 바인딩 뷰에 연결된 DDM 정책은 열 이름을 기준으로 첨부됩니다. 쿼리 시 Amazon Redshift는 지연 바인딩 뷰에 연결된 모든 마스킹 정책이 성공적으로 적용되었는지, 그리고 지연 바인딩 뷰의 출력 열 유형이 연결된 마스킹 정책의 유형과 일치하는지 확인합니다. 검증이 실패하면 Amazon Redshift가 쿼리에 대한 오류를 반환합니다.
+ DDM 정책을 생성할 때 사용자 지정된 세션 컨텍스트 변수를 사용할 수 있습니다. 다음 예제에서는 DDM 정책의 세션 컨텍스트 변수를 설정합니다.

  ```
  -- Set a customized context variable.
  SELECT set_config('app.city', 'XXXX', FALSE);
  
  -- Create a MASKING policy using current_setting() to get the value of a customized context variable.
  CREATE MASKING POLICY city_mask
  WITH (city VARCHAR(30))
  USING (current_setting('app.city')::VARCHAR(30));
  
  -- Attach the policy on the target table to one or more roles.
  ATTACH MASKING POLICY city_mask 
  ON tickit_users_redshift(city) 
  TO ROLE analyst, ROLE dbadmin;
  ```

  사용자 지정 세션 컨텍스트 변수를 설정 및 검색하는 방법을 자세히 알아보려면 [SET](r_SET.md), [SET\$1CONFIG](r_SET_CONFIG.md), [SHOW](r_SHOW.md), [CURRENT\$1SETTING](r_CURRENT_SETTING.md), [reset](r_RESET.md) 섹션으로 이동하세요. 일반적인 서버 구성 수정 방법을 자세히 알아보려면 [서버 구성 수정](cm_chap_ConfigurationRef.md#t_Modifying_the_default_settings) 섹션으로 이동하세요.
**중요**  
 DDM 정책 내에서 세션 컨텍스트 변수를 사용하는 경우 보안 정책은 정책을 간접 호출하는 사용자 또는 역할에 따라 달라집니다. DDM 정책에서 세션 컨텍스트 변수를 사용할 때는 보안 취약성이 발생하지 않도록 주의하세요.

# 동적 데이터 마스킹 엔드 투 엔드 예제
<a name="ddm-example"></a>

다음은 마스킹 정책을 생성하고 열에 연결하는 방법을 보여주는 종합 예제입니다. 이러한 정책을 통해 사용자는 역할에 연결된 정책의 난독화 정도에 따라 열에 액세스하고 다른 값을 볼 수 있습니다. 이 예제를 실행하려면 수퍼유저이거나 [https://docs.aws.amazon.com/redshift/latest/dg/r_roles-default.html](https://docs.aws.amazon.com/redshift/latest/dg/r_roles-default.html) 역할이 있어야 합니다.

## 마스킹 정책 생성
<a name="ddm-example-create"></a>

먼저 테이블을 만들고 신용 카드 값으로 채웁니다.

```
--create the table         
CREATE TABLE credit_cards (
  customer_id INT,
  credit_card TEXT
);

--populate the table with sample values
INSERT INTO credit_cards
VALUES
  (100, '4532993817514842'),
  (100, '4716002041425888'),
  (102, '5243112427642649'),
  (102, '6011720771834675'),
  (102, '6011378662059710'),
  (103, '373611968625635')
;

--run GRANT to grant permission to use the SELECT statement on the table
GRANT SELECT ON credit_cards TO PUBLIC;

--create two users
CREATE USER regular_user WITH PASSWORD '1234Test!';

CREATE USER analytics_user WITH PASSWORD '1234Test!';

--create the analytics_role role and grant it to analytics_user
--regular_user does not have a role
CREATE ROLE analytics_role;

GRANT ROLE analytics_role TO analytics_user;
```

다음으로 분석 역할에 적용할 마스킹 정책을 생성합니다.

```
--create a masking policy that fully masks the credit card number
CREATE MASKING POLICY mask_credit_card_full
WITH (credit_card VARCHAR(256))
USING ('000000XXXX0000'::TEXT);

--create a user-defined function that partially obfuscates credit card data
CREATE FUNCTION REDACT_CREDIT_CARD (credit_card TEXT)
RETURNS TEXT IMMUTABLE
AS $$
    import re
    regexp = re.compile("^([0-9]{6})[0-9]{5,6}([0-9]{4})")
 
    match = regexp.search(credit_card)
    if match != None:
        first = match.group(1)
        last = match.group(2)
    else:
        first = "000000"
        last = "0000"
    
    return "{}XXXXX{}".format(first, last)
$$ LANGUAGE plpythonu;

--create a masking policy that applies the REDACT_CREDIT_CARD function
CREATE MASKING POLICY mask_credit_card_partial
WITH (credit_card VARCHAR(256))
USING (REDACT_CREDIT_CARD(credit_card));

--confirm the masking policies using the associated system views
SELECT * FROM svv_masking_policy;

SELECT * FROM svv_attached_masking_policy;
```

## 마스킹 정책 연결
<a name="ddm-example-attach"></a>

마스킹 정책을 신용 카드 테이블에 연결합니다.

```
--attach mask_credit_card_full to the credit card table as the default policy
--all users will see this masking policy unless a higher priority masking policy is attached to them or their role
ATTACH MASKING POLICY mask_credit_card_full
ON credit_cards(credit_card)
TO PUBLIC;

--attach mask_credit_card_partial to the analytics role
--users with the analytics role can see partial credit card information
ATTACH MASKING POLICY mask_credit_card_partial
ON credit_cards(credit_card)
TO ROLE analytics_role
PRIORITY 10;

--confirm the masking policies are applied to the table and role in the associated system view
SELECT * FROM svv_attached_masking_policy;

--confirm the full masking policy is in place for normal users by selecting from the credit card table as regular_user
SET SESSION AUTHORIZATION regular_user;

SELECT * FROM credit_cards;

--confirm the partial masking policy is in place for users with the analytics role by selecting from the credit card table as analytics_user
SET SESSION AUTHORIZATION analytics_user;

SELECT * FROM credit_cards;
```

## 마스킹 정책 변경
<a name="ddm-example-alter"></a>

다음 섹션은 동적 데이터 마스킹 정책을 변경하는 방법을 설명합니다.

```
--reset session authorization to the default
RESET SESSION AUTHORIZATION;

--alter the mask_credit_card_full policy
ALTER MASKING POLICY mask_credit_card_full
USING ('00000000000000'::TEXT);	
	
--confirm the full masking policy is in place after altering the policy, and that results are altered from '000000XXXX0000' to '00000000000000'
SELECT * FROM credit_cards;
```

## 마스킹 정책 분리 및 삭제
<a name="ddm-example-detach"></a>

다음 섹션에서는 테이블에서 모든 동적 데이터 마스킹 정책을 제거하여 마스킹 정책을 분리 및 삭제하는 방법을 보여줍니다.

```
--reset session authorization to the default
RESET SESSION AUTHORIZATION;

--detach both masking policies from the credit_cards table
DETACH MASKING POLICY mask_credit_card_full 
ON credit_cards(credit_card) 
FROM PUBLIC;

DETACH MASKING POLICY mask_credit_card_partial 
ON credit_cards(credit_card) 
FROM ROLE analytics_role;

--drop both masking policies
DROP MASKING POLICY mask_credit_card_full;

DROP MASKING POLICY mask_credit_card_partial;
```