1. 개요
django에서 ELK로 로깅을 남길 때 request JSON body 내의 데이터에서 불필요한 데이터가 들어갈 경우가 있습니다. 불필요한 데이터의 예시는 고객정보, 사진정보, 민감데이터 등의 다양한 데이터가 있습니다. 또한 데이터의 크기가 너무 크기 때문에 용량 문제로 에러가 발생할 수 있습니다. 이러한 이슈를 해결하기 위해서는 Django에서 ELK로 로그 데이터를 넘길 때 특정 부분을 수정해주는 방법을 고려하면 좋습니다.
불필요한 데이터
•
고객정보(평문, 암호문 등)
•
사진정보(평문, 암호문, 마스킹된 평문 등)
용량 문제로 발생하는 이슈
용량이 너무 크게 되면 event exceeded the permitted size 에러가 발생합니다.
Failed to submit message: 'HTTP 400: {"accepted":3,"errors":[{"message":"event exceeded the permitted size.","document":"{\\"transaction\\": {\\"id\\": \\"51ef4a9a32461bcb\\", \\"trace_id\\": \\"8b65f8f428211d0e9e7368ee2bac3f40\\", \\"name\\": \\"POST api.versioned.v1.kb.account.views.KBAccountDetailViewSet\\", \\"type\\": \\"request\\", \\"duration\\": 1966.8769729999997, \\"result\\": \\"HTTP 2xx\\", \\"timestamp\\": 1652245425453835, \\"sampled\\": true, \\"span_count\\": {\\"started\\": 3, \\"dropped\\": 0}, \\"context\\" ...
Bash
복사
2. Django - elasticapm
django에서 elk로 데이터를 넘길 때 elasticapm 라이브러리를 사용합니다. 해당 라이브러리를 사용할 때 request body 내의 특정 필드를 마스킹할 수 있도록 지원해주는 방법이 있습니다.
2.1 SANITIZE_FIELD_NAMES
elasticapm 내의 세팅으로 SANITIZE_FIELD_NAMES가 있습니다. 해당 필드에 대한 기본 정보는 다음과 같습니다.
default
BASE_SANITIZE_FIELD_NAMES = [
"authorization",
"password",
"secret",
"passwd",
"token",
"api_key",
"access_token",
"sessionid",
]
Python
복사
settings.py
# base.py 혹은 settings.py 내에 추가할 수 있음
ADITIONAL_SANITIZE_FIELD_NAMES = [
"front_image",
"encoded_image",
"license_no",
"customer_no",
"photo_info"
]
BASE_SANITIZE_FIELD_NAMES += ADITIONAL_SANITIZE_FIELD_NAMES
Python
복사
processors.py
elastic/processors.py 파일 내에 있는 함수 중 sanitize_http_request_body 함수에서 선언된 sanitize_field_names에 대한 내용을 확인하고 해당 필드 내용을 필터링합니다. 해당 함수는 불필요한 필드의 경우 body에서 제외하는 과정입니다.
단, 해당 함수에서는 JSON body의 데이터는 sanitize 할 수 없습니다.
# elastic.processor
@for_events(ERROR, TRANSACTION)
def sanitize_http_request_body(client, event):
"""
Sanitizes http request body. This only works if the request body
is a query-encoded string. Other types (e.g. JSON) are not handled by
this sanitizer.
:param client: an ElasticAPM client
:param event: a transaction or error event
:return: The modified event
"""
try:
body = force_text(event["context"]["request"]["body"], errors="replace")
except (KeyError, TypeError):
return event
if "=" in body:
sanitized_query_string = _sanitize_string(
body, "&", "=", sanitize_field_names=client.config.sanitize_field_names
)
event["context"]["request"]["body"] = sanitized_query_string
return event
Python
복사
2.2 Custom sanitize function
DRF에서 JSON body로 데이터를 넘겨주는 형태라면 커스텀 함수를 만들어 processors를 추가해주어야 합니다.
customize - processors.py
JSON body 데이터를 load하여 데이터를 컨트롤합니다. 필드를 삭제하는 것보다는 해당 필드 내의 데이터를 [REDACTED] 하는 방법으로 변경하는 코드입니다.
# elasticapm 5.x
# ./common/elasticapm/processors.py
import json
from elasticapm.utils.encoding import force_text
from elasticapm.processors import for_events
from elasticapm.conf.constants import ERROR, TRANSACTION
@for_events(ERROR, TRANSACTION)
def sanitize_http_request_json_body(client, event):
"""
Sanitizes http request body. This only works if the request body
is a query-encoded string. Other types (e.g. JSON) are not handled by
this sanitizer.
:param client: an ElasticAPM client
:param event: a transaction or error event
:return: The modified event
"""
try:
body = json.loads(force_text(event["context"]["request"]["body"], errors="replace"))
except (KeyError, TypeError):
return event
for field in client.config.sanitize_field_names:
if body.get(field):
body[field] = "[REDACTED]"
event["context"]["request"]["body"] = json.dumps(body)
return event
Python
복사
혹은 다음과 같이 사용할 수 있습니다.
# elasticapm 6.x
import json
from elasticapm.utils.encoding import force_text
from elasticapm.processors import for_events
from elasticapm.conf.constants import ERROR, TRANSACTION
@for_events(ERROR, TRANSACTION)
def sanitize_http_request_json_body(client, event):
"""
Sanitizes http request body.
This only works if the request body is JSON objects
:param client: an ElasticAPM client
:param event: a transaction or error event
:return: The modified event
"""
try:
body = json.loads(force_text(event["context"]["request"]["body"], errors="replace"))
event["context"]["request"]["body"] = json.dumps(
varmap(_sanitize, body, sanitize_field_names=client.config.sanitize_field_names)
)
except (KeyError, TypeError):
pass
Python
복사
customize - base.py
Django 관련하여 APM Agent 정보를 입력하고, 추가적으로 SANITIZE_FIELD_NAMES에 데이터를 추가해주어야 합니다. 또한 위에 선언한 processor를 선언해주어야 합니다.
# base.py 혹은 settings.py 내에 추가할 수 있음
ADITIONAL_SANITIZE_FIELD_NAMES = [
"front_image",
"encoded_image",
"license_no",
"customer_no",
"photo_info"
]
BASE_SANITIZE_FIELD_NAMES += ADITIONAL_SANITIZE_FIELD_NAMES
HARDCODED_PROCESSORS += ["common.elasticapm.processors.sanitize_http_request_json_body"]
Python
복사
3. Kibana
floatFirstTOC: right
YAML
복사
oopy