LabHub
배우기 러닝패스 코스

Air-Gapped Sites — Defence and Government

The batch ran before the queue — the clock was 2.4 seconds fast

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

표기가 제각각인 다섯 호스트의 로그를 한 축으로 모으고, 시각 계통에서 고립된 호스트를 찾고, 요청과 응답의 모순으로 시계 오차의 하한을 구한 뒤, 보정으로 설명되는 것과 설명되지 않는 것을 갈라 시각 신뢰성 진술서를 씁니다.

왜 중요한가

조사도 감사도 "무엇이 먼저 일어났는가" 를 묻습니다. 그 답은 기록의 시각에서 나오는데, 기록의 시각은 그것을 남긴 기계의 시계가 보여 준 값입니다. 2초쯤 어긋난 시계는 아무도 눈치채지 못한 채 원인과 결과를 뒤집습니다. 폐쇄망에서는 바깥 시각원이 없어 망 안의 시각원 하나에 모두가 맞추므로, 서로의 순서는 맞아도 절대 시각은 보증되지 않습니다. 진술서에 그 한계를 쓰지 않으면 나중에 그 문서 전체가 무너집니다.

왜 자료로 판정하는가

실습 파드에는 capability 가 없어 chronyc·ntpdate 를 쓸 수 없고 시스템 시계도 바꿀 수 없습니다. 그래서 이 실습은 동기화 상태 보고와 로그만으로 판정합니다. 실제 현장에서도 감리에 내는 것은 명령 출력이 아니라 이 판정의 결과이며, chronyc trackingsources 의 출력이 여기 sync.json 이 놓인 자리를 차지합니다. 이 실습의 가정입니다.

단계

  1. python3/root/clock/datasync.json·meta.json·로그 다섯 개·requests.csv 를 만듭니다.
  2. 다섯 로그를 /root/clock/normalized.csvhost,seq,epoch_ms,evt 로 모으고, 오프셋 없는 로그를 UTC 로 잘못 읽었을 때의 영향을 /root/clock/naive.json 에 적습니다.
  3. 호스트별 시각원 사슬을 /root/clock/chain.json 에, 선언된 시각원에 닿지 않는 호스트를 /root/clock/isolated.txt 에 적습니다.
  4. 응답이 요청보다 앞선 건을 /root/clock/paradox.csv 에, 시계 오차의 하한을 /root/clock/bound.json 에 적습니다.
  5. 한 호스트의 로그 안에서 시각이 되돌아간 자리를 /root/clock/backward.csv 에 적습니다.
  6. 오프셋으로 보정한 시각을 /root/clock/corrected.csv 에, 보정 전후 모순 수를 /root/clock/paradox_after.json 에 적습니다.
  7. 호스트마다 기록 신뢰 등급을 /root/clock/trust.csvhost,level,reason 으로 적습니다.
  8. /root/clock/statement.json/root/clock/statement.md 에 시각 신뢰성 진술서를 씁니다.

참고

동기화 보고와 다섯 호스트의 로그 만들기

python3/root/clock/datasync.json·meta.json·node-a.log부터 node-e.log·requests.csv 를 만듭니다. 난수를 쓰지 않는 생성 스크립트를 그대로 쓰세요.

폐쇄망에는 내려받을 표본이 없으니 자료부터 직접 만듭니다. 난수를 쓰지 않아야 누가 몇 번을 돌려도 같은 자료가 나오고 서로의 판정을 대조할 수 있습니다. 채점기는 자료를 표준형으로 바꿔 지문을 대조하므로 손으로 고치면 뒤 단계가 전부 막힙니다.

표기 넷을 한 축으로 모으기

/root/clock/normalized.csv 에 첫 줄 host,seq,epoch_ms,evt 를 두고 다섯 로그의 사건을 모두 적으세요. /root/clock/naive.json 에는 naive_utc_hosts·shifted_events·shift_hours 를 적습니다.

