제목을 무엇으로 지을까 고민하다가, 참고한 글의 제목을 그대로 따왔다.

 

# Issue

처음 이 문제가 나타난 것은 syslog-ng의 플러그인 라이브러리를 사용해 MariaDB로 Destination 설정을 해줬을 때 였다.

Default로 설치된 syslog-ng# systemctl start syslog-ng 명령어를 사용해 시작하면 잘 동작하는데, syslog-ng.conf 파일에 MariaDB로의 Destination 설정만 넣으면 서비스 Fail이 발생하는 것이였다.😢

 

관련해서 혼자 해결하기 힘들다고 판단해, syslog-ng를 개발한 Balabit Github에 이슈 등록을 했다.

결론 먼저 말하자면,

리눅스 커널 보안 정책인 SELinux 때문에 발생한 문제였다.

SELinux 보안 정책을 Permissive mode로 변경 후 syslog-ng 서비스를 재시작하니, MariaDB로 Destination 설정이 되어 있더라도 잘 동작하는 것을 볼 수 있었다.👏👏👏

하지만 늘상 Permissive mode로 하고 있을 순 없으니... 궁극적으로 해결할 수 있는 방법이 필요했다.

 

 

Github 이슈에 보면 Balabit 개발자가 참고하라고 알려준 링크가 있는데, 이 링크가 바로 이 문제를 해결할 수 있었던 열쇠이다.

syslog-ng를 사용하면서 등록되는 이슈의 절반 이상이 SELinux 문제여서, 관련 가이드 글을 작성한듯 하다. (👉 링크)

 

부족한 영어실력 & 구글 네이버의 힘을 빌려 변역했으니 참고하실 분은 아래 더보기를 눌러서 참고하세요.😉

 

더보기

SELinux는 리눅스에서 엄격한 보안 정책을 담당하는 서비스이면서 동시에 Syslog-ng 서비스가 동작하는데 이슈의 절반 이상에 해당하는 문제를 야기한다.

환경설정에 비정상적인 포트 번호 또는 디렉토리 이름이 지정되면 Syslog-ng가 정상적이라도 작동하지 않는다.

Enforce mode에서 SELinux와 함께 Syslog-ng를 사용하는 방법을 알아보자.

 

SELinux basics

먼저 SELinux가 컴퓨터에서 Enforcing mode인지 확인한다.

cat 명령어를 사용해서 확인하는 방법과 getenforce 명령어를 사용하는 방법이 있음

[root@selinux ~]# cat /etc/selinux/config 
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
# enforcing - SELinux security policy is enforced.
# permissive - SELinux prints warnings instead of enforcing.
# disabled - No SELinux policy is loaded.
SELINUX=enforcing
# SELINUXTYPE= can take one of three two values:
# targeted - Targeted processes are protected,
# minimum - Modification of targeted policy. Only selected processes are protected. 
# mls - Multi Level Security protection.
SELINUXTYPE=targeted 
 
[root@selinux ~]# getenforce 
Enforcing

 

만약 Enforcing mode가 아닌 경우, 환경설정 파일을 변경하고 재부팅한다.

SELinux를 완전히 비활성화하는 것은 권장되지 않는다.

SELinux를 다시 활성화하려면 restorecon 을 사용하여 파일 시스템의 label 도 다시 지정해야 한다.

setenfoce 명령어를 사용하여 SELinuxM를 일시적으로 비활성화하고 getenforce 명령어를 사용하여 결과를 확인할 수 있다.

[root@selinux ~]# setenforce 0
[root@selinux ~]# getenforce 
Permissive
 
[root@selinux ~]# setenforce 1
[root@selinux ~]# getenforce 
Enforcing

 

Permissive mode에서는 SELinux는 정책 위반을 감지하고 기록하지만, 규칙을 적용하지는 않는다. 이는 디버깅 목적으로 사용할 수 있다.

# setenforce 0 을 사용하면, SELinux가 실수로 비활성화 상태로 유지되지 않게 할 수 있다.

 

 

Logging

SELinux 로그는 /var/log/audit/audit.log 파일에 수집된다.기본 배포 구성으로 Syslog-ng를 시작할 때 로그에 표시되는 유일한 로그는 새 서비스가 시작되었다는 로그이다.

[root@selinux ~]# grep syslog-ng /var/log/audit/audit.log 
type=SERVICE_START msg=audit(1494923144.043:303): pid=1 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:init_t:s0 msg='unit=syslog-ng comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'

 

최근 Syslog-ng 릴리즈의 linux-audit-parser() 기능을 사용하여 이 파일의 내용을 구문 분석할 수 있다. 자세한 내용은 이 링크를 참조

SELinux에서는 label을 기반으로 접근 권한이 부여된다.

일반적으로 명령의 옵션으로 대문자 Z 를 사용하여 파일 및 프로세스에 대해 이러한 label을 나열할 수도 있다.

 

 

