OpenVPN에서 RAND_bytes 실패: 라이브러리 오류 또는 사라진 노드
RAND_bytes 실패는 거부된 엔트로피 원천이나 jail에 가려진 노드를 뜻할 수 있습니다. 장치를 만들기 전에 오류 큐와 프로세스 보기를 읽으십시오.
RAND_bytes() failed 는 하나의 로컬 기본 연산에 대한 진술이며, 계정이나 사전 공유 키, 원격 포트에 대한 진술이 아니다. 아주 다른 두 고장이 같은 줄을 만들고 서로 다른 증거를 남긴다. 하나는 바이트 출력을 거부하는 암호 백엔드이고, 다른 하나는 코드가 전제한 엔트로피 원천에 닿지 못하는 프로세스다. 둘을 가르려면 오류 큐를 한 번 읽고 감금된 프로세스의 파일 시스템 보기를 한 번 보면 되며, 그 확인은 /dev 아래에 무엇을 만들기 전에 끝나야 한다.
반환값이 구분하는 것
문서화된 계약은 두 가지가 아니라 세 가지 결과를 구분한다. 성공이면 1, 적재된 RAND 방식이 요청을 지원하지 않으면 -1, 그 밖의 실패면 0이며 설명은 오류 큐에 남는다. RAND_bytes 참조는 놓치기 쉬운 점을 하나 더한다: 지원되는 플랫폼에서 기본 생성기는 운영 체제에서 씨앗을 받고, 그 씨앗 넣기가 실패하면 예측 가능한 바이트를 돌려주는 대신 오류 상태에 머문다는 점이다.
그 숫자 가운데 환경을 설명하는 것은 하나뿐이다. -1은 빌드나 공급자, 기능의 문제이며, 코드가 현재 구현이 제공하지 않는 것을 요구했기 때문이다. 씨앗 넣기 불만과 함께 오는 0은 환경 문제이며, 생성기가 엔트로피를 전혀 얻지 못했기 때문이다. 숫자만으로는 어느 쪽인지 알 수 없고 함수 이름도 알려주지 않는다.
숨은 장치 노드가 진짜 원인일 때
제한된 서비스는 당신이 입력하는 셸과 다른 나무를 본다. chroot 감옥과 컨테이너 이미지, 강화된 unit 파일은 호스트보다 노드가 적은 /dev 를 흔히 보여 준다. 실패하는 구현이 /dev/urandom 를 경로 이름으로 연다면 그 차이만으로 시작이 깨지고, 호스트 자체는 아주 건강해 보인다. 감옥 밖에 있는 장치는 감금된 프로세스가 무엇을 열 수 있는지에 대해 아무것도 증명하지 않는다.
그렇다고 모든 난수 인터페이스가 경로를 필요로 하지는 않는다. 리눅스의 getrandom 시스템 호출은 파일 이름도 파일 서술자도 받지 않으며, 그 설명서는 이 성질이 chroot가 장치 경로를 감추는 곳에서 특히 쓸모 있다고 적는다.
그러므로 사라진 노드라는 설명은 코드의 한 갈래에 대한 가설이며, 난수 일반에 대한 규칙이 아니다. 증거가 경로를 지목하면 성립하고, 증거가 다른 것을 지목하면 추측에 지나지 않는다.
먼저 오류 큐를 읽고, 다음에 프로세스 보기
문제를 끝내는 가장 빠른 길은 라이브러리가 이미 기록한 것을 읽고, 이어서 감옥 안쪽의 보기를 직접 확인하는 것이다. 먼저 서비스가 실제로 적재한 OpenSSL 빌드에서 시작하라. 공급자 스택은 주 버전 사이에서도 배포판 사이에서도 다르기 때문이다. 다음으로 systemd에 어느 프로세스가 돌고 어떤 제한이 걸려 있는지 묻는다. 두 사실이 모두 탁자 위에 올라온 뒤에야 그 프로세스가 보는 노드를 나열할 가치가 생긴다.
openssl version -a
systemctl show openvpn-server@lab -p MainPID -p PrivateDevices -p DevicePolicy
pid=$(systemctl show -p MainPID --value openvpn-server@lab)
sudo ls -l /proc/"$pid"/root/dev/urandom /proc/"$pid"/root/dev/random
그 읽기는 같은 프로세스에 대고 하고, 우연히 열려 있는 셸에 대고 하지 않는다. 호스트의 /dev 를 무관한 프로세스의 보기와 견주는 것이야말로 잘못된 의존을 두 번 고치는 길이다.
이름을 댈 수 있을 때에만 의존을 더하라
증거가 정말로 경로를 지목하면 수리는 작다. 그 하나의 경로만 감옥 안에서 쓸 수 있게 하고 나머지는 그대로 둔다. 노드 하나를 bind 마운트하는 것으로 대개 충분하며, 마운트가 선택지가 아닌 설치에서는 mknod 와 노드의 표준 major·minor 번호로 같은 결과를 얻는다. 샌드박스를 넓히거나 모든 문자 장치에 권한을 주거나 PrivateDevices 를 끄는 것은 표적 수리를 영구적인 보안 후퇴와 맞바꾸는 일이다.
엔트로피 데몬은 그 수리를 대신하지 못한다. haveged 같은 꾸러미가 바꾸는 것은 커널 풀에 공급되는 방식이며, 감금된 프로세스가 열 수 있는 경로를 만들어 내지는 못한다. 하나를 설치하면 건강 그래프는 나아 보일지 몰라도 open 호출은 여전히 실패한다. 두 문제를 분리해 두지 않으면 다음 고장은 또 잘못된 층에 돌려지게 된다.
생성기와 터널을 따로 검증하라
다시 시작하는 것만이 고장을 만든 것과 같은 설정, 같은 unit 파일, 같은 격리를 그대로 쓰는 시험이다. 그것을 실행하고, 그다음 이전 부팅에서 떠 온 표본이 아니라 저널의 가장 새로운 기록을 읽는다.
sudo systemctl restart openvpn-server@lab
sudo journalctl -u openvpn-server@lab --since -5min --no-pager | grep -iE 'rand|entropy|Initialization Sequence'
그 출력에서 서로 다른 두 가지를 찾아라. 난수 원천에 관한 메시지가 사라지는 것, 그리고 터널이 늘 지나던 시작 지점에 닿는 것이다. 다시 작동하는 생성기는 국소 고장 하나를 없앨 뿐이며 서버 신원이나 자격 증명, 경로 선택에 대해서는 아무 말도 하지 않는다. 예전에 실패했던 것과 같은 클라이언트 설정으로 시험해, 결과가 단지 더 좋은 것이 아니라 견줄 수 있게 하라.