728x90

이 글에서 다루는 이슈는 아직 실무자들 사이에서 폭넓게 검증된 상태는 아니다. Ingo Blechschmidt가 Mastodon에서 공유한 조사 내용을 출발점으로 하며, 원인·영향 범위 중 일부는 본인 환경에서 직접 확인이 필요한 부분임을 먼저 밝혀둔다. 그럼에도 다루는 이유는 명확하다. FDE(Full Disk Encryption)를 굴리는 노트북·서버에서 suspend 후 메모리에 키가 남는다는 건, 우리가 그동안 "당연히 지워진다"고 믿고 세운 위협 모델이 무너진다는 뜻이기 때문이다.

1. 도입: 왜 지금 화제이고 어떤 문제를 푸는지

상황을 실무 시나리오로 그려보자. 회사 노트북에 LUKS로 전체 디스크를 암호화해놨다. 카페에서 작업하다 뚜껑 닫고(suspend-to-RAM) 화장실 다녀오는 사이 누가 노트북을 들고 튄다. 우리가 기대하는 건 이거다. "suspend 상태에서는 디스크 암호화 키가 메모리에서 지워져 있어야 한다. 그래야 콜드부트 공격이나 메모리 덤프로 키를 뽑아내지 못한다."

이 "suspend 시 키 wiping" 기능이 cryptsetup luksSuspend의 핵심 보안 가치다. 그런데 Ingo Blechschmidt의 조사에 따르면 Linux 6.9부터 LUKS suspend가 메모리에서 키를 제대로 지우지 않는 회귀(regression) 버그가 들어갔다는 것이다. 즉, 사용자는 "나는 suspend하면 키가 지워지니까 안전하다"고 믿고 있는데, 실제 커널 메모리에는 키가 그대로 남아있는 상태다. 보안에서 가장 위험한 상황은 "취약한 것"보다 "안전하다고 오해하는 것"인데, 정확히 그 케이스다.

정확한 커널 커밋·수정 여부는 공식 커널 changelog와 cryptsetup 이슈 트래커에서 반드시 재확인해야 한다. 이 글은 원인 분석과 실무 대응에 초점을 맞춘다.

2. 핵심: LUKS/dm-crypt는 키를 어디에 어떻게 들고 있나

먼저 그림을 맞추자. LUKS는 크게 두 층으로 나뉜다.

  • LUKS 헤더 (키 슬롯): 디스크에 저장되는 부분. 사용자 패스프레이즈로 잠긴 "마스터 키의 암호화된 사본"이 들어있다. 슬롯이 여러 개라 패스프레이즈를 여러 개 걸 수 있다.
  • dm-crypt (마스터 키): 부팅/언락 시점에 패스프레이즈로 슬롯을 풀어 마스터 키를 복원하고, 이걸 커널 메모리에 올려서 실제 블록 암복호화에 쓴다.

비유하자면, LUKS 헤더는 "금고 열쇠를 여러 개의 자물쇠 상자에 나눠 보관한 것"이고, dm-crypt는 "그 금고 열쇠를 실제로 손에 쥐고 계속 문을 여닫는 사람"이다. 디스크가 활성 상태인 동안 이 마스터 키는 커널 메모리에 상주한다. 이게 없으면 매 I/O마다 암복호화를 못 한다.

현재 매핑 상태는 이렇게 확인한다.

$ sudo dmsetup table --showkeys cryptroot
0 500107776 crypt aes-xts-plain64 a3f1c2...실제키바이트...9e 0 8:3 4096

# 키를 감춰서 보고 싶으면:
$ sudo dmsetup table cryptroot
0 500107776 crypt aes-xts-plain64 00000000000000000000000000000000000000000000000000000000000000000000 0 8:3 4096

--showkeys를 붙이면 마스터 키 원본이 그대로 출력된다. 이게 곧 "커널이 이 키를 평문으로 들고 있다"는 증거다. suspend 후에도 이 키가 살아있으면 문제인 것.

suspend 시 무슨 일이 일어나야 하는가

정상적인 흐름은 이렇다. cryptsetup luksSuspend를 호출하면:

  1. 해당 dm-crypt 디바이스에 대한 I/O를 얼린다(freeze).
  2. 커널 메모리에서 마스터 키를 wipe한다.
  3. 다시 쓰려면 luksResume로 패스프레이즈를 재입력해 마스터 키를 복원한다.

여기서 핵심은 2번이다. suspend-to-RAM 상태에서는 RAM에 전원이 유지되므로, 키를 지우지 않으면 그 RAM 내용을 그대로 덤프하거나 콜드부트 공격으로 뽑아낼 수 있다. 회귀 버그의 요지는 이 2번 단계가 실질적으로 무력화됐다는 것이다. 커널이 키를 지웠다고 생각하지만 어딘가(예: 키링, 슬랩 캐시, 복사본)에 남아있다는 방향으로 보인다. 정확한 메모리 잔존 위치는 원문 조사 및 커널 소스 확인이 필요하다.