Using a different storage directory

우리는 /var/log 디렉토리에 로컬 로그 메시지를 저장한다.

그러나 중앙 Syslog-ng 서버의 로그는 종종 별도의 파티션(ex: /data/logs 디렉토리)에 저장된다.

syslog-ng.conf 를 수정하고 syslog-ng를 다시 시작하면 디렉토리에서 로그를 볼 수 없다. 어떻게 된걸까?

/var/log/audit/audit.log 에서 syslog-nglogs 라는 디렉토리에 대한 접근이 거부되었음을 알 수 있다.

type=AVC msg=audit(1494927489.413:407): avc: denied { write } for pid=50082 comm="syslog-ng" name="logs" dev="dm-0" ino=35096600 scontext=system_u:system_r:syslogd_t:s0 tcontext=unconfined_u:object_r:default_t:s0 tclass=dir

 

만약 /var/log/messages 를 살펴보면 다음과 비슷한 메시지를 찾을 수 있다.

May 16 11:40:44 selinux syslog-ng[50082]: Error opening file for writing; filename='/data/logs/file', error='No such file or directory (2)'

 

SELinux 문제라고 할 수도 있으며, audit2allow 명령을 사용하여 권한 문제를 해결해야 한다.

늘 그렇듯이 인생이 쉽지 않은 이유는, syslog-ng가 너무 많은 접근 권한을 받도록 하기 떄문이다. 차라리 직접 변경해야 한다.

위 디렉토리 목록에서 볼 수 있듯이 /var/log 디렉토리는 var_log_t label에 있다.

새로 생성된 디렉토리를 나열하면 다음과 같은 다른 내용이 있다.

[root@selinux conf.d]# ls -ldZ /data/logs/
drwxr-xr-x. root root unconfined_u:object_r:default_t:s0 /data/logs/

 

chcon 명령을 사용하여 label을 var_log_t 로 변경하고 ls 명령의 Z 옵션을 사용하여 결과를 확인할 수 있다.

[root@selinux conf.d]# chcon -t var_log_t /data/logs/
[root@selinux conf.d]# ls -ldZ /data/logs/
drwxr-xr-x. root root unconfined_u:object_r:var_log_t:s0 /data/logs/

 

이 접근법의 문제점은 변경이 일시적이라는 것이다.

restorecon 명령어를 사용하여 시스템을 재부팅하거나, SELinux label을 복원하면 손실된다.

[root@selinux conf.d]# restorecon -v /data/logs/
restorecon reset /data/logs context unconfined_u:object_r:var_log_t:s0->unconfined_u:object_r:default_t:s0
 
[root@selinux conf.d]# ls -ldZ /data/logs/
drwxr-xr-x. root root unconfined_u:object_r:default_t:s0 /data/logs/

 

semanage 명령을 사용하면 영구적으로 변경할 수 있다.

[root@selinux conf.d]# semanage fcontext -a -t var_log_t '/data/logs(./*)?'
[root@selinux conf.d]# restorecon -v /data/logs/
restorecon reset /data/logs context unconfined_u:object_r:default_t:s0->unconfined_u:object_r:var_log_t:s0
 
[root@selinux conf.d]# ls -ldZ /data/logs/
drwxr-xr-x. root root unconfined_u:object_r:var_log_t:s0 /data/logs/

이제 로그가 디렉토리에 나타날 것이다.

 

 

Using a different port

기본적으로 SELinux는 기본 syslog 포트에 대한 연결만 허용한다. 다음은 SELinux에 알려진 syslog 관련 포트이다.

[root@selinux conf.d]# semanage port --list | grep syslog
syslog_tls_port_t tcp 6514
syslog_tls_port_t udp 6514
syslogd_port_t tcp 601
syslogd_port_t udp 514, 601

 

어떤 이유로든 다른 포트를 사용해야하는 경우 문제가 될 수 있다.

일반적인 시나리오는 TCP 로그 메시지에 대해서도 포트 514를 활성화하는 것이다.

포트 42에서 일부 로그를 수집하여 삶과 우주 및 모든 것이 대해 배울 수도 있다. 더 심각한 문제는 로그 메시지 유형별로 다른 포트 번호를 사용하여 로그 구문 분석을 더 쉽게 만드는 것이다.

만약 포트42(또는 다른 포트도 마찬가지)를 추가하고 SELinux를 구성하지 않고 syslog-ng를 다시 시작하면 서비스 시작에 실패한다.

journalctl 을 사용하여 오류 메시지를 확인할 수 있다.

May 17 09:55:35 selinux.localdomain setroubleshoot[3640]: SELinux is preventing /usr/sbin/syslog-ng from name_bind access on the tcp_socket port 42. For complete SELinux messages. run sealert -l ff7a7f22-128e-4b
 
May 17 09:55:35 selinux.localdomain python[3640]: SELinux is preventing /usr/sbin/syslog-ng from name_bind access on the tcp_socket port 42.

 

