

# 데이터베이스 활동 스트림 모니터링
<a name="DBActivityStreams.Monitoring"></a>

데이터베이스 활동 스트림은 활동을 모니터링하고 보고합니다. 활동 스트림이 수집되어 Amazon Kinesis에 전송됩니다. Kinesis에서 활동 스트림을 모니터링하거나 다른 서비스 및 애플리케이션이 추가 분석을 위해 활동 스트림을 사용할 수 있습니다. AWS CLI 명령 `describe-db-instances` 또는 RDS API `DescribeDBInstances` 작업을 사용하여 기본 Kinesis 스트림 이름을 찾을 수 있습니다.

Amazon RDS는 다음과 같이 Kinesis 스트림을 관리합니다.
+ Amazon RDS는 24시간 보존 기간으로 Kinesis 스트림을 자동으로 생성합니다.
+  Amazon RDS는 필요한 경우 Kinesis 스트림 크기를 조정합니다.
+  데이터베이스 활동 스트림을 중지하거나 DB 인스턴스를 삭제하면 Amazon RDS에서 Kinesis 스트림을 삭제합니다.

다음 활동 범주가 모니터링되고 활동 스트림 감사 로그에 기록됩니다.
+ **SQL 명령** – 모든 SQL 명령이 감사되고 PL/SQL에서 준비된 문, 내장 함수 및 함수도 제공됩니다. 저장 프로시저에 대한 호출이 감사됩니다. 저장 프로시저 또는 함수 내에서 발급된 모든 SQL 문도 감사됩니다.
+ **다른 데이터베이스 정보** – 모니터링되는 활동에는 전체 SQL 문, DML 명령의 영향을 받은 행의 행 수, 액세스된 객체 및 고유한 데이터베이스 이름이 포함됩니다. 데이터베이스 활동 스트림은 바인딩 변수와 저장 프로시저 파라미터도 모니터링합니다.
**중요**  
각 문의 전체 SQL 텍스트는 중요한 데이터를 포함하여 활동 스트림 감사 로그에 표시됩니다. 그러나 데이터베이스 사용자 암호는 다음 SQL 문에서와 같이 Oracle이 컨텍스트에서 판별할 수 있는 경우 수정됩니다.  

  ```
  ALTER ROLE role-name WITH password
  ```
+ **연결 정보** – 모니터링되는 활동에는 세션 및 네트워크 정보, 서버 프로세스 ID 및 종료 코드가 포함됩니다.

DB 인스턴스를 모니터링하는 동안 활동 스트림에 오류가 발생하면 RDS 이벤트를 통해 사용자에게 알립니다.

다음 섹션에서는 데이터베이스 활동 스트림에 액세스하고, 이를 감사 및 처리할 수 있습니다.

**Topics**
+ [Amazon Kinesis에서 활동 스트림에 액세스](DBActivityStreams.KinesisAccess.md)
+ [데이터베이스 활동 스트림에 대한 감사 로그 내용 및 예제](DBActivityStreams.AuditLog.md)
+ [데이터베이스 활동 스트림에 대한 databaseActivityEventList JSON 배열](DBActivityStreams.AuditLog.databaseActivityEventList.md)
+ [AWS SDK를 사용하여 데이터베이스 활동 스트림 처리](DBActivityStreams.CodeExample.md)

# Amazon Kinesis에서 활동 스트림에 액세스
<a name="DBActivityStreams.KinesisAccess"></a>

데이터베이스에 대해 활동 스트림을 활성화하면 Kinesis 스트림이 생성됩니다. Kinesis에서 데이터베이스 활동을 실시간으로 모니터링할 수 있습니다. 데이터베이스 활동을 추가 분석하려면 Kinesis 스트림을 소비자 애플리케이션에 연결하면 됩니다. 또한 IBM의 Security Guardium 또는 Imperva의 SecureSphere Database Audit and Protection과 같은 규정 준수 관리 애플리케이션에 스트림을 연결할 수 있습니다.

RDS 콘솔 또는 Kinesis 콘솔에서 Kinesis 스트림에 액세스할 수 있습니다.

**RDS 콘솔을 사용하여 Kinesis에서 활동 스트림에 액세스하는 방법**