3. 실무 관점: 확인 방법, 트레이드오프, 흔한 함정

영향 받는지 확인하기

먼저 커널 버전부터. 6.9 이상이면 일단 의심 대상이다.

$ uname -r
6.9.7-arch1-1

$ cryptsetup --version
cryptsetup 2.7.2 flags: UDEV BLKID KEYRING KERNEL_CAPI PWQUALITY 

실제로 키가 남는지 거칠게나마 검증하는 절차는 이렇다. 반드시 데이터 백업이 있는 테스트 환경에서 하자. 루트 파일시스템에 걸린 crypt 디바이스를 실서버에서 suspend/resume 만지다가 시스템을 얼려먹기 딱 좋다.

# 1) suspend 전: 마스터 키 존재 확인
$ sudo dmsetup table --showkeys testcrypt | awk '{print $5}'
a3f1c2...9e   # 키가 보임 (정상, 활성 상태니까)

# 2) suspend 수행
$ sudo cryptsetup luksSuspend testcrypt

# 3) suspend 후: 키가 지워졌는지 확인
$ sudo dmsetup table --showkeys testcrypt | awk '{print $5}'
00000000000000000000000000000000   # 지워졌다면 이렇게 0으로 나와야 정상
# a3f1c2...9e                       # 여전히 보이면 회귀 버그 의심

주의할 점: dmsetup table이 0을 보여준다고 해서 RAM 어딘가의 복사본까지 전부 지워졌다는 보장은 아니다. 반대로 여전히 키가 보인다면 명백히 문제다. 완전한 검증은 실제 물리 메모리 덤프 분석 영역이라 일반 실무 범위를 넘는다.

흔한 함정 1: luksSuspend 후 시스템이 통째로 멈춘다

가장 자주 밟는 지뢰. 루트 파일시스템이 올라간 crypt 디바이스에 luksSuspend를 걸면 그 순간부터 디스크 I/O가 얼어서 luksResume 명령을 실행할 바이너리조차 디스크에서 못 읽어온다. 데드락이다.

$ sudo cryptsetup luksResume cryptroot
# ...무한 대기, 아무 반응 없음. 셸도 먹통.

그래서 노트북 잠금 자동화(예: systemd-suspend hook)에서는 luksResume에 필요한 바이너리·라이브러리를 미리 메모리에 락(mlock)해두는 별도 도구를 쓴다. 이걸 직접 구현하려다 자기 노트북 벽돌 만드는 사람 여럿 봤다. 검증된 훅 스크립트나 배포판 제공 유틸을 쓰자.

흔한 함정 2: Device or resource busy

테스트하겠다고 아무 crypt 디바이스나 suspend하려다 만나는 에러.

$ sudo cryptsetup luksSuspend testcrypt
Device testcrypt is still in use.

# 또는 언마운트/detach 시:
$ sudo cryptsetup close testcrypt
device-mapper: remove ioctl on testcrypt failed: Device or resource busy
Cannot deactivate device.

해당 디바이스를 참조하는 마운트나 프로세스가 남아있어서다. sudo lsof +f -- /dev/mapper/testcryptsudo fuser -m /mnt/test로 물고 있는 놈부터 정리하고 다시 시도해야 한다.

트레이드오프와 완화 조치

회귀 버그가 확인된 환경에서 당장 취할 수 있는 현실적인 선택지들:

  • suspend-to-RAM 대신 hibernate(suspend-to-disk) 또는 완전 종료: RAM에 전원을 유지하지 않으면 콜드부트 공격 표면이 크게 줄어든다. 단, hibernate는 메모리 이미지를 swap에 쓰므로 swap도 반드시 암호화돼 있어야 한다. 안 그러면 키가 평문 swap으로 흘러들어간다. 이건 이 버그와 무관하게 원래 지켜야 하는 원칙.
  • 버그 없는 커널 버전 사용: 6.9 이전(예: 6.6 LTS 계열)으로 고정하거나, 수정 커밋이 백포트된 버전으로 올린다. LTS 커널을 쓰는 게 이런 회귀 대응에 유리하다.
  • 물리 접근 통제 강화: 결국 콜드부트/메모리 덤프는 물리 접근이 전제다. 자리 비울 땐 suspend가 아니라 종료 습관을 조직 정책으로 잡는 게 소프트웨어 패치보다 확실할 때가 많다.

대안 없이 "6.9 이상은 무조건 위험" 식으로 단정하진 말자. 배포판이 자체 패치를 백포트했을 수 있으니, 실제 wipe 여부는 위 dmsetup table --showkeys 절차로 본인 환경에서 직접 확인하는 게 맞다.