다음 명령어를 사용하여 syslogd_port_t 에 TCP 포트 42를 추가하고 포트 목록으로 확인하여 실제 추가되었는지 확인할 수 있다.

[root@selinux ~]# semanage port -a -t syslogd_port_t -p tcp 42
[root@selinux ~]# semanage port --list | grep sysl
syslog_tls_port_t tcp 6514
syslog_tls_port_t udp 6514
syslogd_port_t tcp 42, 601
syslogd_port_t udp 514, 601

 

이후 이 Syslog-ng가 정상적으로 시작되고 netstat 를 사용하면, 포트 42에서 Listening 상태를 볼 수 있다.

외부에서 포트 42로 로그를 보내는 것은 여전히 작동하지 않기 때문에 퀘스트는 아직 끝나지 않았다.

여전히 동작하지 않는 이유는 방화벽 때문일 수도 있다.

따라서 포트 42를 열고 방화벽 규칙을 다시 로드하여 구성을 활성화한 다음, 열린 포트들을 나열한다.

[root@selinux conf.d]# firewall-cmd --permanent --add-port=42/tcp
success
 
[root@selinux conf.d]# firewall-cmd --reload
success
 
[root@selinux conf.d]# firewall-cmd --list-ports
42/tcp

이제 Syslog-ng는 포트 42에서 모든 것에 대한 로그 메시지를 수신할 수 있다.

 

 

Further reading

여기서는 Default가 아닌 디렉토리나 포트를 로깅에 사용하는 방법에 대해 몇 가지 정보를 제공했다.

SELinuxfirewalld에 대해 자세히 알아보기 위해서는 다음의 웹 사이트를 참고하길 바란다.

글이 꽤 길어서 접은글 방식으로 넣어놨는데, 원본 글 번역이 귀찮은 사람들은 천천히 읽어보면 좋을 듯하다.

 

 

# Solution

나의 경우에는 원본 글에서 'Using a different storage directory' 단락이, 해결에 도움이 되었다.

SELinux의 로그를 볼 수 있는 /var/log/audit/audit.log 파일을 살펴보면, 다음을 확인할 수 있었다.

type=AVC msg=audit(1600235930.808:152): avc: denied { read } for pid=1574 comm="syslog-ng" 
name="syslog-ng.conf" dev="dm-0" ino=4217396 scontext=system_u:system_r:syslogd_t:s0 
tcontext=unconfined_u:object_r:admin_home_t:s0 tclass=file

 

중요한 것은 avc: denied { read } 부분인데, 원본 글에서 로그 폴더 접근 권한이 denied 된 부분과 흡사했다.

name="syslog-ng.conf" 인 것을 보니, 정리하면 syslog-ng환경설정 파일을 읽는데 접근 권한 문제가 발생한 것이다.

 

가이드대로 semanage 명령어를 사용해 /var/log 디렉토리와 같은 label 설정을 해주었다.

[root@localhost syslog-ng]# semanage fcontext -a -t var_log_t '/etc/syslog-ng/syslog-ng.conf(./*)?' 
[root@localhost syslog-ng]# restorecon -v /etc/syslog-ng/syslog-ng.conf 
restorecon reset /etc/syslog-ng/syslog-ng.conf context unconfined_u:object_r:admin_home_t:s0->unconfined_u:object_r:var_log_t:s0 

[root@localhost syslog-ng]# ls -ldZ /etc/syslog-ng/syslog-ng.conf 
-rw-r--r--. root root unconfined_u:object_r:var_log_t:s0 /etc/syslog-ng/syslog-ng.conf

 

☝ 참고로,

  • 나는 파일도 label 설정이 되는지 테스트하기 위해, 파일에 label 설정을 했는데 가이드 글과 마찬가지로 폴더(/etc/syslog-ng/)에 label 설정하는 것이 더 좋을 듯 하다.
  • 만약 semanage 명령어가 없어서 'command not found' 메시지가 떨어진다면 다음 명령어를 사용해 관련 패키지 설치를 하면 된다 → # yum install policycoreutils-python

이후 시스템 재부팅을 해서 확인해보면,

[root@localhost ~]# getenforce
Enforcing

[root@localhost ~]# systemctl status syslog-ng 
● syslog-ng.service - System Logger Daemon 
 Loaded: loaded (/usr/lib/systemd/system/syslog-ng.service; enabled; vendor preset: enabled) 
 Active: active (running) since 수 2020-09-16 15:22:34 KST; 26s ago
...

 

SELinux 정책을 비활성화 하지 않았지만, syslog-ng 서비스가 정상 작동하는 것을 볼 수 있다.👏👏👏

 

 

이 글은 syslog-ng 이슈만 참고할 것이 아니라, 다른 서비스에서도 SELinux에 의한 문제가 있을 때 참고할 수 있을 것 같다.