13년차의 서버실

서버, 인프라, 홈랩 기술 블로그

[태그:] 보안 강화

  • [Linux 보안] SELinux vs AppArmor: 선택 가이드와 실전 비교

    [Linux 보안] SELinux vs AppArmor: 선택 가이드와 실전 비교

    [Linux 보안] SELinux vs AppArmor: 선택 가이드와 실전 비교

    리눅스 서버를 운영하다 보면 결국 한 번은 붙잡게 되는 주제가 있습니다. 바로 SELinux AppArmor 비교입니다. 방화벽만 잘 열고 닫는다고 끝나는 게 아니더라고요. 실제 운영 환경에서는 프로세스가 어디까지 접근할 수 있는지, 침해 사고가 났을 때 피해 범위를 얼마나 좁힐 수 있는지가 정말 중요합니다. 저도 홈랩에서 웹 서버, 컨테이너, 파일 공유 서비스를 이것저것 올려보면서 Linux 보안을 강화하려다가 SELinux(Security-Enhanced Linux)와 AppArmor(Application Armor)를 번갈아 만져봤습니다. 처음엔 둘 다 비슷해 보였는데, 직접 써보니까 운영 철학부터 관리 포인트까지 꽤 다르더라고요.

    혹시 이런 경험 있으신가요? 서비스는 분명 정상인데 권한 거부 때문에 접속이 안 되고, 로그를 보면 더 헷갈리는 상황 말입니다. 저도 처음엔 이게 뭔가 싶었는데, 기준만 잡고 보면 선택이 꽤 쉬워집니다. 이번 글에서는 SELinux vs AppArmor를 비교하면서, 어떤 환경에서 무엇을 선택하면 좋은지 경험 기준으로 풀어보겠습니다.

    SELinux AppArmor 비교를 보여주는 리눅스 보안 개요 다이어그램

    SELinux와 AppArmor가 커널 보안 계층에서 어떻게 동작하는지 보여주는 개요 이미지입니다.

    1. 왜 SELinux와 AppArmor가 중요한가

    쉽게 말해 둘 다 MAC(Mandatory Access Control, 강제 접근 통제) 계열입니다. 일반적인 파일 권한처럼 사용자가 알아서 결정하는 DAC(Discretionary Access Control, 임의 접근 통제)보다 훨씬 강하게 제어하는 방식이거든요. 프로세스가 root 권한을 가졌다고 해도, 보안 정책이 막고 있으면 파일을 읽거나 네트워크 동작을 하지 못하게 되는 겁니다.

    이게 왜 중요하냐면, 서비스 하나가 뚫렸을 때 전체 서버로 번지는 걸 줄여주기 때문이에요. 예를 들어 웹 서버 프로세스가 취약점으로 악용되더라도, 원래 접근하면 안 되는 디렉터리나 소켓을 막아두면 피해 확산을 줄일 수 있습니다. 제가 홈랩에서 리버스 프록시, 파일 서버, 테스트용 앱을 굴릴 때도 결국 마지막 안전장치 역할은 이런 보안 정책이 하더라고요. 평소엔 귀찮아 보여도, 문제 생기면 존재감이 정말 확실합니다.

    2. SELinux와 AppArmor 개념 설명

    2-1. SELinux는 라벨 기반입니다

    SELinux는 객체와 프로세스에 보안 컨텍스트(context, 보안 문맥) 라벨을 붙여서 제어합니다. 파일, 포트, 프로세스가 각각 어떤 타입인지 보고 허용 여부를 판단하는 방식이죠. 처음엔 정말 어렵습니다. 저도 파일 권한만 보다가 갑자기 컨텍스트를 보라니까 삽질 좀 했어요. 그런데 익숙해지면 정책이 꽤 정교하고 체계적이더라고요.

    • 파일과 디렉터리에 보안 라벨을 부여합니다.
    • 프로세스도 특정 도메인(domain, 실행 문맥)으로 실행됩니다.
    • 정책이 세밀해서 대규모 운영 환경에 잘 맞는 편입니다.

    2-2. AppArmor는 경로 기반입니다

    AppArmor는 파일 경로(path, 경로)를 기준으로 제어합니다. 그래서 사람이 읽고 이해하기가 상대적으로 훨씬 쉽습니다. 특정 실행 파일이 어느 경로를 읽고 쓸 수 있는지 프로파일(profile, 정책 파일)로 정의하는 방식이거든요. Ubuntu 계열에서 처음 보안 강화 기능을 접할 때 부담이 덜한 이유가 바로 여기에 있습니다.

    • 실행 파일별 프로파일을 적용합니다.
    • 경로 기반이라 정책을 읽기 쉽습니다.
    • 처음 도입할 때 학습 곡선이 비교적 완만합니다.

    3. SELinux와 AppArmor 비교: 무엇이 다른가

    여기서 중요한 포인트! SELinux AppArmor 비교를 할 때 단순히 “누가 더 강한가”로 보면 답이 잘 안 나옵니다. 실제로는 운영 방식에 맞는지가 훨씬 더 중요하거든요.

    항목 SELinux AppArmor
    정책 기준 라벨 기반 경로 기반
    학습 난이도 상대적으로 높음 상대적으로 낮음
    정책 세밀도 매우 세밀함 직관적이고 단순한 편
    대표 사용 환경 RHEL 계열에서 자주 사용 Ubuntu 계열에서 자주 사용
    초기 운영 체감 로그 분석이 중요 프로파일 관리가 중요
    적합한 상황 엄격한 통제, 장기 운영 빠른 도입, 단순한 서비스 보호

    제 경험상 정리하면 이렇습니다.

    • SELinux: 처음엔 어렵지만, 표준화된 운영과 세밀한 정책이 필요한 환경에서 정말 강합니다.
    • AppArmor: 빠르게 적용하고 이해하기 쉬워서 소규모 서비스나 초기 구축에 부담이 훨씬 적습니다.
    • 보안 강도만 볼 게 아니라, 팀이 정책을 유지할 수 있는지가 더 중요한 선택 기준이 됩니다.

    4. 실전 구현: SELinux 기본 확인과 적용

    이제 실전으로 가보겠습니다. 제가 직접 해보니 무조건 정책부터 건드리기보다, 현재 상태를 먼저 보는 게 훨씬 낫습니다. SELinux는 특히 더 그렇습니다. 상태 확인 없이 파일만 만지면 나중에 왜 막혔는지 추적이 훨씬 어려워지거든요.

    1. SELinux 상태를 확인합니다.
    2. 서비스 파일 컨텍스트를 점검합니다.
    3. 필요하면 적절한 컨텍스트를 다시 지정합니다.
    4. 로그를 보고 실제 차단 원인을 확인합니다.
    getenforce
    seststatus
    ls -Z /var/www
    ps -eZ | grep httpd

    getenforce는 현재 모드를 빠르게 보여줍니다. Enforcing이면 정책이 실제로 강제 적용 중이고, Permissive면 차단 대신 로그만 남깁니다. 처음 테스트할 땐 Permissive 모드에서 원인부터 보는 게 훨씬 편하더라고요.

    sudo semanage fcontext -a -t httpd_sys_content_t "/srv/myweb(/.*)?"  
    sudo restorecon -Rv /srv/myweb

    이 명령은 웹 서버 콘텐츠 디렉터리에 적절한 타입을 지정하는 예시입니다. 여기서 정말 중요한 건 chmod로 해결하려고 하지 말고 컨텍스트를 봐야 한다는 점이에요. 저도 예전에 권한은 맞는데 계속 403이 떠서 한참 헤맸는데, 알고 보니 파일 라벨이 안 맞았던 경우가 정말 많았거든요.

    sudo ausearch -m avc -ts recent
    sudo journalctl -t setroubleshoot --since today

    SELinux는 로그를 보는 습관이 정말 핵심입니다. 거부 로그를 보면 무엇이 막혔는지 힌트를 얻을 수 있어요. 드디어 됐다! 하는 순간이 대부분 여기서 옵니다.

    SELinux AppArmor 비교 글의 SELinux 컨텍스트 적용 흐름 이미지

    SELinux에서 컨텍스트를 확인하고 복구하는 흐름을 단계별로 보여주는 이미지입니다.

    5. 실전 구현: AppArmor 기본 확인과 프로파일 적용

    AppArmor는 상대적으로 진입 장벽이 훨씬 낮습니다. 실제로 써보니까 정책 파일이 사람이 읽기 쉬워서, 빠르게 감을 잡기 정말 좋더라고요. 특히 단일 서비스 보호 용도로는 꽤 편했습니다.

    1. AppArmor가 활성화되어 있는지 확인합니다.
    2. 현재 로드된 프로파일과 적용 상태를 봅니다.
    3. 필요한 프로파일을 enforce 모드로 전환합니다.
    4. 로그를 보고 누락된 권한을 보완합니다.
    sudo aa-status
    sudo apparmor_status

    배포판에 따라 둘 중 하나를 쓰게 되는 경우가 있습니다. 출력에서 어떤 프로파일이 enforce 모드인지, complain 모드인지 확인하면 됩니다. complain은 차단 대신 기록만 남기는 모드라서 테스트할 때 정말 유용해요.

    sudo aa-complain /etc/apparmor.d/usr.sbin.nginx
    sudo aa-enforce /etc/apparmor.d/usr.sbin.nginx

    AppArmor는 이렇게 프로파일 단위로 전환하는 방식이 직관적입니다. 경로 기반이라 “이 서비스가 이 디렉터리를 왜 못 읽지?”를 추적할 때 상대적으로 수월했어요. 다만 경로 변경이 잦은 환경에서는 프로파일 관리가 생각보다 귀찮을 수 있습니다.

    sudo journalctl -k | grep DENIED
    sudo dmesg | grep apparmor

    차단 로그도 꼭 봐야 합니다. AppArmor는 쉬워 보이지만, 결국 로그를 안 보면 감으로 수정하게 되거든요. 그럼 나중에 정책이 지저분해져서 관리가 힘들어집니다.

    6. 어떤 환경에서 무엇을 선택할까

    SELinux AppArmor 비교의 결론은 기술 우열보다 운영 적합성에 있습니다. 제가 홈랩과 실무성 테스트 환경에서 느낀 기준을 정리해보면 이렇습니다.

    • SELinux를 권하고 싶은 경우: RHEL 계열을 쓰고 있고, 정책 일관성과 세밀한 제어가 중요할 때
    • AppArmor를 권하고 싶은 경우: Ubuntu 계열을 쓰고 있고, 빠르게 프로파일을 읽고 조정해야 할 때
    • 팀 운영 관점: 로그 분석과 정책 유지에 익숙한 팀이면 SELinux도 충분히 잘 굴릴 수 있습니다.
    • 개인 홈랩 관점: 처음 시작할 땐 AppArmor가 덜 부담스러울 수 있어요.

    사실 제가 직접 써봤을 때 느낀 체감은 이랬습니다. SELinux는 한 번 체계가 잡히면 든든하고, AppArmor는 처음 붙을 때 편하다는 거죠. 둘 다 좋은 도구인데, 도구보다 운영자의 숙련도가 더 크게 작용하더라고요.

    SELinux AppArmor 비교 선택 가이드를 위한 의사결정 이미지

    배포판, 운영 인력, 정책 복잡도에 따라 어떤 선택이 맞는지 보여주는 결정 흐름도입니다.

    7. ⚠️ 주의사항과 트러블슈팅

    이 섹션은 정말 중요합니다. 저도 처음엔 보안 기능을 꺼버리고 끝내고 싶었던 순간이 정말 많았거든요. 근데 그 습관 들이면 나중에 훨씬 더 힘들어집니다.

    7-1. 서비스가 안 되면 바로 비활성화하지 마세요

    가장 흔한 실수가 “일단 꺼서 되게 만들자”라는 생각입니다. 테스트 중 잠깐 상태를 완화하는 건 가능하지만, 영구 비활성화는 정말 신중해야 합니다. 문제 원인을 안 보고 끄면 이후에 보안 사고 대응력이 확 떨어지거든요.

    7-2. 파일 권한과 보안 정책을 혼동하지 마세요

    SELinux에서는 파일 권한이 맞아도 컨텍스트가 틀리면 접근이 막힙니다. AppArmor에서는 프로세스가 파일 경로 접근 권한을 갖고 있는지 별도로 봐야 합니다. 즉, chmod와 chown만으로는 완벽하게 해결되는 게 아닙니다.

    7-3. 로그 없는 수정은 거의 실패합니다

    • SELinux: AVC 거부 로그 확인
    • AppArmor: DENIED 로그 확인
    • 정책 변경 전후로 무엇이 달라졌는지 기록

    제가 실무 비슷한 환경에서 자주 하는 방식은 간단합니다. 먼저 로그를 보고, 그다음 가장 좁은 범위로 수정합니다. 한 번에 크게 열어버리면 편하긴 한데, 나중에 왜 열었는지 기억이 안 나더라고요.

    8. 검증과 결과 확인

    설정을 끝냈다면 반드시 검증해야 합니다. 적용했다고 믿는 것과 실제로 동작하는 건 정말 다르거든요. 여기서 확인할 건 세 가지입니다.

    1. 서비스가 정상 동작하는지 확인합니다.
    2. 보안 정책이 실제로 enforce 중인지 확인합니다.
    3. 거부 로그가 불필요하게 반복되지 않는지 봅니다.
    curl -I http://localhost
    getenforce
    sudo aa-status
    sudo journalctl -k --since "10 minutes ago"

    정상 응답이 오고, 보안 모드가 의도한 상태이며, 로그에 반복적인 거부가 없다면 1차 검증은 통과입니다. ✅ 여기까지 오면 운영 가능한 상태에 꽤 가까워진 겁니다. 저도 이 단계까지 정리해두면 이후 서비스 추가가 훨씬 수월했어요.

    SELinux AppArmor 비교 적용 후 검증 결과를 보여주는 대시보드 이미지

    서비스 정상 응답, 정책 적용 상태, 로그 감소 여부를 한눈에 확인하는 결과 이미지입니다.

    9. 정리와 FAQ

    SELinux vs AppArmor를 한 줄로 요약하면 이렇습니다. 세밀한 통제와 표준 운영이면 SELinux, 빠른 이해와 간결한 관리면 AppArmor를 선택하는 게 맞습니다. 물론 현실에선 배포판 기본값과 팀 경험이 선택에 큰 영향을 줍니다. 그래서 제 추천은 무조건 하나를 고집하기보다, 현재 운영 체계와 문제 해결 방식에 맞추는 거예요.

    다음 단계로는 컨테이너 환경에서의 보안 프로파일, systemd 서비스 하드닝, seccomp(시스템 콜 필터링) 같은 주제까지 이어가면 좋습니다. 이 부분은 다음 글에서 다룰 예정입니다. 이전 글에서 다뤘던 리눅스 권한 구조와 함께 보시면 흐름이 더 잘 잡히실 거예요.

    자주 묻는 질문

    • Q. 둘 중 하나만 꼭 써야 하나요?
      A. 보통은 배포판과 운영 표준에 맞춰 하나를 중심으로 관리하는 편이 현실적입니다.
    • Q. 초보자에게는 뭐가 더 쉬운가요?
      A. 대체로 AppArmor가 더 직관적입니다. 다만 장기 운영 기준에선 SELinux를 배워둘 가치가 정말 큽니다.
    • Q. 보안 기능이 성능을 크게 떨어뜨리나요?
      A. 일반적인 서버 운영에서 체감보다 정책 정확성이 더 큰 이슈인 경우가 많았습니다.
    SELinux AppArmor 비교 장단점을 정리한 인포그래픽

    선택 기준, 장단점, 추천 시나리오를 한 장으로 정리한 요약 인포그래픽입니다.

    마지막으로, SELinux AppArmor 비교를 하다 보면 자꾸 정답 하나를 찾게 되는데요. 실제로 써보니까 정답은 환경마다 달랐습니다. 중요한 건 꺼두는 게 아니라 이해하고 운영하는 거예요. 처음엔 헷갈려도, 로그를 읽고 정책을 조금씩 줄여가다 보면 감이 옵니다. 그 과정이 조금 번거롭긴 해도, 서버를 오래 안정적으로 굴리려면 결국 한 번은 넘어야 할 산이더라고요. 이거 정말 중요합니다.

  • [홈랩] 홈랩 VLAN 설정 완벽 가이드: 스위치와 라우터 연동

    [홈랩] 홈랩 VLAN 설정 완벽 가이드: 스위치와 라우터 연동

    [홈랩] 홈랩 VLAN 설정 완벽 가이드: 스위치와 라우터 연동

    홈랩 VLAN 설정, 한 번 제대로 잡아두면 네트워크가 정말 편해집니다. 서버는 서버끼리, IoT는 IoT끼리, 게스트 Wi-Fi는 내부망과 분리해서 굴릴 수 있거든요. 저도 처음 홈랩을 키울 때는 스위치에 선만 꽂으면 끝인 줄 알았는데, VM 하나 늘고 NAS 하나 붙고 카메라까지 들어오니까 금방 복잡해지더라고요. 결국 VLAN 구성으로 정리하고 나서야 드디어 됐다 싶었습니다. 특히 네트워크 분리와 보안 강화를 같이 챙기고 싶다면, 관리형 스위치와 라우터 VLAN 연동은 거의 필수에 가깝습니다.

    홈랩 VLAN 설정 전체 아키텍처를 보여주는 다이어그램

    관리형 스위치, 라우터, 서버, IoT, 게스트망이 VLAN별로 분리된 전체 구성 예시입니다.

    왜 홈랩 VLAN 설정이 중요한가요

    쉽게 말해 VLAN은 하나의 물리 네트워크를 여러 개의 논리 네트워크로 쪼개는 방식입니다. 선은 같은 스위치에 꽂혀 있어도, VLAN ID가 다르면 서로 다른 네트워크처럼 동작합니다. 이게 왜 좋으냐면요.

    • 관리망(Management)을 따로 빼서 스위치나 하이퍼바이저 관리 페이지를 안전하게 둘 수 있습니다.
    • 서버망(Server Network)과 개인 PC망을 분리해서 사고 범위를 줄일 수 있습니다.
    • IoT망을 따로 두면 카메라나 스마트 플러그가 내부 서버에 함부로 접근하지 못합니다.
    • 게스트망(Guest Network)을 만들면 손님 Wi-Fi를 줘도 마음이 좀 편해집니다.

    여기서 중요한 포인트! VLAN은 만능 보안 장비가 아니라 분리의 기본 단위입니다. 즉, 나누는 것만으로 끝나는 게 아니라 라우터에서 VLAN 간 통신 정책까지 같이 잡아야 진짜 의미가 있습니다.

    VLAN 구성 개념, 쉽게 말해 이렇게 이해하시면 됩니다

    저도 처음엔 태그니 언태그니 하면서 머리가 좀 아팠습니다 ㅎㅎ 그런데 아래 두 가지만 잡으면 금방 감이 옵니다.

    Tagged(태그드)와 Untagged(언태그드)

    Tagged(태그드)는 패킷에 VLAN 번호를 붙여서 보내는 방식입니다. 보통 스위치와 라우터 사이, 스위치와 하이퍼바이저 사이처럼 여러 VLAN을 한 선으로 같이 보낼 때 씁니다. 이 연결을 흔히 Trunk(트렁크)라고 부릅니다.

    Untagged(언태그드)는 패킷에 VLAN 태그를 붙이지 않는 방식입니다. PC 한 대, 프린터 한 대처럼 한 포트에서 한 네트워크만 쓰는 경우에 일반적으로 사용합니다. 이 포트를 흔히 Access(액세스) 포트라고 부르죠.

    PVID와 Native VLAN

    PVID(Port VLAN ID)는 태그 없이 들어온 트래픽을 어떤 VLAN으로 볼지 정하는 값입니다. 관리형 스위치에서 액세스 포트 설정할 때 자주 보게 됩니다. 제조사마다 표현은 조금 달라도 개념은 비슷합니다.

    항목 의미 주로 쓰는 곳
    Tagged VLAN 태그 포함 라우터-스위치, 스위치-서버 업링크
    Untagged VLAN 태그 없음 PC, 프린터, 단일 장비 연결 포트
    PVID 태그 없는 프레임의 기본 VLAN 액세스 포트 기본 소속 설정
    Trunk 여러 VLAN을 한 링크로 전달 업링크 포트

    실제로 써보니까, 홈랩 VLAN 설정에서 가장 많이 꼬이는 부분이 바로 여기였습니다. 스위치에서는 태그드로 보냈는데 라우터는 언태그드만 받고 있다거나, PVID가 엉뚱하게 남아 있다거나요. 증상은 인터넷 안 됨 하나로 보이는데 원인은 꽤 다양합니다.

    실전 설계: 먼저 VLAN 번호부터 정리해보겠습니다

    제가 홈랩에서 자주 쓰는 방식은 아래처럼 역할별로 VLAN을 나누는 겁니다. 꼭 이 숫자를 따라야 하는 건 아니지만, 일단 규칙을 정해두면 나중에 훨씬 덜 헷갈립니다.

    1. VLAN 10: 관리망 (스위치, 라우터, 하이퍼바이저 관리)
    2. VLAN 20: 서버망 (NAS, VM, 컨테이너 호스트)
    3. VLAN 30: IoT망 (카메라, 센서, 스마트 기기)
    4. VLAN 40: 게스트망 (외부 사용자용 Wi-Fi)

    예시 주소 체계도 같이 정해두면 좋습니다.

    vlans:
      10:
        name: mgmt
        subnet: 192.168.10.0/24
        gateway: 192.168.10.1
      20:
        name: servers
        subnet: 192.168.20.0/24
        gateway: 192.168.20.1
      30:
        name: iot
        subnet: 192.168.30.0/24
        gateway: 192.168.30.1
      40:
        name: guest
        subnet: 192.168.40.0/24
        gateway: 192.168.40.1

    이렇게 해두면 문서화도 쉽고, 방화벽(Firewall, 네트워크 접근 제어 장치) 규칙 만들 때도 편합니다.

    관리형 스위치와 라우터 VLAN 연동, 단계별로 해보겠습니다

    여기서는 특정 제조사 화면이 아니라, 대부분의 관리형 스위치와 Linux 기반 라우터에서 공통으로 이해할 수 있는 흐름으로 설명드릴게요. 모델마다 메뉴 이름은 달라도 핵심은 같습니다.

    1. 라우터 쪽에 VLAN 인터페이스 만들기

    라우터의 물리 인터페이스가 <code>eth0라고 가정해보겠습니다. 802.1Q(이더넷 VLAN 태깅 표준) 기반 서브인터페이스를 생성합니다.

    ip link add link eth0 name eth0.10 type vlan id 10
    ip link add link eth0 name eth0.20 type vlan id 20
    ip link add link eth0 name eth0.30 type vlan id 30
    ip link add link eth0 name eth0.40 type vlan id 40
    
    ip addr add 192.168.10.1/24 dev eth0.10
    ip addr add 192.168.20.1/24 dev eth0.20
    ip addr add 192.168.30.1/24 dev eth0.30
    ip addr add 192.168.40.1/24 dev eth0.40
    
    ip link set eth0 up
    ip link set eth0.10 up
    ip link set eth0.20 up
    ip link set eth0.30 up
    ip link set eth0.40 up

    이 작업은 재부팅해도 유지되도록 배포판 설정 파일이나 라우터 UI에 반영해야 하더라고요. CLI로 테스트한 뒤 영구 설정으로 옮기는 방식이 여러 번 배웠던 삽질을 줄여줍니다.

    2. DHCP 범위도 VLAN별로 분리하기

    라우터가 DHCP 서버 역할도 한다면, 네트워크별로 주소 풀을 따로 나눠서 줘야 합니다.

    dhcp:
      - interface: eth0.10
        range: 192.168.10.100-192.168.10.199
      - interface: eth0.20
        range: 192.168.20.100-192.168.20.199
      - interface: eth0.30
        range: 192.168.30.100-192.168.30.199
      - interface: eth0.40
        range: 192.168.40.100-192.168.40.199

    저는 예전에 이걸 빼먹어서, VLAN은 잘 나뉘었는데 IP가 안 붙는 바람에 한참 헤맸습니다. 핑도 안 되고, 장비는 링크 업인데 네트워크는 죽어 있고… 이런 경우 DHCP부터 보시면 됩니다.

    홈랩 VLAN 설정에서 관리형 스위치 포트 구성을 설명하는 이미지

    라우터-스위치 업링크는 트렁크, 단말 포트는 액세스 형태로 나뉘는 구성을 보여주는 예시입니다.

    3. 관리형 스위치 포트 역할 정하기

    예를 들어 포트 1번은 라우터와 연결, 포트 2번은 하이퍼바이저, 포트 3번은 NAS, 포트 4번은 IoT AP, 포트 5번은 관리용 PC라고 가정해보겠습니다.

    포트 연결 대상 설정 비고
    1 라우터 VLAN 10/20/30/40 Tagged 트렁크
    2 하이퍼바이저 VLAN 10/20 Tagged VM별 VLAN 사용
    3 NAS VLAN 20 Untagged, PVID 20 서버망 전용
    4 무선 AP VLAN 30/40 Tagged, VLAN 10 Untagged 또는 Tagged SSID 분리
    5 관리 PC VLAN 10 Untagged, PVID 10 관리망 접속

    여기서 중요한 포인트! 스위치 관리 IP를 어느 VLAN에 둘지 먼저 정하셔야 합니다. 저는 보통 관리망 VLAN 10에 둡니다. 나중에 장비 찾기가 훨씬 쉽거든요.

    4. 스위치에 VLAN 멤버십 적용하기

    제조사마다 화면은 다르지만 보통 이런 순서로 진행합니다.

    1. VLAN 10, 20, 30, 40 생성
    2. 포트 1을 각 VLAN의 Tagged 멤버로 추가
    3. 포트 3은 VLAN 20의 Untagged 멤버로 설정하고 PVID 20 지정
    4. 포트 5는 VLAN 10의 Untagged 멤버로 설정하고 PVID 10 지정
    5. AP 연결 포트는 SSID 설계에 맞춰 Tagged VLAN 추가

    혹시 메인 SSID는 직원망, 게스트 SSID는 손님망처럼 나누고 싶다면 여기서 라우터 VLAN과 무선 SSID 매핑까지 함께 설계하면 됩니다.

    5. VLAN 간 접근 정책 만들기

    VLAN을 나누는 것만으로는 부족합니다. 라우터에서 어디까지 통신을 허용할지 정해야 진짜 보안 강화가 됩니다. 저는 보통 이렇게 시작합니다.

    # 예시 개념
    # guest(40) -> internet only
    # iot(30) -> internet allowed, mgmt(10) blocked
    # servers(20) -> mgmt(10) from admin PC only
    
    iptables -A FORWARD -s 192.168.40.0/24 -d 192.168.10.0/24 -j DROP
    iptables -A FORWARD -s 192.168.40.0/24 -d 192.168.20.0/24 -j DROP
    iptables -A FORWARD -s 192.168.30.0/24 -d 192.168.10.0/24 -j DROP
    iptables -A FORWARD -s 192.168.10.50 -d 192.168.20.0/24 -j ACCEPT

    물론 실제 환경에서는 기본 정책, 상태 기반(Stateful) 허용, DNS/NTP 예외도 같이 보셔야 합니다. 다만 처음에는 차단 먼저, 필요한 것만 허용 이 원칙으로 가는 게 훨씬 안전합니다.

    ⚠️ 제가 직접 겪은 트러블슈팅 포인트

    홈랩 VLAN 설정에서 많이 겪는 문제를 정리해보겠습니다. 이건 진짜 현장에서, 아니 제 방 서버실에서 삽질하면서 얻은 체크리스트입니다.

    • 인터넷은 되는데 내부 장비가 안 보임: 방화벽 규칙이 너무 강하거나, 반대로 라우팅은 됐는데 DNS가 VLAN별로 안 열려 있을 수 있습니다.
    • 아예 IP를 못 받음: DHCP가 해당 VLAN 인터페이스에 바인딩되지 않았거나, 스위치 포트 PVID가 틀렸을 가능성이 큽니다.
    • 스위치 관리 페이지 접속 불가: 스위치 관리 IP가 속한 VLAN과 접속 포트 VLAN이 안 맞는 경우가 많습니다. 이거 한 번 꼬이면 공장 초기화 유혹이 엄청 강해집니다.
    • 하이퍼바이저 VM만 통신 안 됨: 가상 스위치(vSwitch)나 브리지에서 VLAN 태깅을 따로 켜야 하는 경우가 있습니다.
    • 무선 AP의 게스트 SSID 분리가 안 됨: AP 업링크 포트가 트렁크가 아니거나, SSID별 VLAN ID 매핑이 다를 수 있습니다.

    저도 처음엔 라우터 문제인 줄 알고 라우터만 계속 봤었는데, 알고 보니 스위치 포트 하나가 Untagged로 남아 있더라고요. 이런 건 진짜 허무합니다. 그래서 저는 이제 변경할 때마다 포트별 역할을 메모해둡니다.

    빠르게 확인하는 점검 명령어

    ip -d link show
    ip addr show
    ip route show
    ping 192.168.10.1
    ping 192.168.20.1
    arp -n

    ip -d link show는 VLAN 서브인터페이스가 제대로 올라왔는지 볼 때 꽤 유용합니다. 태그 ID까지 보여서 실수 잡기 좋습니다.

    홈랩 VLAN 설정 검증을 위한 라우터 VLAN 상태 점검 이미지

    라우터에서 VLAN 서브인터페이스와 접근 제어 정책을 점검하는 장면을 표현한 이미지입니다.

    검증: 네트워크 분리와 통신 결과는 어떻게 확인할까요

    구성이 끝나면 아래 순서로 검증해보시면 됩니다. 이 과정을 건너뛰면 나중에 어디가 잘못됐는지 찾기가 더 어려워집니다.

    1. 관리 PC를 VLAN 10 포트에 연결하고 스위치/라우터 관리 페이지 접속 확인
    2. 서버 장비가 VLAN 20 주소를 정상적으로 받는지 확인
    3. IoT 장비가 VLAN 30 대역에서 인터넷만 되는지 확인
    4. 게스트망 장비가 내부 NAS나 관리 페이지에 접근되지 않는지 확인
    5. 필요한 예외 통신만 허용되는지 로그로 점검

    예를 들어, 게스트망에서 아래 테스트를 해보는 식입니다.

    ping 192.168.10.1
    ping 192.168.20.10
    ping 8.8.8.8
    nslookup example.com

    정상이라면 관리망/서버망 핑은 막히고, 외부 인터넷과 DNS는 동작해야겠죠. 이런 식으로 시나리오 기반으로 확인해보면 설정이 눈에 잘 들어옵니다. 🎉

    정리 표: 어떤 식으로 나누면 운영이 편한가요

    VLAN 용도 권장 정책 운영 팁
    10 관리망 관리자 PC만 접근 허용 장비 관리 IP 일관성 유지
    20 서버망 필요 포트만 외부/내부 허용 서비스별 방화벽 로그 확인
    30 IoT망 인터넷 허용, 내부망 최소화 제조사 클라우드 의존성 주의
    40 게스트망 인터넷 전용, 내부 접근 차단 DNS/NTP만 예외 허용 검토
    홈랩 VLAN 설정 결과와 네트워크 분리 상태를 요약한 이미지

    각 VLAN 간 허용/차단 관계와 인터넷 접근 여부를 한눈에 보여주는 요약 이미지입니다.

    자주 묻는 질문

    Q1. VLAN 하나만 써도 되는데 굳이 나눠야 하나요?

    장비가 3~4대 수준이면 당장은 괜찮을 수 있습니다. 근데 홈랩은 보통 점점 커지거든요. NAS 붙고, 미니 PC 붙고, AP 붙고, 카메라 들어오면 그때부터 한 네트워크에 다 섞여 있는 게 더 불편해집니다.

    Q2. 관리형 스위치가 꼭 필요한가요?

    홈랩 VLAN 설정을 제대로 하려면 사실상 필요합니다. 비관리형 스위치는 VLAN 태그 처리나 포트별 정책이 안 되니까, 라우터 VLAN만으로는 한계가 있습니다.

    Q3. 라우터 한 대로도 가능한가요?

    가능합니다. 라우터가 802.1Q VLAN 인터페이스와 방화벽 정책을 지원하면 됩니다. 다만 포트 수나 무선 SSID 분리까지 생각하면 관리형 스위치와 AP까지 같이 보는 편이 현실적입니다.

    마무리: 홈랩 VLAN 설정은 귀찮지만, 한 번 해두면 오래 갑니다

    처음엔 이게 뭔가 싶었는데, 막상 구성해두면 체감 차이가 큽니다. 관리망은 깔끔해지고, 서버는 좀 더 안전해지고, IoT 장비 때문에 찝찝한 마음도 줄어들거든요. 제가 직접 해보니 핵심은 딱 세 가지였습니다. VLAN 번호 규칙 통일, 스위치 포트 역할 문서화, 라우터 방화벽 정책 분리입니다.

    혹시 지금 홈랩이 점점 복잡해지고 있다면, 이번 기회에 VLAN 구성부터 정리해보셔도 좋겠습니다. 다음 글에서는 VLAN 위에 얹는 Inter-VLAN Routing(인터 VLAN 라우팅) 정책과 홈랩 방화벽 룰 설계 팁도 다뤄볼 예정입니다. 이전 글에서 다뤘던 백업 네트워크 분리 구성과도 연결되는 내용이라 같이 보시면 이해가 더 잘 되실 거예요. 💡

    구축 후 점검해야 할 체크리스트와 다음 확장 단계 아이디어를 담은 마무리 이미지입니다.

  • [Linux] 컨테이너 없이 리눅스 네임스페이스로 프로세스 격리하기: 실제 사례 연구

    [Linux] 컨테이너 없이 리눅스 네임스페이스로 프로세스 격리하기: 실제 사례 연구

    [리눅스] 컨테이너 없이 네임스페이스로 프로세스 격리하기

    리눅스 네임스페이스 사례를 찾다 보면 대부분 Docker나 Kubernetes 이야기로 바로 넘어가더라고요. 근데 현장에서는 꼭 컨테이너 런타임(container runtime)이 있어야만 프로세스 격리를 할 수 있는 건 아닙니다. 저도 홈랩에서 작은 배치 작업, 외부에서 받은 스크립트 검증, 네트워크가 민감한 유지보수 작업을 분리할 때 처음부터 컨테이너를 올리기엔 오버헤드가 애매한 경우가 있었거든요.

    그래서 이번 글에서는 컨테이너 원리의 핵심인 Namespace(네임스페이스, 커널 자원 뷰 분리)를 직접 써서 프로세스를 격리한 사례를 정리해보겠습니다. 제가 직접 해보니 처음엔 이게 뭔가 싶었는데, 구조를 한 번 이해하고 나니까 특정 작업을 빠르게 샌드박스(sandbox, 제한된 실행 공간)로 감싸는 데 꽤 유용했습니다. 특히 보안 강화와 시스템 설계 관점에서 어디까지 가능한지 감이 잡히더라고요.

    리눅스 네임스페이스 사례를 설명하는 프로세스 격리 아키텍처 개요 이미지

    호스트와 격리된 프로세스가 PID, 네트워크, 마운트 관점에서 어떻게 분리되는지 보여주는 개요 이미지입니다.

    1. 왜 컨테이너 없이 격리를 보려고 했는가

    실무에서 늘 Docker가 정답은 아니었습니다. 예를 들어 이런 경우가 있었습니다.

    • 운영 서버에 컨테이너 엔진 설치를 최소화해야 하는 경우
    • 일회성 스크립트를 네트워크에서 분리해 실행하고 싶은 경우
    • 빌드 작업이나 백업 검증 작업을 호스트와 다른 PID 뷰로 띄우고 싶은 경우
    • 문제 재현용 프로세스를 빠르게 분리해 테스트하고 싶은 경우

    저는 홈랩에서 외부 저장소에서 받은 백업 복구 스크립트를 바로 호스트에서 돌리기 좀 꺼려졌습니다. 사실 스크립트 한 줄 잘못되면 마운트 포인트를 건드리거나, 예상 못 한 네트워크 접근을 할 수도 있거든요. 그때 느낀 게, “아 컨테이너 이미지를 만들기 전에 커널 기능만으로도 1차 격리는 가능하겠구나”였습니다.

    2. 네임스페이스 개념 설명: 쉽게 말해 무엇이 분리되나

    쉽게 말해 Namespace(네임스페이스)는 프로세스가 보는 세상 자체를 따로 만드는 기능입니다. 같은 리눅스 커널 위에서 돌지만, 프로세스 입장에서는 자기만의 PID 목록, 네트워크 인터페이스, 호스트 이름, 마운트 뷰를 보게 되는 거죠.

    컨테이너 원리를 아주 거칠게 줄이면 이겁니다. Namespace로 보이는 범위를 나누고, Cgroup(컨트롤 그룹, 자원 사용 제한)으로 CPU/메모리를 제한하고, 파일시스템 레이어를 얹는다. 오늘은 그중 Namespace 쪽에 집중해보겠습니다.

    자주 쓰는 네임스페이스 종류

    • PID Namespace: 프로세스 ID 공간 분리
    • Mount Namespace: 마운트 포인트 뷰 분리
    • Network Namespace: 네트워크 인터페이스, 라우팅 테이블 분리
    • UTS Namespace: hostname, domainname 분리
    • IPC Namespace: 프로세스 간 통신 자원 분리
    • User Namespace: 사용자/권한 매핑 분리

    여기서 중요한 포인트! 네임스페이스만 쓴다고 완전한 보안 샌드박스가 되는 건 아닙니다. 그래도 적어도 “호스트와 같은 뷰를 그대로 공유하지 않게 한다”는 점에서 상당히 큰 차이가 납니다.

    기술별 차이 한눈에 보기

    기술 격리 범위 장점 한계
    chroot(루트 변경) 파일 경로 중심 단순함 보안 격리 수단으로는 약함
    Namespace(네임스페이스) PID, 네트워크, 마운트 등 커널 자원 뷰 가볍고 빠름 자원 제한은 별도 구성 필요
    Container(컨테이너) Namespace + Cgroup + 이미지/런타임 운영 자동화에 유리 런타임 의존성과 운영 복잡도 증가

    3. 실제 사례 연구: 백업 검증 스크립트를 안전하게 분리하기

    제가 실험한 시나리오는 이렇습니다. 백업 파일 무결성을 확인하고 압축을 풀어보는 스크립트를 테스트해야 했는데, 호스트 네트워크를 그대로 쓰게 두고 싶지 않았고, /tmp 아래에서 이것저것 생성하는 것도 호스트와 분리하고 싶었습니다. 그래서 아래 목표를 잡았습니다.

    1. 호스트와 다른 PID 공간에서 실행할 것
    2. 호스트 네트워크를 끊거나 별도 네트워크만 사용할 것
    3. 마운트 뷰를 분리해서 /proc, 작업 디렉터리를 별도로 보이게 할 것
    4. 가능하면 hostname도 바꿔서 “격리된 환경”임을 명확히 할 것

    이 작업은 컨테이너 엔진 없이도 unshare와 nsenter만으로 꽤 깔끔하게 구성할 수 있었습니다.

    리눅스 네임스페이스 사례의 실전 구성과 unshare 기반 프로세스 격리 이미지

    unshare 실행 후 PID, UTS, Mount, Network 네임스페이스가 분리되는 흐름을 설명하는 구성 이미지입니다.

    4. 실전 구현: unshare로 프로세스 격리 만들기

    실제로 써보니까 첫 진입점은 unshare가 제일 직관적이었습니다. 아래 예시는 격리된 셸(shell, 명령 실행 환경)을 띄우는 기본 형태입니다.

    4-1. 가장 기본적인 격리 셸 실행

    sudo unshare \
      --fork \
      --pid \
      --mount \
      --uts \
      --ipc \
      --net \
      --mount-proc \
      bash

    옵션 의미는 이렇습니다.

    • --fork: 새로운 프로세스로 진입
    • --pid: 새로운 PID Namespace 생성
    • --mount: 새로운 Mount Namespace 생성
    • --uts: hostname 분리
    • --ipc: IPC 자원 분리
    • --net: Network Namespace 분리
    • --mount-proc: 새 PID 공간에 맞는 /proc 마운트

    이 상태로 들어가서 ps를 치면, 호스트 전체 프로세스가 아니라 격리된 프로세스 뷰만 보입니다. 처음 확인했을 때 “오, 진짜 분리됐네” 싶더라고요. 이런 순간이 좀 재밌습니다 ㅎㅎ

    4-2. 격리 환경 안에서 hostname 바꾸기

    hostname isolated-lab
    uname -n

    UTS Namespace 덕분에 호스트 이름을 바꿔도 호스트 본체에는 영향이 없습니다. 작은 부분 같아도 테스트 로그를 볼 때 꽤 유용합니다.

    4-3. 마운트 뷰 분리와 작업 디렉터리 고립

    제가 삽질했던 부분이 여기였습니다. Mount Namespace를 만들었는데도 기존 마운트 전파(propagation) 설정 때문에 예상과 다르게 보이는 경우가 있더라고요. 그래서 보통은 아래처럼 먼저 private으로 바꿔주는 쪽이 안전했습니다.

    mount --make-rprivate /
    mkdir -p /tmp/lab-root
    mount -t tmpfs tmpfs /tmp/lab-root
    cd /tmp/lab-root

    이렇게 하면 작업 디렉터리를 메모리 기반 tmpfs로 띄워서 테스트 흔적을 최소화할 수 있습니다. 외부 스크립트를 검증할 때 꽤 편했습니다.

    4-4. 네트워크를 완전히 막고 실행하기

    Network Namespace를 새로 만들면 기본적으로 인터페이스가 거의 없는 상태로 시작합니다. “네트워크 없는 환경에서 이 스크립트가 깨끗하게 도는지” 확인할 때 딱 좋습니다.

    ip link set lo up
    ip addr
    ping -c 1 8.8.8.8

    루프백(loopback)만 올리고 외부 인터페이스를 연결하지 않으면 외부 통신은 되지 않습니다. 저는 백업 검증 스크립트가 혹시라도 외부로 뭔가 호출하는지 확인할 때 이 방법을 자주 썼습니다.

    4-5. 실제 테스트 스크립트 실행 예시

    cat > /tmp/verify-backup.sh <<'EOF'
    #!/usr/bin/env bash
    set -euo pipefail
    mkdir -p work
    cd work
    echo "test file" > sample.txt
    tar -czf sample.tar.gz sample.txt
    tar -xzf sample.tar.gz
    ps -ef
    ip addr || true
    hostname
    EOF
    
    chmod +x /tmp/verify-backup.sh
    /tmp/verify-backup.sh

    여기서 보게 되는 ps, ip addr, hostname 결과가 전부 호스트와 다르게 보이면 1차 격리는 성공입니다. 이게 컨테이너 원리 이해에도 정말 도움이 됩니다.

    프로세스 격리 결과를 보여주는 리눅스 네임스페이스 사례 터미널 이미지

    격리된 프로세스 공간과 제한된 네트워크 환경이 실제 명령 결과에서 어떻게 보이는지 보여주는 예시 이미지입니다.

    5. 조금 더 현실적인 시스템 설계 포인트

    단순 데모를 넘어서 실제 운영에 붙이려면 몇 가지를 같이 봐야 합니다.

    • User Namespace를 함께 검토해서 권한 매핑을 분리할 것
    • Cgroup으로 CPU/메모리 제한을 따로 둘 것
    • seccomp 같은 시스템 콜 필터링까지 가면 더 단단해질 것
    • 파일시스템은 가능하면 읽기 전용(read-only) 바인드 마운트도 고려할 것

    즉, Namespace는 시작점입니다. 보안 강화라는 말이 과장되지 않으려면, “무엇을 분리했고 무엇은 아직 공유하는가”를 명확히 이해해야 합니다. 저도 처음엔 네임스페이스만 쓰면 거의 컨테이너랑 같은 줄 알았는데, 운영 관점에서는 그 사이에 꽤 많은 층이 있더라고요.

    6. ⚠️ 주의사항과 트러블슈팅: 제가 실제로 막혔던 지점

    여기서는 진짜 삽질 포인트만 적어보겠습니다. 혹시 비슷한 경험 있으신가요? 아래 부분에서 많이 막힙니다.

    6-1. /proc가 기대와 다르게 보이는 문제

    원인: 새 PID Namespace를 만들었는데 /proc를 새로 마운트하지 않은 경우입니다.

    해결: --mount-proc 옵션을 쓰거나, 진입 후 직접 proc를 마운트합니다.

    mount -t proc proc /proc

    6-2. 네트워크가 완전히 끊긴 줄 알았는데 아니었던 문제

    원인: 별도 네임스페이스를 안 만들고 호스트 네트워크를 그대로 쓴 경우입니다.

    해결: --net 사용 여부를 먼저 확인하세요. 그리고 격리 환경 안에서 ip addr를 꼭 확인해야 합니다.

    6-3. 마운트가 호스트까지 영향을 주는 것처럼 보이는 문제

    원인: 마운트 전파 설정이 공유(shared) 상태인 경우입니다.

    해결: 작업 초기에 아래 명령으로 전파 범위를 조정합니다.

    mount --make-rprivate /

    6-4. 이게 보안 경계인가요? 라는 질문

    중요한 답은 “상황에 따라 다릅니다”입니다. Namespace만으로 충분한 경우도 있지만, 신뢰할 수 없는 코드를 장시간 돌리거나 외부 입력이 많은 환경이라면 추가 방어 계층이 필요합니다. 그래서 저는 보통 아래 순서로 생각합니다.

    1. Namespace로 뷰 분리
    2. Cgroup으로 자원 제한
    3. 권한 최소화
    4. 읽기 전용 마운트, 임시 작업 공간 분리
    5. 필요시 VM(가상머신) 수준 격리 검토

    7. 검증과 결과: 무엇이 달라졌는지 확인하기

    격리가 제대로 되었는지는 감으로 보면 안 됩니다. 저는 아래 항목을 체크리스트처럼 확인했습니다.

    1. ps -ef 출력에서 호스트 전체 프로세스가 보이지 않는지
    2. hostname 결과가 격리된 값으로 나오는지
    3. ip addr 결과에 호스트 인터페이스가 안 보이는지
    4. 작업 중 생성한 파일이 의도한 임시 공간에만 남는지
    5. 작업 종료 후 흔적 정리가 쉬운지

    결론부터 말하면, 컨테이너 없이도 특정 목적의 프로세스 격리는 충분히 실용적이었습니다. 특히 테스트성 작업, 분석성 작업, 외부 스크립트 검증 같은 용도에서는 빠르게 적용할 수 있었고요. 반대로 이미지 배포, 재현 가능한 패키징, 대규모 운영 자동화까지 가면 컨테이너 쪽이 더 낫습니다.

    리눅스 네임스페이스 사례의 검증 결과와 프로세스 격리 비교 요약 이미지

    PID, 네트워크, 마운트, hostname 항목별로 격리 전후 차이를 정리한 결과 요약 이미지입니다.

    8. 자주 묻는 질문 정리

    Q1. chroot만 쓰면 안 되나요?

    chroot는 파일 경로 뷰를 바꾸는 데는 유용하지만, PID나 네트워크까지 분리해주지는 않습니다. 그래서 프로세스 격리 목적이면 네임스페이스가 훨씬 적합합니다.

    Q2. 이게 Docker를 완전히 대체하나요?

    아닙니다. Docker 같은 컨테이너 도구는 이미지 관리, 배포, 네트워크 구성, 볼륨 운영까지 묶어서 편의성을 제공합니다. 네임스페이스는 그 아래 레이어를 이해하고 직접 다루는 방식에 가깝습니다.

    Q3. 어떤 상황에서 특히 유용했나요?

    저는 홈랩에서 아래 같은 상황에 잘 맞았습니다.

    • 일회성 유지보수 스크립트 검증
    • 네트워크 차단 상태 재현
    • 호스트 프로세스 목록과 분리된 테스트 셸 구성
    • 컨테이너 엔진 없는 환경에서의 임시 샌드박스

    9. 마무리: 네임스페이스를 알면 컨테이너가 더 잘 보입니다

    이번 리눅스 네임스페이스 사례를 통해 느낀 건, 컨테이너는 갑자기 하늘에서 떨어진 기술이 아니라는 점이었습니다. 결국 커널 기능을 조합해서 보안 강화와 운영 편의성을 만든 결과물이더라고요. 제가 직접 해보니 Docker 명령어만 외우던 때보다, 장애를 볼 때도 구조가 훨씬 잘 읽혔습니다.

    처음엔 unshare 옵션이 낯설고, /proc나 마운트 전파 때문에 좀 헷갈릴 수 있습니다. 저도 처음엔 꽤 헤맸거든요. 근데 한 번 손으로 만들어보면 시스템 설계 감각이 정말 좋아집니다. 다음 글에서는 이 흐름을 이어서 Cgroup(컨트롤 그룹, 자원 제한)과 함께 묶어 더 실전적인 샌드박스를 만드는 방법도 다뤄볼 예정입니다. 이전 글에서 다룬 리눅스 프로세스 관리 글이 있다면 같이 보셔도 흐름이 잘 이어질 겁니다. ✅

  • [보안] HashiCorp Vault, 1년 사용 후기: 보안 강화와 운영 효율성 회고

    [보안] HashiCorp Vault, 1년 사용 후기: 보안 강화와 운영 효율성 회고

    [DevOps] HashiCorp Vault 1년 사용 후기와 운영 회고

    인프라를 오래 만지다 보면 결국 한 번은 부딪히는 문제가 있습니다. 비밀번호, API Token(토큰, 인증용 비밀값), 인증서, 데이터베이스 계정 같은 비밀 정보(secret)를 어디에 두고 어떻게 돌볼 것인가 하는 문제입니다. 저도 예전에는 환경 변수, CI/CD 변수, 사설 위키, 심지어 급할 때는 메신저 DM까지 섞여 있던 시절이 있었거든요. 그런데 팀이 커지고 서비스 수가 늘어나니까 그 방식이 한계가 너무 واضح해졌습니다. 그래서 지난 1년 동안 HashiCorp Vault 사용 후기를 쌓아 보자는 마음으로 운영에 붙여 봤고, 결론부터 말씀드리면 보안 강화와 운영 효율성 둘 다 꽤 체감했습니다.

    물론 처음부터 매끈하진 않았습니다. 오히려 초반엔 정책(policy, 접근 제어 규칙) 설계 때문에 삽질 좀 했습니다 ㅎㅎ 그래도 실제로 써보니까, 비밀 관리가 사람 손에 덜 의존하게 되고 누가 무엇에 접근했는지 추적하기 쉬워지더라고요. 이번 글에서는 제가 겪은 HashiCorp Vault 운영 경험을 바탕으로, 왜 도입했고 어떤 식으로 붙였는지, 그리고 1년 돌려보니 무엇이 달라졌는지를 솔직하게 정리해보겠습니다.

    HashiCorp Vault 사용 후기를 설명하는 비밀 관리 아키텍처 다이어그램

    Vault를 중심으로 애플리케이션, CI/CD, 운영자 접근 흐름을 한눈에 보여주는 아키텍처 예시입니다.

    1. 왜 굳이 Vault였을까: 비밀 관리가 운영 비용이 되는 순간

    쉽게 말해 Vault는 Secret Management(비밀 관리) 전용 금고입니다. 그냥 값을 저장하는 저장소가 아니라, 누가 어떤 비밀을 언제 읽었는지 통제하고, 필요하면 동적으로 자격 증명(credentials, 인증 정보)을 발급하고, 주기적으로 회전(rotation, 교체)하는 데 초점이 맞춰져 있습니다.

    제가 직접 해보니 중요한 건 저장보다 수명 주기 관리였습니다. 비밀은 한 번 넣고 끝나는 데이터가 아니더라고요. 생성, 배포, 접근 통제, 만료, 교체, 폐기까지 계속 관리해야 합니다. 이걸 사람이 엑셀이나 문서로 붙잡고 있으면 언젠가 사고가 납니다. 혹시 이런 경험 있으신가요? 퇴사자 계정은 막았는데, 그 사람이 발급해 둔 외부 API 키는 그대로 살아 있는 상황이요. 저는 실제로 그런 걸 정리하면서 Vault의 필요성을 절실하게 느꼈습니다.

    • 보안 강화: 비밀을 평문 파일이나 문서에 두지 않게 됩니다.
    • 접근 통제: 애플리케이션별, 팀별로 읽을 수 있는 경로(path)를 나눌 수 있습니다.
    • 감사 추적: Audit Log(감사 로그) 관점에서 누가 접근했는지 확인하기 편합니다.
    • 운영 효율: 만료와 교체를 자동화하기 쉬워집니다.

    2. HashiCorp Vault 개념 설명: 처음엔 복잡해 보여도 핵심은 단순합니다

    저도 처음엔 용어가 많아서 헷갈렸는데, 딱 몇 가지만 이해하면 흐름이 잡힙니다.

    개념 쉽게 말하면 운영에서 체감한 포인트
    Secrets Engine(시크릿 엔진) 비밀을 저장하거나 발급하는 기능 단위 KV, PKI, Database처럼 목적별로 분리해서 쓰기 좋습니다.
    Auth Method(인증 방식) 사용자나 서비스가 Vault에 로그인하는 방법 Token, AppRole, Kubernetes Auth 등을 상황별로 나눌 수 있습니다.
    Policy(정책) 어디까지 읽고 쓰게 할지 정하는 권한 규칙 처음 설계를 잘해야 운영이 편합니다.
    Lease(임대) 발급된 비밀의 유효 기간 영구 자격 증명 대신 짧게 쓰는 습관이 생깁니다.
    Audit Device(감사 장치) 접근 기록을 남기는 기능 사고 대응과 추적에 정말 중요합니다.

    여기서 중요한 포인트! Vault를 도입한다고 해서 갑자기 모든 비밀이 안전해지는 건 아닙니다. 어떤 인증 방식으로 접속시키고, 어떤 정책으로 경로를 나누고, 애플리케이션이 어떻게 비밀을 가져가게 할지까지 같이 설계해야 진짜 효과가 납니다. 그래서 저는 Vault를 제품 하나로 보기보다, 비밀 관리 운영 체계를 만드는 도구로 보는 편입니다.

    3. 도입 전후 비교: 운영 습관이 어떻게 바뀌었는가

    1년 전과 지금을 비교하면 가장 큰 차이는 “비밀을 사람이 들고 다니지 않게 됐다”는 점입니다. 예전엔 신규 서비스가 뜰 때마다 환경 변수 파일을 복사해 배포하고, 누가 최신값인지 물어보는 일이 잦았거든요. 지금은 최소한 기준 저장소와 접근 절차가 분리되어 있어서 훨씬 낫습니다.

    항목 도입 전 도입 후
    비밀 저장 위치 여러 군데 흩어짐 Vault 경로 기준으로 정리
    권한 관리 사람 기억과 문서 의존 Policy 기반 통제
    교체 작업 수동 공지 후 반영 주기화와 자동화 설계 가능
    장애 대응 누가 뭘 바꿨는지 찾기 어려움 감사 로그로 추적 쉬움
    DevOps 협업 운영팀 병목 발생 경로와 역할을 나눠 위임 가능

    이 변화가 생각보다 큽니다. 특히 DevOps 환경에서는 CI/CD 파이프라인, 컨테이너 워크로드, 운영자 접근이 동시에 얽히거든요. Vault를 넣고 나면 적어도 “어디가 원본이냐”는 질문은 줄어듭니다. 이거 진짜 편하더라고요.

    4. 실전 구현: 제가 초기에 잡았던 최소 구성

    이번 섹션은 처음 구축할 때 제가 사용했던 접근을 최대한 단순하게 정리한 것입니다. 운영 환경에서는 네트워크 분리, TLS(전송 구간 암호화), 백업, 접근 통제, 고가용성 설계를 반드시 더해야 합니다. 아래 예시는 흐름 이해용에 가깝습니다.

    4-1. Vault 서버 기본 구성 예시

    storage "raft" {
      path    = "/opt/vault/data"
      node_id = "vault-1"
    }
    
    listener "tcp" {
      address     = "0.0.0.0:8200"
      tls_disable = 0
      tls_cert_file = "/opt/vault/tls/tls.crt"
      tls_key_file  = "/opt/vault/tls/tls.key"
    }
    
    api_addr = "https://vault.example.internal:8200"
    cluster_addr = "https://vault.example.internal:8201"
    ui = true

    처음엔 외부 스토리지와 따로 연동할지 고민했는데, 실제로 써보니까 Integrated Storage(통합 스토리지, Raft 기반 저장소)가 운영 복잡도를 낮추는 데 도움이 되더라고요. 물론 조직 상황에 따라 선택은 달라질 수 있습니다.

    4-2. 초기화와 언실(unseal) 절차

    vault operator init
    vault operator unseal
    vault login

    여기서 나오는 Unseal Key(언실 키)와 초기 Root Token(루트 토큰)은 정말 조심해서 다뤄야 합니다. 저는 초반에 테스트 환경에서만 가볍게 생각했다가, 나중에 누가 어떤 키를 갖고 있는지 정리하느라 고생했습니다. 운영 환경에서는 보관 정책부터 먼저 정해야 합니다.

    4-3. KV 엔진으로 애플리케이션 비밀 저장

    vault secrets enable -path=kv kv-v2
    vault kv put kv/apps/payment DB_USER="app_user" DB_PASSWORD="change-me"
    vault kv get kv/apps/payment

    처음 시작은 대부분 KV(Key-Value) Engine부터 하게 됩니다. 저도 그랬습니다. 일단 애플리케이션이 읽어 가는 기준 경로를 만드는 것만으로도 운영 정리가 꽤 됩니다.

    HashiCorp Vault 운영에서 정책과 KV 경로 구성을 보여주는 이미지

    서비스별 경로, 팀별 정책, 인증 방식이 어떻게 연결되는지 보여주는 구성 예시입니다.

    4-4. 정책 분리: 서비스별 최소 권한으로 시작

    path "kv/data/apps/payment" {
      capabilities = ["read"]
    }
    vault policy write payment-read payment-read.hcl

    제가 초기에 가장 많이 했던 실수가 이 부분입니다. 귀찮아서 넓게 열어두면 나중에 정리하기가 더 어렵습니다. Least Privilege(최소 권한) 원칙으로 서비스별 경로를 쪼개 두는 게 결국 덜 힘듭니다.

    4-5. 애플리케이션 인증 연결

    환경에 따라 Token, AppRole, Kubernetes Auth를 선택할 수 있는데, 저는 사람이 직접 접근하는 경우와 워크로드가 접근하는 경우를 분리해서 생각했습니다. 사람은 SSO나 운영 계정 기준으로, 서비스는 AppRole 또는 플랫폼 네이티브 인증을 우선 검토하는 식이었습니다.

    vault auth enable approle
    vault write auth/approle/role/payment-role token_policies="payment-read"
    vault read auth/approle/role/payment-role/role-id
    vault write -f auth/approle/role/payment-role/secret-id

    이렇게 발급한 값으로 애플리케이션이 로그인해서 필요한 값만 읽게 만들 수 있습니다. 처음엔 번거로워 보여도, 장기적으로는 운영자가 직접 비밀번호를 전달하는 일 자체가 줄어듭니다.

    5. 1년 써보니 좋았던 점: 보안 강화와 운영 효율성은 같이 갑니다

    HashiCorp Vault 사용 후기를 한 줄로 줄이면, “보안 때문에 시작했는데 운영 효율까지 따라왔다”입니다. 제가 체감한 장점은 아래와 같았습니다.

    1. 비밀의 원본 위치가 명확해졌습니다. 장애가 나도 어디를 봐야 하는지 알 수 있습니다.
    2. 비밀 관리가 요청 기반에서 정책 기반으로 바뀝니다. 운영자가 매번 전달하지 않아도 됩니다.
    3. 회전(rotation) 설계를 붙이기 쉬워집니다. 특히 만료 개념이 들어오면 영구 계정에 대한 경각심이 생깁니다.
    4. 감사 로그가 남습니다. 누가 읽었는지, 어느 경로에 접근했는지 확인이 쉬워집니다.

    특히 여러 팀이 같이 쓰는 환경에서 효과가 컸습니다. 이전에는 “이 값 최신 맞나요?”라는 질문이 자주 왔는데, 이제는 “이 서비스가 읽을 권한이 있나요?”로 질문의 성격이 바뀌었습니다. 이 차이가 큽니다. 운영의 초점이 값 전달에서 권한 설계로 이동하거든요.

    6. ⚠️ 실제로 겪은 문제들: HashiCorp Vault 운영에서 막혔던 지점

    좋은 점만 있던 건 아닙니다. 저도 처음엔 “금고 하나 세우면 끝이겠지”라고 생각했었는데, 현실은 그렇지 않았습니다. 아래는 제가 실제로 자주 부딪힌 문제들입니다.

    6-1. 정책 경로를 잘못 잡아 접근이 안 되는 문제

    Vault는 경로와 정책 문법이 익숙해질 때까지 헷갈립니다. KV v2는 내부적으로 data 경로가 들어가서, 눈으로 보는 경로와 정책 대상 경로가 달라 보일 때가 있거든요. 처음엔 이게 뭔가 싶었는데, 경로 규칙을 문서화해 두고 나서야 정리가 됐습니다.

    • 증상: 로그인은 되는데 secret read가 거부됩니다.
    • 원인: 정책 경로와 실제 엔진 경로 불일치
    • 해결: 엔진 버전과 정책 대상 경로를 분리해서 표준 문서로 정리

    6-2. 루트 토큰 의존

    초반엔 급하니까 Root Token으로 다 해버리기 쉽습니다. 저도 테스트 환경에서 그랬고요. 근데 여기서 운영 습관이 잘못 들면 나중에 정리 비용이 큽니다. 관리자 역할도 세분화해서 일상 작업은 일반 관리 정책으로 하시는 걸 추천드립니다.

    6-3. 비밀 주입 방식 미정

    Vault를 넣어도 애플리케이션이 비밀을 어떻게 받아갈지 정하지 않으면 반쪽짜리입니다. 시작 전에 아래 셋 중 하나는 정해야 합니다.

    1. 애플리케이션 시작 시 가져와 환경 변수로 주입
    2. 사이드카(sidecar, 보조 컨테이너) 또는 에이전트(agent)로 파일 렌더링
    3. 애플리케이션이 직접 API로 조회

    저는 서비스 특성에 따라 다르게 갔습니다. 단순한 배치 작업은 시작 시 주입이 편했고, 회전이 중요한 워크로드는 갱신이 쉬운 방식이 낫더라고요.

    6-4. 운영자 교육 비용

    이건 의외로 큽니다. Vault는 강력하지만, 익숙하지 않은 팀에게는 진입장벽이 있습니다. 용어도 많고 정책 문법도 낯설거든요. 그래서 저는 내부 위키에 “자주 쓰는 경로, 정책 예시, 장애 시 체크 순서”를 짧게 정리해 두었습니다. 이거 하나만 있어도 온보딩 속도가 꽤 달라집니다.

    HashiCorp Vault 사용 후기의 초기 설정과 CLI 구성 흐름 이미지

    초기화, 언실, 정책 적용, 인증 방식 연결까지의 흐름을 단계적으로 보여주는 이미지입니다.

    7. 검증과 결과: 무엇이 실제로 달라졌는지

    1년 운영하면서 제가 가장 중요하게 본 건 “얼마나 화려한 기능을 썼는가”가 아니라, 실제 운영에서 반복 작업이 줄었는가였습니다. 그 기준으로 보면 결과는 꽤 만족스러웠습니다.

    • ✅ 신규 서비스 온보딩 때 비밀 전달 절차가 단순해졌습니다.
    • ✅ 운영자가 개별 비밀번호를 전달하는 횟수가 줄었습니다.
    • ✅ 접근 경로와 책임 범위가 명확해졌습니다.
    • ✅ 감사 로그 중심으로 사고 대응 흐름을 잡기 쉬워졌습니다.

    물론 모든 문제가 자동으로 해결되진 않습니다. 예를 들어 애플리케이션 코드가 비밀 갱신을 고려하지 않으면 Vault를 써도 회전 효과를 충분히 못 누릴 수 있습니다. 그래서 저는 보안 강화를 제품 도입만으로 보지 않고, 애플리케이션 수명 주기까지 함께 보는 편입니다.

    vault status
    vault token lookup
    vault audit list
    vault kv get kv/apps/payment

    운영 중에는 이런 기본 확인 명령만 자주 써도 상태 파악이 빨라집니다. 특히 audit 설정 여부는 꼭 챙기세요. “나중에 붙여야지” 하다가 잊기 쉽습니다. 저도 한 번 그랬다가 식은땀 흘렸습니다.

    HashiCorp Vault 운영 결과와 보안 강화 상태를 보여주는 대시보드 이미지

    비밀 접근 통제, 감사 로그, 서비스별 정책 적용 결과를 대시보드 형태로 표현한 이미지입니다.

    8. 정리와 FAQ: HashiCorp Vault 사용 후기에서 남은 교훈

    정리해보면, HashiCorp Vault 사용 후기에서 제가 얻은 가장 큰 교훈은 “비밀 관리는 저장이 아니라 운영”이라는 점입니다. Vault는 분명 강력합니다. 하지만 진짜 효과는 제품 기능보다 정책, 인증, 배포 흐름, 운영 문서화가 맞물릴 때 나옵니다.

    처음 도입하시는 분이라면 욕심내서 모든 기능을 한 번에 붙이기보다, 아래 순서로 가시는 걸 추천드립니다.

    1. KV 엔진으로 비밀의 원본 위치를 단일화합니다.
    2. 서비스별 정책을 최소 권한으로 나눕니다.
    3. 사람과 애플리케이션의 인증 방식을 분리합니다.
    4. 감사 로그와 백업 절차를 운영 문서에 포함합니다.
    5. 그다음에 동적 자격 증명이나 회전 자동화를 확장합니다.

    💡 개인적으로는 이 순서가 가장 덜 아프더라고요. 처음부터 거대한 보안 플랫폼처럼 접근하면 지칩니다. 작게 시작해서 운영 습관을 바꾸는 쪽이 오래 갑니다.

    HashiCorp Vault 사용 후기 기반 도입 전후 비교와 운영 체크리스트 인포그래픽

    도입 전후 차이, 권장 구축 순서, 운영 체크리스트를 요약한 인포그래픽입니다.

    자주 묻는 질문

    Q. 소규모 팀도 Vault가 필요할까요?
    A. 비밀이 여러 서비스에 걸쳐 있고, 담당자가 둘 이상이면 충분히 검토할 만합니다. 반대로 단일 서비스, 단일 운영자, 짧은 수명 프로젝트라면 과할 수도 있습니다.

    Q. 도입하면 바로 운영 효율이 올라가나요?
    A. 바로라기보다는, 정책과 인증 구조를 정리하는 과정에서 효율이 올라옵니다. 초반 학습 비용은 분명 있습니다.

    Q. 무엇부터 시작하는 게 좋을까요?
    A. KV 기반 비밀 통합과 정책 분리부터입니다. 동적 비밀은 그다음입니다.

    다음 글에서는 Vault Agent(에이전트)나 Kubernetes Auth 같은 실제 연동 패턴을 조금 더 깊게 다뤄볼 예정입니다. 이전 글에서 다룬 CI/CD 비밀 주입 방식과 같이 보시면 흐름이 더 잘 잡히실 거예요. 혹시 지금 비밀 관리가 점점 사람 손에 의존하고 있다면, 이 시점이 구조를 바꿀 타이밍일 수도 있습니다. 저도 처음엔 헷갈렸지만, 하나씩 정리하니까 분명히 운영이 가벼워졌습니다. 🎉

  • [Cloud] AWS IAM 권한 설계 베스트 프랙티스 – CISA GovCloud 키 유출 사건으로 배우는 클라우드 보안

    [Cloud] AWS IAM 권한 설계 베스트 프랙티스 – CISA GovCloud 키 유출 사건으로 배우는 클라우드 보안

    AWS IAM 권한 설계 베스트 프랙티스 – CISA GovCloud 키 유출 사건으로 배우는 클라우드 보안

    안녕하세요, 13년차 서버실 지킴이 ’13년차의 서버실’입니다. 오늘은 최근 발생했던 흥미롭지만 무서운 사건을 통해 AWS IAM 권한 설계의 중요성을 다시 한번 되짚어보려고 합니다. 바로 CISA (Cybersecurity and Infrastructure Security Agency)의 AWS GovCloud 키 유출 사건인데요. 미국 연방 기관에서 이런 보안 사고가 터졌다는 소식을 듣고 저도 처음엔 ‘설마 저런 일이…’ 싶었는데, 내용을 살펴보니 우리가 평소에 간과하기 쉬운 부분에서 발생한 문제더라고요.

    솔직히 인프라 엔지니어라면 누구나 한 번쯤은 ‘빨리 배포해야 하는데’, ‘이거 권한 없어서 안 되네, 그냥 다 열어버릴까?’ 하는 유혹에 빠져본 적 있을 겁니다. 저도 처음엔 이게 뭔가 싶어서 그냥 `*` (와일드카드)로 대충 권한 설정했다가 나중에 등골이 오싹했던 경험이 있거든요. 실제로 이런 클라우드 보안 사고가 터지면 수습하기 정말 힘들고, 기업 이미지에도 치명타를 입을 수 있습니다. 그래서 오늘은 CISA 사건을 교훈 삼아, AWS IAM(Identity and Access Management) 권한 설계를 어떻게 해야 안전하고 효율적으로 할 수 있을지, 제 삽질 경험을 녹여서 이야기해볼까 합니다.

    AWS IAM이 중심이 되는 클라우드 보안 아키텍처 다이어그램

    클라우드 환경에서 IAM은 단순한 사용자 관리를 넘어 전체 보안의 핵심입니다.

    AWS IAM, 최소 권한 원칙(Principle of Least Privilege)이란?

    본격적인 이야기에 앞서, 핵심 개념인 AWS IAM과 최소 권한 원칙(Principle of Least Privilege)에 대해 잠깐 짚고 넘어갈게요.

    • AWS IAM (Identity and Access Management, 아이덴티티 및 접근 관리): AWS 클라우드 리소스에 대한 접근을 안전하게 관리하는 웹 서비스입니다. 누가 어떤 리소스에 어떤 작업을 할 수 있는지 정의하는 역할을 하죠. 쉽게 말해, ‘회사 문지기’라고 생각하시면 편합니다. 누가 회사에 들어올 수 있고(인증), 어디까지 갈 수 있는지(권한 부여)를 결정하는 거죠.
    • 최소 권한 원칙 (Principle of Least Privilege): 이 원칙은 ‘필요한 최소한의 권한만 부여하라’는 강력한 보안 철학입니다. 예를 들어, 웹 서버가 S3 버킷에 파일을 업로드해야 한다면, S3에 파일을 읽고 쓰는 권한만 주면 됩니다. S3의 모든 설정 변경 권한이나 다른 서비스의 권한까지 줄 필요는 없다는 거죠. CISA 사건도 이 최소 권한 원칙이 제대로 지켜지지 않아 발생한 부분이 크다고 볼 수 있습니다.

    AWS IAM은 크게 IAM 사용자(User), IAM 그룹(Group), IAM 역할(Role), 그리고 이들의 권한을 정의하는 정책(Policy)으로 구성됩니다. 이 네 가지 요소를 잘 조합해서 안전한 환경을 만드는 게 핵심이에요.

    실전 구현: AWS IAM 권한 설계 베스트 프랙티스

    자, 이제 저의 홈랩에서 직접 적용하고 있는 AWS IAM 권한 설계 베스트 프랙티스 몇 가지를 소개해드릴게요. 이건 제가 직접 여러 번의 삽질 끝에 깨달은 소중한 경험들이거든요.

    1. 루트 사용자(Root User)는 금고에! MFA(Multi-Factor Authentication)는 필수!

      AWS 계정을 처음 만들면 ‘루트 사용자’가 생성되죠? 이 루트 사용자는 계정의 모든 권한을 가지고 있는 슈퍼 계정입니다. 절대! 일상적인 작업에 사용하면 안 됩니다. 저도 처음엔 그냥 루트 계정으로 다 했었는데, 나중에 보안 교육을 받고 식겁했어요. 루트 사용자는 계정 생성 후 한 번만 사용해서 IAM 사용자를 만들고, 강력한 암호와 함께 MFA (Multi-Factor Authentication, 다단계 인증)를 설정한 뒤 금고에 넣어두세요. 그리고 다시는 사용하지 않는 것이 좋습니다. 혹시 아직 MFA 설정 안 하셨다면 지금 당장 설정하세요! ⚠️

    2. IAM 사용자(User) 대신 IAM 역할(Role)을 적극 활용하세요!

      많은 분들이 EC2 인스턴스나 람다(Lambda) 함수에 권한을 줄 때, IAM 사용자 자격 증명(Access Key, Secret Key)을 직접 코드에 하드코딩하는 경우가 있습니다. 절대 금물입니다! 이 키가 유출되면 CISA 사건처럼 큰일 날 수 있어요. 대신 IAM 역할(Role)을 사용해야 합니다. IAM 역할은 특정 AWS 서비스나 사용자가 임시 자격증명을 자동으로 받아서 다른 리소스에 접근할 수 있게 해주는 기능이거든요. 키를 직접 관리할 필요가 없어서 훨씬 안전하고 편리하죠.

      예를 들어, EC2 인스턴스가 S3 버킷에 파일을 업로드해야 한다면, 다음과 같은 정책을 가진 IAM 역할을 만들어서 EC2 인스턴스에 할당하면 됩니다.

      {
      "Version": "2012-10-17",
      "Statement": [
      {
      "Effect": "Allow",
      "Action": [
      "s3:PutObject",
      "s3:GetObject",
      "s3:ListBucket"
      ],
      "Resource": [
      "arn:aws:s3:::my-secure-bucket",
      "arn:aws:s3:::my-secure-bucket/*"
      ]
      }
      ]
      }

      이 역할은 <code>my-secure-bucket이라는 S3 버킷에 대해서만 객체를 넣고, 가져오고, 버킷 내용을 나열하는 최소한의 권한만 부여합니다. 🎉

    3. 최소 권한 원칙에 기반한 정책(Policy) 설계

      위 예시처럼, 필요한 최소한의 작업(Action)과 리소스(Resource)만 명시하는 커스텀 정책(Custom Policy)을 만드는 습관을 들여야 합니다. AWS에서 제공하는 관리형 정책(Managed Policy)도 편리하지만, 너무 포괄적인 권한을 포함하는 경우가 많아요. 예를 들어, AmazonS3FullAccess 정책은 S3의 모든 작업을 허용하는데, 이건 대부분의 경우 과도한 권한입니다. 제가 직접 해보니 커스텀 정책이 손은 더 가지만, 훨씬 안전하더라고요. 처음엔 좀 어렵게 느껴질 수 있지만, 몇 번 만들어보면 익숙해집니다.

    4. 조건 키(Condition Keys)를 활용한 정교한 제어

      IAM 정책은 단순히 ‘누가 무엇을 할 수 있는가’를 넘어, ‘언제, 어디서, 어떻게’ 할 수 있는가까지 제어할 수 있습니다. 바로 조건 키(Condition Keys)를 활용하는 건데요. 특정 IP 주소 대역에서만 접근을 허용하거나, MFA 인증이 된 사용자만 특정 작업을 수행할 수 있도록 강제하는 등의 설정이 가능합니다. CISA 사건처럼 키가 유출되더라도, 추가적인 조건이 없다면 접근을 막을 수 있는 강력한 방어선이 됩니다.

      {
      "Version": "2012-10-17",
      "Statement": [
      {
      "Effect": "Allow",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::my-secure-bucket/*",
      "Condition": {
      "IpAddress": {
      "aws:SourceIp": "203.0.113.0/24"
      },
      "Bool": {
      "aws:MultiFactorAuthPresent": "true"
      }
      }
      }
      ]
      }

      위 정책은 203.0.113.0/24 IP 대역에서 MFA 인증을 거친 사용자만 S3 객체를 가져올 수 있도록 허용합니다. 💡

    5. AWS Access Analyzer로 권한 검토하기

      아무리 열심히 정책을 설계해도, 사람인지라 실수는 할 수 있습니다. 이때 AWS Access Analyzer가 정말 큰 도움이 됩니다. 이 서비스는 외부 엔티티(다른 AWS 계정, IAM 사용자, 역할 등)가 내 계정의 리소스(S3 버킷, SQS 큐 등)에 접근할 수 있는 경로를 분석하고 경고해줍니다. 제가 직접 써보니 예상치 못한 경로로 외부에 리소스가 공유된 걸 찾아내서 바로 조치할 수 있었어요. 정기적으로 Access Analyzer를 돌려 외부 접근 권한을 점검하는 습관을 들이는 게 좋습니다.

    AWS Access Analyzer 대시보드 화면

    Access Analyzer는 예상치 못한 권한 설정을 찾아내고 시각적으로 경고해줍니다.

    ⚠️ 주의사항 및 트러블슈팅: 삽질은 나의 힘!

    저도 AWS IAM 권한 설계를 하면서 수많은 삽질을 했습니다. 여러분은 저 같은 실수 하지 마시라고 몇 가지 팁을 공유해드려요.

    • 와일드카드(`*`) 사용은 정말 신중하게!

      특히 Action: "*"이나 Resource: "*"는 치명적일 수 있습니다. 처음엔 귀찮아서 이렇게 줬다가 나중에 ‘아차!’ 싶었던 적이 한두 번이 아니거든요. 항상 필요한 최소한의 범위만 지정하는 연습을 해야 합니다.

    • IAM Policy Simulator로 미리 테스트해보세요

      정책을 만들었는데 제대로 작동하는지 확신이 없을 때, IAM Policy Simulator를 사용하면 아주 유용합니다. 특정 사용자/역할이 특정 리소스에 대해 특정 작업을 수행할 수 있는지 시뮬레이션해볼 수 있거든요. 이거 써보니 삽질 많이 줄었습니다. ‘아, 이렇게 하면 되는구나!’ 하고 바로 알 수 있어서 진짜 편하더라고요.

    • 너무 빡빡한 권한은 오히려 문제!

      최소 권한 원칙도 좋지만, 너무 권한을 빡빡하게 설정해서 정작 필요한 작업이 안 되는 경우도 있습니다. 예를 들어, S3 버킷에 객체를 업로드하는 권한만 줬는데, 버킷 리스트를 볼 수 없어서 디버깅이 어려운 경우가 있었어요. 이때는 임시로 디버깅용 권한을 추가했다가, 문제 해결 후 다시 최소 권한으로 돌리는 유연함도 필요하더라고요. 역시 디버깅이 중요하더라고요.

    AWS IAM Policy Simulator 사용 화면

    정책 적용 전 IAM Policy Simulator로 미리 검증하면 불필요한 오류를 줄일 수 있습니다.

    AWS Access Analyzer를 통한 최종 검증

    권한 설정을 모두 마쳤다면, 다시 한번 AWS Access Analyzer를 통해 점검하는 과정을 거쳐야 합니다. 저는 이 과정을 습관처럼 하고 있는데요, 실제로 개발팀에서 실수로 특정 S3 버킷을 ‘Public’으로 열어둔 것을 Access Analyzer가 잡아내서 바로 수정했던 경험이 있습니다. 이렇게 검증하는 과정이 진짜 중요합니다. 단순한 실수가 큰 보안 사고로 이어질 수 있거든요.

    Access Analyzer는 지속적으로 계정을 모니터링하여 예상치 못한 외부 접근을 감지하고, 이에 대한 상세한 보고서를 제공합니다. 이 보고서를 바탕으로 정책을 조정하거나, 문제가 되는 설정을 수정하는 것이 중요합니다. ✅

    마무리하며: 보안은 끝이 없는 마라톤!

    오늘은 CISA AWS GovCloud 키 유출 사건을 통해 AWS IAM 권한 설계의 중요성과 베스트 프랙티스에 대해 이야기해봤습니다. 13년차 인프라 엔지니어로 살아오면서 느낀 건데, 보안은 정말 끝이 없는 마라톤과 같아요. 한 번 설정했다고 끝이 아니라, 지속적으로 검토하고 개선해야 합니다.

    오늘 제가 소개해드린 내용은 AWS IAM 권한 설계의 기본적인 베스트 프랙티스이지만, 이것만 잘 지켜도 대부분의 보안 위협으로부터 계정을 안전하게 보호할 수 있을 겁니다. 특히 최소 권한 원칙과 IAM 역할 활용은 꼭 기억해주세요. 혹시 이 글을 읽고 여러분의 AWS 환경을 다시 한번 점검해보는 계기가 된다면, 정말 기쁠 것 같네요.

    다음 글에서는 AWS GuardDuty나 Security Hub 같은 다른 보안 서비스들을 활용한 클라우드 보안 강화 방안에 대해 다뤄볼까 합니다. 기대해주세요! 👋

    AWS IAM 권한 설계 베스트 프랙티스 요약 인포그래픽

    안전한 AWS 환경을 위한 IAM 베스트 프랙티스 요약.

  • [Cloud] Cloudflare Zero Trust 구축: VPN 대체 및 보안 강화 실전 가이드

    [Cloud] Cloudflare Zero Trust 구축: VPN 대체 및 보안 강화 실전 가이드

    VPN의 한계를 넘어, Cloudflare Zero Trust로 보안을 강화하다

    안녕하세요, 13년차 서버실 지킴이입니다. 제가 13년 동안 인프라 엔지니어로 일하면서 가장 많이 들었던 말 중 하나가 "보안"이에요. 특히 재택근무가 일상화되고 클라우드 전환이 가속화되면서, 기존 VPN(Virtual Private Network)만으로는 한계를 느끼는 순간이 많아졌습니다. 저도 홈랩을 운영하면서 내부 서비스에 안전하게 접속하는 방법을 항상 고민했거든요. 기존 VPN은 설정도 복잡하고, 모든 트래픽을 내부망으로 보내는 방식이라 보안 위협에 취약할 수 있다는 생각도 들었고요. 그러다 문득, Cloudflare Zero Trust가 떠올랐습니다. "이거다!" 싶었죠. VPN을 대체하고 보안 강화까지 가능한 실전 가이드를 제가 직접 구축해본 경험을 바탕으로 여러분께 공유해볼까 합니다.

    Cloudflare Zero Trust, 그게 대체 뭔데요?

    Cloudflare Zero Trust(클라우드플레어 제로 트러스트)는 이름 그대로 "아무것도 신뢰하지 않는다"는 전제에서 시작하는 보안 모델이에요. 기존 보안 모델은 내부 네트워크에 들어오면 신뢰하고, 외부 네트워크는 불신하는 "성곽과 해자(Castle and Moat)" 방식이었죠. 하지만 Zero Trust는 내부든 외부든 모든 접근 시도를 "기본적으로 신뢰하지 않고(Never Trust), 항상 검증한다(Always Verify)"는 원칙을 따릅니다.

    쉽게 말해, 어떤 사용자가 어떤 기기에서 어떤 애플리케이션에 접근하려 할 때마다, 그 사용자가 누구인지, 기기가 안전한지, 접근하려는 애플리케이션에 대한 권한이 있는지 등 모든 요소를 실시간으로 검증하는 방식이에요. Cloudflare Zero Trust는 이 원칙을 구현하기 위한 다양한 도구와 서비스를 제공하는데, 특히 Cloudflare Access(클라우드플레어 액세스)와 Cloudflare WARP(클라우드플레어 워프)가 핵심적인 역할을 합니다.

    Cloudflare Zero Trust는 기존 VPN과 달리, 모든 접근을 개별적으로 검증하여 보안을 한층 더 높입니다.

    왜 Zero Trust 보안이 필요한가요?

    • 보안 강화: 내부 네트워크 침투 시 측면 이동(Lateral Movement) 공격을 어렵게 만듭니다. 각 리소스 접근 시마다 인증과 권한 검증을 거치니까요.
    • 유연한 접근: 사용자가 어디에 있든(사무실, 재택, 카페 등) 안전하게 필요한 리소스에 접근할 수 있습니다.
    • VPN 대체: 복잡한 VPN 설정 없이도 특정 애플리케이션에 대한 접근 제어가 가능해요. 저처럼 홈랩에서 특정 서비스만 외부에서 접근하고 싶을 때 정말 유용하더라고요.
    • 성능 향상: 모든 트래픽을 데이터 센터로 모으는 VPN과 달리, 최적의 경로로 리소스에 연결되므로 성능 저하가 훨씬 덜합니다.

    Cloudflare Zero Trust, 실전 구축 가이드

    이제 본격적으로 Cloudflare Zero Trust 구축 과정을 살펴볼까요? 저도 처음엔 좀 헤맸는데, 막상 해보니 별거 아니더라고요. 단계별로 차근차근 따라오시면 됩니다.

    Step 1: Cloudflare Teams 계정 활성화

    1. Cloudflare 대시보드에 로그인합니다.
    2. 왼쪽 메뉴에서 "Zero Trust"를 클릭하세요.
    3. 처음 접근하는 경우, Cloudflare Teams 계정을 활성화하라는 메시지가 나타날 거예요. "Launch Zero Trust" 버튼을 눌러 활성화하고, 팀 이름(Team Name)을 설정해줍니다. 저는 제 홈랩 이름으로 만들었죠.
    4. 요금제는 우선 무료 플랜인 "Free"로 시작하시면 됩니다. 소규모 팀에 충분한 수의 사용자를 지원하거든요.

    Step 2: Cloudflare WARP 클라이언트 설정

    WARP는 사용자 기기와 Cloudflare Edge 네트워크 사이에 암호화된 터널을 생성해주는 클라이언트 프로그램입니다. 이걸 설치해야 Zero Trust 정책이 적용돼요.

    1. Cloudflare Zero Trust 대시보드에서 "Settings" > "WARP Client"로 이동합니다.
    2. "Device enrollment" 탭에서 "Manage"를 클릭하고, 팀 도메인(예: <code>myhomelab.cloudflareaccess.com)을 확인해둡니다.
    3. 사용자 기기(PC, 모바일)에 맞는 WARP 클라이언트를 다운로드하여 설치합니다. 저는 리눅스 서버에 설치할 거라 아래 명령어를 사용했어요.
    # Debian/Ubuntu 기준
    curl https://pkg.cloudflareclient.com/pubkey.gpg | sudo gpg --yes --dearmor --output /usr/share/keyrings/cloudflare-warp-archive-keyring.gpg
    echo "deb [arch=amd64 signed-by=/usr/share/keyrings/cloudflare-warp-archive-keyring.gpg] https://pkg.cloudflareclient.com/ $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/cloudflare-client.list
    sudo apt update
    sudo apt install cloudflare-warp
    
    # WARP 등록
    warp-cli register
    warp-cli set-mode tunnel
    warp-cli set-gateway-mode proxy
    warp-cli set-license <YOUR_LICENSE_KEY_IF_PAID> # 무료 플랜은 필요 없음
    warp-cli connect
    

    설치 후에는 웹 브라우저가 열리면서 Cloudflare Zero Trust 계정으로 로그인하라고 할 거예요. 로그인하면 WARP가 활성화됩니다. WARP 대시보드에서 "Connected" 상태를 확인하면 성공!

    Cloudflare Zero Trust 대시보드에서 Access 애플리케이션을 손쉽게 관리할 수 있습니다.

    Step 3: Access 애플리케이션 생성

    이제 특정 내부 서비스에 접근할 수 있도록 Cloudflare Access 애플리케이션을 만들어볼까요? 저는 홈랩의 Prometheus(프로메테우스) 대시보드에 접근하는 시나리오를 예로 들겠습니다.

    1. Zero Trust 대시보드에서 "Access" > "Applications"로 이동합니다.
    2. "Add an application" 버튼을 클릭하고, "Self-hosted"를 선택합니다.
    3. "Subdomain"에 접근할 도메인(예: prometheus.myhomelab.com)을 입력하고, "Session Duration" 등 필요한 설정을 합니다.
    4. 여기서 중요한 것이 Cloudflare Tunnel(클라우드플레어 터널)입니다. 내부망에 있는 서비스를 외부로 노출하지 않고 Cloudflare Edge 네트워크로 연결해주는 방식이죠. 저는 cloudflared라는 클라이언트 프로그램을 사용해서 터널을 만들었어요.
    # cloudflared 설치 (Debian/Ubuntu 기준)
    curl -L --output cloudflared.deb https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
    sudo dpkg -i cloudflared.deb
    
    # 터널 생성 및 인증
    cloudflared tunnel login
    cloudflared tunnel create prometheus-tunnel # 터널 이름 지정
    
    # 터널 설정 파일 (config.yaml) 생성
    # nano ~/.cloudflared/config.yaml
    # --- (아래 내용 붙여넣기) ---
    tunnel: <YOUR_TUNNEL_UUID> # tunnel create 명령 실행 후 나오는 UUID
    credentials-file: /root/.cloudflared/<YOUR_TUNNEL_UUID>.json
    
    ingress:
      - hostname: prometheus.myhomelab.com
        service: http://localhost:9090 # Prometheus가 실행되는 내부 주소
      - service: http_status:404 # 일치하는 규칙이 없으면 404 반환
    # --- (여기까지) ---
    
    # 터널 실행 (서비스로 등록하여 자동 시작 설정 권장)
    sudo cloudflared tunnel run prometheus-tunnel
    

    Cloudflare Tunnel을 통해 내부의 Prometheus 서비스(http://localhost:9090)가 prometheus.myhomelab.com 도메인으로 Cloudflare Edge 네트워크에 안전하게 연결됩니다.

    Step 4: 정책 설정 및 사용자 인증

    이제 누가 이 애플리케이션에 접근할 수 있는지 정책(Policy)을 설정할 차례입니다. 이게 바로 Zero Trust 보안의 핵심이에요!

    1. Access 애플리케이션 설정 화면에서 "Policies" 탭으로 이동합니다.
    2. "Add a policy"를 클릭하여 새로운 정책을 만듭니다.
    3. 저는 다음과 같은 정책을 설정했어요:

      필드 (Field) 조건 (Rule) 값 (Value) 설명
      Emails in ['[email protected]'] 특정 이메일 주소만 허용
      Countries in ['KR'] 대한민국 IP에서만 접근 허용
      Device Posture Requires ['WARP is connected'] WARP 클라이언트가 연결된 기기에서만 허용
    4. "Action"은 "Allow"로 설정합니다. 이렇게 하면 지정된 조건(제 이메일, 한국 IP, WARP 연결 기기)을 모두 만족하는 사용자만 prometheus.myhomelab.com에 접근할 수 있게 됩니다.
    5. 사용자 인증은 Cloudflare Access가 제공하는 다양한 IDP(Identity Provider)와 연동할 수 있어요. 저는 주로 Google Workspace(구 G Suite)나 GitHub를 사용하는데, 무료 플랜에서도 연동이 가능해서 정말 편하더라고요.

    ⚠️ 삽질 경험 공유: 저도 이거 때문에 고생 좀 했습니다

    13년차 엔지니어라고 삽질을 안 하는 건 아니죠! 저도 몇 가지 문제 때문에 머리를 쥐어뜯었거든요. 혹시 여러분도 겪을 수 있는 문제들이니 참고하세요.

    • Cloudflare Tunnel 서비스 문제: cloudflared tunnel run 명령어로 터널을 실행했는데, 서버 재부팅 후 터널이 끊어져 있는 경우가 있었습니다. 당연히 서비스로 등록해서 자동 시작되도록 해야 하는데, 처음엔 수동으로 실행하고 "왜 안되지?" 했지 뭐예요. 꼭 systemd 등으로 서비스 등록해서 관리해주세요.

      # 서비스 파일 예시 (/etc/systemd/system/cloudflared-prometheus.service)
      [Unit]
      Description=Cloudflared Tunnel for Prometheus
      After=network.target
      
      [Service]
      TimeoutStartSec=0
      Type=notify
      ExecStart=/usr/local/bin/cloudflared tunnel run --config /root/.cloudflared/config.yaml prometheus-tunnel
      Restart=on-failure
      RestartSec=5s
      
      [Install]
      WantedBy=multi-user.target
      
      # 서비스 활성화 및 시작
      sudo systemctl enable cloudflared-prometheus
      sudo systemctl start cloudflared-prometheus
      sudo systemctl status cloudflared-prometheus
      
    • DNS 설정 누락: Cloudflare Access 애플리케이션을 만들면, 해당 서브도메인에 대한 CNAME 레코드를 Cloudflare DNS에 추가하라고 안내 메시지가 나옵니다. 이걸 빼먹으면 외부에서 접근이 안 돼요. prometheus.myhomelab.com CNAME -> <UUID>.cfargotunnel.com 이런 식으로요.

    • 정책 순서와 조건: Zero Trust 정책은 순서가 중요합니다. 특정 조건을 먼저 허용하고 다음 조건에서 거부하면, 의도치 않게 접근이 허용될 수 있어요. 항상 가장 엄격한 규칙을 위에 두는 것이 좋습니다. 또한, AND/OR 조건 조합을 잘 활용해야 하는데, 저는 처음에 이메일과 국가 조건을 OR로 묶어서 "왜 다른 사람이 접근되지?" 하고 당황했거든요. 각 조건이 모두 충족되어야 할 때는 AND처럼 동작하도록 여러 Require 규칙을 추가해야 합니다.

    🎉 드디어 성공! Cloudflare Zero Trust의 위력

    모든 설정을 마치고 제 홈랩의 Prometheus 대시보드에 접속해보니… 드디어 됐다! 처음에 웹 브라우저가 Cloudflare Access 인증 페이지로 리디렉션되고, 제 Google 계정으로 로그인한 후에야 Prometheus 화면이 나타났습니다. WARP 클라이언트가 연결되지 않은 상태에서는 아예 접근이 차단되는 것을 확인했고요.

    이거 진짜 편하더라고요! 기존 VPN 접속처럼 전체 트래픽이 느려지는 느낌도 없고, 필요한 서비스에만 딱 접근할 수 있으니 훨씬 직관적이고 빨랐어요. 게다가 Cloudflare의 글로벌 네트워크를 통해 트래픽이 처리되니 안정성도 높고요. 기존 VPN에서 발생했던 IP 충돌 문제나 복잡한 라우팅 설정이 필요 없다는 점도 정말 큰 장점입니다.

    Cloudflare Zero Trust를 통해 안전하게 내부 Prometheus 대시보드에 접속한 모습.

    마무리하며: Zero Trust, 이제 선택이 아닌 필수!

    오늘은 제가 직접 Cloudflare Zero Trust를 구축하여 VPN을 대체하고 보안을 한층 더 높인 실전 경험을 공유해드렸습니다. 처음엔 낯설게 느껴질 수 있지만, 한번 구축하고 나면 기존 VPN 방식보다 훨씬 강력하고 유연한 보안 환경을 갖출 수 있다는 것을 몸소 느꼈습니다.

    Cloudflare Zero Trust는 단순히 VPN을 대체하는 것을 넘어, 사용자와 애플리케이션, 데이터의 위치에 상관없이 일관된 보안 정책을 적용할 수 있게 해주는 미래 지향적인 보안 모델입니다. 특히 재택근무가 활성화되고 클라우드 환경이 보편화된 요즘에는 선택이 아닌 필수가 되어가고 있다고 생각해요. 여러분도 저처럼 삽질 좀 하시면서 직접 경험해보시면, 이 강력한 보안 솔루션의 매력에 푹 빠지실 겁니다. 혹시 이 글을 읽고 궁금한 점이 있다면 언제든지 댓글로 물어봐 주세요!

    Cloudflare Zero Trust와 전통 VPN의 주요 특징 비교.

    다음 글에서는 Cloudflare Zero Trust의 또 다른 강력한 기능인 WARP Gateway(워프 게이트웨이)를 활용한 DNS 필터링과 L7 방화벽 설정에 대해 더 깊이 다뤄볼게요. 기대해주세요!