# SystemD 서비스 보안 강화 (Hardening)

> Clean Markdown view of GeekNews topic #22621. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=22621](https://news.hada.io/topic?id=22621)
- GeekNews Markdown: [https://news.hada.io/topic/22621.md](https://news.hada.io/topic/22621.md)
- Type: GN+
- Author: [neo](https://news.hada.io/@neo)
- Published: 2025-08-20T10:15:31+09:00
- Updated: 2025-08-20T10:15:31+09:00
- Original source: [roguesecurity.dev](https://roguesecurity.dev/blog/systemd-hardening)
- Points: 5
- Comments: 1

## Summary

**systemd**는 손쉬운 서비스 관리를 제공하지만, 기본 설정은 **보안**보다는 사용성에 치중되어 있어, 운영 환경에서는 추가적인 **하드닝** 적용이 중요합니다. `systemd-analyze security`로 각 서비스의 **위험 노출 지표**를 분석하고, `ProtectSystem`, `NoNewPrivileges`, `SystemCallFilter` 등 다양한 **세분화된 보안 옵션**을 개별 서비스 단위로 적용하여 잠재적 침해 가능성을 효율적으로 줄일 수 있습니다. 모든 서비스에 일괄 적용하기보다는 **외부 노출 서비스** 위주로 우선 적용함으로써 실질적인 **리스크 감소 효과**를 기대할 수 있습니다. 각 옵션은 **세밀한 권한 제한** 조정이 가능하므로 self-hosting, 컨테이너 기반 등 다양한 환경에서 유연하게 활용할 수 있습니다.

## Topic Body

- systemd는 강력한 **서비스 관리 기능**을 제공하지만 기본 설정은 보안보다는 사용성에 최적화되어 있어 별도의 **하드닝 옵션 적용**이 필요함  
- `systemd-analyze security` 명령어를 통해 전체 서비스 또는 특정 서비스의 **보안 노출 지표**를 분석하고 우선순위를 정할 수 있음  
- 서비스 단위에서 적용할 수 있는 다양한 **보안 옵션**이 존재하며, 이는 `/etc/systemd/system/ServiceName.service.d/override.conf` 등을 통해 개별적으로 수정 가능함  
- 주요 옵션에는 `ProtectSystem`, `PrivateTmp`, `NoNewPrivileges`, `SystemCallFilter`, `MemoryDenyWriteExecute` 등 프로세스 권한과 자원 접근을 제한하는 항목이 포함됨  
- 완벽한 보안을 목표로 하기보다는 **외부 노출 서비스**를 우선적으로 하드닝하여 위험을 줄이고, self-hosting 환경에서도 큰 효과를 볼 수 있음  
  
---  
  
### systemd 개요   
- systemd는서비스 관리에서 매우 완성도 높고 견고한 방식을 제공함  
- 하지만 보안보다는 즉시 사용성을 우선시해 기본 설정이 느슨하게 되어 있음  
- 본 문서는 systemd 서비스 유닛과 podman quadlet에 적용할 수 있는 여러 보안 강화 옵션을 소개하여 침해 가능성을 줄이고, 침해 발생 시 피해 범위를 최소화하고자 함  
- 모든 서비스에 일괄 적용하는 가이드가 아니며, 각각의 서비스 특성과 요구 기능에 맞는 개별 실험과 로그 확인, 조정이 필요함  
- 인프라 보안 책임은 전적으로 운영자에게 있으며, 본 문서는 참고 도구임  
  
### systemd 보안 분석  
- `systemd-analyze security` 명령어로 전체 서비스 보안 상태를 확인하거나 특정 서비스(예: `sshd.service`)의 세부 설정을 분석할 수 있음  
  - 출력에는 체크 여부, 기능 이름, 설명, **Exposure 점수**가 포함되어 있으며 Exposure가 높을수록 위험도가 큼  
- 보안 옵션은 `[Service]` 섹션(systemd) 또는 `[Container]` 섹션(podman quadlet)에 추가 설정 가능함  
- `systemctl edit ServiceName.service`를 통해 override 파일을 만드는 방식이 권장되며, 실패 시 필요한 권한을 확인 후 조정해야 함  
  
### 서비스 보안 옵션  
- systemd는 다양한 **보안 옵션 키워드**를 제공하며 `man systemd.exec 5`, `man capabilities 7` 등을 통해 확인 가능함  
- 대표적인 보안 관련 옵션  
  - `ProtectSystem` → 파일시스템을 읽기 전용으로 제한하는 옵션임  
  - `ProtectHome` → `/home`, `/root`, `/run/user` 접근 차단 옵션임  
  - `PrivateDevices` → 물리 장치 접근 차단, `/dev/null` 등 가상 장치만 허용하는 옵션임  
  - `ProtectKernelTunables`, `ProtectKernelModules`, `ProtectKernelLogs` → 커널 자원 접근 차단 옵션임  
  - `NoNewPrivileges` → setuid/setgid 등을 통한 신규 권한 획득 방지 옵션임  
  - `MemoryDenyWriteExecute` → 쓰기 및 실행 가능한 메모리 동시 사용 차단, 일부 JIT 언어에는 문제 발생 가능성 있음  
  - `SystemCallFilter` → 허용할 시스템 콜을 제한하는 옵션임, 위반 시 프로세스 종료 또는 EPERM 반환 가능함  
  
### 각 옵션 설명  
  
- **ProtectSystem**: `strict` 설정 시 전체 파일시스템을 읽기 전용 마운트, `/dev`, `/proc`, `/sys`는 별도 보호 옵션 필요  
- **ReadWritePaths**: 일부 경로만 다시 쓰기 가능하게 설정  
- **ProtectHome**: `/home`, `/root`, `/run/user` 접근 차단  
- **PrivateDevices**: 물리 장치 접근 비활성화, `/dev/null` 등 Pseudo 장치만 허용  
- **ProtectKernelTunables**: `/proc`, `/sys`를 읽기 전용 처리  
- **ProtectControlGroups**: cgroup 읽기 전용 접근만 허용  
- **ProtectKernelModules**: 커널 모듈 명시적 로딩 금지  
- **ProtectKernelLogs**: 커널 로그 버퍼 접근 제한  
- **ProtectProc**: `invisible` 설정 시 타 사용자 소유 프로세스를 `/proc/`에서 숨김  
- **ProcSubset**: 특정 PID관련 항목 외 내용 `/proc`에서 차단  
- **NoNewPrivileges**: setuid, setgid, 파일 시스템 capability를 통한 새로운 권한 상승 차단  
- **ProtectClock**: 시스템/하드웨어 클럭 쓰기 차단  
- **SystemCallArchitectures**: `native` 설정 시 x86-64 등 네이티브 syscall만 허용  
- **RestrictNamespaces**: 컨테이너 특화 네임스페이스 제한  
- **RestrictSUIDSGID**: 파일 setuid, setgid 비트 설정 차단  
- **LockPersonality**: 실행 도메인 변경 방지 (구형 어플리케이션 등에만 필요)  
- **RestrictRealtime**: 실시간 스케줄링 제한 (일부 특수 목적 서비스만 필요)  
- **RestrictAddressFamilies**: 허용하는 소켓 주소 패밀리 제한 (예: AF_INET, AF_INET6, AF_UNIX 등 지정)  
- **MemoryDenyWriteExecute**: 쓰기+실행 가능한 메모리영역 추가 생성 차단 (JIT 사용 서비스는 주의)  
- **ProtectHostname**: sethostname, setdomainname syscall 사용 금지  
- **SystemCallFilter**: 서비스별 syscall 허용/차단 설정, 세밀하게 필터링 가능  
   - 그룹, 개별 syscall, 허용/차단 방식 등 조정 가능  
   - 위반 시 종료 대신 EPERM 등 오류코드 반환 설정도 지원  
   - 전체 목록은 `systemd-analyze syscall-filter` 또는 `man systemd.exec(5)` 통해 확인 가능  
   - `~` 접두사로 리스트 전체 음수화 가능 (예: `CapabilityBoundingSet=~CAP_SETUID` 등)  
  
### SystemCallFilter 제한 조정 과정  
  
- `auditd`를 이용해 서비스 실패 시 어떤 syscall이 차단됐는지 로그 확인 가능  
    - `sudo ausearch -i -m SECCOMP -ts recent` 실행 후, syscall 값 확인  
    - 해당 syscall 혹은 관련 그룹을 `SystemCallFilter`에 추가하여 순차적으로 문제 해결 가능  
  
### 보안 강화 적용 우선순위 및 운영 팁  
  
- 모든 서비스에 전부 적용할 필요는 없음  
- 위협 모델과 위험 관리가 핵심, 특히 **외부 노출 서비스**(httpd, nginx, ssh 등)는 필수 고려  
- 커스텀 커맨드, timer 유닛(구 cron 대체) 등도 선제 적용이 효과적임  
- 복잡하지 않은 서비스일수록 미세한 조정 가능성이 높음  
  
#### 체크리스트: 추천 보안 옵션 조합 (초기 적용 우선순위)  
  
- `ProtectSystem=strict`  
- `PrivateTmp=yes`  
- `ProtectHome=yes` 또는 `ProtectHome=tmpfs`  
- `ProtectClock=yes`, `ProtectKernelLogs=yes`, `ProtectKernelModules=yes`  
- `RestrictSUIDGUID=yes`  
- `UMask=0077`  
- `LockPersonality=yes`  
- `RestrictRealtime=yes`  
- `MemoryDenyWriteExecute=yes`  
- `DynamicUser=yes` 또는 `User`를 root 이외의 특정 사용자로 지정   
  
* 위 항목들은 일반적으로 서비스에 거의 지장 없이 사용할 수 있는 조합  
* 추가로 syscall 필터링(`SystemCallFilter`)까지 적용하려면 상세 테스트 필요  
  
### Traefik 예시 설정  
- 컨테이너 기반 Traefik 서비스를 systemd quadlet으로 실행하며, 보안 옵션을 다수 적용한 사례임  
  - `ProtectSystem=full`, `ProtectHome=yes`, `SystemCallFilter=@system-service @mount @privileged` 등 적용  
  - `CapabilityBoundingSet=~CAP_SETUID CAP_SETPCAP`로 특정 권한 제거  
  - `RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX AF_NETLINK` 등 네트워크 접근 제한 적용  
  
### 결론  
- systemd 보안 강화 옵션은 유닉스 계열 시스템 관리자라면 도구 상자에 하나쯤 넣어둘 만한 실용적 수단임  
- 완벽한 보안책이 아니라 **리스크를 줄이는 도구**로 활용해야 하며, 모든 서비스에 무분별한 보안 설정을 적용할 필요는 없음  
- 특히 self-hosting 환경의 관리자가 활용할 경우 보안 수준 향상에 큰 도움이 됨  
- "완벽함보다 실용성"을 우선으로, 업무와 환경에 맞는 범위 내에서 부분적으로라도 적용하는 것을 권장

## Comments



### Comment 42685

- Author: neo
- Created: 2025-08-20T10:15:31+09:00
- Points: 1

###### [Hacker News 의견](https://news.ycombinator.com/item?id=44937550) 
* 자동화된 systemd 서비스 하드닝을 strace 프로파일링을 통해서 구현할 수 있다는 점이 흥미롭다고 생각함  
  [https://github.com/desbma/shh](https://github.com/desbma/shh)

  * 내가 찾아낸 좋은 방법이 있는데, ProtectSystem=을 예제에선 사용하지 않았지만  
    TemporaryFileSystem=/:ro, BindReadOnly=/usr/bin/binary /lib /lib64 /usr/lib usr/lib64 와 같이 하면  
    원하는 바이너리와 읽기 원하는 경로만 포함시킬 수 있음  
    ProtectSystem=은 현재 이 동작과 호환되지 않음  
    더 자세한 내용은 [여기](https://github.com/systemd/systemd/issues/33688) 참고

  * 이 방식이 에러 발생 시 이메일을 보내는 등 추가 동작이 필요한 서비스에는 문제가 될 수 있다고 생각함

* 어제 올라온 systemd 하드닝 관련 글에 비해 훨씬 현실적이며 바로 적용 가능한 좋은 팁들이 많음  
  내가 어제 글 댓글에서 더 실제적인 예시를 들려주려고 노력했었는데, 오늘 글은 실질적인 내용을 멋지게 잘 정리해서 systemd로 격리와 보안을 빠르고 쉽게 강화할 수 있는 방법들을 알려줌  
  훌륭한 글이라고 생각함  
  어제 글도 참고로 남김  
  [https://us.jlcarveth.dev/post/hardening-systemd.md](https://us.jlcarveth.dev/post/hardening-systemd.md)  
  [https://news.ycombinator.com/item?id=44928504](https://news.ycombinator.com/item?id=44928504)

  * 사이트 인증서 이슈를 수정해주면 좋겠음  
    일부 브라우저에서는 인증서 오류 때문에 접근 자체가 불가능함

* 공유해줘서 고마움  
  systemd-analyze를 --user 플래그와 함께 사용하면 systemd 사용자 유닛의 보안을 확인할 수 있음("systemd-analyze --user security")  
  컨테이너를 Podman으로 이전하면서 systemd를 더 많이 쓰기 시작했고, 이 툴이 systemd 유닛/컨테이너 서비스의 보안 향상에 많은 도움이 될 것임

* 예전 init 스크립트는 모두 제각각이라서 이런 일관된 강화 작업이 불가능했음

  * 물론 기존 init 스크립트로도 이런 강화 작업을 할 수 있긴 하지만, systemd는 커널의 좋은 기능들을 표준적이고 일관된 방법으로 쉽게 쓸 수 있게 도와줌  
    나는 리눅스에 비교적 늦게 입문해서 systemd 없는 시스템을 상상하기 힘들고, systemd 없는 시스템은 다루기 너무 불편했음  
    최근엔 "unshare"라는 툴을 발견해서 /nix 전체를 RW로 다시 마운트하는 등의 실험을 다른 프로세스에 영향 없이 할 수 있었음  
    systemd는 사용성이 다소 투박하긴 하지만 대안은 솔직히 내게는 Windows뿐이라고 생각함

* 왜 리눅스 배포판에서 이런 보안 스위치를 기본적으로 더 많이 활성화하지 않는지 궁금함  
  보수적으로 강화하는 데에 단점이 있나 생각함  
  많은 사용자에게는 세팅이 너무 많고 복잡할 수 있음

  * 너무 공격적으로 세팅을 변경하면 의도치 않게 기존 설정이 깨질 수 있음  
    예를 들어 NetworkManager를 강화했다면 IPv4, IPv6 모두 연결되는지, dns=systemd-resolved와 dns=default 모드가 정상 동작하는지, ModemManager와 셀룰러 연동, openvpn이나 cisco anyconnect 플러그인, NetworkManager-dispatcher hook 등 다양한 부분을 일일이 검증해야 함  
    또 얼마나 많은 배포판 관리자가 자신이 관리하는 패키지의 스위치를 어느 정도까지 바꿔도 사용자 환경 0.01% 이상이 깨지지 않는지 확신할 수 있는지도 문제임  
    이러한 플래그를 배포판에서 관리하면 업스트림 릴리즈 때마다 호환성 이슈가 덤으로 따라오고, 반대로 업스트림이 설정하면 하위 호환성 때문에 더 신중하게만 쓸 수밖에 없음

  * 이 질문은 "왜 배포판에서 기본적으로 MAC(SELinux 등)을 강하게 안 쓰는가?"와 비슷함  
    sshd 같은 것도 더 제한을 두는 게 좋긴 하지만  
    1) 적용을 위한 초기 개발 비용  
    2) 각종 사용자 환경마다 벌어지는 버그 리포트 처리 비용  
    3) 배포판/업스트림 변화에 맞춘 지속 관리 비용  
    이런 것 때문에 메이저 배포판에서는 부담이 큼  
    SELinux, AppArmor도 마찬가지로 유지 관리자들이 투자 대비 효과를 낮게 보는 경우가 많음

  * 핵심 시스템 서비스의 정상 동작을 각 파라미터마다 일일이 통합 테스트할 역량이나 리소스가 없는 것도 큰 이유임  
    관련 대화  
    [https://news.ycombinator.com/item?id=29995566](https://news.ycombinator.com/item?id=29995566)  
    systemd-analyze security 결과가 배포판별로 다름  
    desbma/shh는 strace로 수집한 내용을 SyscallFilter 등 단위별 룰로 자동 생성해주는데, SELinux의 audit2allow와 유사함  
    하지만 strace를 운영 환경에 설치하는 것은 논란이 가능함  
    [https://github.com/desbma/shh](https://github.com/desbma/shh)

  * 나도 잘 모르겠지만, 일부 세팅은 새로 추가된 것들이라 많은 사용자가 잘 모를 수도 있음  
    systemd 고수만 있는 게 아니고, 설정을 켜면 이전 버전 systemd에서 정상 동작하지 않을 위험도 있음  
    SELinux, AppArmor 등 다양한 기능이 있지만, 많은 배포판이나 개발자, 사용자들이 굳이 필요하다고 느끼지 않아서 자동 적용이 어려운 부분임

* 보안 강화를 위한 옵션이 너무 많아서, 일반적인 서비스별 하드닝 예시를 모아둔 저장소가 있으면 좋겠다고 생각함  
  사용자들이 공통적으로 적용하는 강화 스크립트를 활용하는 경우가 많은데, 의외로 권한을 더 넓게 설정해야 예외 상황이 발생하지 않음을 발견하게 됨

  * nixpkgs같이 업스트림 지원이 부족한 배포판에서 패키징할 때는  
    메인스트림 배포판에서 어떻게 패키징 및 하드닝하는지 참고하는 게 제일 유용함  
    그런 하드닝 방법들이 보통 충분히 테스트된 경우가 많으니, postgresql 등 강화 예시가 궁금하다면 Debian, Ubuntu, RHEL 패키지에서 출발하는 게 좋음

* systemd가 제공하는 훌륭한 보안 기능 중 하나가 크리덴셜 관리임  
  이를 통해 환경 변수나 파일 시스템에 저장하는 것보다 더 안전하게 애플리케이션에 자격 증명을 전달할 수 있음  
  Vault 등이 없는 환경, 예를 들어 개인 프로젝트에선 항상 이 방법을 선호함  
  해당 기능과 연동되는 Go 패키지도 직접 만듦  
  [systemd에서의 credentials](https://systemd.io/CREDENTIALS/)  
  [credential-go 패키지](https://sr.ht/~jamesponddotco/credential-go/)

  * nodejs나 npm처럼 2줄짜리 코드도 패키지로 만드는 문화 같다고 생각함  
    실제로는  
    ```
    dir, err := os.Getenv("CREDENTIALS_DIRECTORY")
    cred, err := os.ReadFile(filepath.Join(dir, "name"))
    ```  
    left-pad보다도 복잡하지 않음  
    Go 커뮤니티에서는 원래 의존성을 줄이고, 불필요한 추상화(함수 호출 등)를 피하는 게 미덕이었던 것으로 아는데  
    이런 간단한 동작은 다들 즉석에서 직접 작성하곤 했었음

  * 이 credential 전달방식이 포크된 자식 프로세스까지 자격 증명 상속을 어떻게 막는지 궁금함

* 정말 유용한 글임  
  systemd 각 옵션 리스트와, "man을 참고하고 행운을 빈다" 같은 조언도 마음에 들음  
  systemd는 정말 훌륭해서 내 서버에 적극 배포하고 싶음

* 사소한 팁이지만 제목 표기에서 systemd의 올바른 표기는 systemd임  
  SystemD, system D, system d 등이 아닌 systemd가 맞음  
  이유는 system daemon이어서, 유닉스/리눅스 전통대로 소문자 d로 끝나는 이름을 쓴 것임

  * 흥미로운 사실임  
    나는 보통 systemD로 부르는 걸 많이 봤는데 왜 그렇게 널리 쓰였는지 궁금함

* systemd에서 syscall 이슈를 디버깅하는 팁이 정말 유용함
