MAC 주소를 통한 NIC 제조사 분석

네트워크 인터페이스 카드는 고유의 MAC 주소가 할당되어 있습니다. MAC 주소는 48비트의 길이로, 3바이트는 제조사에 할당된 OUI (Organizationally unique identifier), 이어지는 3바이트는 일련번호가 지정됩니다. 시스템 사용자가 별도로 MAC 주소를 재지정하지 않았다면, MAC 주소를 통해 제조사 정보를 추출할 수 있습니다.

OUI 코드는 IEEE(Institute of Electrical and Electronics Engineers)에서 관리하며, https://standards-oui.ieee.org/oui/oui.txt에서 전체 데이터를 다운로드 할 수 있습니다. 하지만 이 정보는 구조화된 텍스트가 아니기 때문에, 분석에 사용하려면 가공이 필요합니다.

로그프레소에서 아래와 같은 쿼리로 구조화된 정보를 추출할 수 있습니다.

wget url="https://standards-oui.ieee.org/oui/oui.txt" | fields line 
| eval line = split(line, "\r\n\r\n") 
| explode line
| eval mapping = trim(valueof(line, 1)), street = trim(valueof(line, 2)), city = trim(valueof(line, 3)), country = trim(valueof(line, 4)) 
| eval mapping = split(mapping, "\t"), oui = left(valueof(mapping, 0), 6), company = valueof(mapping, 2)
| search len(company) > 0
| sort oui
| fields oui, company, country, city, street

OUI 추출 쿼리

각 명령어를 풀어서 설명하면 아래와 같습니다:

wget url="https://standards-oui.ieee.org/oui/oui.txt" | fields line 
| eval line = split(line, "\r\n\r\n") 
| explode line

다운로드 데이터 빈 줄 구분

wget 명령어를 이용하여 지정된 URL의 데이터를 다운로드하면 전체 텍스트가 line 필드에 할당됩니다. oui.txt 파일을 보면 각 OUI 엔트리가 빈 줄로 구분된 것을 볼 수 있습니다. 빈 줄은 개행 문자의 연속으로 볼 수 있으므로, split 함수를 사용하여 \r\n\r\n으로 분할하면 배열이 됩니다. 그 다음에 explode 명령어를 사용하여 이 배열을 독립된 레코드로 분할합니다.

레코드는 이제 아래의 형태로 구성되어 있습니다.

00-1C-14   (hex)		VMware, Inc.
001C14     (base 16)		VMware, Inc.
				3401 Hillview Avenue
				Palo Alto  CA  94304
				US

첫번째와 두번째 줄은 표현이 다르지만 같은 내용이고, 세번째 줄은 거리 주소, 네번째 줄은 도시와 지번, 다섯번째 줄은 국가 코드를 포함합니다. 따라서, 줄 단위로 다시 분할하여 번호 순으로 추출할 수 있습니다.

| eval line = split(line, "\n") 
| eval mapping = trim(valueof(line, 1)), street = trim(valueof(line, 2)), city = trim(valueof(line, 3)), country = trim(valueof(line, 4)) 
| eval mapping = split(mapping, "\t"), oui = left(valueof(mapping, 0), 6), company = valueof(mapping, 2)

eval line = split(line, "\n")은 line 필드의 값을 개행 문자로 분할하여 생성된 배열을 다시 line 필드에 할당합니다. valueof() 함수를 사용하면 배열 중 특정 위치의 값을 가져올 수 있습니다. 첫번째 배열 요소는 0번이므로, valueof(line, 2)는 line 배열의 세번째 값을 추출한다는 의미입니다. trim() 함수는 불필요한 앞뒤의 공백 문자를 제거합니다.

쿼리 구문의 세번째 줄은 mapping 필드에 할당된 레코드의 두번째 줄을 가져와서 탭 문자 기준으로 분할하여 다시 mapping 필드에 할당합니다. 첫번째 값에 대해 left() 함수를 사용하여 왼쪽 6개의 문자를 잘라 oui 필드에 할당하고, 탭 문자 뒤에 있는 VMware, Inc. 문자열을 company 필드에 할당합니다.

