Apigee Edge 문서입니다.
Go to the
Apigee X documentation. info
증상
클라이언트 애플리케이션은 API 요청에 대한 응답으로 "Service Unavailable" 메시지와 함께 HTTP 상태 코드 503 을 수신합니다.
UI trace에서 실패한 API 요청의 대상 요청 흐름에 error.cause
가 Received fatal alert: bad_certificate임을 확인할 수 있습니다.
메시지 프로세서 로그에 액세스할 수 있는 경우 실패한 API 요청에 대한 오류 메시지가 Received fatal alert: bad_certificate
로 표시됩니다. 이 오류는 메시지 프로세서와 백엔드 서버 간의 SSL 핸드셰이크
프로세스 중에 양방향 TLS 설정에서 발생합니다.
오류 메시지
클라이언트 애플리케이션은 다음 응답 코드를 가져옵니다.
HTTP/1.1 503 Service Unavailable
또한 다음 오류 메시지가 표시될 수 있습니다.
{
"fault": {
"faultstring":"The Service is temporarily unavailable",
"detail":{
"errorcode":"messaging.adaptors.http.flow.ServiceUnavailable"
}
}
}Private Cloud 사용자는 메시지 프로세서 로그 /opt/apigee/var/log/edge-message-processor/system.log에서 특정 API 요청에 대해 다음 오류를 확인합니다
.
2017-10-23 05:28:57,813 org:org-name env:env-name api:apiproxy-name
rev:revision-number messageid:message_id NIOThread@0 ERROR HTTP.CLIENT - HTTPClient$Context.handshakeFailed() :
SSLClientChannel[C:IP address:port # Remote host:IP address:port #]@65461
useCount=1 bytesRead=0 bytesWritten=0 age=529ms lastIO=529ms handshake failed,
message: Received fatal alert: bad_certificate
가능한 원인
이 문제의 가능한 원인은 다음과 같습니다.
| 원인 | 설명 | 다음에 관한 문제 해결 안내 |
| 클라이언트 인증서 없음 | 대상 서버의 대상 엔드포인트에 사용된 키 저장소에 클라이언트 인증서가 없습니다. | Edge Private 및 Public Cloud 사용자 |
| 인증 기관 불일치 | 메시지 프로세서의 키 저장소에 있는 리프 인증서 (인증서 체인의 첫 번째 인증서) 의 인증 기관이 백엔드 서버에서 허용하는 인증 기관과 일치하지 않습니다. | Edge Private 및 Public Cloud 사용자 |
일반적인 진단 단계
- Edge UI에서 trace를 사용 설정하고 API를 호출하여 문제를 재현합니다.
- UI trace 결과에서 각 단계를 탐색하고 오류가 발생한 위치를 확인합니다. 오류는 대상 요청 흐름에서 발생했을 것입니다.
- 오류를 표시하는 흐름을 검사합니다. 아래 예시 trace와 같이 오류가 표시됩니다.

- 위 스크린샷에서 볼 수 있듯이 error.cause 는 "Received fatal alert: bad_certificate"입니다.
- Private Cloud 사용자인 경우 아래 안내를 따르세요.
- trace에서 AX로 표시된 단계에서 오류 헤더 "
X-Apigee.Message-ID"의 값을 확인하여 실패한 API 요청의 메시지 ID를 가져올 수 있습니다. - 메시지 프로세서 로그
/opt/apigee/var/log/edge-message-processor/system.log에서 이 메시지 ID를 검색하고 오류에 관한 추가 정보를 찾을 수 있는지 확인합니다.2017-10-23 05:28:57,813 org:org-name env:env-name api:apiproxy-name rev:revision-number messageid:message_id NIOThread@0 ERROR HTTP.CLIENT - HTTPClient$Context.handshakeFailed() : SSLClientChannel[C:IP address:port # Remote host:IP address:port #]@65461 useCount=1 bytesRead=0 bytesWritten=0 age=529ms lastIO=529ms handshake failed, message: Received fatal alert: bad_certificate 2017-10-23 05:28:57,813 org:org-name env:env-name api:apiproxy-name rev:revision-number messageid:message_id NIOThread@0 ERROR HTTP.CLIENT - HTTPClient$Context.handshakeFailed() : SSLInfo: KeyStore:java.security.KeyStore@52de60d9 KeyAlias:KeyAlias TrustStore:java.security.KeyStore@6ec45759 2017-10-23 05:28:57,814 org:org-name env:env-name api:apiproxy-name rev:revision-number messageid:message_id NIOThread@0 ERROR ADAPTORS.HTTP.FLOW - RequestWriteListener.onException() : RequestWriteListener.onException(HTTPRequest@6071a73d) javax.net.ssl.SSLException: Received fatal alert: bad_certificate at sun.security.ssl.Alerts.getSSLException(Alerts.java:208) ~[na:1.8.0_101] at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1666) ~[na:1.8.0_101] at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1634) ~[na:1.8.0_101] at sun.security.ssl.SSLEngineImpl.recvAlert(SSLEngineImpl.java:1800) ~[na:1.8.0_101] at com.apigee.nio.NIOSelector$SelectedIterator.findNext(NIOSelector.java:496) [nio-1.0.0.jar:na] at com.apigee.nio.util.NonNullIterator.computeNext(NonNullIterator.java:21) [nio-1.0.0.jar:na] at com.apigee.nio.util.AbstractIterator.hasNext(AbstractIterator.java:47) [nio-1.0.0.jar:na] at com.apigee.nio.NIOSelector$2.findNext(NIOSelector.java:312) [nio-1.0.0.jar:na] at com.apigee.nio.NIOSelector$2.findNext(NIOSelector.java:302) [nio-1.0.0.jar:na] at com.apigee.nio.util.NonNullIterator.computeNext(NonNullIterator.java:21) [nio-1.0.0.jar:na] at com.apigee.nio.util.AbstractIterator.hasNext(AbstractIterator.java:47) [nio-1.0.0.jar:na] at com.apigee.nio.handlers.NIOThread.run(NIOThread.java:59) [nio-1.0.0.jar:na]
메시지 프로세서 로그에 오류
Received fatal alert: bad_certificate의 스택 트레이스가 있지만 이 문제의 원인을 나타내는 추가 정보는 없습니다.
- trace에서 AX로 표시된 단계에서 오류 헤더 "
- 이 문제를 추가로 조사하려면
tcpdump 도구를 사용하여 TCP/IP 패킷을 캡처해야 합니다.
- Private Cloud 사용자인 경우 백엔드 서버 또는 메시지 프로세서에서 TCP/IP 패킷을 캡처할 수 있습니다. 패킷은 백엔드 서버에서 복호화되므로 백엔드 서버에서 캡처하는 것이 좋습니다.
- Public Cloud 사용자인 경우 백엔드 서버에서 TCP/IP 패킷을 캡처합니다.
- TCP/IP 패킷을 캡처할 위치를 결정한 후 아래 tcpdump 명령어를 사용하여 TCP/IP 패킷을 캡처합니다.
tcpdump -i any -s 0 host <IP address> -w <File name>
메시지 프로세서에서 TCP/IP 패킷을 가져오는 경우 `tcpdump`
tcpdump명령어에서 백엔드 서버의 공개 IP 주소를 사용합니다.백엔드 서버/메시지 프로세서에 여러 IP 주소가 있는 경우 다른 tcpdump 명령어를 사용해야 합니다. 이 도구 및 이 명령어의 다른 변형에 관한 자세한 내용은 tcpdump 를 참조하세요.
- Wireshark 도구 또는 익숙한 유사한 도구를 사용하여 TCP/IP 패킷을 분석합니다.
다음은 Wireshark 도구를 사용하여 샘플 TCP/IP 패킷 데이터를 분석한 결과입니다.

- 위의 tcpdump의 메시지 #4는 메시지 프로세서 (소스) 가 'Client Hello' 메시지를 백엔드 서버 (대상)에 보냈음을 보여줍니다.
- 메시지 #5는 백엔드 서버가 메시지 프로세서의 Client Hello 메시지 를 승인함을 보여줍니다.
- 백엔드 서버는 인증서와 함께 "Server Hello" 메시지를 보낸 후, 메시지 #7에서 클라이언트에게 인증서를 보내도록 요청합니다.
- 메시지 프로세서는 인증서 확인을 완료하고 메시지 #8에서 백엔드 서버의 ServerHello 메시지를 승인합니다.
- 메시지 프로세서는 메시지 #9에서 백엔드 서버로 인증서를 보냅니다.
- 백엔드 서버는 메시지 #11에서 메시지 프로세서의 인증서 수신을 승인합니다.
하지만 즉시 Fatal Alert: Bad Certificate를 메시지 프로세서 (메시지 #12)에 보냅니다. 이는 메시지 프로세서에서 보낸 인증서가 잘못되었으므로 백엔드 서버에서 인증서 확인이 실패했음을 나타냅니다. 따라서 SSL 핸드셰이크가 실패하고 연결 이 닫힙니다.

이제 메시지 #9를 살펴보고 메시지 프로세서에서 보낸 인증서의 콘텐츠를 확인해 보겠습니다.

- 백엔드 서버가 클라이언트로부터 인증서를 가져오지 않았음을 알 수 있습니다 (인증서 길이: 0). 따라서 백엔드 서버는 Fatal Alert: Bad Certificate를 보냅니다.
- 일반적으로 이는 클라이언트, 즉 메시지 프로세서 (Java 기반 프로세스)가 다음과 같은 경우에 발생합니다.
- 키 저장소에 클라이언트 인증서가 없거나
- 클라이언트 인증서를 보낼 수 없습니다. 이는 백엔드 서버의 허용 가능한 인증 기관 중 하나에서 발급한 인증서를 찾을 수 없는 경우에 발생할 수 있습니다. 즉, 클라이언트의 리프 인증서 (체인의 첫 번째 인증서)의 인증 기관이 백엔드 서버의 허용 가능한 인증 기관과 일치하지 않으면 메시지 프로세서가 인증서를 보내지 않습니다.
다음과 같이 이러한 각 원인을 개별적으로 살펴보겠습니다.
원인: 클라이언트 인증서 없음
진단
대상 엔드포인트의 SSL 정보 섹션 또는 대상 엔드포인트에 사용된 대상 서버 에 지정된 키 저장소에 인증서가 없으면 이 오류가 발생합니다.
아래 단계를 따라 이 문제가 원인인지 확인하세요.
- 아래 단계를 사용하여 특정 API 프록시의 대상 엔드포인트 또는 대상 서버
에서 사용 중인 키 저장소를 확인합니다.
- 대상 엔드포인트 또는 대상 서버의 SSLInfo 섹션에 있는 키 저장소 요소
에서 키 저장소 참조 이름을 가져옵니다.
대상 엔드포인트 구성의 샘플 SSLInfo 섹션을 살펴보겠습니다.
<SSLInfo> <Enabled>true</Enabled> <ClientAuthEnabled>true</ClientAuthEnabled> <KeyStore>ref://myKeystoreRef</KeyStore> <KeyAlias>myKey</KeyAlias> <TrustStore>ref://myTrustStoreRef</TrustStore> </SSLInfo>
- 위의 예시에서 키 저장소 참조 이름은 "myKeystoreRef"입니다.
- Edge UI로 이동하여 API 프록시 -> 환경 구성 을 선택합니다.
참조 탭을 선택하고 키 저장소 참조 이름을 검색합니다. 특정 키 저장소 참조의 참조 열에 이름을 적어둡니다. 이 이름이 키 저장소 이름이 됩니다.

- 위의 예시에서 myKeystoreRef에 'myKeystore'에 대한 참조가 있음을 알 수 있습니다 . 따라서 키 저장소 이름은 myKeystore입니다.
- 대상 엔드포인트 또는 대상 서버의 SSLInfo 섹션에 있는 키 저장소 요소
에서 키 저장소 참조 이름을 가져옵니다.
- Edge UI 또는 키 저장소 API의 인증서 나열을 사용하여 이 키 저장소에 인증서가 포함되어 있는지 확인합니다.
- 키 저장소에 인증서가 포함되어 있으면 원인: 인증 기관 불일치로 이동합니다.
- 키 저장소에 인증서가 포함되어 있지 않으면 메시지 프로세서에서 클라이언트 인증서를 보내지 않는 이유입니다.
해결 방법
- 올바르고 완전한 클라이언트 인증서 체인이 메시지 프로세서의 특정 키 저장소에 업로드되었는지 확인합니다.
원인: 인증 기관 불일치
일반적으로 서버는 클라이언트에게 인증서를 보내도록 요청할 때 허용되는 발급기관 또는 인증 기관 집합을 나타냅니다. 메시지 프로세서의 키 저장소에 있는 리프 인증서 (인증서 체인의 첫 번째 인증서)의 발급기관/인증 기관이 백엔드 서버에서 허용하는 인증 기관과 일치하지 않으면 메시지 프로세서 (Java 기반 프로세스)가 백엔드 서버로 인증서를 보내지 않습니다.
아래 단계를 사용하여 이 문제가 원인인지 확인합니다.
- 키 저장소 API의 인증서 나열.
- 키 저장소 API의 인증서 가져오기를 사용하여 위의 1단계에서 가져온 각 인증서의 세부정보를 가져옵니다.
- 키 저장소에 저장된 리프 인증서 (인증서 체인의 첫 번째 인증서)의 발급기관을 적어둡니다.
샘플 리프 인증서
{ "certInfo" : [ { "basicConstraints" : "CA:FALSE", "expiryDate" : 1578889324000, "isValid" : "Yes", "issuer" : "CN=MyCompany Test SHA2 CA G2, DC=testcore, DC=test, DC=dir, DC=mycompany, DC=com", "publicKey" : "RSA Public Key, 2048 bits", "serialNumber" : "65:00:00:00:d2:3e:12:d8:56:fa:e2:a9:69:00:06:00:00:00:d2", "sigAlgName" : "SHA256withRSA", "subject" : "CN=nonprod-api.mycompany.com, OU=ITS, O=MyCompany, L=MELBOURNE, ST=VIC, C=AU", "subjectAlternativeNames" : [ ], "validFrom" : 1484281324000, "version" : 3 } ], "certName" : "nonprod-api.mycompany.com.key.pem-cert" }위의 예시에서 발급기관/인증 기관은
"CN=MyCompany Test SHA2 CA G2, DC=testcore, DC=test, DC=dir, DC=mycompany, DC=com"입니다. - 다음 기법 중 하나를 사용하여 백엔드 서버의 허용되는 발급기관 또는 인증 기관 목록을 확인합니다.
기법 1: 아래 openssl 명령어 사용
openssl s_client -host <backend server host name> -port <Backend port#> -cert <Client Certificate> -key <Client Private Key>
아래와 같이 이 명령어의 출력에서 "허용 가능한 클라이언트 인증서 CA 이름" 이라는 섹션을 참조하세요.
Acceptable client certificate CA names /C=AU/ST=VIC/L=MELBOURNE/O=MyCompany/OU=ITS/CN=nonprod-api.mycompany.com /C=AU/ST=VIC/L=MELBOURNE/O=MyCompany/OU=ITS/CN=nonprod-api.mycompany.com
기법 2: 백엔드 서버가 클라이언트에게 인증서를 보내도록 요청하는 TCP/IP 패킷에서
Certificate Request패킷 확인:위에 표시된 샘플 TCP/IP 패킷에서
Certificate Request패킷은 메시지 #7입니다. 백엔드 서버의 허용 가능한 인증 기관이 포함된 "고유 이름" 섹션을 참조하세요.
3단계에서 가져온 인증 기관이 백엔드 서버의 허용되는 발급기관 또는 인증 기관 목록 과 4단계에서 가져온 백엔드 서버의 허용되는 발급기관 또는 인증 기관 목록과 일치하는지 확인합니다. 일치하지 않으면 메시지 프로세서가 백엔드 서버로 클라이언트 인증서를 보내지 않습니다.
위의 예시에서 메시지 프로세서의 키 저장소에 있는 클라이언트의 리프 인증서의 발급기관이 백엔드 서버의 허용되는 인증 기관 과 일치하지 않음을 알 수 있습니다. 따라서 메시지 프로세서는 백엔드 서버로 클라이언트 인증서를 보내지 않습니다. 이로 인해 SSL 핸드셰이크가 실패하고 백엔드 서버가 '
Fatal alert: bad_certificate' 메시지를 보냅니다.
해결 방법
- 클라이언트의 리프 인증서 (체인의 첫 번째 인증서)의 발급기관/인증 기관과 일치하는 발급기관/인증 기관이 있는 인증서가 백엔드 서버의 트러스트 저장소에 저장되어 있는지 확인합니다.
- 이 플레이북에 설명된 예시에서 발급기관
"issuer" : "CN=MyCompany Test SHA2 CA G2, DC=testcore, DC=test, DC=dir, DC=mycompany, DC=com"이 있는 인증서가 백엔드 서버의 트러스트 저장소에 추가되어 문제를 해결했습니다.
문제가 계속되면 진단 정보를 수집해야 함으로 이동합니다.
진단 정보 수집 필요
위 안내를 따른 후에도 문제가 지속되면 다음 진단 정보를 수집하세요. Apigee Edge 지원팀에 문의하고 공유하세요.:
- Public Cloud 사용자인 경우 다음 정보를 제공합니다.
- 조직 이름
- 환경 이름
- API 프록시 이름
- 오류를 재현하는 완전한 curl 명령어
- 오류를 보여주는 trace 파일
- 백엔드 서버에서 캡처된 TCP/IP 패킷
- Private Cloud 사용자인 경우 다음 정보를 제공합니다.
- 확인된 완전한 오류 메시지
- API 프록시 번들
- 오류를 보여주는 trace 파일
- 메시지 프로세서 로그
/opt/apigee/var/log/edge-message-processor/logs/system.log - 백엔드 서버 또는 메시지 프로세서에서 캡처된 TCP/IP 패킷
- 키 저장소 API의 인증서 가져오기의 출력
- 이 플레이북에서 시도한 섹션과 이 문제의 해결을 신속하게 처리하는 데 도움이 되는 기타 통찰에 관한 세부정보