Skip to content
isdnetworks
Go back

지우기 전에 대안이 있는지 봤다

접속 키가 svn 이력에 들어갔다는 것을 알았다. 지워야 하는데 그 키로 지금 여러 장치가 붙어 있었다.

Table of contents

Open Table of contents

지우면 당장 멈춘다

OLD_KEY 를 무효화하면 그것을 쓰는 장치가 전부 못 붙는다.

수집 장치 40대
배치 3종
관리 화면 1곳

전부 NEW_KEY 로 바꿔야 하는데 장치는 현장에 있어서 원격으로 갱신해야 한다. 그동안 자료가 안 들어오면 그것도 사고이므로 위험을 없애려다 다른 사고를 만드는 셈이 된다.

위험을 없애는 것이 맞아도 순서가 있다.

순서를 정했다

1. 새 키를 발급한다 (옛 키는 아직 살림)
2. 서버가 두 키를 다 받아들이게 한다
3. 장치를 하나씩 새 키로 바꾼다
4. 전부 바뀐 것을 확인한다
5. 옛 키를 무효화한다
6. 이력에서 옛 키를 지운다

2번이 핵심이었고 OLD_KEYNEW_KEY 를 동시에 받으면 전환 중에 안 끊긴다.

$valid = [OLD_KEY, NEW_KEY];
if (!in_array($given, $valid, true)) {
    return unauthorized();
}

in_array 로 둘 다 통과시키면 어느 시점에도 멈추는 장치가 없다.

어느 것이 아직 옛 키인지 봤다

3번을 하려면 누가 아직 안 바뀌었는지 알아야 했다. 접속할 때 어느 키를 썼는지 log_message 로 남겼다.

log_message('info', "auth ok device={$id} key=" . ($given === OLD_KEY ? 'old' : 'new'));

auth_log 를 집계해서 봤다.

SELECT key_type, COUNT(DISTINCT device_id) FROM auth_log
WHERE reg_date >= DATE_SUB(NOW(), INTERVAL 1 DAY) GROUP BY key_type;
old   12
new   28

12대가 남았고 목록을 뽑아 하나씩 처리했다.

안 오는 장치의 확인

oldnew 도 안 나오는 장치가 있었다. 하루 동안 접속을 안 한 것이다.

SELECT device_id FROM device
WHERE device_id NOT IN (SELECT DISTINCT device_id FROM auth_log WHERE reg_date >= DATE_SUB(NOW(), INTERVAL 1 DAY));

device 에만 있고 auth_log 에 없는 것이 3대였고 원래 꺼져 있는 것인지 확인이 필요했다. 둘 다 아님을 따로 세지 않으면 그 3대를 놓치고 40대 중 37대만 세고 있었다.

두 대는 현장에서 꺼 둔 것이었고 한 대는 통신이 끊긴 상태였다. 그 한 대를 고치고 나서 진행했다.

검증 — 무효화 뒤와 재발 방지

5번을 하고 나서 접속 실패가 있는지 봤다.

SELECT COUNT(*) FROM auth_log WHERE result='fail' AND reg_date >= '2016-10-10 14:00';

몇 건 나왔고 확인해 보니 시험용 PHP 스크립트가 OLD_KEY 를 들고 있었다. 목록에 없던 것인데 장치와 배치만 세고 개인 스크립트는 안 셌다.

쓰는 곳을 목록으로 만들 때 놓치는 것이 있어서 무효화 뒤에 실패를 감시해서 잡았다.

문제가 크면 원래 상태로 가야 하므로 옛 키를 바로 삭제하지 않고 비활성으로만 뒀다.

활성   NEW_KEY
비활성 OLD_KEY   (2016-10-24 삭제 예정)

2주 두고 문제가 없으면 OLD_KEY 를 지운다. 다시 살리려면 비활성을 활성으로 바꾸면 되고 한 줄이다.

저장소 이력에서 값을 지우는 것은 이력을 다시 쓰는 일이라 받아 간 사본이 있으면 그쪽에는 남는다. 그래서 키를 무효화하는 것이 실질적 방어이고 이력에서 지우는 것은 흔적 정리다.

값을 못 쓰게 만드는 것이 먼저고 흔적을 지우는 것이 나중이다.

애초에 왜 들어갔는지도 봤는데 config/secret.php 가 무시 목록에 없었다.

config/secret.php
*.key
.env

무시 목록에 넣고 예시 파일만 남겼다. 커밋 전에 키처럼 보이는 문자열이 있는지 보는 검사도 넣었다.

# 커밋 전 훅에서 바뀐 파일을 훑는다
for f in $(svn status | awk '/^[AM]/ {print $2}'); do
  if grep -qE '(api[_-]?key|secret|password)[ ]*[=:][ ]*.{16,}' "$f"; then
    echo "자격증명으로 보이는 값이 포함돼 있습니다: $f"
    exit 1
  fi
done

완벽하지 않지만 명백한 것은 잡힌다.

정리


Share this post on:

Previous Post
처음 감시 체계를 세우며
Next Post
데이터시트를 처음 읽을 때