4. 정리: 한 줄 요약 + 누가 언제 챙겨야 하나

한 줄 요약: Linux 6.9 이후 LUKS suspend가 메모리에서 마스터 키를 제대로 지우지 않는 회귀가 보고됐고, "suspend하면 키가 지워진다"는 전제를 깔고 있던 FDE 위협 모델을 다시 점검해야 한다.

지금 당장 챙겨야 하는 사람:

  • LUKS FDE 노트북을 들고 다니는 사람, 특히 자리 비울 때 suspend 습관이 있는 경우
  • 보안 컴플라이언스(예: 디바이스 암호화 정책)를 문서로 관리하는 팀 — "suspend 시 키 wiping"을 근거로 삼았다면 근거가 흔들린다
  • 물리 접근 위협이 실재하는 환경(공유 오피스, 데이터센터 콜로, 현장 배치 장비)

당장 안 급한 사람: 물리 접근이 강하게 통제되는 서버룸의 상시 가동 서버는 우선순위가 낮다. 애초에 suspend를 안 쓰고, RAM 물리 탈취 위협이 낮다면 이 버그의 실질 리스크는 제한적이다. 그래도 커널 버전 트래킹 대상에는 올려두자.

액션 아이템 체크리스트:

  1. uname -r로 6.9 이상 여부 확인
  2. 테스트 환경에서 luksSuspenddmsetup table --showkeys로 wipe 실제 동작 검증
  3. 영향받으면: LTS 커널 고정 / 종료·hibernate 정책 전환 / swap 암호화 확인
  4. cryptsetup·커널 이슈 트래커에서 수정 커밋 상태 추적

참고 자료

※ 이 글의 원인·영향 범위 일부는 원문 제보 기반이며, 배포판별 패치 여부에 따라 실제 동작이 다를 수 있다. 프로덕션 적용 전 반드시 본인 환경에서 검증하고 공식 소스를 교차 확인하길 권한다.

728x90
728x90

이번 포스팅에서는 DB와 서버를 생성해보도록 하겠습니다. 

 

제일 먼저 생성할 자원은 DB입니다 

(CDB for MySQL은 2 vCPU, 4GB RAM 사용시 160원/시간이 청구됩니다)

 

아래 사진과 같이 CDB for MySQL로 이동하여 DB생성을 눌러서 진행합니다. 

CDB for MySQL 생성

 

 

생성을 누르게 되면 아래와 같이 설정을 하는 창이 뜨는데 다음과 같이 입력해주시고 넘어가시면 되겠습니다. 

    - DB 엔진 버전 mysql(8.0.25)

    - 고가용성 지원 체크해제 

    - VPC 및 Subnet(issac-db) 선택

    - DB Server 이름 및 서비스 이름 임의로 설정

DB 생성 창 - 1

DB생성 두번째 창입니다. 이 부분은 실제로 DB접속 정보와 DB를 구성하는 정보를 입력하는 페이지 입니다 

    - User_ID는 DB에 접속할때 사용하는 ID 입니다

    - HOST(IP)는 DB에 접속허용할 IP를 정하는 옵션입니다. 여기서는 모든 IP를 허용하기 위해 '%' 를 입력하였습니다

      (좋은 방법은 아닙니다, 실제에서는 최소한의 권한을 주기위해 WAS IP대역을 주는 것을 권장합니다만,

       연습이니까 그냥 줬습니다)

    - USER 암호는 접속 암호입니다.

    - 기본 DB명은 최초에 생성할 DB명입니다, 여기서 생성할 DB를 Wordpress설치시 사용할것이기 때문에, 기억해주도록        합시다 

DB 생성 창 - 2

이렇게 하시면 DB는 생성완료입니다, 참 쉽죠? ㅋㅋㅋ

 

자 이제 서버 생성입니다 

 

서버는 총 2대(Web, WAS)를 생성할 시간입니다. 

저는 미리 서버를 생성해서 서버2대가 보이지만.. 

Server -> + 서버 생성을 클릭하여 서버 생성창으로 이동합니다.

서버 생성 버튼 클릭

 

서버 생성 첫번째 창입니다. 

저희는 CentOS 7.8버전을 사용하겠습니다

NCP는 서버 용량이 Windows는 100GB, Linux는 50GB로 고정되어 있습니다. 

서버 타입은 제일 저렴한 서버타입이 있는 High CPU를 고르시고 넘어가시면 되겠습니다

(서버는 2 vCPU, 4GB RAM 사용시 100원/시간이 청구됩니다)

서버 생성 - 1

 

