콘텐츠로 이동

English · 한국어

기대 결과(샘플)

데모(../scripts/up.sh → demo.sh)를 실행하면 얻는 대표 결과입니다. 실행하기 전에 무엇이 보일지 확인할 수 있습니다. (완전히 관측된 웜 실행에서 캡처했습니다.) 데모는 일곱 단계(0/6부터 6/6까지)입니다. 접근 준비 → SSH 확인 → 관측 → 보기 → 토폴로지 → 인벤토리 → 전환물 생성입니다. 아래 샘플은 관측 보기(3/6)를 캡처한 것입니다.

파일 내용
discover-view.txt 콘솔 출력: 발견한 자산(OpenSSL · JCA/BouncyCastle)과 관측한 통신 연결 간선별 등급
topology.svg 관측한 토폴로지(색 = 등급: 🟢 양자내성 / 🔴 고전 / ⚪ 등급 미정, 실선 = 관측함)

핵심 이야기: 최신 스택과 레거시 스택이 TLS와 SSH 모두에서 서로 다릅니다.

연결 간선 등급 까닭
web-gw→pay-app TLS 🟢 X25519MLKEM768 Go crypto/tls 하이브리드
web-gw→pay-app SSH 🟢 sntrup761 양쪽 모두 OpenSSH 9 이상
web-gw→pay-db TLS 🔴 x25519 OpenSSL 1.1.1에는 양자내성 그룹이 없음
web-gw→pay-db SSH 🔴 curve25519 레거시 OS의 OpenSSH 8.2에는 양자내성 KEX가 없음

pay-app에서는 BouncyCastle을 포함한 JCA provider 체인(실행 중에 addProvider로 추가되므로 정적 스캔으로는 보이지 않음)도 attach로 관측합니다. 구성은 topology/topology.yaml이 정의하며, 그 파일을 고치면 이 결과도 바뀝니다.

등급은 설정이 아니라 관측입니다. SSH 등급은 양쪽 KEXINIT의 교집합(RFC 4253)으로 계산합니다. 클라이언트가 sntrup761을 제시해도 서버가 지원하지 않으면 그 연결 간선은 🔴입니다. 한쪽만 관측했을 때는 협상을 지어내지 않고 연결 간선을 ⚪ 등급 미정으로 둡니다.

뒤 단계에서 추가로 보이는 것: - 접근 준비(0): pqcota-hosts가 hosts.csv를 Ansible 인벤토리(접속 키, 실행 중에만 존재)로 바꾸고 엔드포인트를 upsert합니다. 인벤토리에 비밀은 0개입니다. - 중앙 인벤토리(5): ▸ Payments DB (ip:22) │ Payments DB · production · db · owner=DBA team과 같은 엔드포인트와 프로파일 머리말, 그리고 @app 라벨입니다. pay-db가 공유하는 libssl.so.1.1은 두 앱 모두에 귀속됩니다. @/opt/apps/api-gw,/opt/apps/payment-gw - 연결 간선의 앱(5): 관측한 연결 간선 줄 끝의 @app입니다. 관측이 잡았으면 @payment.service, 실행 파일 경로로 잡았으면 @/usr/bin/openssl(exe-path), 잡지 못했으면 @?입니다. 이 데모에서는 네 연결 간선 가운데 셋이 @?이고 까닭이 함께 출력됩니다. socket closed between capture and lookup — short-lived connections are missed(3). 데모의 트래픽이 모두 짧게 끝나는 연결이어서 생깁니다. 그중 하나를 pqcota-declare-attribution으로 지정하면 @batch-runner.service(declared)가 되고, 관측이 이미 잡은 칸은 그대로 남습니다. - 전환물 생성(6): 확정된 계획 → L2·L3 플레이북과 되돌림 기록입니다. affected apps: /opt/apps/api-gw, /opt/apps/payment-gw · before : libssl.so.1.1@1.1.1f

실제로 실행하면 달라질 수 있는 것과 까닭

결정성을 위해 두 장치를 더했으므로 처음 실행도 위 결과와 같습니다. - 연결 간선 캡처를 완전해질 때까지 재시도: demo.sh는 목표 연결 간선 수(토폴로지의 연결 간선 수)에 닿을 때까지 최대 4번 다시 수집합니다. netcap의 관측 창과 트래픽 시점 사이의 경합을 흡수하므로, 콜드 스타트인 첫 실행도 완전한 연결 간선을 얻습니다. (DEMO_TARGET_EDGES / DEMO_MAX_ATTEMPTS로 조절합니다. 최대 시도 안에 목표에 닿지 못하는 극도로 제한된 환경에서만 연결 간선이 모자랍니다.) - 베이스 이미지를 고정했고, BouncyCastle 1.85도 고정했습니다(해시 확인). 그래서 OpenSSL/Go/JDK 버전과 1.1.1f/3.0.13/3.5.5 같은 문자열은 태그가 갱신되어도 대체로 같습니다(배포판이 보안 업데이트를 내면 마이너 버전이 오를 수 있습니다).

그래도 달라질 수 있는 것: - 컨테이너 IP(172.18.0.x)는 실행할 때마다 동적으로 바뀝니다. 이야기에는 상관없습니다(노드는 이름으로 이어집니다). - 토폴로지를 고치면 노드, 연결 간선, 등급이 그에 맞게 바뀝니다. 이 샘플은 기본 구성을 기준으로 합니다.

결정성

같은 입력은 같은 출력을 냅니다. 등급 분류(🟢/🔴/⚪), 발견한 자산, 세 가지 대조 상태(별도 확장에서)는 모두 결정적인 로직입니다. 위의 「차이」는 무엇이 관측되는가(캡처 시점)와 베이스 이미지 버전의 문제이지, 분류나 판정 로직의 비결정성이 아닙니다.

English