1. [https://console.aws.amazon.com/rds/](https://console.aws.amazon.com/rds/)에서 Amazon RDS 콘솔을 엽니다.

1. 탐색 창에서 **데이터베이스**를 선택합니다.

1. 활동 스트림을 시작한 Amazon RDS 데이터베이스 인스턴스를 선택합니다.

1. **Configuration**(구성)을 선택합니다.

1. **데이터베이스 활동 스트림**에서 **Kinesis 스트림** 아래의 링크를 선택합니다.

1. Kinesis 콘솔에서 **모니터링**을 선택하여 데이터베이스 활동 관찰을 시작합니다.

**Kinesis 콘솔을 사용하여 Kinesis에서 활동 스트림에 액세스하는 방법**

1. [https://console.aws.amazon.com/kinesis](https://console.aws.amazon.com/kinesis)에서 Kinesis 콘솔을 엽니다.

1. Kinesis 스트림 목록에서 활동 스트림을 선택합니다.

   활동 스트림의 이름에는 접두사 `aws-rds-das-db-`와 그 뒤의 데이터베이스의 리소스 ID가 포함됩니다. 다음은 예제입니다.

   ```
   aws-rds-das-db-NHVOV4PCLWHGF52NP
   ```

   Amazon RDS 콘솔을 사용하여 데이터베이스의 리소스 ID를 찾으려면 데이터베이스 목록에서 DB 인스턴스를 선택한 다음 **구성(Configuration)** 탭을 선택합니다.

   AWS CLI를 사용하여 활동 스트림의 전체 Kinesis 스트림 이름을 찾으려면 [describe-db-instances CLI](https://docs.aws.amazon.com/cli/latest/reference/rds/describe-db-instances.html) 요청을 사용하고 응답에서 `ActivityStreamKinesisStreamName` 값을 기록합니다.

1. 데이터베이스 활동을 관찰하려면 **모니터링**을 선택하십시오.

Amazon Kinesis 사용에 대한 자세한 내용은 [Amazon Kinesis Data Streams이란 무엇입니까?](https://docs.aws.amazon.com/streams/latest/dev/introduction.html)를 참조하십시오.

# 데이터베이스 활동 스트림에 대한 감사 로그 내용 및 예제
<a name="DBActivityStreams.AuditLog"></a>

모니터링되는 이벤트는 데이터베이스 활동 스트림에 JSON 문자열로 표시됩니다. 구조는 `DatabaseActivityMonitoringRecord`를 포함하는 JSON 객체로 구성되며, 여기에는 `databaseActivityEventList` 활동 이벤트 배열이 포함됩니다.

**참고**  
데이터베이스 활동 스트림의 경우 `paramList` JSON 배열에는 최대 절전 모드 애플리케이션의 null 값이 포함되지 않습니다.

**Topics**
+ [활동 스트림 감사 로그 예제](#DBActivityStreams.AuditLog.Examples)
+ [DatabaseActivityMonitoringRecords JSON 객체](#DBActivityStreams.AuditLog.DatabaseActivityMonitoringRecords)
+ [databaseActivityEvents JSON 객체](#DBActivityStreams.AuditLog.databaseActivityEvents)

## 활동 스트림 감사 로그 예제
<a name="DBActivityStreams.AuditLog.Examples"></a>

다음은 활동 이벤트 레코드의 해독된 JSON 감사 로그 샘플입니다.

**Example CONNECT SQL 문 의 활동 이벤트 레코드**  
다음 활동 이벤트 레코드는 Oracle DB의 JDBC 씬 클라이언트(`clientApplication`)에서 `CONNECT` SQL 문(`command`)을 사용하여 로그인한 것을 보여줍니다.  

```
{
    "class": "Standard",
    "clientApplication": "JDBC Thin Client",
    "command": "LOGON",
    "commandText": null,
    "dbid": "0123456789",
    "databaseName": "ORCL",
    "dbProtocol": "oracle",
    "dbUserName": "TEST",
    "endTime": null,
    "errorMessage": null,
    "exitCode": 0,
    "logTime": "2021-01-15 00:15:36.233787",
    "netProtocol": "tcp",
    "objectName": null,
    "objectType": null,
    "paramList": [],
    "pid": 17904,
    "remoteHost": "123.456.789.012",
    "remotePort": "25440",
    "rowCount": null,
    "serverHost": "987.654.321.098",
    "serverType": "oracle",
    "serverVersion": "19.0.0.0.ru-2020-01.rur-2020-01.r1.EE.3",
    "serviceName": "oracle-ee",
    "sessionId": 987654321,
    "startTime": null,
    "statementId": 1,
    "substatementId": null,
    "transactionId": "0000000000000000",
    "engineNativeAuditFields": {
        "UNIFIED_AUDIT_POLICIES": "TEST_POL_EVERYTHING",
        "FGA_POLICY_NAME": null,
        "DV_OBJECT_STATUS": null,
        "SYSTEM_PRIVILEGE_USED": "CREATE SESSION",
        "OLS_LABEL_COMPONENT_TYPE": null,
        "XS_SESSIONID": null,
        "ADDITIONAL_INFO": null,
        "INSTANCE_ID": 1,
        "DBID": 123456789
        "DV_COMMENT": null,
        "RMAN_SESSION_STAMP": null,
        "NEW_NAME": null,
        "DV_ACTION_NAME": null,
        "OLS_PROGRAM_UNIT_NAME": null,
        "OLS_STRING_LABEL": null,
        "RMAN_SESSION_RECID": null,
        "OBJECT_PRIVILEGES": null,
        "OLS_OLD_VALUE": null,
        "XS_TARGET_PRINCIPAL_NAME": null,
        "XS_NS_ATTRIBUTE": null,
        "XS_NS_NAME": null,
        "DBLINK_INFO": null,
        "AUTHENTICATION_TYPE": "(TYPE\u003d(DATABASE));(CLIENT ADDRESS\u003d((ADDRESS\u003d(PROTOCOL\u003dtcp)(HOST\u003d205.251.233.183)(PORT\u003d25440))));",
        "OBJECT_EDITION": null,
        "OLS_PRIVILEGES_GRANTED": null,
        "EXCLUDED_USER": null,
        "DV_ACTION_OBJECT_NAME": null,
        "OLS_LABEL_COMPONENT_NAME": null,
        "EXCLUDED_SCHEMA": null,
        "DP_TEXT_PARAMETERS1": null,
        "XS_USER_NAME": null,
        "XS_ENABLED_ROLE": null,
        "XS_NS_ATTRIBUTE_NEW_VAL": null,
        "DIRECT_PATH_NUM_COLUMNS_LOADED": null,
        "AUDIT_OPTION": null,
        "DV_EXTENDED_ACTION_CODE": null,
        "XS_PACKAGE_NAME": null,
        "OLS_NEW_VALUE": null,
        "DV_RETURN_CODE": null,
        "XS_CALLBACK_EVENT_TYPE": null,
        "USERHOST": "a1b2c3d4e5f6.amazon.com",
        "GLOBAL_USERID": null,
        "CLIENT_IDENTIFIER": null,
        "RMAN_OPERATION": null,
        "TERMINAL": "unknown",
        "OS_USERNAME": "sumepate",
        "OLS_MAX_READ_LABEL": null,
        "XS_PROXY_USER_NAME": null,
        "XS_DATASEC_POLICY_NAME": null,
        "DV_FACTOR_CONTEXT": null,
        "OLS_MAX_WRITE_LABEL": null,
        "OLS_PARENT_GROUP_NAME": null,
        "EXCLUDED_OBJECT": null,
        "DV_RULE_SET_NAME": null,
        "EXTERNAL_USERID": null,
        "EXECUTION_ID": null,
        "ROLE": null,
        "PROXY_SESSIONID": 0,
        "DP_BOOLEAN_PARAMETERS1": null,
        "OLS_POLICY_NAME": null,
        "OLS_GRANTEE": null,
        "OLS_MIN_WRITE_LABEL": null,
        "APPLICATION_CONTEXTS": null,
        "XS_SCHEMA_NAME": null,
        "DV_GRANTEE": null,
        "XS_COOKIE": null,
        "DBPROXY_USERNAME": null,
        "DV_ACTION_CODE": null,
        "OLS_PRIVILEGES_USED": null,
        "RMAN_DEVICE_TYPE": null,
        "XS_NS_ATTRIBUTE_OLD_VAL": null,
        "TARGET_USER": null,
        "XS_ENTITY_TYPE": null,
        "ENTRY_ID": 1,
        "XS_PROCEDURE_NAME": null,
        "XS_INACTIVITY_TIMEOUT": null,
        "RMAN_OBJECT_TYPE": null,
        "SYSTEM_PRIVILEGE": null,
        "NEW_SCHEMA": null,
        "SCN": 5124715
    }
}
```
다음 활동 이벤트 레코드는 SQL Server DB의 로그인 실패를 보여줍니다.  

```
{
    "type": "DatabaseActivityMonitoringRecord",
    "clusterId": "",
    "instanceId": "db-4JCWQLUZVFYP7DIWP6JVQ77O3Q",
    "databaseActivityEventList": [
        {
            "class": "LOGIN",
            "clientApplication": "Microsoft SQL Server Management Studio",
            "command": "LOGIN FAILED",
            "commandText": "Login failed for user 'test'. Reason: Password did not match that for the login provided. [CLIENT: local-machine]",
            "databaseName": "",
            "dbProtocol": "SQLSERVER",
            "dbUserName": "test",
            "endTime": null,
            "errorMessage": null,
            "exitCode": 0,
            "logTime": "2022-10-06 21:34:42.7113072+00",
            "netProtocol": null,
            "objectName": "",
            "objectType": "LOGIN",
            "paramList": null,
            "pid": null,
            "remoteHost": "local machine",
            "remotePort": null,
            "rowCount": 0,
            "serverHost": "172.31.30.159",
            "serverType": "SQLSERVER",
            "serverVersion": "15.00.4073.23.v1.R1",
            "serviceName": "sqlserver-ee",
            "sessionId": 0,
            "startTime": null,
            "statementId": "0x1eb0d1808d34a94b9d3dcf5432750f02",
            "substatementId": 1,
            "transactionId": "0",
            "type": "record",
            "engineNativeAuditFields": {
                "target_database_principal_id": 0,
                "target_server_principal_id": 0,
                "target_database_principal_name": "",
                "server_principal_id": 0,
                "user_defined_information": "",
                "response_rows": 0,
                "database_principal_name": "",
                "target_server_principal_name": "",
                "schema_name": "",
                "is_column_permission": false,
                "object_id": 0,
                "server_instance_name": "EC2AMAZ-NFUJJNO",
                "target_server_principal_sid": null,
                "additional_information": "<action_info "xmlns=\"http://schemas.microsoft.com/sqlserver/2008/sqlaudit_data\"><pooled_connection>0</pooled_connection><error>0x00004818</error><state>8</state><address>local machine</address><PasswordFirstNibbleHash>B</PasswordFirstNibbleHash></action_info>"-->,
                "duration_milliseconds": 0,
                "permission_bitmask": "0x00000000000000000000000000000000",
                "data_sensitivity_information": "",
                "session_server_principal_name": "",
                "connection_id": "98B4F537-0F82-49E3-AB08-B9D33B5893EF",
                "audit_schema_version": 1,
                "database_principal_id": 0,
                "server_principal_sid": null,
                "user_defined_event_id": 0,
                "host_name": "EC2AMAZ-NFUJJNO"
            }
        }
    ]
}
```
데이터베이스 활동 스트림이 활성화되지 않은 경우 JSON 문서의 마지막 필드는 `"engineNativeAuditFields": { }`입니다.

**Example CREATE TABLE 문의 활동 이벤트 레코드**  
다음 예시는 Oracle 데이터베이스에 대한 `CREATE TABLE` 이벤트를 보여줍니다.  

```
{
    "class": "Standard",
    "clientApplication": "sqlplus@ip-12-34-5-678 (TNS V1-V3)",
    "command": "CREATE TABLE",
    "commandText": "CREATE TABLE persons(\n    person_id NUMBER GENERATED BY DEFAULT AS IDENTITY,\n    first_name VARCHAR2(50) NOT NULL,\n    last_name VARCHAR2(50) NOT NULL,\n    PRIMARY KEY(person_id)\n)",
    "dbid": "0123456789",
    "databaseName": "ORCL",
    "dbProtocol": "oracle",
    "dbUserName": "TEST",
    "endTime": null,
    "errorMessage": null,
    "exitCode": 0,
    "logTime": "2021-01-15 00:22:49.535239",
    "netProtocol": "beq",
    "objectName": "PERSONS",
    "objectType": "TEST",
    "paramList": [],
    "pid": 17687,
    "remoteHost": "123.456.789.0",
    "remotePort": null,
    "rowCount": null,
    "serverHost": "987.654.321.01",
    "serverType": "oracle",
    "serverVersion": "19.0.0.0.ru-2020-01.rur-2020-01.r1.EE.3",
    "serviceName": "oracle-ee",
    "sessionId": 1234567890,
    "startTime": null,
    "statementId": 43,
    "substatementId": null,
    "transactionId": "090011007F0D0000",
    "engineNativeAuditFields": {
        "UNIFIED_AUDIT_POLICIES": "TEST_POL_EVERYTHING",
        "FGA_POLICY_NAME": null,
        "DV_OBJECT_STATUS": null,
        "SYSTEM_PRIVILEGE_USED": "CREATE SEQUENCE, CREATE TABLE",
        "OLS_LABEL_COMPONENT_TYPE": null,
        "XS_SESSIONID": null,
        "ADDITIONAL_INFO": null,
        "INSTANCE_ID": 1,
        "DV_COMMENT": null,
        "RMAN_SESSION_STAMP": null,
        "NEW_NAME": null,
        "DV_ACTION_NAME": null,
        "OLS_PROGRAM_UNIT_NAME": null,
        "OLS_STRING_LABEL": null,
        "RMAN_SESSION_RECID": null,
        "OBJECT_PRIVILEGES": null,
        "OLS_OLD_VALUE": null,
        "XS_TARGET_PRINCIPAL_NAME": null,
        "XS_NS_ATTRIBUTE": null,
        "XS_NS_NAME": null,
        "DBLINK_INFO": null,
        "AUTHENTICATION_TYPE": "(TYPE\u003d(DATABASE));(CLIENT ADDRESS\u003d((PROTOCOL\u003dbeq)(HOST\u003d123.456.789.0)));",
        "OBJECT_EDITION": null,
        "OLS_PRIVILEGES_GRANTED": null,
        "EXCLUDED_USER": null,
        "DV_ACTION_OBJECT_NAME": null,
        "OLS_LABEL_COMPONENT_NAME": null,
        "EXCLUDED_SCHEMA": null,
        "DP_TEXT_PARAMETERS1": null,
        "XS_USER_NAME": null,
        "XS_ENABLED_ROLE": null,
        "XS_NS_ATTRIBUTE_NEW_VAL": null,
        "DIRECT_PATH_NUM_COLUMNS_LOADED": null,
        "AUDIT_OPTION": null,
        "DV_EXTENDED_ACTION_CODE": null,
        "XS_PACKAGE_NAME": null,
        "OLS_NEW_VALUE": null,
        "DV_RETURN_CODE": null,
        "XS_CALLBACK_EVENT_TYPE": null,
        "USERHOST": "ip-10-13-0-122",
        "GLOBAL_USERID": null,
        "CLIENT_IDENTIFIER": null,
        "RMAN_OPERATION": null,
        "TERMINAL": "pts/1",
        "OS_USERNAME": "rdsdb",
        "OLS_MAX_READ_LABEL": null,
        "XS_PROXY_USER_NAME": null,
        "XS_DATASEC_POLICY_NAME": null,
        "DV_FACTOR_CONTEXT": null,
        "OLS_MAX_WRITE_LABEL": null,
        "OLS_PARENT_GROUP_NAME": null,
        "EXCLUDED_OBJECT": null,
        "DV_RULE_SET_NAME": null,
        "EXTERNAL_USERID": null,
        "EXECUTION_ID": null,
        "ROLE": null,
        "PROXY_SESSIONID": 0,
        "DP_BOOLEAN_PARAMETERS1": null,
        "OLS_POLICY_NAME": null,
        "OLS_GRANTEE": null,
        "OLS_MIN_WRITE_LABEL": null,
        "APPLICATION_CONTEXTS": null,
        "XS_SCHEMA_NAME": null,
        "DV_GRANTEE": null,
        "XS_COOKIE": null,
        "DBPROXY_USERNAME": null,
        "DV_ACTION_CODE": null,
        "OLS_PRIVILEGES_USED": null,
        "RMAN_DEVICE_TYPE": null,
        "XS_NS_ATTRIBUTE_OLD_VAL": null,
        "TARGET_USER": null,
        "XS_ENTITY_TYPE": null,
        "ENTRY_ID": 12,
        "XS_PROCEDURE_NAME": null,
        "XS_INACTIVITY_TIMEOUT": null,
        "RMAN_OBJECT_TYPE": null,
        "SYSTEM_PRIVILEGE": null,
        "NEW_SCHEMA": null,
        "SCN": 5133083
    }
}
```
다음 예시는 SQL Server 데이터베이스의 `CREATE TABLE` 이벤트를 보여줍니다.  

```
{
    "type": "DatabaseActivityMonitoringRecord",
    "clusterId": "",
    "instanceId": "db-4JCWQLUZVFYP7DIWP6JVQ77O3Q",
    "databaseActivityEventList": [
        {
            "class": "SCHEMA",
            "clientApplication": "Microsoft SQL Server Management Studio - Query",
            "command": "ALTER",
            "commandText": "Create table [testDB].[dbo].[TestTable2](\r\ntextA varchar(6000),\r\n    textB varchar(6000)\r\n)",
            "databaseName": "testDB",
            "dbProtocol": "SQLSERVER",
            "dbUserName": "test",
            "endTime": null,
            "errorMessage": null,
            "exitCode": 1,
            "logTime": "2022-10-06 21:44:38.4120677+00",
            "netProtocol": null,
            "objectName": "dbo",
            "objectType": "SCHEMA",
            "paramList": null,
            "pid": null,
            "remoteHost": "local machine",
            "remotePort": null,
            "rowCount": 0,
            "serverHost": "172.31.30.159",
            "serverType": "SQLSERVER",
            "serverVersion": "15.00.4073.23.v1.R1",
            "serviceName": "sqlserver-ee",
            "sessionId": 84,
            "startTime": null,
            "statementId": "0x5178d33d56e95e419558b9607158a5bd",
            "substatementId": 1,
            "transactionId": "4561864",
            "type": "record",
            "engineNativeAuditFields": {
                "target_database_principal_id": 0,
                "target_server_principal_id": 0,
                "target_database_principal_name": "",
                "server_principal_id": 2,
                "user_defined_information": "",
                "response_rows": 0,
                "database_principal_name": "dbo",
                "target_server_principal_name": "",
                "schema_name": "",
                "is_column_permission": false,
                "object_id": 1,
                "server_instance_name": "EC2AMAZ-NFUJJNO",
                "target_server_principal_sid": null,
                "additional_information": "",
                "duration_milliseconds": 0,
                "permission_bitmask": "0x00000000000000000000000000000000",
                "data_sensitivity_information": "",
                "session_server_principal_name": "test",
                "connection_id": "EE1FE3FD-EF2C-41FD-AF45-9051E0CD983A",
                "audit_schema_version": 1,
                "database_principal_id": 1,
                "server_principal_sid": "0x010500000000000515000000bdc2795e2d0717901ba6998cf4010000",
                "user_defined_event_id": 0,
                "host_name": "EC2AMAZ-NFUJJNO"
            }
        }
    ]
}
```

**Example SELECT 문의 활동 이벤트 레코드**  
다음 예시는 Oracle DB에 대한 `SELECT` 이벤트를 보여줍니다.  

```
{
    "class": "Standard",
    "clientApplication": "sqlplus@ip-12-34-5-678 (TNS V1-V3)",
    "command": "SELECT",
    "commandText": "select count(*) from persons",
    "databaseName": "1234567890",
    "dbProtocol": "oracle",
    "dbUserName": "TEST",
    "endTime": null,
    "errorMessage": null,
    "exitCode": 0,
    "logTime": "2021-01-15 00:25:18.850375",
    "netProtocol": "beq",
    "objectName": "PERSONS",
    "objectType": "TEST",
    "paramList": [],
    "pid": 17687,
    "remoteHost": "123.456.789.0",
    "remotePort": null,
    "rowCount": null,
    "serverHost": "987.654.321.09",
    "serverType": "oracle",
    "serverVersion": "19.0.0.0.ru-2020-01.rur-2020-01.r1.EE.3",
    "serviceName": "oracle-ee",
    "sessionId": 1080639707,
    "startTime": null,
    "statementId": 44,
    "substatementId": null,
    "transactionId": null,
    "engineNativeAuditFields": {
        "UNIFIED_AUDIT_POLICIES": "TEST_POL_EVERYTHING",
        "FGA_POLICY_NAME": null,
        "DV_OBJECT_STATUS": null,
        "SYSTEM_PRIVILEGE_USED": null,
        "OLS_LABEL_COMPONENT_TYPE": null,
        "XS_SESSIONID": null,
        "ADDITIONAL_INFO": null,
        "INSTANCE_ID": 1,
        "DV_COMMENT": null,
        "RMAN_SESSION_STAMP": null,
        "NEW_NAME": null,
        "DV_ACTION_NAME": null,
        "OLS_PROGRAM_UNIT_NAME": null,
        "OLS_STRING_LABEL": null,
        "RMAN_SESSION_RECID": null,
        "OBJECT_PRIVILEGES": null,
        "OLS_OLD_VALUE": null,
        "XS_TARGET_PRINCIPAL_NAME": null,
        "XS_NS_ATTRIBUTE": null,
        "XS_NS_NAME": null,
        "DBLINK_INFO": null,
        "AUTHENTICATION_TYPE": "(TYPE\u003d(DATABASE));(CLIENT ADDRESS\u003d((PROTOCOL\u003dbeq)(HOST\u003d123.456.789.0)));",
        "OBJECT_EDITION": null,
        "OLS_PRIVILEGES_GRANTED": null,
        "EXCLUDED_USER": null,
        "DV_ACTION_OBJECT_NAME": null,
        "OLS_LABEL_COMPONENT_NAME": null,
        "EXCLUDED_SCHEMA": null,
        "DP_TEXT_PARAMETERS1": null,
        "XS_USER_NAME": null,
        "XS_ENABLED_ROLE": null,
        "XS_NS_ATTRIBUTE_NEW_VAL": null,
        "DIRECT_PATH_NUM_COLUMNS_LOADED": null,
        "AUDIT_OPTION": null,
        "DV_EXTENDED_ACTION_CODE": null,
        "XS_PACKAGE_NAME": null,
        "OLS_NEW_VALUE": null,
        "DV_RETURN_CODE": null,
        "XS_CALLBACK_EVENT_TYPE": null,
        "USERHOST": "ip-12-34-5-678",
        "GLOBAL_USERID": null,
        "CLIENT_IDENTIFIER": null,
        "RMAN_OPERATION": null,
        "TERMINAL": "pts/1",
        "OS_USERNAME": "rdsdb",
        "OLS_MAX_READ_LABEL": null,
        "XS_PROXY_USER_NAME": null,
        "XS_DATASEC_POLICY_NAME": null,
        "DV_FACTOR_CONTEXT": null,
        "OLS_MAX_WRITE_LABEL": null,
        "OLS_PARENT_GROUP_NAME": null,
        "EXCLUDED_OBJECT": null,
        "DV_RULE_SET_NAME": null,
        "EXTERNAL_USERID": null,
        "EXECUTION_ID": null,
        "ROLE": null,
        "PROXY_SESSIONID": 0,
        "DP_BOOLEAN_PARAMETERS1": null,
        "OLS_POLICY_NAME": null,
        "OLS_GRANTEE": null,
        "OLS_MIN_WRITE_LABEL": null,
        "APPLICATION_CONTEXTS": null,
        "XS_SCHEMA_NAME": null,
        "DV_GRANTEE": null,
        "XS_COOKIE": null,
        "DBPROXY_USERNAME": null,
        "DV_ACTION_CODE": null,
        "OLS_PRIVILEGES_USED": null,
        "RMAN_DEVICE_TYPE": null,
        "XS_NS_ATTRIBUTE_OLD_VAL": null,
        "TARGET_USER": null,
        "XS_ENTITY_TYPE": null,
        "ENTRY_ID": 13,
        "XS_PROCEDURE_NAME": null,
        "XS_INACTIVITY_TIMEOUT": null,
        "RMAN_OBJECT_TYPE": null,
        "SYSTEM_PRIVILEGE": null,
        "NEW_SCHEMA": null,
        "SCN": 5136972
    }
}
```
다음 예시는 SQL Server DB에 대한 `SELECT` 이벤트를 보여줍니다.  

```
{
    "type": "DatabaseActivityMonitoringRecord",
    "clusterId": "",
    "instanceId": "db-4JCWQLUZVFYP7DIWP6JVQ77O3Q",
    "databaseActivityEventList": [
        {
            "class": "TABLE",
            "clientApplication": "Microsoft SQL Server Management Studio - Query",
            "command": "SELECT",
            "commandText": "select * from [testDB].[dbo].[TestTable]",
            "databaseName": "testDB",
            "dbProtocol": "SQLSERVER",
            "dbUserName": "test",
            "endTime": null,
            "errorMessage": null,
            "exitCode": 1,
            "logTime": "2022-10-06 21:24:59.9422268+00",
            "netProtocol": null,
            "objectName": "TestTable",
            "objectType": "TABLE",
            "paramList": null,
            "pid": null,
            "remoteHost": "local machine",
            "remotePort": null,
            "rowCount": 0,
            "serverHost": "172.31.30.159",
            "serverType": "SQLSERVER",
            "serverVersion": "15.00.4073.23.v1.R1",
            "serviceName": "sqlserver-ee",
            "sessionId": 62,
            "startTime": null,
            "statementId": "0x03baed90412f564fad640ebe51f89b99",
            "substatementId": 1,
            "transactionId": "4532935",
            "type": "record",
            "engineNativeAuditFields": {
                "target_database_principal_id": 0,
                "target_server_principal_id": 0,
                "target_database_principal_name": "",
                "server_principal_id": 2,
                "user_defined_information": "",
                "response_rows": 0,
                "database_principal_name": "dbo",
                "target_server_principal_name": "",
                "schema_name": "dbo",
                "is_column_permission": true,
                "object_id": 581577110,
                "server_instance_name": "EC2AMAZ-NFUJJNO",
                "target_server_principal_sid": null,
                "additional_information": "",
                "duration_milliseconds": 0,
                "permission_bitmask": "0x00000000000000000000000000000001",
                "data_sensitivity_information": "",
                "session_server_principal_name": "test",
                "connection_id": "AD3A5084-FB83-45C1-8334-E923459A8109",
                "audit_schema_version": 1,
                "database_principal_id": 1,
                "server_principal_sid": "0x010500000000000515000000bdc2795e2d0717901ba6998cf4010000",
                "user_defined_event_id": 0,
                "host_name": "EC2AMAZ-NFUJJNO"
            }
        }
    ]
}
```

## DatabaseActivityMonitoringRecords JSON 객체
<a name="DBActivityStreams.AuditLog.DatabaseActivityMonitoringRecords"></a>

데이터베이스 작업 이벤트 레코드는 다음 정보가 포함된 JSON 객체에 있습니다.


****  

| JSON 필드 | 데이터 형식 | 설명 | 
| --- | --- | --- | 
|  `type`  | string |  JSON 레코드 형식입니다. 이 값은 `DatabaseActivityMonitoringRecords`입니다.  | 
| version | string |  데이터베이스 작업 모니터링 레코드의 버전입니다. Oracle DB는 버전 1.3을 사용하고 SQL Server는 버전 1.4를 사용합니다. 이러한 엔진 버전에는 engineNativeAuditFields JSON 객체가 도입됩니다.  | 
|  [databaseActivityEvents](#DBActivityStreams.AuditLog.databaseActivityEvents)  | 문자열 |  작업 이벤트를 포함하는 JSON 객체입니다.  | 
| 키 | 문자열 | [databaseActivityEventList JSON 배열](DBActivityStreams.AuditLog.databaseActivityEventList.md)를 해독하는 데 사용되는 암호화 키  | 

## databaseActivityEvents JSON 객체
<a name="DBActivityStreams.AuditLog.databaseActivityEvents"></a>

`databaseActivityEvents` JSON 객체에는 다음과 같은 정보가 포함되어 있습니다.

### JSON 레코드의 최상위 필드
<a name="DBActivityStreams.AuditLog.topLevel"></a>

 감사 로그의 각 이벤트는 JSON 형식의 레코드 내에 래핑됩니다. 이 레코드에는 다음 필드가 포함되어 있습니다.

**type**  
 이 필드는 항상 값이 `DatabaseActivityMonitoringRecords`입니다.

**version**  
 이 필드는 데이터베이스 활동 스트림 데이터 프로토콜 또는 계약 버전을 나타냅니다. 이는 사용 가능한 필드를 정의합니다.

**databaseActivityEvents**  
 하나 이상의 활동 이벤트를 나타내는 암호화된 문자열입니다. base64 바이트 배열로 표현됩니다. 문자열을 해독하면 결과는 이 단원의 예제와 같이 필드가 있는 JSON 형식의 레코드입니다.

**키**  
 `databaseActivityEvents` 문자열을 암호화하는 데 사용되는 암호화된 데이터 키입니다. 이 키는 데이터베이스 활동 스트림을 시작할 때 제공한 AWS KMS key와(과) 동일합니다.

 다음 예제에서는 이 레코드의 형식을 보여줍니다.

```
{
  "type":"DatabaseActivityMonitoringRecords",
  "version":"1.3",
  "databaseActivityEvents":"encrypted audit records",
  "key":"encrypted key"
}
```

```
           "type":"DatabaseActivityMonitoringRecords",
           "version":"1.4",
           "databaseActivityEvents":"encrypted audit records",
           "key":"encrypted key"
```

`databaseActivityEvents` 필드의 내용을 해독하려면 다음 단계를 수행합니다.

1.  데이터베이스 활동 스트림을 시작할 때 제공한 키를 사용하여 `key` JSON 필드의 값을 복호화합니다. 이렇게 하면 데이터 암호화 키가 일반 텍스트로 반환됩니다.

1.  Base64로 `databaseActivityEvents` JSON 필드의 값을 디코딩하여 감사 페이로드의 암호화 텍스트를 이진 형식으로 가져옵니다.

1.  첫 번째 단계에서 디코딩한 데이터 암호화 키를 사용하여 이진 암호화 텍스트를 해독합니다.

1.  해독된 페이로드의 압축을 풉니다.
   +  암호화된 페이로드가 `databaseActivityEvents` 필드에 있습니다.
   +  `databaseActivityEventList` 필드에는 감사 레코드 배열이 포함되어 있습니다. 배열의 `type` 필드는 `record` 또는 `heartbeat`일 수 있습니다.

감사 로그 활동 이벤트 레코드는 다음 정보가 포함된 JSON 객체입니다.


****  

| JSON 필드 | 데이터 형식 | 설명 | 
| --- | --- | --- | 
|  `type`  | string |  JSON 레코드 형식입니다. 이 값은 `DatabaseActivityMonitoringRecord`입니다.  | 
| instanceId | string | DB 인스턴스 리소스 식별자입니다. DB 인스턴스 속성 DbiResourceId에 해당합니다. | 
|  [databaseActivityEventList JSON 배열](DBActivityStreams.AuditLog.databaseActivityEventList.md)   | string |  활동 감사 레코드 또는 하트비트 메시지의 배열입니다.  | 

# 데이터베이스 활동 스트림에 대한 databaseActivityEventList JSON 배열
<a name="DBActivityStreams.AuditLog.databaseActivityEventList"></a>

감사 로그 페이로드는 암호화된 `databaseActivityEventList` JSON 배열입니다. 다음 표에는 감사 로그의 복호화된 `DatabaseActivityEventList` 배열에 있는 각 활동 이벤트의 필드가 알파벳 순으로 나열되어 있습니다. 

Oracle 데이터베이스에서 통합 감사가 활성화된 경우 이 새 감사 추적에 감사 레코드가 채워집니다. `UNIFIED_AUDIT_TRAIL` 보기는 감사 추적에서 감사 레코드를 검색하여 감사 레코드를 테이블 형식으로 표시합니다. 데이터베이스 활동 스트림을 시작하려면 `UNIFIED_AUDIT_TRAIL`의 열이 `databaseActivityEventList` 배열의 필드에 매핑됩니다.

**중요**  
이벤트 구조는 변경될 수 있습니다. Amazon RDS는 향후 활동 이벤트에 새 필드를 추가할 수 있습니다. JSON 데이터를 구문 분석하는 애플리케이션에서 코드는 알 수 없는 필드 이름에 대해 무시할 수 있는지 또는 적절한 작업을 수행할 수 있는지 확인합니다.

## Amazon RDS for Oracle에 대한 databaseActivityEventList 필드
<a name="DBActivityStreams.AuditLog.databaseActivityEventList.ro"></a>

Amazon RDS for Oracle에 대한 `databaseActivityEventList` 필드는 다음과 같습니다.


| 필드 | 데이터 형식 | 소스 | 설명 | 
| --- | --- | --- | --- | 
|  `class`  |  string  |  `UNIFIED_AUDIT_TRAIL`의 `AUDIT_TYPE` 열  |  활동 이벤트의 클래스입니다. 이는 `UNIFIED_AUDIT_TRAIL` 보기의 `AUDIT_TYPE` 열에 해당합니다. Amazon RDS for Oracle에 대한 유효한 값은 다음과 같습니다. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/AmazonRDS/latest/UserGuide/DBActivityStreams.AuditLog.databaseActivityEventList.html) 자세한 내용은 Oracle 문서의 [UNIFIED\$1AUDIT\$1TRAIL](https://docs.oracle.com/en/database/oracle/oracle-database/19/refrn/UNIFIED_AUDIT_TRAIL.html#GUID-B7CE1C02-2FD4-47D6-80AA-CF74A60CDD1D)을 참조하세요.  | 
|  `clientApplication`  |  string  |  `CLIENT_PROGRAM_NAME`의 `UNIFIED_AUDIT_TRAIL`  |  클라이언트가 보고한 대로 클라이언트가 연결에 사용한 애플리케이션입니다. 클라이언트는 이 정보를 제공할 필요가 없으므로 값은 null일 수 있습니다. 샘플 값은 `JDBC Thin Client`입니다.  | 
|  `command`  |  string  |  `UNIFIED_AUDIT_TRAIL`의 `ACTION_NAME` 열  |  사용자가 실행한 작업 이름입니다. 전체 작업을 이해하려면 명령 이름과 `AUDIT_TYPE` 값을 숙지합니다. 샘플 값은 `ALTER DATABASE`입니다.  | 
|  `commandText`  |  string  |  `UNIFIED_AUDIT_TRAIL`의 `SQL_TEXT` 열  |  이벤트와 연결된 SQL 문 샘플 값은 `ALTER DATABASE BEGIN BACKUP`입니다.  | 
|  `databaseName`  |  string  |  `V$DATABASE`의 `NAME` 열  |  데이터베이스의 이름입니다.  | 
|  `dbid`  |  숫자  |  `UNIFIED_AUDIT_TRAIL`의 `DBID` 열  |  데이터베이스의 숫자 식별자입니다. 샘플 값은 `1559204751`입니다.  | 
|  `dbProtocol`  |  string  |  해당 사항 없음  |  데이터베이스 프로토콜. 이 베타에서 값은 `oracle`입니다.  | 
|  `dbUserName`  |  string  |  `UNIFIED_AUDIT_TRAIL`의 `DBUSERNAME` 열  |  작업이 감사된 데이터베이스 사용자의 이름입니다. 샘플 값은 `RDSADMIN`입니다.  | 
|  `endTime`  |  string  |  해당 사항 없음  |  이 필드는 RDS for Oracle에 사용되지 않으며 항상 null입니다.  | 
|  `engineNativeAuditFields`  |  객체  |  `UNIFIED_AUDIT_TRAIL`  |  기본적으로 이 객체는 비어 있습니다. `--engine-native-audit-fields-included` 옵션을 사용하여 활동 스트림을 시작하면 이 객체에는 다음과 같은 열과 값이 포함됩니다. <pre>ADDITIONAL_INFO<br />APPLICATION_CONTEXTS<br />AUDIT_OPTION<br />AUTHENTICATION_TYPE<br />CLIENT_IDENTIFIER<br />CURRENT_USER<br />DBLINK_INFO<br />DBPROXY_USERNAME<br />DIRECT_PATH_NUM_COLUMNS_LOADED<br />DP_BOOLEAN_PARAMETERS1<br />DP_TEXT_PARAMETERS1<br />DV_ACTION_CODE<br />DV_ACTION_NAME<br />DV_ACTION_OBJECT_NAME<br />DV_COMMENT<br />DV_EXTENDED_ACTION_CODE<br />DV_FACTOR_CONTEXT<br />DV_GRANTEE<br />DV_OBJECT_STATUS<br />DV_RETURN_CODE<br />DV_RULE_SET_NAME<br />ENTRY_ID<br />EXCLUDED_OBJECT<br />EXCLUDED_SCHEMA<br />EXCLUDED_USER<br />EXECUTION_ID<br />EXTERNAL_USERID<br />FGA_POLICY_NAME<br />GLOBAL_USERID<br />INSTANCE_ID<br />KSACL_SERVICE_NAME<br />KSACL_SOURCE_LOCATION<br />KSACL_USER_NAME<br />NEW_NAME<br />NEW_SCHEMA<br />OBJECT_EDITION<br />OBJECT_PRIVILEGES<br />OLS_GRANTEE<br />OLS_LABEL_COMPONENT_NAME<br />OLS_LABEL_COMPONENT_TYPE<br />OLS_MAX_READ_LABEL<br />OLS_MAX_WRITE_LABEL<br />OLS_MIN_WRITE_LABEL<br />OLS_NEW_VALUE<br />OLS_OLD_VALUE<br />OLS_PARENT_GROUP_NAME<br />OLS_POLICY_NAME<br />OLS_PRIVILEGES_GRANTED<br />OLS_PRIVILEGES_USED<br />OLS_PROGRAM_UNIT_NAME<br />OLS_STRING_LABEL<br />OS_USERNAME<br />PROTOCOL_ACTION_NAME<br />PROTOCOL_MESSAGE<br />PROTOCOL_RETURN_CODE<br />PROTOCOL_SESSION_ID<br />PROTOCOL_USERHOST<br />PROXY_SESSIONID<br />RLS_INFO<br />RMAN_DEVICE_TYPE<br />RMAN_OBJECT_TYPE<br />RMAN_OPERATION<br />RMAN_SESSION_RECID<br />RMAN_SESSION_STAMP<br />ROLE<br />SCN<br />SYSTEM_PRIVILEGE<br />SYSTEM_PRIVILEGE_USED<br />TARGET_USER<br />TERMINAL<br />UNIFIED_AUDIT_POLICIES<br />USERHOST<br />XS_CALLBACK_EVENT_TYPE<br />XS_COOKIE<br />XS_DATASEC_POLICY_NAME<br />XS_ENABLED_ROLE<br />XS_ENTITY_TYPE<br />XS_INACTIVITY_TIMEOUT<br />XS_NS_ATTRIBUTE<br />XS_NS_ATTRIBUTE_NEW_VAL<br />XS_NS_ATTRIBUTE_OLD_VAL<br />XS_NS_NAME<br />XS_PACKAGE_NAME<br />XS_PROCEDURE_NAME<br />XS_PROXY_USER_NAME<br />XS_SCHEMA_NAME<br />XS_SESSIONID<br />XS_TARGET_PRINCIPAL_NAME<br />XS_USER_NAME</pre> 자세한 내용은 Oracle 데이터베이스 문서의 [UNIFIED\$1AUDIT\$1TRAIL](https://docs.oracle.com/database/121/REFRN/GUID-B7CE1C02-2FD4-47D6-80AA-CF74A60CDD1D.htm#REFRN29162)을 참조하세요.  | 
|  `errorMessage`  |  string  |  해당 사항 없음  |  이 필드는 RDS for Oracle에 사용되지 않으며 항상 null입니다.  | 
|  `exitCode`  |  숫자  |  `UNIFIED_AUDIT_TRAIL`의 `RETURN_CODE` 열  |  작업으로 인해 생성된 Oracle 데이터베이스 오류 코드입니다. 작업이 성공한 경우 값은 `0`입니다.  | 
|  `logTime`  |  string  |  `UNIFIED_AUDIT_TRAIL`의 `EVENT_TIMESTAMP_UTC` 열  |  감사 추적 항목 작성에 대한 타임스탬프입니다. 샘플 값은 `2020-11-27 06:56:14.981404`입니다.  | 
|  `netProtocol`  |  string  |  `UNIFIED_AUDIT_TRAIL`의 `AUTHENTICATION_TYPE` 열  |  네트워크 통신 프로토콜. 샘플 값은 `TCP`입니다.  | 
|  `objectName`  |  string  |  `UNIFIED_AUDIT_TRAIL`의 `OBJECT_NAME` 열  |  작업의 영향을 받는 객체의 이름입니다. 샘플 값은 `employees`입니다.  | 
|  `objectType`  |  string  |  `UNIFIED_AUDIT_TRAIL`의 `OBJECT_SCHEMA` 열  |  작업의 영향을 받는 객체의 스키마 이름입니다. 샘플 값은 `hr`입니다.  | 
|  `paramList`  |  목록  |  `UNIFIED_AUDIT_TRAIL`의 `SQL_BINDS` 열  |  해당되는 경우 `SQL_TEXT`와 관련된 경우 바인딩 변수 목록입니다. 샘플 값은 `parameter_1,parameter_2`입니다.  | 
|  `pid`  |  숫자  |  `UNIFIED_AUDIT_TRAIL`의 `OS_PROCESS` 열  |  Oracle 데이터베이스 프로세스의 운영 체제 프로세스 식별자입니다. 샘플 값은 `22396`입니다.  | 
|  `remoteHost`  |  string  |  `UNIFIED_AUDIT_TRAIL`의 `AUTHENTICATION_TYPE` 열  |  세션을 생성한 호스트의 클라이언트 IP 주소 또는 클라이언트 이름입니다. 샘플 값은 `123.456.789.123`입니다.  | 
|  `remotePort`  |  string  |  `UNIFIED_AUDIT_TRAIL`의 `AUTHENTICATION_TYPE` 열  |  클라이언트 포트 번호. Oracle 데이터베이스 환경의 일반적인 값은 `1521`입니다.  | 
|  `rowCount`  |  숫자  |  해당 사항 없음  |  이 필드는 RDS for Oracle에 사용되지 않으며 항상 null입니다.  | 
|  `serverHost`  |  string  |  데이터베이스 호스트  |  데이터베이스 서버 호스트 IP 주소. 샘플 값은 `123.456.789.123`입니다.  | 
|  `serverType`  |  string  |  해당 사항 없음  |  데이터베이스 서버 유형입니다. 이 값은 항상 `ORACLE`입니다.  | 
|  `serverVersion`  |  string  |  데이터베이스 호스트  |  Amazon RDS for Oracle 버전, RU(릴리스 업데이트) 및 RUR(릴리스 업데이트 버전) 샘플 값은 `19.0.0.0.ru-2020-01.rur-2020-01.r1.EE.3`입니다.  | 
|  `serviceName`  |  string  |  데이터베이스 호스트  |  서비스의 이름입니다. 샘플 값은 `oracle-ee`입니다.  | 
|  `sessionId`  |  숫자  |  `UNIFIED_AUDIT_TRAIL`의 `SESSIONID` 열  |  감사의 세션 식별자입니다. 예를 들면, `1894327130`입니다.  | 
|  `startTime`  |  string  |  해당 사항 없음  |  이 필드는 RDS for Oracle에 사용되지 않으며 항상 null입니다.  | 
|  `statementId`  |  숫자  |  `UNIFIED_AUDIT_TRAIL`의 `STATEMENT_ID` 열  |  각 문 실행에 대한 숫자 ID입니다. 문은 많은 작업을 일으킬 수 있습니다. 샘플 값은 `142197`입니다.  | 
|  `substatementId`  |  해당 사항 없음  |  해당 사항 없음  |  이 필드는 RDS for Oracle에 사용되지 않으며 항상 null입니다.  | 
|  `transactionId`  |  string  |  `UNIFIED_AUDIT_TRAIL`의 `TRANSACTION_ID` 열  |  객체가 수정된 트랜잭션의 식별자입니다. 샘플 값은 `02000800D5030000`입니다.  | 

## Amazon RDS for SQL Server에 대한 databaseActivityEventList 필드
<a name="DBActivityStreams.AuditLog.databaseActivityEventList.rss"></a>

Amazon RDS for SQL Server에 대한 `databaseActivityEventList` 필드는 다음과 같습니다.


| 필드 | 데이터 형식 | 소스 | 설명 | 
| --- | --- | --- | --- | 
|  `class`  |  문자열  |  ` sys.fn_get_audit_file.class_type`이 `sys.dm_audit_class_type_map.class_type_desc`에 매핑됨  |  활동 이벤트의 클래스입니다. 자세한 내용은 Microsoft 설명서의 [SQL Server Audit(데이터베이스 엔진)](https://learn.microsoft.com/en-us/sql/relational-databases/security/auditing/sql-server-audit-database-engine?view=sql-server-ver16)를 참조하세요.  | 
|  `clientApplication`  |  문자열  |  `sys.fn_get_audit_file.application_name`  |  클라이언트가 보고한 대로 클라이언트가 연결하는 애플리케이션(SQL Server 버전 14 이상). SQL Server 버전 13에서는 이 필드가 null입니다.  | 
|  `command`  |  문자열  |  `sys.fn_get_audit_file.action_id`이 `sys.dm_audit_actions.name`에 매핑됨  |  SQL 문의 일반 범주입니다. 이 필드의 값은 클래스의 값에 따라 달라집니다.  | 
|  `commandText`  |  문자열  |  `sys.fn_get_audit_file.statement`  |  이 필드는 SQL 문을 나타냅니다.  | 
|  `databaseName`  |  문자열  |  `sys.fn_get_audit_file.database_name`  |  데이터베이스 이름  | 
|  `dbProtocol`  |  문자열  |  해당 사항 없음  |  데이터베이스 프로토콜. 이 값은 `SQLSERVER`입니다.  | 
|  `dbUserName`  |  문자열  |  `sys.fn_get_audit_file.server_principal_name`  |  클라이언트 인증을 위한 데이터베이스 사용자.  | 
|  `endTime`  |  문자열  |  해당 사항 없음  |  이 필드는 Amazon RDS for SQL Server에서 사용되지 않으며 값은 null입니다.  | 
|  `engineNativeAuditFields`  |  객체  |  `sys.fn_get_audit_file`에서 이 열에 나열되지 않은 각 필드.  |  기본적으로 이 객체는 비어 있습니다. `--engine-native-audit-fields-included` 옵션을 사용하여 활동 스트림을 시작하면 이 객체에는 이 JSON 맵에서 반환되지 않는 다른 네이티브 엔진 감사 필드가 포함됩니다.  | 
|  `errorMessage`  |  문자열  |  해당 사항 없음  |  이 필드는 Amazon RDS for SQL Server에서 사용되지 않으며 값은 null입니다.  | 
|  `exitCode`  |  정수  |  `sys.fn_get_audit_file.succeeded`  |  이벤트를 시작한 작업의 성공 여부를 나타냅니다. 이 필드는 null일 수 없습니다. 로그인 이벤트를 제외한 모든 이벤트의 경우 이 필드는 권한 검사의 성공 또는 실패 여부를 보고하지만 작업의 성공 또는 실패 여부는 보고하지 않습니다. 값은 다음과 같습니다. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/AmazonRDS/latest/UserGuide/DBActivityStreams.AuditLog.databaseActivityEventList.html)  | 
|  `logTime`  |  문자열  |  `sys.fn_get_audit_file.event_time`  |  SQL Server에서 기록되는 이벤트 타임스탬프입니다.  | 
|  `netProtocol`  |  문자열  |  해당 사항 없음  |  이 필드는 Amazon RDS for SQL Server에서 사용되지 않으며 값은 null입니다.  | 
|  `objectName`  |  문자열  |  `sys.fn_get_audit_file.object_name`  |  SQL 문이 하나의 객체에서 작동하는 경우 데이터베이스 객체의 이름.  | 
|  `objectType`  |  문자열  |  `sys.fn_get_audit_file.class_type`이 `sys.dm_audit_class_type_map.class_type_desc`에 매핑됨  |  SQL 문이 하나의 객체 유형에서 작동하는 경우 데이터베이스 객체의 유형.  | 
|  `paramList`  |  문자열  |  해당 사항 없음  |  이 필드는 Amazon RDS for SQL Server에서 사용되지 않으며 값은 null입니다.  | 
|  `pid`  |  정수  |  N/A  |  이 필드는 Amazon RDS for SQL Server에서 사용되지 않으며 값은 null입니다.  | 
|  `remoteHost`  |  문자열  |  `sys.fn_get_audit_file.client_ip`  |  SQL 문을 실행한 클라이언트의 IP 주소 또는 호스트 이름(SQL Server 버전 14 이상). SQL Server 버전 13에서는 이 필드가 null입니다.  | 
|  `remotePort`  |  정수  |  N/A  |  이 필드는 Amazon RDS for SQL Server에서 사용되지 않으며 값은 null입니다.  | 
|  `rowCount`  |  정수  |  `sys.fn_get_audit_file.affected_rows`  |  SQL 문에 의해 영향을 받는 테이블 행 수(SQL Server 버전 14 이상). 이 필드는 SQL Server 버전 13에 있습니다.  | 
|  `serverHost`  |  문자열  |  데이터베이스 호스트  |  호스트 데이터베이스 서버의 IP 주소.  | 
|  `serverType`  |  문자열  |  해당 사항 없음  |  데이터베이스 서버 유형입니다. 이 값은 `SQLSERVER`입니다.  | 
|  `serverVersion`  |  문자열  |  데이터베이스 호스트  |  데이터베이스 서버 버전(예: SQL Server 2017의 경우 15.00.4073.23.v1.R1)  | 
|  `serviceName`  |  문자열  |  데이터베이스 호스트  |  서비스의 이름입니다. 예시 값은 `sqlserver-ee`입니다.  | 
|  `sessionId`  |  정수  |  `sys.fn_get_audit_file.session_id`  |  세션의 고유 식별자.  | 
|  `startTime`  |  문자열  |  해당 사항 없음  |  이 필드는 Amazon RDS for SQL Server에서 사용되지 않으며 값은 null입니다.  | 
|  `statementId`  |  문자열  |  `sys.fn_get_audit_file.sequence_group_id`  |  클라이언트의 SQL 문에 대한 고유 식별자. 생성되는 이벤트마다 식별자가 다릅니다. 샘플 값은 `0x38eaf4156267184094bb82071aaab644`입니다.  | 
|  `substatementId`  |  정수  |  `sys.fn_get_audit_file.sequence_number`  |  문의 시퀀스 번호를 결정하는 식별자. 이 식별자는 대용량 레코드를 여러 레코드로 분할할 때 유용합니다.  | 
|  `transactionId`  |  정수  |  `sys.fn_get_audit_file.transaction_id`  |  트랜잭션의 식별자. 활성 트랜잭션이 없으면 값은 0입니다.  | 
|  `type`  |  문자열  |  데이터베이스 활동 스트림 생성됨  |  이벤트의 유형입니다. 값은 `record` 또는 `heartbeat`입니다.  | 

# AWS SDK를 사용하여 데이터베이스 활동 스트림 처리
<a name="DBActivityStreams.CodeExample"></a>

AWS SDK를 사용하여 프로그래밍 방식으로 활동 스트림을 처리할 수 ​​있습니다. 다음은 제대로 작동하는 Java 및 Python 예시로, 인스턴스 기반 활성화를 위해 데이터베이스 활동 스트림을 사용하는 방법을 보여줍니다.

------
#### [ Java ]

```
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Security;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.zip.GZIPInputStream;

import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;

import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.encryptionsdk.AwsCrypto;
import com.amazonaws.encryptionsdk.CryptoInputStream;
import com.amazonaws.encryptionsdk.jce.JceMasterKey;
import com.amazonaws.services.kinesis.clientlibrary.exceptions.InvalidStateException;
import com.amazonaws.services.kinesis.clientlibrary.exceptions.ShutdownException;
import com.amazonaws.services.kinesis.clientlibrary.exceptions.ThrottlingException;
import com.amazonaws.services.kinesis.clientlibrary.interfaces.IRecordProcessor;
import com.amazonaws.services.kinesis.clientlibrary.interfaces.IRecordProcessorCheckpointer;
import com.amazonaws.services.kinesis.clientlibrary.interfaces.IRecordProcessorFactory;
import com.amazonaws.services.kinesis.clientlibrary.lib.worker.InitialPositionInStream;
import com.amazonaws.services.kinesis.clientlibrary.lib.worker.KinesisClientLibConfiguration;
import com.amazonaws.services.kinesis.clientlibrary.lib.worker.ShutdownReason;
import com.amazonaws.services.kinesis.clientlibrary.lib.worker.Worker;
import com.amazonaws.services.kinesis.clientlibrary.lib.worker.Worker.Builder;
import com.amazonaws.services.kinesis.model.Record;
import com.amazonaws.services.kms.AWSKMS;
import com.amazonaws.services.kms.AWSKMSClientBuilder;
import com.amazonaws.services.kms.model.DecryptRequest;
import com.amazonaws.services.kms.model.DecryptResult;
import com.amazonaws.util.Base64;
import com.amazonaws.util.IOUtils;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.SerializedName;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class DemoConsumer {

    private static final String STREAM_NAME = "aws-rds-das-[instance-external-resource-id]"; // aws-rds-das-db-ABCD123456
    private static final String APPLICATION_NAME = "AnyApplication"; //unique application name for dynamo table generation that holds kinesis shard tracking
    private static final String AWS_ACCESS_KEY = "[AWS_ACCESS_KEY_TO_ACCESS_KINESIS]";
    private static final String AWS_SECRET_KEY = "[AWS_SECRET_KEY_TO_ACCESS_KINESIS]";
    private static final String RESOURCE_ID = "[external-resource-id]"; // db-ABCD123456
    private static final String REGION_NAME = "[region-name]"; //us-east-1, us-east-2...
    private static final BasicAWSCredentials CREDENTIALS = new BasicAWSCredentials(AWS_ACCESS_KEY, AWS_SECRET_KEY);
    private static final AWSStaticCredentialsProvider CREDENTIALS_PROVIDER = new AWSStaticCredentialsProvider(CREDENTIALS);

    private static final AwsCrypto CRYPTO = new AwsCrypto();
    private static final AWSKMS KMS = AWSKMSClientBuilder.standard()
            .withRegion(REGION_NAME)
            .withCredentials(CREDENTIALS_PROVIDER).build();

    class Activity {
        String type;
        String version;
        String databaseActivityEvents;
        String key;
    }

    class ActivityEvent {
        @SerializedName("class") String _class;
        String clientApplication;
        String command;
        String commandText;
        String databaseName;
        String dbProtocol;
        String dbUserName;
        String endTime;
        String errorMessage;
        String exitCode;
        String logTime;
        String netProtocol;
        String objectName;
        String objectType;
        List<String> paramList;
        String pid;
        String remoteHost;
        String remotePort;
        String rowCount;
        String serverHost;
        String serverType;
        String serverVersion;
        String serviceName;
        String sessionId;
        String startTime;
        String statementId;
        String substatementId;
        String transactionId;
        String type;
    }

    class ActivityRecords {
        String type;
        String clusterId; // note that clusterId will contain an empty string on RDS Oracle and RDS SQL Server
        String instanceId;
        List<ActivityEvent> databaseActivityEventList;
    }

    static class RecordProcessorFactory implements IRecordProcessorFactory {
        @Override
        public IRecordProcessor createProcessor() {
            return new RecordProcessor();
        }
    }

    static class RecordProcessor implements IRecordProcessor {

        private static final long BACKOFF_TIME_IN_MILLIS = 3000L;
        private static final int PROCESSING_RETRIES_MAX = 10;
        private static final long CHECKPOINT_INTERVAL_MILLIS = 60000L;
        private static final Gson GSON = new GsonBuilder().serializeNulls().create();

        private static final Cipher CIPHER;
        static {
            Security.insertProviderAt(new BouncyCastleProvider(), 1);
            try {
                CIPHER = Cipher.getInstance("AES/GCM/NoPadding", "BC");
            } catch (NoSuchAlgorithmException | NoSuchPaddingException | NoSuchProviderException e) {
                throw new ExceptionInInitializerError(e);
            }
        }

        private long nextCheckpointTimeInMillis;

        @Override
        public void initialize(String shardId) {
        }

        @Override
        public void processRecords(final List<Record> records, final IRecordProcessorCheckpointer checkpointer) {
            for (final Record record : records) {
                processSingleBlob(record.getData());
            }

            if (System.currentTimeMillis() > nextCheckpointTimeInMillis) {
                checkpoint(checkpointer);
                nextCheckpointTimeInMillis = System.currentTimeMillis() + CHECKPOINT_INTERVAL_MILLIS;
            }
        }

        @Override
        public void shutdown(IRecordProcessorCheckpointer checkpointer, ShutdownReason reason) {
            if (reason == ShutdownReason.TERMINATE) {
                checkpoint(checkpointer);
            }
        }

        private void processSingleBlob(final ByteBuffer bytes) {
            try {
                // JSON $Activity
                final Activity activity = GSON.fromJson(new String(bytes.array(), StandardCharsets.UTF_8), Activity.class);

                // Base64.Decode
                final byte[] decoded = Base64.decode(activity.databaseActivityEvents);
                final byte[] decodedDataKey = Base64.decode(activity.key);

                Map<String, String> context = new HashMap<>();
                context.put("aws:rds:db-id", RESOURCE_ID);

                // Decrypt
                final DecryptRequest decryptRequest = new DecryptRequest()
                        .withCiphertextBlob(ByteBuffer.wrap(decodedDataKey)).withEncryptionContext(context);
                final DecryptResult decryptResult = KMS.decrypt(decryptRequest);
                final byte[] decrypted = decrypt(decoded, getByteArray(decryptResult.getPlaintext()));

                // GZip Decompress
                final byte[] decompressed = decompress(decrypted);
                // JSON $ActivityRecords
                final ActivityRecords activityRecords = GSON.fromJson(new String(decompressed, StandardCharsets.UTF_8), ActivityRecords.class);

                // Iterate throught $ActivityEvents
                for (final ActivityEvent event : activityRecords.databaseActivityEventList) {
                    System.out.println(GSON.toJson(event));
                }
            } catch (Exception e) {
                // Handle error.
                e.printStackTrace();
            }
        }

        private static byte[] decompress(final byte[] src) throws IOException {
            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(src);
            GZIPInputStream gzipInputStream = new GZIPInputStream(byteArrayInputStream);
            return IOUtils.toByteArray(gzipInputStream);
        }

        private void checkpoint(IRecordProcessorCheckpointer checkpointer) {
            for (int i = 0; i < PROCESSING_RETRIES_MAX; i++) {
                try {
                    checkpointer.checkpoint();
                    break;
                } catch (ShutdownException se) {
                    // Ignore checkpoint if the processor instance has been shutdown (fail over).
                    System.out.println("Caught shutdown exception, skipping checkpoint." + se);
                    break;
                } catch (ThrottlingException e) {
                    // Backoff and re-attempt checkpoint upon transient failures
                    if (i >= (PROCESSING_RETRIES_MAX - 1)) {
                        System.out.println("Checkpoint failed after " + (i + 1) + "attempts." + e);
                        break;
                    } else {
                        System.out.println("Transient issue when checkpointing - attempt " + (i + 1) + " of " + PROCESSING_RETRIES_MAX + e);
                    }
                } catch (InvalidStateException e) {
                    // This indicates an issue with the DynamoDB table (check for table, provisioned IOPS).
                    System.out.println("Cannot save checkpoint to the DynamoDB table used by the Amazon Kinesis Client Library." + e);
                    break;
                }
                try {
                    Thread.sleep(BACKOFF_TIME_IN_MILLIS);
                } catch (InterruptedException e) {
                    System.out.println("Interrupted sleep" + e);
                }
            }
        }
    }

    private static byte[] decrypt(final byte[] decoded, final byte[] decodedDataKey) throws IOException {
        // Create a JCE master key provider using the random key and an AES-GCM encryption algorithm
        final JceMasterKey masterKey = JceMasterKey.getInstance(new SecretKeySpec(decodedDataKey, "AES"),
                "BC", "DataKey", "AES/GCM/NoPadding");
        try (final CryptoInputStream<JceMasterKey> decryptingStream = CRYPTO.createDecryptingStream(masterKey, new ByteArrayInputStream(decoded));
             final ByteArrayOutputStream out = new ByteArrayOutputStream()) {
            IOUtils.copy(decryptingStream, out);
            return out.toByteArray();
        }
    }

    public static void main(String[] args) throws Exception {
        final String workerId = InetAddress.getLocalHost().getCanonicalHostName() + ":" + UUID.randomUUID();
        final KinesisClientLibConfiguration kinesisClientLibConfiguration =
                new KinesisClientLibConfiguration(APPLICATION_NAME, STREAM_NAME, CREDENTIALS_PROVIDER, workerId);
        kinesisClientLibConfiguration.withInitialPositionInStream(InitialPositionInStream.LATEST);
        kinesisClientLibConfiguration.withRegionName(REGION_NAME);
        final Worker worker = new Builder()
                .recordProcessorFactory(new RecordProcessorFactory())
                .config(kinesisClientLibConfiguration)
                .build();

        System.out.printf("Running %s to process stream %s as worker %s...\n", APPLICATION_NAME, STREAM_NAME, workerId);

        try {
            worker.run();
        } catch (Throwable t) {
            System.err.println("Caught throwable while processing data.");
            t.printStackTrace();
            System.exit(1);
        }
        System.exit(0);
    }

    private static byte[] getByteArray(final ByteBuffer b) {
        byte[] byteArray = new byte[b.remaining()];
        b.get(byteArray);
        return byteArray;
    }
}
```

------
#### [ Python ]

```
import base64
import json
import zlib
import aws_encryption_sdk
from aws_encryption_sdk import CommitmentPolicy
from aws_encryption_sdk.internal.crypto import WrappingKey
from aws_encryption_sdk.key_providers.raw import RawMasterKeyProvider
from aws_encryption_sdk.identifiers import WrappingAlgorithm, EncryptionKeyType
import boto3

REGION_NAME = '<region>'                    # us-east-1
RESOURCE_ID = '<external-resource-id>'      # db-ABCD123456
STREAM_NAME = 'aws-rds-das-' + RESOURCE_ID  # aws-rds-das-db-ABCD123456

enc_client = aws_encryption_sdk.EncryptionSDKClient(commitment_policy=CommitmentPolicy.FORBID_ENCRYPT_ALLOW_DECRYPT)

class MyRawMasterKeyProvider(RawMasterKeyProvider):
    provider_id = "BC"

    def __new__(cls, *args, **kwargs):
        obj = super(RawMasterKeyProvider, cls).__new__(cls)
        return obj

    def __init__(self, plain_key):
        RawMasterKeyProvider.__init__(self)
        self.wrapping_key = WrappingKey(wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING,
                                        wrapping_key=plain_key, wrapping_key_type=EncryptionKeyType.SYMMETRIC)

    def _get_raw_key(self, key_id):
        return self.wrapping_key


def decrypt_payload(payload, data_key):
    my_key_provider = MyRawMasterKeyProvider(data_key)
    my_key_provider.add_master_key("DataKey")
    decrypted_plaintext, header = enc_client.decrypt(
        source=payload,
        materials_manager=aws_encryption_sdk.materials_managers.default.DefaultCryptoMaterialsManager(master_key_provider=my_key_provider))
    return decrypted_plaintext


def decrypt_decompress(payload, key):
    decrypted = decrypt_payload(payload, key)
    return zlib.decompress(decrypted, zlib.MAX_WBITS + 16)


def main():
    session = boto3.session.Session()
    kms = session.client('kms', region_name=REGION_NAME)
    kinesis = session.client('kinesis', region_name=REGION_NAME)

    response = kinesis.describe_stream(StreamName=STREAM_NAME)
    shard_iters = []
    for shard in response['StreamDescription']['Shards']:
        shard_iter_response = kinesis.get_shard_iterator(StreamName=STREAM_NAME, ShardId=shard['ShardId'],
                                                         ShardIteratorType='LATEST')
        shard_iters.append(shard_iter_response['ShardIterator'])

    while len(shard_iters) > 0:
        next_shard_iters = []
        for shard_iter in shard_iters:
            response = kinesis.get_records(ShardIterator=shard_iter, Limit=10000)
            for record in response['Records']:
                record_data = record['Data']
                record_data = json.loads(record_data)
                payload_decoded = base64.b64decode(record_data['databaseActivityEvents'])
                data_key_decoded = base64.b64decode(record_data['key'])
                data_key_decrypt_result = kms.decrypt(CiphertextBlob=data_key_decoded,
                                                      EncryptionContext={'aws:rds:db-id': RESOURCE_ID})
                print (decrypt_decompress(payload_decoded, data_key_decrypt_result['Plaintext']))
            if 'NextShardIterator' in response:
                next_shard_iters.append(response['NextShardIterator'])
        shard_iters = next_shard_iters


if __name__ == '__main__':
    main()
```

------