서버 생성 2번째 페이지 입니다. 

    - VPC와 Subnet을 알맞게 정하고 

    - 서버 타입은 vCPU 2개 4GB RAM

    - 시간 요금제

    - 서버 이름은 web서버는 wordpress-web, WAS는 wordpress-was, 

    - Network Interface에서 IP를 입력하지 않으시고 추가를 누르시면 자동으로 IP가 할당됩니다 

    - wordpress-web 서버는 새로운 공인IP 할당을 해줍니다. 

서버 생성 - 2

 

서버 생성 세번째 페이지 입니다. 

인증키를 설정하는 페이지 입니다. 

이미 인증키아 있으신분들은 선택하시고 넘어가시고

없으신 분들은 "새로운 인증키 생성"을 통해 인증키를 생성 및 다운로드 하시고 넘어가면 되겠습니다.

(두번째 서버는 보유하고 있는 인증키 이용 하시면 됩니다)

서버 생성 - 3

 

서버 생성 네번째 페이지 입니다 

이전 포스팅에서 생성했던 ACG를 할당하는 페이지 입니다. 

wordpress-web 서버는 issac-pub-acg를 할당하고 넘어가시고

wordpress-was 서버는 issac-pub-pri를 할당하시고 넘어가시면 되겠습니다. 

서버 생성 - 4

 

이로써 서버 생성도 완료되었습니다!

728x90
728x90

안녕하세요, 이번 포스팅에서는 NCP상에서 3 Tier 구성으로 Wordpress를 구축을 해보는 과정을 보여드리려고 합니다. 

 

긴말하지 않고 보시죠 

 

일단 인터넷에서 말하는 2 Tier와 3 Tier의 차이점은 다음과 같습니다. 

    1.  2 Tier 에서는 클라이언트 서버에서 DB서버로 집적 데이터를 입력하고 불러오는 방식이다

         장점 개발이 편리하다, 개발비용이 저렴하다, 유지보수가 쉽다

         단점 보안에 취약하다, 서버에 부하가 일어나기 쉽다.

    2.  3 Tier 에서는 클라이언트 서버에서 비즈니스 로직을 담당하는 역할을 떼어내 독립된 서버로 만든 구조이다

         장점 보안이 강화된다, 서버의 부하를 줄일 수 있다.

         단점 관리 포인트가 늘어난다, 개발기간이 늘어난다

 

구성은 다음과 같이 차이가 나구요! 

2Tier vs 3Tier

진짜 기초부터 차근차근 만들어 보겠습니다. 

 

일단 NCP에 로그인을 하신뒤 아무것도 없는 가정하에 VPC부터 생성해보겠습니다. 

10.0.0.0/16 대역 VPC 생성

저는 10.0.0.0/16 대역으로 VPC를 생성하였습니다

 

 

다음은 VPC내부에 서브넷 생성입니다. 

 

Subnet 생성

서브넷은 총 3개를 생성합니다, 하나는 Web서버가 할당될 public 서브넷, WAS 전용 private 서브넷, DB전용 private 서브넷,

서브넷 정보는 다음과 같습니다. 

Subnet 이름  IP 주소  internet Gateway 전용 여부 용도
issac-db 10.0.2.0/24 N(Private) 일반
issac-pri 10.0.1.0/24 N(Private) 일반
issac-pub 10.0.0.0/24 Y(Public) 일반

 

다음은 Private Subnet에서 만들어지는 WAS서버에서 Yum으로 프로그램 설치를 위한 NAT Gateway 생성 및 Route Table 설정입니다. 

Nat Gateway 생성

 

Route table은 AWS에서와는 조금 다르게 default Private route table 에 집적 걸어줍니다!

Route Table 설정
Route Table  내용 추가

다음은 서버에 적용할 ACG를 생성해보겠습니다.

(본 포스팅에서는 NACL은 따로 적용하지 않겠습니다 따로 기회가 되면 올려보도록 할게요!ㅎㅎ)

 

Server -> ACG생성

ACG이름 적용 Network Interface
issac-pub-pri wordpress-was
issac-pub-acg wordpress-web

(*만들다 보니... 이름을 잘못지었네요..ㅠㅠ issac-pub-pri는 private Subnet의 was에 적용되는 ACG입니다)

 

룰은 다음과 같이 만들어 줍니다.

issac-pub-acg inbound
issac-pub-acg outbound
issac-pub-pri inbound
issac-pub-pri outbound

 

마지막으로 아래의 룰을 두개의 ACG의 outbound에 추가합니다. 

(추가하지 않으면 epel 로 설치하는 Package가 설치 되지 않는다.)

공통 outbound 룰

 

아래 ACG설정은 CDB for MySQL을 생성후 진행한다,(아래 CDB for MySQL 생성하는 스텝 진행 후 올라와서 진행합니다)

CDB for MySQL inbound

 

ACG 설정하시느라 고생하셨어요! 이제 사전작업은 끝났습니다!

 

이제 서버와 DB를 생성하러 가보시죠!

728x90

+ Recent posts