반응형
250x250
Notice
Recent Posts
Recent Comments
Link
«   2024/04   »
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
Archives
Today
Total
관리 메뉴

가끔 보자, 하늘.

Openssl 버전 업그레이드 중 사고 발생! 주의하세요!! 본문

개발 이야기/인프라 구축 및 운영

Openssl 버전 업그레이드 중 사고 발생! 주의하세요!!

가온아 2023. 12. 22. 18:07

얼마전에 stunnel을 사용한 서버와 클라이언트들이 있었는데 그 중 한 서버가 윈도우 였습니다. 

해당 서버에 클라이언트에서 연결을 시도하면 wrong version number 에러가 발생하면 connection이 바로 끊어지더군요. 

서버는 openssl 3.1.2, 클라이언트는 openssl 3.0.9 였습니다. 다른 설정 문제는 없었기에 openssl 버전 이슈인 듯 했죠.

윈도우 서버는 직접 관리하는 서버가 아닌데다 라이브 서비스를 위한 서버였기에 교체하려면 절차가 너무 복잡해서 클라이언트의 openssl 버전을 업그레이드 하기로 결정했습니다. 저장소의 최신 버전이 3.0.9 였기에 3.1.2 버전 소스를 다운받아 설치했습니다. 

$ openssl version # 버전 확인

# https://www.openssl.org/source/old/ 필요한 버전의 소스 다운로드 받아 압축 해제 후 해당 폴더로 이동

$ sudo ./config --prefix=/usr/local/openssl --openssldir=/usr/local/openssl shared zlib
$ sudo make
$ sudo make install
$ sudo ldconfig  # reloading libraries

$ openssl version # 설치된 버전 확인

일단 stunnel은 잘 연결되는데 이 이후가 문제였네요. openssl 업그레이드 후 재부팅하니 sshd가 실행이 안되었습니다. 원인은 openssl 버전 틀림. 

$ ssh
OpenSSL verson mismatch. Build against 30000020, you have 30100020.

네트웍 설정도 꺼지고 설정도 사라져 모두 재설정했습니다. -0-;; 이런 경우는 또 처음이라. 아마 openssl 설치 후 ldconfig를 실행했음에도 library 링크들이 깨지면서 발생한 듯 한데.. 구글링해보니 생각보다 이런 경우가 자주 발생하는 듯 하군요. 어쨌든 당장은 시스템을 정상으로 복구하는게 중요했습니다.

$ sudo ip link set enp5 up  # nic 활성화
$ ip a # nic 확인. 
# inet 설정 안보이면 netplan 설정 확인 및 적용
$ sudo vi /etc/netplan/00-nic-setting.yaml
  network:
    ethernets:
      enp5xxx:
        addresses:
        - 172.31.1.9/24
        nameservers:
          addresses: [xxx.xxx.xxx.xxx]
          search: []
        routes:
        - to: default
          via: 172.31.1.1
    version: 2
$ sudo netplan apply

이제 네트웍은 다시 돌아왔으니 sshd를 해결합니다.

# lib 설치 위치 확인
$ ldconfig -p | grep libcrypto

# 각 어플리케이션들이 사용하는 library 확인
$ ldd $(which sshd) | grep libcrypto
$ ldd $(which ssh) | grep libcrypto
$ ldd $(which openssl) | grep libcrypto

