SNMP(Simple Network Management Protocol) 은 원래 네트워크 장비를 관리하기 위한 통신 규약입니다. 그런데, 이제는 네트워크 장비뿐만아니라 컴퓨터, 전자장비까지 확장해서 사용하고 있습니다. 리눅스 시스템에서도 SNMP를 사용할 수 있습니다.
이를 이용하면 SNMP 를 이용해서 중앙집중식으로 각각의 장비들의 자원, 자원사용량등을 장비에 거의 모든 것을 알 수 있고 가지고 올 수 있습니다. 저의 경우에는 Cacti 라는 시스템 자원 모니터링 시스템에서 원격 시스템의 자원 사용량을 가지고 오기 위해서 각 서버마다 SNMP를 사용합니다.
준비
이 문서는 다음과 같은 환경에서 작성되었습니다.
CentOS 7
X86_64
SNMP는 서버/클라언트 구조를 가지고 있습니다. 중앙 집중식으로 한 곳에서 정보를 모을 경우에는 중앙 서버를 제외하고 SNMP 데몬만 설치해주면 됩니다.
설치
설치는 Yum 을 이용해 다음과 같이 해주면 됩니다.
SNMP 설치
Shell
1
yum install net-snmp[net-snmp-utils]
위에 뒷부분 ‘net-snmp-utils’ 는 SNMP 데몬하고는 아무런 관련이 없기 때문에 설치를 않해되 되지만 SNMP 데몬의 제대로 동작하는지를 테스트하기 위해서는 설치해주는 것이 좋습니다. ‘net-snmp-utils’ 는 말 그대로 SNMP를 다루기위한 여러가지 명령어들이 들어 있습니다.
설정
CentOS7 의 특징은 데몬이 실행될때에 옵션을 제공해 줄 수 있는데, 이를 위해서 ‘/etc/sysconfig’ 디렉토리에 데몬이름으로 파일을 가지게 됩니다. 그러면 데몬 실행 프로그램에서 이를 import 해서 사용하곤 하는데 SNMP 데몬도 이와 같습니다.
-Ls 는 로그 메시지 stderr, stdout 으로 내보내고 로그레벨을 정한다. 기본은 -Lsd 로 d 는 LOG_DEBUG 을 말한다. 로그의 수준은 0 ~ 7 까지 존재하는데 다음과 같다.
SNMPD 로그 레벨
1
2
3
4
5
6
7
8
0or!forLOG_EMERG,
1oraforLOG_ALERT,
2orcforLOG_CRIT,
3oreforLOG_ERR,
4orwforLOG_WARNING,
5ornforLOG_NOTICE,
6oriforLOG_INFO,and
7ordforLOG_DEBUG.
이는 -LSwd 나 -LS4d 식으로 숫자와 알파벳으로 지정할 수 있다. -LSed / -LS3d 같은 예제이다. 또, -LS1-5d 처럼 로그레벨 수준을 어디서 어디까지로 정할 수도 있다. 위 예제에서는 데몬 메시지를 syslog 로 보내는데 로그 레벨 1~5까지를 보내라는 뜻이다.
-Lf 는 지정한 파일로 로그 메시지를 보낸다. 위 예제에서는 /dev/null 임으로 로그 메시지를 삭제하는 효과를 보인다.
-p 는 pid 파일을 지정해 준다.
다음으로 SNMP 자체 설정을 합니다. 아래의 예제는 시스템 자원을 읽기 전용으로만 설정하는 것입니다.
SNMP 설정은 ‘sec.name’ 별로 설정을 할 수 있습니다. sec.name 을 여러게 정의하면 group도 여러개 설정할 수 있고 이렇게 되면 access 도 여러개 설정할 수 있습니다. 주목할 것은 access 에서 뒷부분에 read, write, notif 가 보이는데, 위 예제가 시스템 자원을 읽기만 할 것이기 때문에 read 부분만 all 로 하고 나머지를 none 으로 한 것입니다.
마지막으로 systemd 에 snmpd 를 활성화 해주고 시작해 줍니다.
systemd 에 snmpd 를 활성화하고 시작
Shell
1
2
systemctl enable snmpd
systemctl start snmpd
로깅 변경
위 설정대로 하면 snmpd 로그가 /var/log/messages 에 저장이 됩니다. 하지만 /var/log/messages 는 커널 메시지도 저장되고 하는 중요한 것이여서 별도 파일에 저장하는 것이 좋습니다.
이를 위해서 snmpd 를 위한 별도의 로그 파일 설정을 해주는데, 먼저 /etc/sysconfig/snmpd 설정을 다음과같이 바꿔 줍니다.
제가 운영하는 시스템에는 snmpd 가 기본으로 서비스되고 있습니다. 각종 시스템의 상태를 파악하기 위해서 snmpd 를 활용하는 거지요. 그런데, 얼마전에 이 snmpd 때문에 아주 큰 문제가 된 일이 있었습니다.
이 문서는 그것이 무엇이며 왜 발생했고 어떻게 처리하는지에 대한 문서 입니다.
snmpd
snmpd 는 국제표준으로 IT기기에 각종 상태들을 네트워크를 통해서 제공할 수 있도록 설게된 SNMP를 제공하는 데몬이다. 수 많은 서버에 기본으로 탑재되어 있어 별다른 노력없이 사용이 가능하다.
리눅스 플랫폼에서 snmpd 를 사용하는데 있어 현재 인자값 사용에 문제가 있다. 인자값의 잘못된 사용으로 인해서 리눅스 전체 시스템에 미치는 영향은 치명적이다 못해 시스템을 재부팅한다하더라도 콘솔접속이 되지 않는한 문제를 해결될 수 없다.
Problems
대부분의 리눅스는 많은 배포판을 이룬다. 내가 테스트한 배포판은 Ubuntu 12.0.4 LTS 와 CentOS 6, 7 이다. 여기서는 Ubuntu 배포판을 기반으로 내용을 전개할 것이다. snmpd 의 문제만 체크하면 되는 것이기에 기타 하드웨어 스펙과 배포판에 설치된 각종 라이브러리등은 중요하지 않아 기술하지 않는다.
이제 문제에 접근해보자. Ubuntu 에서 snmpd 를 설치하면 다음과 같은 파일이 설치된다.
파일
내용
/etc/default/snmpd
snmpd 의 init 파일에서 사용되는 snmpd 데몬 실행 옵션
/etc/init.d/snmpd
snmpd 데몬 init 스크립트
주목해야할 파일은 ‘/etc/default/snmpd’ 파일이며 이 파일에서 주목해야할 내용은 다음과 같다.
자세히 보지 않으면 뭐가 바뀌었는지 알수 없게 된다. ‘-Lf’ 를 빠졌다. 이렇게 바꾸고 snmpd 를 재시작하면 문제가 재현된다.
1
2
service snmpd restart
*Restarting network management services:
증상
snmpd 를 재시작한 터미널에서는 별다른 증상을 알 수가 없다. 이제 다른 터미널을 열고 snmpd 를 재시작한 서버에 접속해보자. 아마 다음과 같이 나올 것이다.
1
2
]$ssh root@192.168.96.17
ssh_exchange_identification:read:Connection reset by peer
root 계정이던 일반 계정이든 아무 상관이 없다. 바로 이게 문제다. 아무것도 접속할 수 없다.
콘솔에서 접속해도 다음과 같은 증상이 나온다.
Shell
1
2
3
4
5
6
7
8
9
10
11
12
13
ubuntu login:root
password:
-bash:/dev/null:No such device oraddress<--이게무수히나오고
-bash:/dev/null:No such device oraddress
-bash:/dev/null:No such device oraddress
-bash:/dev/null:No such device oraddress
-bash:/dev/null:No such device oraddress
root@ubuntu:~# cd / [탭을 누르면] -bash: /dev/null: No such device or address
bash:_upvars:`-a2':invalid number specifier
-bash:/dev/null:No such device oraddress
-bash:/dev/null:No such device oraddress
-bash:/dev/null:No such device oraddress
-bash:/dev/null:No such device oraddress
원인분석
원인은 ‘/etc/default/snmpd’ 에서 정의한 snmpd 의 시작 옵션에 있다. snmpd 는 다음과 같이 커맨드라인에서 시작할 수 있다.
1
snmpd[OPTIONS][LISTENING ADDRESSES]
문제는 snmpd 에서 옵션은 반드시 ‘-L’, ‘-a’ 등과 같이 – 로 시작한다. 이것이 없이 그냥 값을 주게되면 그것은 바로 [LISTENING ADDRESSES] 가 된다. 여기서 중요한 것이 [LISTENING ADDRESSES]는 어떤값들이 올수 있느냐인데 이는 snmpd 맨페이지(man)를 통해서 확인할 수 있다.
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
[<transport-specifier>:]<transport-address>
At its simplest,alistening address may consist only ofaport number,inwhich casesnmpd listens on that UDP port on all IPv4 interfaces.Oth-
erwise,the<transport-address>part of the specification isparsed according tothe following table:
sshd1014root mem REG8,1521201835042/lib/x86_64-linux-gnu/libnss_files-2.15.so
sshd1014root mem REG8,1476801835036/lib/x86_64-linux-gnu/libnss_nis-2.15.so
sshd1014root mem REG8,1356801835044/lib/x86_64-linux-gnu/libnss_compat-2.15.so
sshd1014root mem REG8,11052881835043/lib/x86_64-linux-gnu/libresolv-2.15.so
sshd1014root mem REG8,1143601835328/lib/x86_64-linux-gnu/libkeyutils.so.1.4
sshd1014root mem REG8,1312002098198/usr/lib/x86_64-linux-gnu/libkrb5support.so.0.1
sshd1014root mem REG8,11581682098187/usr/lib/x86_64-linux-gnu/libk5crypto.so.3.1
sshd1014root mem REG8,1147681835050/lib/x86_64-linux-gnu/libdl-2.15.so
sshd1014root mem REG8,1972481835041/lib/x86_64-linux-gnu/libnsl-2.15.so
sshd1014root mem REG8,118111281835037/lib/x86_64-linux-gnu/libc-2.15.so
sshd1014root mem REG8,1146961835113/lib/x86_64-linux-gnu/libcom_err.so.2.1
sshd1014root mem REG8,18446482098194/usr/lib/x86_64-linux-gnu/libkrb5.so.3.3
sshd1014root mem REG8,12527202098190/usr/lib/x86_64-linux-gnu/libgssapi_krb5.so.2.2
sshd1014root mem REG8,1432881835047/lib/x86_64-linux-gnu/libcrypt-2.15.so
sshd1014root mem REG8,1927201835237/lib/x86_64-linux-gnu/libz.so.1.2.3.4
sshd1014root mem REG8,1106321835035/lib/x86_64-linux-gnu/libutil-2.15.so
sshd1014root mem REG8,119306481835040/lib/x86_64-linux-gnu/libcrypto.so.1.0.0
sshd1014root mem REG8,11353661835038/lib/x86_64-linux-gnu/libpthread-2.15.so
sshd1014root mem REG8,11219361835071/lib/x86_64-linux-gnu/libselinux.so.1
sshd1014root mem REG8,1557441835091/lib/x86_64-linux-gnu/libpam.so.0.83.0
sshd1014root mem REG8,1364321839207/lib/x86_64-linux-gnu/libwrap.so.0.7.6
sshd1014root mem REG8,11492801835048/lib/x86_64-linux-gnu/ld-2.15.so
sshd1014root0uCHR1,30t05862/dev/null
sshd1014root1uCHR1,30t05862/dev/null
sshd1014root2uCHR1,30t05862/dev/null
sshd1014root3uIPv697620t0TCP*:ssh(LISTEN)
sshd1014root4uIPv497660t0TCP*:ssh(LISTEN)
root@ubuntu:~#
위에서 아래쪽을 보면 TYPE 이 CHR 이며 DVICE 1,3 나오는 ‘/dev/null’ 이 보인다.
그런데, 이것을 위에 문제처럼 snmpd 의 Unix Domain Socket 으로 하게되면 /dev/null 는 더 이상 장치파일이 아닌 소켓 파일로 변경되어 이 장치를 사용하는 모든 프로그램에 문제가 발생하게 된다. 다음과 같이 이전에 장치파일이 아닌 그냥 일반파일로 변경된것을 알 수 있다.
1
2
]# ls -lh /dev/null
srwxr-xr-x1root root0Apr2722:57/dev/null
그리고 netstat 로 보면 snmpd 가 /dev/null 을 Unix Domain Socket 으로 사용하고 있다는 것이 보인다.
Shell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
root@ubuntu:~# netstat -lpn
Active Internet connections(only servers)
Proto Recv-QSend-QLocal Address Foreign Address State PID/Program name
가장 좋은 방법은 아직 연결이 유지되고 있는 터미널에서 ‘/etc/default/snmpd’ 의 옵션을 고쳐주는 것이다. 그리고 반드시 재부팅을 해줘야 한다.
그런데, 재부팅을 해서는 안되는 서버라면 어떻게 해야 할까?
첫째, ‘/etc/default/snmpd’ 에서 옵션을 변경하고 snmpd 를 정지시킨다. 재시작해줘도 /dev/null 파일이 장치로 복구가 안된다.
둘째, /dev/null Unix Domain Socket 파일을 삭제한다. 더이상 장치 파일이 아니기 때문에 과감히 삭제한다.
Shell
1
sudo rm-f/dev/null
셋째, /dev/null 파일을 다시 만들어 준다.
1
sudo mknod-m666/dev/nullc13
위와같이 장치파일을 생성해주자 마자 바로 sshd 가 복구된다.
문제의 핵심
문제는 /dev/null 를 Domain Unix Socket 이던 무엇이던간에 프로그램에서 파일이 속성을 변경되도록 했다는데 있다. 애초에 snmpd 인자로 /dev/null 을 주었던게 문제였고 그 이전에 오타발생이 문제였다.
비단 snmpd 만 인자값으로 Unix Domain Socket 을 사용한다고 생각하지 않는다. 리눅스에는 수많은 프로그램들이 존재하고 snmpd 와 같이 옵션으로 Unix Domain Socket 을 받는 경우도 분명 존재한다. 그것도 하필이면 /dev/null 를 준다면 똑같은 문제가 발생할 수 있다.
위의 snmpd 문제로 영향받는 프로그램들
위 문제(snmpd 로 발생되는 문제) 로 영향받는 프로그램들은 /dev/null 장치를 사용하는 프로그램이라면 다 영향을 받는다.
sshd
nginx ← 동작에는 문제가 없어 보이지만 재시작하면 다음과 같이 나오면서 시작되지 않는다.
Shell
1
2
3
4
5
6
root@ubuntu:~# service nginx restart
Restarting nginx:/etc/init.d/nginx:30:/etc/init.d/nginx:cannot create/dev/null:No such device oraddress
아마도 개인적인 추측인데, CentOS 7 로 넘어오면서 기본 옵션이 변경된데에는 systemd 의 도입때문으로 보인다. systemd 의 도입으로 각 데몬 프로그램들은 systemd 가 상태, 로깅들을 담당하게 되어 이전 CentOS 6 과는 다르게 각 데몬 프로그램들 각자가 로깅을 할 필요가 없게 되었다.
최종결론
어찌되었든 /dev/null 파일을 삭제하거나 일반파일로 바꾸거나 해서는 안된다. 그렇게되면 sshd 는 접속을 거부할 것이다. 혹시나 다른 방법으로 슈퍼유저인 root 로 커맨드를 날릴 수 있다면 당황하지 말고 다음과 같이하면 적어도 sshd 는 돌아온다.
Shell
1
2
]$sudo rm-f/dev/null
]$sudo mknod-m666/dev/nullc13
그리고 ubuntu 에서 ‘/etc/default/snmpd’ 를 수정할때는 오타 를 항상 조심해야 한다.
snmpd 는 시스템의 자원들에 대해서 SNMP 프로토콜을 통해서 볼 수 있는 기능을 제공 한다. 그런데, 알고 싶은 자원들에 대한 목록들을 조회하기 위해 MIB 값들이 할당되어 있으며 자주 사용되는 운영체제, 라우터, 스위치 같은 장비들에 대한 MIB 값들을 미리 할당되어 전 세계적으로 표준으로 재정해 사용하고 있다.
그런데, 표준으로 재정된 MIB 값외에 사용자가 필요한 자원들을 조회하기 위한 MIB 값을 등록해야 하는데 이때 사용하는 것이 SNMP Extend 를 사용하면 된다.
SNMP Extend 는 ‘.1.3.6.1.4.1.2021.8.10’ 같은 MIB 에 조회하고자하는 값들을 등록하면 된다.