TT Lab
블로그 시작하기
배우기 러닝패스 코스

지운 토큰이 기록에서 문을 연다

ps 한 줄에 비밀번호가 보였다

TT Lab 에서 이어서 보기

한 줄 요약

명령행 인자와 환경 변수는 비밀값을 넘기는 가장 쉬운 길이지만, 같은 서버의 다른 계정에게도 보이는 길입니다. systemd 의 LoadCredential= 은 비밀값을 root 만 읽는 파일에 두고 그 서비스만 읽게 넘겨 줍니다.

왜 이게 문제인가

리눅스에서 /proc/<pid>/cmdline 은 기본으로 누구나 읽습니다. 그래서 --db-password 로 넘긴 값은 ps 한 줄에 보입니다. 환경 변수는 프로세스 소유자만 읽지만, systemd 유닛의 Environment= 는 systemctl show 로 일반 계정에게도 보이고 유닛 파일 자체도 대개 누구나 읽는 권한입니다.

서버에 사람 계정이 하나만 더 있어도, 웹 애플리케이션 하나가 뚫려 그 계정으로 명령을 칠 수 있게 돼도, 공격자는 권한 상승 없이 DB 비밀번호를 줍습니다. 장애를 보다가 켜 둔 디버그 로그가 같은 값을 적고 있는 경우도 흔합니다.

어떻게 동작하나

systemd 자격 증명은 세 부분으로 이루어집니다.

자리 하는 일
/etc/credstore/<이름> root 만 읽는(디렉터리 700, 파일 600) 원본
LoadCredential=<이름>:<경로> 서비스가 뜰 때 원본을 서비스 전용 자리로 복사하라는 지시
$CREDENTIALS_DIRECTORY 서비스 안에서 보이는 자리(/run/credentials/<유닛>/), 그 서비스만 읽는다

ExecStart 에서는 %d/<이름> 으로 파일 경로를 넘길 수 있습니다. 명령행에는 경로만 보이고 값은 보이지 않습니다. 환경 변수도 쓰지 않으므로 systemctl show 에도 나타나지 않습니다.

바꾼 뒤 확인할 자리가 셋입니다. systemd 가 새 정의를 읽었는지(daemon-reload 뒤 NeedDaemonReload=no), 돌고 있는 프로세스가 새 정의로 다시 떴는지(/proc/<pid>/cmdline 과 environ), 그리고 서비스가 여전히 정상인지입니다. 정의를 고친 것과 프로세스가 바뀐 것은 다른 사실이라, 셋 다 확인하지 않으면 "고쳤다" 고 말할 수 없습니다.

현장에서 만나는 모습

자격 증명으로 옮기는 일보다 이미 노출된 값을 정리하는 일이 더 오래 걸립니다. 노출됐던 값은 회전하고, 디버그 로그·백업한 유닛 파일·셸 기록처럼 일반 계정이 읽을 수 있는 자리에 남은 사본을 찾아 치워야 합니다. 이때 root 로 찾으면 모든 파일이 다 보이니 의미가 없습니다. 일반 계정의 권한으로 찾아야 그 계정이 실제로 볼 수 있는 것만 나옵니다.

또 하나는 감사입니다. 원본 파일을 감사할 때 파일만 감시하면, 상위 디렉터리에서 권한이 막힌 시도는 그 파일까지 닿지 않아 기록되지 않습니다. 누가 열어 보려 했는지가 궁금하다면 디렉터리를 감시해야 합니다.

고친 뒤 무엇으로 확인하나

서버 쪽 비밀값 정리는 확인할 자리가 많아서 순서를 정해 두면 빠뜨리지 않습니다.

  1. systemd 가 새 정의를 들고 있는가. systemctl show -p NeedDaemonReload 가 no 인지 봅니다.
  2. 돌고 있는 프로세스가 새 정의로 떴는가. 메인 PID 의 /proc/<pid>/cmdline 과 /proc/<pid>/environ 을 봅니다.
  3. 권한 없는 계정이 무엇을 보는가. runuser -u <계정> -- 로 프로세스 목록과 systemctl show 를 다시 봅니다.
  4. 서비스가 정상인가. 상태 확인 주소나 실제 요청으로 봅니다.
  5. 노출됐던 값이 회전됐고, 그 사본이 남아 있지 않은가.

1번과 2번이 다른 질문이라는 것이 이 모듈의 핵심입니다. 정의를 고치는 일과 프로세스를 바꾸는 일 사이에는 항상 다시 띄우는 단계가 있고, 그 단계를 빠뜨린 채 "고쳤다" 고 보고하는 일이 가장 흔합니다.

English corner

다음 실습에서 할 것

일반 계정의 눈으로 정산 서비스의 비밀번호가 보이는 세 자리를 확인합니다. 비밀번호를 자격 증명 파일로 옮기고, 유닛을 고치고, 다시 띄워 확인합니다. 노출됐던 값을 회전하고, 열어 보려는 시도를 감사로 남기고, 남은 사본을 치웁니다.

한 걸음 더 — 자격 증명의 수명

systemd 자격 증명은 값을 안전한 자리에 두는 것까지입니다. 그 값이 언제 바뀌는가 는 여전히 따로 설계해야 합니다. 파일을 바꾸고 서비스를 다시 띄우는 회전을 사람이 기억에 맡기면 결국 몇 달째 그대로가 됩니다. 그래서 자격 증명 파일을 비밀 관리자(Vault·클라우드 시크릿)에서 주기적으로 내려받아 갱신하는 사이드카나 타이머를 함께 두는 경우가 많습니다. 이 코스의 마지막 모듈(동적 비밀값)이 바로 그 자동 회전을 다루며, 여기서 한 '파일로 안전하게 넘기기' 가 그 토대가 됩니다.