이제 나머지는 출력을 정리하는 용도입니다.

| search len(company) > 0
| sort oui
| fields oui, company, country, city, street

텍스트 파일 시작부의 설명문 등 불필요한 부분을 제거하고, sort 명령어를 사용하여 OUI 순서대로 정렬한 다음, fields 명령어를 사용하여 보기 좋게 필드 순서를 정리하였습니다.

이제 이 결과를 룩업에 등록하여 사용할 수 있습니다. 사실 로그프레소는 geomac 이름의 룩업을 내장하고 있으며 MAC 주소에서 제조사 이름과 국가를 추출하는 기능을 제공합니다. 예를 들면 아래와 같이 쿼리할 수 있습니다.

json "{}" | eval mac = "00:1C:14:00:11:22" | lookup geomac mac output country, name

geomac 룩업 활용 쿼리

네트워크 접근 제어(NAC) 솔루션 등으로부터 MAC 주소가 수집되면 이제 이렇게 기기 정보를 분석해보세요.

둘러보기

더보기

RFC6587: TCP를 통한 SYSLOG 전송 규약

통합로그관리(LMS) 시스템이나 통합보안관제(SIEM) 시스템에 방화벽, IPS, 웹 방화벽 등 네트워크 보안 장비를 연동하는 경우, 우리는 20년 이상 UDP를 통한 SYSLOG 전송 프로토콜을 사용해왔습니다. 이는 [RFC3164 - The BSD syslog Protocol](https://www.ietf.org/rfc/rfc3164.txt) 문서에 정의된 것으로 대부분의 사람들이 익숙합니다. UDP를 통한 SYSLOG 전송 방식은 흐름 제어(Flow Control)를 사용하지 않으므로, 수신 시스템의 성능이 느리거나 심지어 장애가 발생하더라도 송신 시스템까지 영향을 미치지 않는다는 장점이 있습니다. 특히 네트워크 장비가 로그로 인해 성능에 영향이 있다면 통신 장애로 귀결되므로, 자연스럽게 UDP 기반 SYSLOG 전송이 매우 선호되어 왔습니다. 그러나 UDP는 프로토콜 수준에서 암호화를 지원하지 않으므로 로그 내용이 그대로 노출될 수 있습니다. 클라우드 기반의 원격 관제 서비스를 구성할 때 전용선이나 VPN이 아닌 인터넷 구간을 통해 네트워크 보안 장비를 직접 SIEM에 접속시켜야 할 경우가 자주 발생합니다. 이런 시나리오에서는 반드시 TLS 채널을 통해 안전하게 로그를 전송하도록 구성해야 합니다. 그런데 TCP 또는 TLS 채널을 통해 로그를 전송할 때 비표준 프로토콜 설계를 종종 보게 됩니다. UDP 소켓에서 수신할 때는 송신한 메시지대로 패킷이 전달되기 때문에 멀티라인 등 어떤 형태라도 의도한 메시지 단위로 로그가 전송됩니다. 반면 TCP 소켓에서는 스트림으로 데이터가 수신되기 때문에, 메시지의 경계를 직접 정의해주어야 합니다. [RFC6587 - Transmission of Syslog Messages over TCP](https://www.ietf.org/rfc/rfc6587.txt) 문서는 2012년에 나왔지만 의외로 이 내용을 알고 있는 사람을 찾아보기가 상당히 어려웠습니다. 그것이 보안 솔루션 개발 시 비표준 구현을 만드는 원인이라 생각되어 오늘 간단히 TCP 프로토콜에서 사용하는 SYSLOG 메시지 프레이밍을 소개하고자 합니다. ### Non-Transparent-Framing 레거시 시스템이 오래 전부터 사용하는 방법은 메시지 구분자를 이용하는 것입니다. 개행 문자(Line Feed)를 사용하여 메시지를 구분하는 것이 가장 흔한 방법입니다. 다만 여러 줄로 구성된 로그를 전송할 때는 개행 문자를 구분자로 사용할 수 없습니다. 이런 경우 NULL 문자를 구분자로 사용하기도 합니다. ### Octet Counting [RFC6587](https://www.ietf.org/rfc/rfc6587.txt)이나 TLS 채널을 통한 Syslog 전송을 다룬 [RFC5425](https://www.ietf.org/rfc/rfc5425.txt)에 정의된 규칙은 메시지 시작 위치에 10진수로 뒤에 오게 될 페이로드의 길이를 바이트 단위로 기록하는 것입니다. 예를 들어, 이 [PCAP 파일](/media/ko/2023-05-20-rfc6587-syslog-over-tcp/rfc6587-sample.pcap)의 첫번째 메시지 프레임은 MSG-LEN 94와 공백 문자로 시작하며 이어지는 메시지 텍스트는 <30>부터 Server… 뒤의 개행 (0x0a) 문자까지 94바이트가 이어집니다: ``` 94 <30>1 2023-01-12T19:29:28+09:00 ubuntu20host systemd 1 - - Starting Squid Web Proxy Server... ``` ![Octet Counting 예제](/media/ko/2023-05-20-rfc6587-syslog-over-tcp/octet-counting-example.png) ### 정리 인터넷 규약대로 로그 전송을 구현하면 기존의 많은 시스템에 한 번에 호환시킬 수 있습니다. 반면, 비표준 방식으로 로그를 전송하면 자사의 장비를 새로운 유형의 시스템에 연동해야 할 때마다 많은 시간과 비용을 야기합니다. 이 글이 업계의 상호 운영성을 향상시키는데 도움이 되기를 바랍니다.

2023-05-20

rsyslog TLS 상호 인증 연동 설정

리눅스 서버에서 인터넷을 거쳐 클라우드 SIEM에 로그를 전송하려면 TLS 설정이 필수적입니다. 하지만 TLS를 통해 안전하게 시스로그(Syslog)를 전송하도록 설정하려면 인증서를 설치하는 과정이 포함되기 때문에 좀 더 복잡하고 어렵게 느껴질 수 있습니다. 이 글에서는 rsyslog를 로그프레소에 연동하는 방법과 문제 발생 시 진단 방법을 소개합니다. ### CA 인증서 준비 아래는 유효 기간 100년으로 CA 인증서를 생성하고, syslog-ca.pem과 syslog-ca-key.pem 파일을 합쳐서 PKCS#12 인증서 파일을 생성합니다. 아래는 RSA 키를 생성하는 과정의 예시입니다. ``` $ openssl req -new -x509 -keyout syslog-ca-key.pem -out syslog-ca.pem -days 36500 Generating a RSA private key .......................+++++ ..........+++++ writing new private key to 'syslog-ca-key.pem' Enter PEM pass phrase: Verifying - Enter PEM pass phrase: ----- You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [XX]:KR State or Province Name (full name) []:Seoul Locality Name (eg, city) [Default City]:Mapo Organization Name (eg, company) [Default Company Ltd]:Logpresso Organizational Unit Name (eg, section) []: Common Name (eg, your name or your server's hostname) []:syslog-ca ``` 아래는 PKCS#12 인증서 파일을 생성하는 과정의 예시입니다. PEM 파일에서 비밀 키를 읽어들이기 위해 암호를 물어보고, 새로 생성하는 PKCS#12 파일에 설정할 암호를 다시 요구합니다. ``` $ openssl pkcs12 -export -out syslog-ca.pfx -in syslog-ca.pem -inkey syslog-ca-key.pem Enter pass phrase for syslog-ca-key.pem: Enter Export Password: Verifying - Enter Export Password: ``` syslog-ca.pem 파일은 자바 애플리케이션에서 신뢰할 수 있는 루트 인증 기관을 인식할 수 있도록 JKS (Java KeyStore) 파일 형식으로 변환해야 합니다. 먼저 비밀 키를 포함하지 않은 PKCS#12 형식의 CA 인증서 syslog-ca-nokey.pfx 파일을 생성합니다. ``` $ keytool -importcert -keystore syslog-ca-nokey.pfx -file syslog-ca.pem -alias ca Enter keystore password: Re-enter new password: Owner: CN=syslog-ca, O=Logpresso, L=Mapo, ST=Seoul, C=KR Issuer: CN=syslog-ca, O=Logpresso, L=Mapo, ST=Seoul, C=KR Serial number: 1b7cada9fedd02d1980ea28619719d7647ab037e Valid from: Sat May 27 18:31:05 KST 2023 until: Mon May 03 18:31:05 KST 2123 Certificate fingerprints: SHA1: 8D:72:78:0D:75:85:A2:68:1E:31:69:37:E8:57:5C:1D:79:90:FA:C5 SHA256: 4B:6E:E6:BE:17:7D:FC:3E:BE:E1:3B:06:3C:8B:84:43:97:84:23:32:72:5D:72:1D:03:AE:A1:30:EA:72:64:E2 Signature algorithm name: SHA256withRSA Subject Public Key Algorithm: 2048-bit RSA key Version: 3 Extensions: #1: ObjectId: 2.5.29.35 Criticality=false AuthorityKeyIdentifier [ KeyIdentifier [ 0000: F3 1B 54 63 91 2A DF 6D 1D FD 17 77 51 30 6D 63 ..Tc.*.m...wQ0mc 0010: 5F 40 35 EB _@5. ] ] #2: ObjectId: 2.5.29.19 Criticality=true BasicConstraints:[ CA:true PathLen:2147483647 ] #3: ObjectId: 2.5.29.15 Criticality=false KeyUsage [ Key_CertSign ] #4: ObjectId: 2.5.29.14 Criticality=false SubjectKeyIdentifier [ KeyIdentifier [ 0000: F3 1B 54 63 91 2A DF 6D 1D FD 17 77 51 30 6D 63 ..Tc.*.m...wQ0mc 0010: 5F 40 35 EB _@5. ] ] Trust this certificate? [no]: yes Certificate was added to keystore ``` 이 PKCS#12 파일을 JKS 형식의 파일로 변환하면 공개적으로 배포 가능한 키스토어 파일이 됩니다. ``` $ keytool -importkeystore -srckeystore syslog-ca-nokey.pfx -srcstoretype pkcs12 -destkeystore syslog-ca.jks -deststoretype jks Importing keystore syslog-ca-nokey.pfx to syslog-ca.jks... Enter destination keystore password: Enter source keystore password: Entry for alias ca successfully imported. Import command completed: 1 entries successfully imported, 0 entries failed or cancelled ``` ### 서버 인증서 준비 ``` $ openssl genpkey -algorithm RSA -out logpresso-key.pem -pkeyopt rsa_keygen_bits:4096 $ openssl req -new -key logpresso-key.pem -out logpresso-csr.pem -subj "/CN=logpresso" $ openssl x509 -req -in logpresso-csr.pem -CA syslog-ca.pem -CAkey syslog-ca-key.pem -CAcreateserial -out logpresso-cert.pem -days 36500 $ openssl pkcs12 -export -out logpresso.pfx -inkey logpresso-key.pem -in logpresso-cert.pem -certfile syslog-ca.pem ``` 첫번째 명령은 4096비트의 RSA 비밀 키를 생성합니다. 두번째 명령은 이 RSA 키를 이용해서 CSR (Certificate Signing Request) 파일을 생성합니다. 세번째 명령은 사설 CA 인증서를 이용하여 서명된 logpresso-cert.pem 파일을 생성합니다. 네번째 명령은 비밀 키가 포함된 logpresso-key.pem 파일, 공개 키가 포함된 logpresso-cert.pem과 syslog-ca.pem 파일을 결합하여 PKCS#12 형식의 logpresso.pfx 파일을 생성합니다. ### 클라이언트 인증서 준비 로그프레소 서버가 클라이언트를 인증하려면 rsyslog 데몬이 접속할 때 클라이언트 인증서를 제출하도록 해야 합니다. 임의의 클라이언트가 서버에 접속하는 것을 허용한다면 이 단계는 생략할 수 있습니다. 아래의 명령들은 클라이언트 인증서 파일 이름을 제외하면 서버 인증서 준비 단계의 명령과 동일합니다. ``` $ openssl genpkey -algorithm RSA -out rsyslog-key.pem -pkeyopt rsa_keygen_bits:4096 $ openssl req -new -key rsyslog-key.pem -out rsyslog-csr.pem -subj "/CN=rsyslog" $ openssl x509 -req -in rsyslog-csr.pem -CA syslog-ca.pem -CAkey syslog-ca-key.pem -CAcreateserial -out rsyslog-cert.pem -days 36500 $ openssl pkcs12 -export -out rsyslog.pfx -inkey rsyslog-key.pem -in rsyslog-cert.pem -certfile syslog-ca.pem ``` ### 로그프레소 TLS 포트 설정 `/opt/logpresso/cert` 디렉터리를 생성하고, 이 디렉터리에 이전 단계에서 만든 인증서 파일들을 복사합니다. - syslog-ca.jks: 신뢰할 수 있는 CA 인증서를 포함한 파일 - logpresso.pfx: 로그프레소가 TLS 서버를 여는데 필요한 비밀 키를 포함한 PKCS#12 파일 로그프레소 쉘에 접속하여 각 인증서를 등록합니다. ``` logpresso> keystore.register syslog-key PKCS12 /opt/logpresso/cert/logpresso.pfx Password? [syslog-key] key store registered logpresso> keystore.register syslog-ca JKS /opt/logpresso/cert/syslog-ca.jks Password? [syslog-ca] key store registered ``` 이제 등록한 인증서를 이용하여 TLS 시스로그 서버 포트를 개방합니다. ``` logpresso> syslog.openTls mtls syslog-key 6514 0.0.0.0 utf-8 syslog-ca opened TLS syslog server [/0.0.0.0:6514] ``` 로그프레소 서버에서 클라이언트를 인증하지 않고 임의의 TLS 접속을 허용하려면 마지막 `syslog-ca` 인자를 제외합니다. ### rsyslog 설정 rsyslog에서 TLS 전송을 사용하려면 `rsyslog-gnutls` 패키지를 설치해야 합니다. 아래는 Rocky 8.7 서버에서 `rsyslog-gnutls` 패키지를 설치하는 방법입니다. ``` $ sudo yum install rsyslog-gnutls ``` `/etc/rsyslog.d/cert` 디렉터리를 생성하고, 이 디렉터리에 이전 단계에서 생성한 파일을 복사합니다. 복사 후에는 rsyslog 데몬 구동 계정으로 소유자를 변경하고, `chmod 400 /etc/rsyslog.d/cert/*` 명령으로 소유자만 읽기 권한을 가지도록 조정합니다. - syslog-ca.pem: rsyslog에서 신뢰할 수 있는 CA를 지정하는데 필요한 인증서 파일 - rsyslog-cert.pem: 클라이언트 인증서 (공개 키) - rsyslog-key.pem: 클라이언트 비밀 키 이제 `/etc/rsyslog.d/logpresso.conf` 파일을 아래의 내용으로 생성합니다. `LOGPRESSO_IP` 부분을 로그프레소 서버의 IP 주소로 변경합니다. ``` $WorkDirectory /var/spool/rsyslog # 네트워크 단절 시 데이터를 임시 보관할 디렉터리 $ActionQueueFileName logpresso # 데이터 임시 보관 시 생성되는 파일의 접두어 $ActionQueueMaxDiskSpace 1g # 임시 보관 최대 용량 $ActionQueueSaveOnShutdown on # rsyslog 데몬 중지 시 디스크에 저장 $ActionQueueType LinkedList # 제한 없이 데이터 유지 $ActionResumeRetryCount -1 # TLS 서버에 접속 될 때까지 지속적으로 재시도 # rsyslog-gnutls 설정 $DefaultNetstreamDriverCAFile /etc/rsyslog.d/cert/syslog-ca.pem $DefaultNetstreamDriverCertFile /etc/rsyslog.d/cert/rsyslog-cert.pem $DefaultNetstreamDriverKeyFile /etc/rsyslog.d/cert/rsyslog-key.pem template(name="Logpresso" type="string" string="<%pri%>%timestamp:::date-rfc3339% %HOSTNAME% %app-name% %msg%\n") # 6514 포트로 TLS 접속한 후 Logpresso 템플릿으로 포맷팅된 로그를 전송 action(type="omfwd" protocol="tcp" target="LOGPRESSO_IP" port="6514" template="Logpresso" StreamDriver="gtls" StreamDriverMode="1" StreamDriverAuthMode="x509/name" StreamDriverPermittedPeers="*logpresso") ``` 로그프레소 서버에서 클라이언트를 인증하지 않는다면 $DefaultNetstreamDriverCertFile 와 $DefaultNetstreamDriverKeyFile 항목은 설정할 필요가 없습니다. StreamDriverPermittedPeers 설정은 rsyslog 측에서 로그프레소 TLS 서버 인증서의 CN을 검증하는 용도로 사용합니다. `/var/spool/rsyslog` 디렉터리를 생성합니다. 이 디렉터리를 생성하지 않고 rsyslog 서비스를 시작하면 아래와 같은 에러 로그가 발생하면서 정상적으로 동작하지 않습니다. ``` May 27 00:32:36 demo rsyslogd: $WorkDirectory: /var/spool/rsyslog can not be accessed, probably does not exist - directive ignored [v8.24.0-57.el7_9.3 try http://www.rsyslog.com/e/2181 ] ``` 이제 모든 준비가 끝났습니다. rsyslog 서비스를 시작합니다. ``` $ sudo systemctl start rsyslog ``` ### 시스로그 수신 검증 로그프레소 쉘에서 `syslog.trace` 명령을 실행하면 실시간으로 아래 예시와 유사한 출력을 확인할 수 있습니다. ``` logpresso> syslog.trace mtls press ctrl-c to stop ------------------------ [2023-05-27 18:25:26.221+0900] (/LOGPRESSO_IP:50436) => [fc:3, sv:6] 2023-05-27T20:20:01.127517+09:00 demo systemd Started Session 36661 of user logpresso. ``` 만약 rsyslog에서 로그프레소 TLS 서버에 설치된 인증서에 대한 `StreamDriverPermittedPeers` 설정이 잘못되면 rsyslog 로그에서 아래와 같은 에러를 보게 됩니다. ``` May 27 20:21:42 wood rsyslogd: error: peer name not authorized - not permitted to talk to it. Names: CN: logpresso; [v8.24.0-57.el7_9.3 try http://www.rsyslog.com/e/2088 ] ``` 만약 rsyslog에 설치된 CA 인증서가 로그프레소 서버의 CA 인증서와 일치하지 않으면, 로그프레소 서버에서는 아래와 같은 에러 로그를 보게 됩니다. ``` [2023-05-27 19:40:47.764] ERROR (TlsSyslogReceiver) - logpresso syslog: TLS client [/LOGPRESSO_IP:51558] error javax.net.ssl.SSLHandshakeException: No trusted certificate found at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131) at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:352) at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:295) at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:290) at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkClientCerts(CertificateMessage.java:700) at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.onCertificate(CertificateMessage.java:411) at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.consume(CertificateMessage.java:375) at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:392) at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:443) at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:421) at java.base/sun.security.ssl.TransportContext.dispatch(TransportContext.java:182) at java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:172) at java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1501) at java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1411) at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:451) at java.base/sun.security.ssl.SSLSocketImpl.ensureNegotiated(SSLSocketImpl.java:916) at java.base/sun.security.ssl.SSLSocketImpl$AppInputStream.read(SSLSocketImpl.java:1007) at java.base/java.io.InputStream.read(InputStream.java:205) at org.araqne.syslog.TlsSyslogReceiver$TlsClientReceiver.run(TlsSyslogReceiver.java:303) Caused by: sun.security.validator.ValidatorException: No trusted certificate found at java.base/sun.security.validator.SimpleValidator.buildTrustedChain(SimpleValidator.java:411) at java.base/sun.security.validator.SimpleValidator.engineValidate(SimpleValidator.java:135) at java.base/sun.security.validator.Validator.validate(Validator.java:264) at java.base/sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:313) at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:222) at java.base/sun.security.ssl.X509TrustManagerImpl.checkClientTrusted(X509TrustManagerImpl.java:123) at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkClientCerts(CertificateMessage.java:688) ... 14 more ``` 이 때 rsyslog 호스트에서는 아래와 같은 로그를 확인할 수 있습니다. ``` May 27 19:44:50 demo systemd: Started System Logging Service. May 27 19:44:50 demo rsyslogd: unexpected GnuTLS error -12 in nsd_gtls.c:1840: A TLS fatal alert has been received. [v8.24.0-57.el7_9.3 try http://www.rsyslog.com/e/2078 ] May 27 19:44:50 demo rsyslogd: action 'action 1' suspended, next retry is Sat May 27 19:45:20 2023 [v8.24.0-57.el7_9.3 try http://www.rsyslog.com/e/2007 ] ```

2023-05-27

액티브 디렉터리 LDAP 연동

액티브 디렉터리는 중앙 집중적으로 인증을 처리하며 그룹 정책을 관리하기 때문에 계정, 호스트 등 많은 양의 정보가 내재되어 있습니다. 온프레미스 환경에서 액티브 디렉터리의 정보를 통합하려면 LDAP 프로토콜을 사용해야 합니다. 로그프레소에서 액티브 디렉터리를 연동하려면 먼저 LDAP 프로파일을 등록해야 합니다. ![](/media/ko/2023-05-23-ldapsearch/ldap_profile.png) 설정이 완료되면 아래와 같이 `ldapsearch` 쿼리와 LDAP 필터를 이용하여 액티브 디렉터리에 등록된 계정 목록을 조회할 수 있습니다: ``` ldapsearch profile=AD filter="(&(userPrincipalName=*))" ``` ![LDAP 계정 목록 조회](/media/ko/2023-05-23-ldapsearch/ldap_users.png) 수십 가지의 계정 정보를 확인할 수 있습니다만, 타임스탬프는 [윈도우 FileTime 형식](https://learn.microsoft.com/ko-kr/windows/win32/api/minwinbase/ns-minwinbase-filetime)이기 때문에 보기가 어렵습니다. FileTime은 아래와 같이 변환하여 볼 수 있습니다. ``` ldapsearch profile=AD filter="(&(userPrincipalName=*))" | eval lastLogon = if(lastLogon == "0", null, epoch(floor(long(lastLogon) / 10000 - 11644473600000))) | eval badPasswordTime = if(badPasswordTime == "0", null, epoch(floor(long(badPasswordTime) / 10000 - 11644473600000))) | order sAMAccountName, lastLogon, badPasswordTime ``` ![LDAP FileTime 변환](/media/ko/2023-05-23-ldapsearch/ldap_users_filetime.png) 액티브 디렉터리에 조인된 호스트 목록은 아래와 같이 확인할 수 있습니다. ``` ldapsearch profile=AD filter="(&(servicePrincipalName=*))" | eval lastLogon = epoch(floor(long(lastLogon) / 10000 - 11644473600000)) | order cn, operatingSystem, operatingSystemVersion, lastLogon, whenCreated, whenChanged ``` ![LDAP 호스트 목록](/media/ko/2023-05-23-ldapsearch/ldap_hosts.png) 이렇게 로그프레소에 액티브 디렉터리 데이터를 통합하면 더 이상 사용되지 않는 계정이나 오래된 시스템을 주기적으로 식별하고 정리할 수 있으므로, 잠재적인 공격 표면을 줄이고 안정적으로 내부 IT 인프라를 관리할 수 있습니다.

2023-05-23