55 lines
2.2 KiB
Python
55 lines
2.2 KiB
Python
"""
|
|
GUARDiA ITSM — 자격증명 암호화 공통 유틸리티
|
|
|
|
외부 연동 자격증명(API 키·시크릿·토큰·SNMP 커뮤니티 문자열 등)을 DB에 평문으로
|
|
저장하지 않기 위한 AES-256-GCM 암호화/복호화 모듈. 여러 라우터(jira_sync·multicloud·
|
|
ncloud·public_api_hub·snmp_discovery·sso_provider·upstage_ocr 등)가 공유한다.
|
|
|
|
키 소스: GUARDIA_ENC_KEY 환경변수 (문자열을 UTF-8 인코딩 후 32바이트로 패딩/절단).
|
|
core/seed.py · routers/citizen_portal.py 와 동일한 컨벤션 — 운영 배포 시
|
|
반드시 32자 이상의 고유 값으로 설정할 것 (미설정 시 데모 기본값 사용).
|
|
저장 형식: base64(nonce[12] + ciphertext + GCM tag[16])
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import base64
|
|
import os
|
|
|
|
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
|
|
|
|
|
|
def _enc_key() -> bytes:
|
|
raw = os.environ.get("GUARDIA_ENC_KEY", "guardia-demo-key-32bytes-padding!").encode("utf-8")
|
|
return raw[:32].ljust(32, b"\x00")
|
|
|
|
|
|
def encrypt_secret(plain: str | None) -> str | None:
|
|
"""평문 자격증명을 AES-256-GCM으로 암호화하여 base64 문자열로 반환한다."""
|
|
if not plain:
|
|
return plain
|
|
nonce = os.urandom(12)
|
|
ct = AESGCM(_enc_key()).encrypt(nonce, plain.encode("utf-8"), None)
|
|
return base64.b64encode(nonce + ct).decode("ascii")
|
|
|
|
|
|
def decrypt_secret(enc_value: str | None) -> str | None:
|
|
"""encrypt_secret()으로 암호화된 문자열을 복호화한다.
|
|
|
|
평문으로 저장된 레거시 값(이번 암호화 적용 이전 데이터)이나 손상된 값을 만나면
|
|
예외를 전파하지 않고 입력값을 그대로 반환한다 — Fail-Safe 원칙(CLAUDE.md)에 따라
|
|
기존 연동이 끊기지 않도록 한다.
|
|
"""
|
|
if not enc_value:
|
|
return enc_value
|
|
try:
|
|
raw = base64.b64decode(enc_value, validate=True)
|
|
nonce, ct = raw[:12], raw[12:]
|
|
return AESGCM(_enc_key()).decrypt(nonce, ct, None).decode("utf-8")
|
|
except Exception:
|
|
return enc_value
|
|
|
|
|
|
# kubernetes.py 등에서 참조하는 이름과 호환되는 별칭
|
|
encrypt_password = encrypt_secret
|
|
decrypt_password = decrypt_secret
|