OpenSSH의 권한 분리(privsep) 구조와 sshd, sshd-session, sshd-auth의 역할, 그리고 관련 빌드 옵션과 실행 예시를 설명합니다.
탐색 전환
모양 설정
플랫폼
*
AI 코드 생성 * GitHub Copilot AI로 더 나은 코드 작성 * GitHub Copilot app 이슈부터 병합까지 에이전트 직접 지정 * MCP Registry 신규 외부 도구 통합
*
개발자 워크플로 * Actions 모든 워크플로 자동화 * Codespaces 즉시 사용 가능한 개발 환경 * Issues 작업 계획 및 추적 * Code Review 코드 변경 관리
*
애플리케이션 보안 * GitHub Advanced Security 취약점 탐지 및 수정 * Code security 빌드하면서 코드 보안 유지 * Secret protection 유출이 시작되기 전에 차단
*
둘러보기 * Why GitHub * Documentation * Blog * Changelog * Marketplace
솔루션
*
회사 규모별 * Enterprises * 중소 규모 팀 * 스타트업 * 비영리 단체
*
사용 사례별 * 앱 현대화 * DevSecOps * DevOps * CI/CD * 모든 사용 사례 보기
*
산업별 * 헬스케어 * 금융 서비스 * 제조 * 정부 * 모든 산업 보기
리소스
*
주제별 둘러보기 * AI * 소프트웨어 개발 * DevOps * 보안 * 모든 주제 보기
*
유형별 둘러보기 * 고객 사례 * 이벤트 및 웨비나 * 전자책 및 보고서 * 비즈니스 인사이트 * GitHub Skills
*
지원 및 서비스 * Documentation * 고객 지원 * 커뮤니티 포럼 * 신뢰 센터 * 파트너
오픈 소스
*
커뮤니티 * GitHub Sponsors 오픈 소스 개발자 후원
*
프로그램 * Security Lab * Maintainer Community * Accelerator * GitHub Stars * Archive Program
*
저장소 * Topics * Trending * Collections
Enterprise
*
엔터프라이즈 솔루션 * Enterprise platform AI 기반 개발자 플랫폼
*
사용 가능한 추가 기능 * GitHub Advanced Security 엔터프라이즈급 보안 기능 * Copilot for Business 엔터프라이즈급 AI 기능 * Premium Support 엔터프라이즈급 24/7 지원
검색 또는 이동...
검색
지우기
저희는 모든 피드백을 읽으며, 여러분의 의견을 매우 중요하게 생각합니다.
취소 피드백 제출
이름
쿼리
사용 가능한 모든 한정자를 보려면 문서를 참조하세요.
취소 저장된 검색 만들기
모양 설정
포커스 재설정
다른 탭 또는 창에서 로그인했습니다. 세션을 새로 고치려면 Reload하세요.다른 탭 또는 창에서 로그아웃했습니다. 세션을 새로 고치려면 Reload하세요.다른 탭 또는 창에서 계정을 전환했습니다. 세션을 새로 고치려면 Reload하세요.알림 닫기
{{ message }}
로딩 중 오류가 발생했습니다. 이 페이지를 다시 불러오세요.
openssh/**openssh-portable**Public
Notifications알림 설정을 변경하려면 로그인해야 합니다
추가 탐색 옵션
master
이 저장소 검색(forward slash)forward slash/
.github
contrib
m4
openbsd-compat
regress
.depend
.git_allowed_signers
.git_allowed_signers.asc
.gitignore
.skipped-commit-ids
CREDITS
INSTALL
LICENCE
Makefile.in
OVERVIEW
PROTOCOL
PROTOCOL.agent
PROTOCOL.key
PROTOCOL.krl
PROTOCOL.mux
PROTOCOL.sshsig
PROTOCOL.u2f
README
README.dns
README.md
README.platform
README.privsep
README.tun
SECURITY.md
TODO
addr.c
addr.h
addrmatch.c
atomicio.c
atomicio.h
audit-bsm.c
audit-linux.c
audit.c
audit.h
auth-bsdauth.c
auth-krb5.c
auth-options.c
auth-options.h
auth-pam.c
auth-pam.h
auth-passwd.c
auth-rhosts.c
auth-shadow.c
auth-sia.c
auth-sia.h
auth.c
auth.h
auth2-chall.c
auth2-gss.c
auth2-hostbased.c
auth2-kbdint.c
auth2-methods.c
auth2-none.c
auth2-passwd.c
auth2-pubkey.c
auth2-pubkeyfile.c
auth2.c
authfd.c
authfd.h
authfile.c
authfile.h
bitmap.c
bitmap.h
buildpkg.sh.in
canohost.c
canohost.h
chacha.c
chacha.h
channels.c
channels.h
cipher-aes.c
cipher-aesctr.c
cipher-aesctr.h
cipher-chachapoly-libcrypto.c
cipher-chachapoly.c
cipher-chachapoly.h
cipher.c
cipher.h
cleanup.c
clientloop.c
clientloop.h
compat.c
compat.h
config.guess
config.sub
configure.ac
crypto_api.h
defines.h
dh.c
dh.h
digest-libc.c
digest-openssl.c
digest.h
dispatch.c
dispatch.h
dns.c
dns.h
ed25519-openssl.c
ed25519.c
ed25519.sh
entropy.c
entropy.h
fatal.c
fixalgorithms
fixpaths
groupaccess.c
groupaccess.h
gss-genr.c
gss-serv-krb5.c
gss-serv.c
hmac.c
hmac.h
hostfile.c
hostfile.h
includes.h
install-sh
kex-names.c
kex.c
kex.h
kexc25519.c
kexdh.c
kexecdh.c
kexgen.c
kexgex.c
kexgexc.c
kexgexs.c
kexmlkem768x25519.c
kexsntrup761x25519.c
krl.c
krl.h
libcrux-mlkem-mldsa.c
libcrux_internal.h
log.c
log.h
loginrec.c
loginrec.h
logintest.c
mac.c
mac.h
match.c
match.h
mdoc2man.awk
misc-agent.c
misc.c
misc.h
mkinstalldirs
mlkem_mldsa.sh
moduli
moduli.5
moduli.c
monitor.c
monitor.h
monitor_fdpass.c
monitor_fdpass.h
monitor_wrap.c
monitor_wrap.h
msg.c
msg.h
mux.c
myproposal.h
nchan.c
nchan.ms
nchan2.ms
openssh.xml.in
opensshd.init.in
packet.c
packet.h
pathnames.h
pkcs11.h
platform-listen.c
platform-misc.c
platform-pledge.c
platform-tracing.c
platform.c
platform.h
poly1305.c
poly1305.h
progressmeter.c
progressmeter.h
readconf.c
readconf.h
readpass.c
rijndael.c
rijndael.h
sandbox-capsicum.c
sandbox-darwin.c
sandbox-null.c
sandbox-rlimit.c
sandbox-seccomp-filter.c
sandbox-solaris.c
scp.1
scp.c
servconf.c
servconf.h
serverloop.c
serverloop.h
session.c
session.h
sftp-client.c
sftp-client.h
sftp-common.c
sftp-common.h
sftp-glob.c
sftp-realpath.c
sftp-server-main.c
sftp-server.8
sftp-server.c
sftp-usergroup.c
sftp-usergroup.h
sftp.1
sftp.c
sftp.h
sk-api.h
sk-usbhid.c
smult_curve25519_ref.c
sntrup761.c
sntrup761.sh
srclimit.c
srclimit.h
ssh-add.1
ssh-add.c
ssh-agent.1
ssh-agent.c
ssh-ecdsa-sk.c
ssh-ecdsa.c
ssh-ed25519-sk.c
ssh-ed25519.c
ssh-gss.h
ssh-keygen.1
ssh-keygen.c
ssh-keyscan.1
ssh-keyscan.c
ssh-keysign.8
ssh-keysign.c
ssh-mldsa-eddsa.c
ssh-pkcs11-client.c
ssh-pkcs11-helper.8
ssh-pkcs11-helper.c
ssh-pkcs11.c
ssh-pkcs11.h
ssh-rsa.c
ssh-sandbox.h
ssh-sk-client.c
ssh-sk-helper.8
ssh-sk-helper.c
ssh-sk.c
ssh-sk.h
ssh.1
ssh.c
ssh.h
ssh2.h
ssh_api.c
ssh_api.h
ssh_config
ssh_config.5
sshbuf-getput-basic.c
sshbuf-getput-crypto.c
sshbuf-io.c
sshbuf-misc.c
sshbuf.c
sshbuf.h
sshconnect.c
sshconnect.h
sshconnect2.c
sshd-auth.c
sshd-debug.sh
sshd-session.c
sshd.8
sshd.c
sshd_config
sshd_config.5
ssherr-libcrypto.c
ssherr-nolibcrypto.c
ssherr.c
ssherr.h
sshkey.c
sshkey.h
sshlogin.c
sshlogin.h
sshpty.c
sshpty.h
sshsig.c
sshsig.h
sshtty.c
survey.sh.in
ttymodes.c
ttymodes.h
uidswap.c
uidswap.h
umac.c
umac.h
umac128.c
utf8.c
utf8.h
version.h
xmalloc.c
xmalloc.h
/
경로 복사
Blame 추가 파일 작업
Blame 추가 파일 작업
2026년 7월 3일
aab5620·2026년 7월 3일
커밋 세부 정보 열기
173줄 (144 loc) · 7.99 KB
/
경로 복사
맨 위
173줄 (144 loc) · 7.99 KB
원시 파일 복사
원시 파일 다운로드
심볼 패널 열기
편집 및 원시 작업
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
권한 분리(privsep)는 OpenSSH에서 루트 권한이 필요한 작업을 별도의 권한 있는 모니터 프로세스가 수행하도록 하는 방법입니다. 그 목적은 다음과 같은 방식으로 권한 상승을 방지하고 공격을 완화하는 것입니다:
신뢰할 수 없는 데이터가 관련된 대부분의 작업을 비권한 코드에서 수행함으로써 권한 있는 공격 표면을 줄이고,
공격에 가장 많이 노출되는 구성 요소에 대해 OS 수준 샌드박싱을 용이하게 하며,
권한 있는 코드와 비권한 코드 사이의 정보 공유를 줄이고,
공격이 발생하더라도 가능한 한 비권한 프로세스 안에 국한되도록 합니다.
OpenSSH의 sshd에서 권한 분리를 구현하기 위해, 수행하는 기능은 세 개의 분리된 바이너리로 나뉩니다:
sshd는 서버의 주 진입점 바이너리입니다. 이 바이너리는 권한을 유지하지만 매우 제한된 작업 집합만 수행합니다. 즉, 설정을 불러오고 확인하며, 들어오는 연결을 수신하고, 연결 생명주기의 인증 전 단계 동안 연결 상태를 모니터링하여 MaxStartups 및 PerSourcePenalties 기능을 구현합니다.
연결을 수신하고 받아들이는 것 외에는 sshd 바이너리가 신뢰할 수 없는 네트워크 유래 데이터를 처리하지 않으며, 대신 새 연결마다 sshd-session 바이너리를 fork 및 exec 합니다.
+---------------------------------------------------------------+
| |
| listening socket +-------------------+ |
| \--------------+ sshd (listener) | |
| +--------++---------+ |
| || |
| || fork+exec |
| || |
| +--------------++------------------+ |
| | sshd-session (preauth monitor) | |
| +--------------++------------------+ |
| || |
| || fork+exec |
| || |
| network socket +------------++--------------+ |
| \-----------+ sshd-auth (unprivileged) | |
| +------------++--------------+ |
| |
+---------------------------------------------------------------+
pre-authentication process structure
sshd-session은 처음에는 연결이 인증을 완료하기 전까지 해당 연결의 권한 있는 모니터 프로세스로 동작합니다. 이 단계에서는 네트워크 유래 데이터를 직접 다루지 않고, 대신 네트워크 소켓을 통한 SSH 프로토콜 통신을 처리하기 위해 세 번째 바이너리(sshd-auth, 다음에 설명함)를 fork 및 exec 합니다. sshd-session은 계정 존재 여부 확인, 호스트 키로 서명, 사용자 비밀번호 확인과 같은 권한 있는 작업이 필요할 때 sshd-auth 하위 프로세스로부터 RPC 메시지를 받습니다. 모니터 프로세스는 sshd-auth가 요청할 수 있는 작업의 필수 구조와 순서를 강제하는 느슨한 상태 기계를 구현합니다.
sshd-auth는 SSH 프로토콜의 초기 키 합의 및 인증 단계를 구현하는 네트워크 대면 프로세스입니다. 이 프로세스는 권한을 가진 상태로 시작되지만, 어떤 네트워크 트래픽도 처리하기 전에 스스로를 샌드박스 처리 및/또는 chroot(2) 하고 비권한 계정으로 권한을 낮춥니다. 사용자 정보 조회, 개인 키 서명, 비밀번호 확인 등 권한이 필요한 모든 작업은 부모 sshd-session 프로세스에 대한 RPC를 통해 수행됩니다. 인증이 완료되면 sshd-auth는 자신의 SSH 프로토콜 및 연결 상태를 직렬화하고, 이를 부모 sshd-session 프로세스에 내보낸 뒤 종료합니다.
부모와 자식 프로세스 사이의 통신은 공유 파일 디스크립터를 통해 이루어집니다. 부모 프로세스는 또한 exit(3) 상태를 통한 충돌이나 시그널링 같은 비정상 종료 조건이 있는지 자식들을 모니터링합니다. 이러한 조건은 sshd에서 PerSourcePenalties 제어를 구현하는 데 사용됩니다.
+---------------------------------------------------------------+
| |
| +---------------++------------------+ |
| | sshd-session (postauth monitor) | |
| +---------------++------------------+ |
| || |
| || fork |
| || |
| network socket +--------------++---------------+ |
| \-----------+ sshd-session (unprivileged) | |
| +--------------++---------------+ |
| |
+---------------------------------------------------------------+
post-authentication process structure
인증 이후 sshd-session은 부모 리스너 sshd로부터 분리됩니다. 인증이 성공한 뒤에는 이 리스너가 연결을 추적하지 않기 때문입니다. 그리고 다시 한 번 fork 합니다. fork된 sshd-session 자식 프로세스는 인증된 사용자의 권한으로 권한을 낮추고, sshd-auth로부터 이전에 직렬화된 연결 상태를 가져와 세션의 남은 기간 동안 네트워크 및 SSH 프로토콜 작업을 계속 수행합니다.
부모 sshd-session 프로세스는 계속해서 권한 있는 모니터 프로세스로 동작하며, RPC를 통해 요청받으면 권한이 필요한 작업을 수행합니다. 이러한 작업에는 PTY 할당과 키 재교환 메시지 서명이 포함됩니다.
portable OpenSSH에서는 몇 가지 컴파일 시점 옵션이 권한 분리에 영향을 줍니다:
--with-sandbox=style
sshd-auth가 사용하는 샌드박싱 구현을 제어합니다. 여러 플랫폼에서 OS 수준 샌드박싱이 지원됩니다. 대체 수단으로 rlimit(2) 기반 샌드박스가 더 넓은 플랫폼 집합에서 기본적인 제어를 제공합니다. 대부분의 지원되는 샌드박스는 자동으로 감지되고 활성화되므로, 이 옵션은 주로 샌드박스를 비활성화하는 데 사용됩니다(디버깅하거나 AddressSanitizer 같은 도구 아래에서 실행할 때 유용합니다).
--with-privsep-user=user
sshd-auth가 신뢰할 수 없는 데이터를 처리하기 시작하기 전에 전환할 비권한 사용자를 지정합니다. 이 사용자는 다른 어떤 시스템 서비스와도 공유되어서는 안 되며, 어떤 파일도 소유하지 않아야 하고, 비밀번호는 잠겨 있어야 하며, 접근을 거부하는 셸(/bin/nologin 또는 /bin/false 등)을 사용해야 하고, 홈 디렉터리는 권한 분리 경로로 설정되어야 합니다. 대부분의 플랫폼에서 기본 사용자는 "sshd"입니다.
--with-privsep-path=/path
sshd-auth가 권한을 낮추기 전에 chroot(2) 할 디렉터리를 제어합니다. 이 디렉터리는 비어 있어야 하며, 다른 시스템 계정과 공유되어서는 안 되고, 샌드박스 사용자에게 읽기 또는 쓰기 가능해서도 안 됩니다. 기본 privsep 경로는 "/var/empty"입니다.
privsep 인증 전 환경을 준비하려면 다음과 같이 해야 합니다:
# mkdir /var/empty
# chown root:sys /var/empty
# chmod 755 /var/empty
# groupadd sshd
# useradd -g sshd -c 'sshd privsep' -d /var/empty -s /bin/false sshd
일부 플랫폼에서는 privsep의 인증 전 부분만 지원되며, 운영 체제의 지원 부족으로 인해 인증 후 부분은 비활성화됩니다.
다음은 인증 전 단계에 있는 연결의 프로세스 목록 예시입니다:
PID PPID UID CMD
1436 1 0 sshd: /usr/sbin/sshd -D [listener] 1 of 10-100 startups
47077 1436 0 sshd-session: djm [priv]
47078 47077 107 sshd-auth: djm [net]
여기서 프로세스 1436은 리스너이고, 47077은 권한 있는 sshd-session 모니터 프로세스이며, 47078은 비권한의 네트워크 대면 sshd-auth 프로세스입니다.
그리고 인증 후 단계에서는:
PID PPID UID CMD
47077 1436 0 sshd-session: djm [priv]
47091 47077 1000 sshd-session: djm@pts/1
47092 47091 1000 -bash
여기서 프로세스 47077은 계속해서 권한 있는 모니터 역할을 수행하고, 47091은 사용자 권한의 네트워크 대면 인증 후 프로세스이며, 47092는 세션을 위해 시작된 사용자 셸입니다.
지금은 해당 작업을 수행할 수 없습니다.
코드에 포커스가 맞춰져 있는 동안 작업 메뉴를 열려면 Alt+F1을 누르세요.