epoch_ms 는 UTC 기준 밀리초 정수입니다. 오프셋이 붙은 것은 그대로 읽히고, 오프셋이 없는 것은 meta.json 이 알려 주는 시간대로 읽어야 합니다. 그것을 UTC 로 읽으면 몇 시간이 밀리는지가 naive.json 의 내용입니다.

시각원 계통을 끝까지 따라가기

/root/clock/chain.json 에 호스트마다 따라간 시각원 사슬을 목록으로 적고, 선언된 시각원에 닿지 않는 호스트를 /root/clock/isolated.txt 에 한 줄에 하나씩 적으세요.

사슬은 그 호스트의 source 부터 시작해 한 걸음씩 따라갑니다. LOCAL 을 만나거나 이미 지나온 이름을 다시 만나면 거기서 멈추고, 그 이름까지 사슬에 넣습니다. 선언된 시각원 자신은 고립 판정에서 빼세요.

응답이 요청보다 앞선 건으로 오차의 하한 구하기

/root/clock/paradox.csv 에 첫 줄 req_id,sender,receiver,delta_ms 를 두고 delta_ms 가 음수인 건을 적고, /root/clock/bound.jsonmin_skew_ms·sender·receiver 를 적으세요.

delta_ms 는 수신 시각에서 전송 시각을 뺀 값입니다. 음수라면 두 시계가 최소한 그 크기만큼 벌어져 있다는 뜻이고, 가장 큰 음수의 크기가 하한입니다. 하한은 양수로 적습니다.

한 호스트 안에서 시각이 되돌아간 자리 찾기

/root/clock/backward.csv 에 첫 줄 host,seq,prev_epoch_ms,epoch_ms 를 두고, 같은 호스트의 로그에서 바로 앞줄보다 시각이 작아진 지점을 적으세요.

호스트별로 seq 순서대로 읽으며 바로 앞 줄의 시각과 견줍니다. 호스트가 섞이지 않게 나눠서 보세요. 시각이 되돌아간 구간의 기록은 순서를 근거로 쓸 수 없습니다.

오프셋으로 보정하고 남는 것 보기

/root/clock/corrected.csv 에 첫 줄 host,seq,epoch_ms 를 두고 보정한 시각을 적고, /root/clock/paradox_after.jsonbefore·after·remaining 을 적으세요.

보정은 관측값에서 그 호스트의 offset_ms 를 빼는 것입니다. 부호를 뒤집으면 모순이 오히려 늘어납니다. 요청도 같은 방법으로 양쪽을 보정한 뒤 다시 음수를 세면, 남는 것이 시계로 설명되지 않는 진짜 결함입니다.

호스트마다 기록 신뢰 등급 매기기

/root/clock/trust.csv 에 첫 줄 host,level,reason 을 두고 로그가 있는 다섯 호스트를 판정하세요. 규칙은 실습 안내의 순서대로 적용합니다.

규칙은 먼저 맞는 것 하나만 적용합니다. 계통이 닿지 않는 호스트는 다른 근거를 볼 것도 없이 설명안됨입니다. 보정 전에 모순에 끼었지만 보정 뒤 사라졌다면 조건부로 쓸 수 있는 구간입니다.

믿을 수 있는 것과 없는 것을 함께 적은 진술서 쓰기

/root/clock/statement.jsonroot·root_has_external_reference·confirmed·corrected·unexplained·min_skew_ms·remaining_contradictions 를 적고, /root/clock/statement.md## 판단·## 근거·## 믿을 수 없는 것·## 남은 의심 네 절로 500자 이상 쓰세요.

진술서의 값은 손으로 세지 말고 앞 단계와 같은 계산에서 가져옵니다. 시각원이 바깥 기준을 가지고 있는지는 그 시각원의 source 가 무엇인지로 정해집니다. 믿을 수 없는 호스트는 이름을 적어야 읽는 사람이 무엇을 빼고 읽어야 하는지 압니다.