이런!! 예상외로 모두 동일한 lib를 제대로 가르키고 있네요. 이 문제가 아니라면 대체 뭐가 문제지! 라고 고민하다 이런 문구를 발견했습니다. (참조 링크 : https://www.linuxfromscratch.org/lfs/view/stable/chapter08/openssl.html)

You should update OpenSSL when a new version which fixes vulnerabilities is announced. Since OpenSSL 3.0.0, the OpenSSL versioning scheme follows the MAJOR.MINOR.PATCH format. API/ABI compatibility is guaranteed for the same MAJOR version number. Because LFS installs only the shared libraries, there is no need to recompile packages which link to libcrypto.so or libssl.so when upgrading to a version with the same MAJOR version number.

If OpenSSH is installed, it will be an exception of the general rule above. It contains an over-restrictive OpenSSL version check, so both SSH client and SSH server will refuse to start if OpenSSL is updated with MAJOR version number unchanged but MINOR version number changed. You need to rebuild OpenSSH after such an upgrade. If OpenSSH is being used to access the system, you must rebuild and reinstall it after upgrading OpenSSL to a new MINOR version number before logout or you won't be able to login via SSH anymore.

취약점을 수정한 새 버전이 발표되면 OpenSSL을 업데이트해야 합니다. OpenSSL 3.0.0부터 OpenSSL 버전 관리 체계는 MAJOR.MINOR.PATCH 형식을 따릅니다. 동일한 MAJOR 버전 번호에 대해 API/ABI 호환성이 보장됩니다. LFS는 공유 라이브러리만 설치하기 때문에 MAJOR 버전 번호가 동일한 버전으로 업그레이드할 때 libcrypto.so 또는 libssl.so에 링크하는 패키지를 다시 컴파일할 필요가 없습니다.

OpenSSH가 설치되어 있는 경우 위의 일반 규칙에서 예외가 됩니다. 여기에는 지나치게 제한적인 OpenSSL 버전 검사가 포함되어 있으므로, MAJOR 버전 번호는 변경되지 않고 MINOR 버전 번호만 변경된 상태로 OpenSSL이 업데이트되면 SSH 클라이언트와 SSH 서버 모두 시작을 거부합니다. 이러한 업그레이드 후에는 OpenSSH를 다시 빌드해야 합니다. 시스템에 액세스하는 데 OpenSSH를 사용하는 경우, 로그아웃하기 전에 OpenSSL을 새 MINOR 버전 번호로 업그레이드한 후 다시 빌드하고 다시 설치해야 하며, 그렇지 않으면 더 이상 SSH를 통해 로그인할 수 없습니다.

이럴수가 이렇게 떡 하니 써있다니!!! ㅠ_ㅜ 

(feat. DALL E)

하지만 지금 설치된 openssh-server가 최신 버전이라 apt로는 추가 설치가 어려운 상황! 직접 빌드하는 방법 밖에 없습니다. 고고!!

우선 이전에 openssl을 어디에 설치했는지 확인합니다.

# openssl 다운로드 주소 참고용입니다. 이미 빌드했다면 실행하지 마세요.
$ wget https://www.openssl.org/source/old/3.1/openssl-3.1.2.tar.gz --no-check-certificate

# make 전에 openssl-3.1.2 폴더에서 설정 참고용. 이미 빌드했다면 실행하지 마세요.
$ ./config --prefix=/usr/local/openssl --openssldir=/usr/local/openssl shared zlib

# 혹시... 만약 openssl을 별도로 설치하지 않고 apt-get으로 최신 버전을 설치했다면 아래와 같이 
# libssl-dev의 버전을 확인할 수 있습니다.
$ dpkg -l | grep libssl-dev # libssl-dev의 버전 확인
 libssl-dev:amd64     3.0.2-0ubuntu1.12   ....

openssl을 빌드 할 때 위와 같은 폴더로 설정했다면 현재 버전의 header 와 lib 파일은 /usr/local/openssl/header와 /usr/local/openssl/lib64(32일 경우 lib)에 있습니다. 이 파일을 이용해 openssh를 아래와 같이 빌드 합니다. 

$ sudo apt-get update
$ sudo apt-get install build-essential libssl-dev zlib1g-dev
$ wget http://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-9.6p1.tar.gz 
$ tar -xzf openssh-9.6p1.tar.gz 
$ cd openssh-9.6p1
$ which openssl # 설치 경로 확인 like /usr/bin or /usr/local/bin
$ ./configure --prefix=/usr/local/openssh --with-ssl-dir=/usr/local/openssl --with-pam

# 만약 configure 시 ERROR : Your OpenSSL's headers do not match your library. 
# 와 같은 메세지가 나온다면 /usr/local/openssl 아닌 다른 경로에 
# 현재 사용중인 openssl이 설치된 겁니다. 다시 경로를 확인 후 진행하세요.

$ make
$ sudo make install

빌드가 성공적으로 되었다면 /usr/local/openssh/bin에 ssh가 생성되었을 겁니다. ssh가 언제든 실행될 수 있게 환경 변수에 아래와 같이 등록합니다.

# 설치된 버전 확인
$ /usr/local/openssh/bin/ssh -V

# bash에 등록
$ echo 'export PATH="/usr/local/openssh/bin:$PATH"' >> ~/.bashrc
$ source ~/.bashrc

# /etc/environment에도 추가합니다
$ sudo vi /etc/environment
  PATH = "/usr/local/openssl/bin:..."
  
$ service sshd start

# 만약 서비스를 시작했을 때 에러가 발생했다면 기존 openssh-server가 remove 되면서 
# /lib/systemd/system/sshd.service의 내용이 삭제되었을 가능성이 있습니다.
# 만약 그렇다면 아래와 같이 다시 등록 해두세요.

$sudo vi /lib/systemd/system/sshd.service
[Unit]
Description=OpenBSD Secure Shell server
After=network.target auditd.service

[Service]
ExecStartPre=/usr/local/openssh/sbin/sshd -t -f /etc/ssh/sshd_config
ExecStart=/usr/local/openssh/sbin/sshd -D -f /etc/ssh/sshd_config
ExecReload=/usr/local/openssh/sbin/sshd -t -f /etc/ssh/sshd_config
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartPreventExitStatus=255
Type=notify
RuntimeDirectory=sshd
RuntimeDirectoryMode=0755

[Install]
WantedBy=multi-user.target
Alias=sshd.service


$ sudo systemctl daemon-reload

아마 지금 실행해 보시면 no hostkeys available 이라는 오류가 뜨면서 실행되지 않을텐데 수동으로 설치 시 호스트 키를 자동으로 생성하지 않았거나 hotkeys가 설정되지 않았을 때 발생하는 에러입니다. /usr/local/openssl/etc에서 hostkey들이 생성되어 있습니다. 없다면 호스트 키를 아래와 같이 생성하세요. 키 생성 시 DSA, ECDSA, ED2551, RSA 등의 알고리즘 중 하나를 선택할 수 있는데, ED25519를 추천합니다. 저는 ED25519를 이용해 생성하겠습니다. 

$ ssh-keygen -t ed25519 -f /usr/local/openssl/etc/ssh_host_ed25519_key -N ""

sshd_config 파일에 사용할 hotkey를 설정합니다.

$ sudo vi /etc/ssh/sshd_config
 ...
 Port 9090   # 접속 포트를 22가 아닌 9090으로 바꿨다고 가정해 보겠습니다.
 HostKey /usr/local/openssh/etc/ssh_host_ed25519_key
 ...

잘 되시나요? 저는 두 가지 문제가 발생합니다. 일단 sshd가 데몬으로 실행되지 않고 foreground로 실행되고 timeout으로 곧 다운되고 맙니다. 게다가 /etc/ssd/sshd_config의 설정값이 적용되지 않는 문제가 있습니다.

왜 sshd_config 파일의 설정 내용이 적용되지 않는지, 무슨 내용이 적용되는지를 확인해 봅니다.

$ sudo /usr/local/openssh/sbin/sshd -T | more

내용을 살펴보니 sshd_config의 내용과는 상관없이 기본 설정값이 그대로 적용된 듯 한 내용입니다.

$ sudo /usr/local/openssh/sbin/sshd -T -f /etc/ssh/sshd_config | more

이제 원하는 설정이 잘 적용된 듯 합니다. sshd.service 파일에도 위 내용 그대로 적용합니다.

인프라를 구축하고 나면 정말 중요한 업데이트가 아니면 ssl 처럼 중요한 라이브러리는 손대지 않는데 이번처럼 마이너 버전 업데이트에 충돌이 발생하는 경우는 저도 처음이라 좀 당황하면서 작업을 진행했네요. 

다른 분들은 부디 이런 나쁜 경험은 안하시길...  !!

(in house 툴 서버에서 발생했기에 망정이지 정말 .. 휴 .... !!! )

반응형