HAProxy SSL终止+客户端证书验证+ curl/Java客户端 [英] HAProxy SSL termination + client certificate validation + curl / java client

查看:191
本文介绍了HAProxy SSL终止+客户端证书验证+ curl/Java客户端的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用自己的自签名证书在HAProxy上进行SSL终止,并希望使用我创建的客户端证书来验证客户端访问权限.

I would like to have SSL termination on HAProxy, using my own self-signed certificates, and to validate client access using client certificates I create.

我通过以下方式创建服务器(也是CA)证书:

I create the server (which is also the CA) certificates the following way:

openssl genrsa -out ca.key 1024
openssl req -new -key ca.key -out ca.csr
openssl x509 -req -days 365 -in ca.csr -signkey ca.key -out ca.crt

和:

cat ca.crt ca.key > haproxy.pem

在HAProxy上,我配置: 绑定*:443 ssl crt/path/server.pem ca文件/path/ca.crt验证所需的crt-ignore-err all

at HAProxy, I configure: bind *:443 ssl crt /path/server.pem ca-file /path/ca.crt verify required crt-ignore-err all

我以类似的方式创建客户端证书:

I create the client certificates in a similar way:

openssl req -new -key client.key -out client.csr
openssl x509 -req -days 365 -in client.csr -signkey ca.key -out client.crt
cat client.crt client.key > client.pem

我的逻辑是:我正在创建一个客户端密钥,一个证书签名请求,然后使用CA(也是服务器证书,因此有一个服务器可以识别的简单链)对其进行签名.

My logic is: I'm creating a client key, a certificate signing request for it, and then I sign it using the CA (which is also the server certificate, so there's a simple chain that the server would recognize).

要测试,我首先尝试使用服务器证书作为客户端证书:

To test, I first try with the server certificate as the client cert:

curl https://my.service:443/ping -E ./haproxy.pem -k
pong

好的,它可以工作.现在,我尝试使用客户端证书作为客户端证书:

ok, it works. Now I try with the client certificate as the client certificate:

curl https://my.service:443/ping -E ./client.pem -k
curl: (58) unable to set private key file: './client.pem' type PEM

我的问题: 1)我想创建此服务器将支持的客户端证书,并使用curl对其进行测试. 2)我想使用keytool将此证书和CA导入到新的Java密钥库/信任库中,以便Java(Jersey客户端)代码可以访问相同的内容.

My question: 1) I would like to create a client certificate that this server will accpet, and test it using curl. 2) I would like to import this certificate and the CA into a new java keystore / truststore using keytool, so that Java (Jersey client) code could access the same content.

我在1/2上花了2天的时间. 我敢肯定,以前做过此事的人可以在5m内回答.还是我希望. :)

I have spent 2 days on 1/2. I'm pretty sure someone that's done this before could answer this in 5m. Or so I hope. :)

谢谢!

推荐答案

1.创建客户端证书

错误: openssl x509 -req -signkey创建一个自签名证书,根据定义,这意味着该证书中的密钥(主题密钥)是同一密钥的公共部分,其私有部分在证书上签名.证书(非要求)案例的文档很清楚,它用签名密钥替换了证书中先前的密钥. -req文档不太清楚,但是它做同样的事情.它将来自CSR的主题名称(也作为颁发者)和来自-signkey的密钥放入证书中.您已经使用了包含客户端名称的CSR,但是使用了包含CA密钥的-signkey,从而产生了无法使用的嵌合体.

wrong: openssl x509 -req -signkey creates a self-signed cert, which by definition means the key in the cert (the subject key) is the public half of the same key whose private half signs the cert. The documentation for the cert (not req) case is clear that it replaces the key previously in the cert with the signing key. The -req doc is less clear, but it does the same thing; it puts in the cert the subject name from the CSR, also as the issuer, and the key from -signkey. You have used a CSR containing the client name, but a -signkey containing the CA key, producing an unusable chimera.

:使用x509签署子"(非自签名)证书,使用-CA并可能使用-CAkey,如文档

right: to sign a "child" (not self-signed) cert with x509, use -CA and possibly -CAkey as described in the documentation https://www.openssl.org/docs/apps/x509.html#SIGNING-OPTIONS (or man [where] x509 on any Unix with openssl doc installed). If there is or ever will be more than one child cert for a given CA (defined by its DN), either use the serial-number file scheme to automatically and conveniently assign sequential serial numbers, or use -set_serial to manually assign unique serial numbers (sequential is the easiest way to do unique, but if you a prefer another way that's okay).

旁边::对于自签名CA(和服务器?!)证书,您不需要单独的req -newx509 -req -signkey步骤,只需一个req -new -x509 .请参阅req的文档/手册.实际上,您不需要单独的genrsa步骤,req -newkey [-nodes] -x509也可以执行此操作.注意事项:在OpenSSL 1.0.0+中,它将生成通用PKCS#8格式的密钥文件,而不是genrsa(和rsa)使用的旧式" PKCS#1格式;所有OpenSSL函数都可以接受,但是其他一些可能不接受.特别是最后一次,我检查了一段时间(前一段时间)的Wireshark选项,以使用akRSA的服务器密钥来解密SSL/TLS(还有其他选项),仅接受PKCS#1而不接受PKCS#8.

aside: for the self-signed CA (and server?!) cert, you don't need separate req -new and x509 -req -signkey steps, you can do it in one req -new -x509. See the doc/manpage for req. In fact you don't need a separate genrsa step, req -newkey [-nodes] -x509 can do that as well. One note: in OpenSSL 1.0.0+ this generates the generic PKCS#8 format keyfile instead of the "legacy" PKCS#1 format used by genrsa (and rsa); all OpenSSL functions can accept either, but some other things might not. In particular last I checked (a while ago) the Wireshark option to decrypt SSL/TLS using server key for akRSA (there are other options too) accepted only PKCS#1 not PKCS#8.

2. 请注意,进行客户端身份验证的任何 SSL/TLS客户端(包括Java)都需要证书和私钥,并且在大多数情况下证书使用链"或中间"证书的情况,您也需要这些证书.有些人(咳嗽)微软(咳嗽)鼓励您误解并忽略这一重要区别,但是,如果您仅尝试使用证书,则根本无法使用.另一方面, truststore 条目仅需要证书,几乎总是只需要 root (CA)证书,通常必须仅拥有证书.对于PKC,您由同一个人操作CA 服务器客户端的情况有些不同寻常.

2. use in Java (Jersey). Note that any SSL/TLS client doing client authentication, including Java, needs both the certificate and the privatekey, and in most cases the certificate uses "chain" or "intermediate" certs which you need also. Some people (cough) Microsoft (cough) encourage you to misunderstand and ignore this important distinction, but if you try to use only a certificate it won't work at all. On the other hand a truststore entry needs only the certificate, almost always only the root (CA) certificate, and usually must have only the certificate. Your situation where the same person operates the CA and server and client(s) is somewhat unusual for PKC.

2a. Java并不直接支持密钥的openssl格式,但是Java和openssl都支持PKCS#12(Microsoft,Mozilla,Apple以及其他可能也支持).由于您在client.pem中将客户端密钥和(叶子)证书结合在一起

2a. maybe just convert to pkcs12. Java does not directly support the openssl format(s) for keys, but both Java and openssl support PKCS#12 (and so do Microsoft, Mozilla, Apple, and probably others). Since you combined client key and (leaf) cert in client.pem do

openssl pkcs12 -export <client.pem -CA ca.crt [-name whatever] >client.p12
# if you use separate key,cert files see the doc about -in and -inkey

Java加密货币(JCE和JSSE)可以将此PKCS#12用作密钥库,如果您可以配置密钥库类型"(作为pkcs12).默认的SSLSocketFactory支持此功能,我使用过的其他应用程序也支持此功能,但是我不使用Jersey,也不知道它在这里做什么.通常不支持PKCS#12携带单独的"证书(不包含私钥),但是在您的情况下,客户端的CA证书也是服务器的证书,因此它会起作用作为您的信任库;否则,您需要将服务器CA或服务器自签名证书(仅证书而非私钥)导入JKS信任库(这可能是JRE/lib/security/[jsse] cacerts中的默认信任库).

Java crypto (JCE and JSSE) can use this PKCS#12 as a keystore, if you can configure the keystore "type" (as pkcs12). The default SSLSocketFactory supports this, and so do other apps I've used, but I don't use Jersey and don't know what it does here. PKCS#12 isn't generally supported to carry "separate" certs (without privatekey), but in your case the CA cert for the client is also the cert for the server, so it will happen to work as your truststore as well; otherwise you would need to import the server CA or server selfsigned cert (only cert not privatekey) into a JKS truststore (which might be the default truststore in JRE/lib/security/[jsse]cacerts).

2b.也许可以进一步转换为JKS.如果Jersey无法直接使用PKCS#12,Java可以将其转换为任何合理的Java代码可以使用的JKS,例如:

2b. maybe further convert to JKS. If Jersey cannot use PKCS#12 directly, Java can convert it to JKS which any sane Java code can use, like:

keytool -importkeystore -srckeystore client.p12 -srcstoretype pkcs12 -destkeystore client.jks 

UPDATE 2018:在编写此答案后,增加了Java对PKCS12的支持,从而减少了转换为JKS的频率. 8u60于2017年秋季发布,并且仍默认使用密钥库类型JKS,但作为一项特殊功能(?),JKS类型实际上可以读取(尽管不能写入)PKCS12;请参见发行说明和项目keystore.type.compat中的文件JRE/lib/security/java.security. Java9 2017年发布了默认密钥库类型PKCS12,该密钥库类型(如预期的那样)读取和写入PKCS12,尽管显式JKS不再读取PKCS12.但是,如果由于某种原因确实需要使用Java9进行转换,则现在需要指定-deststoretype jks,而不再需要指定-srcstoretype pkcs12.

UPDATE 2018: after this answer was written Java support of PKCS12 increased, making it less often necessary to convert to JKS. 8u60 released fall 2017 and up still defaults to keystore type JKS, but as a special feature(?) type JKS can actually read (though not write) PKCS12; see the release notes and item keystore.type.compat in file JRE/lib/security/java.security. Java9 released 2017 makes the default keystore type PKCS12 which (as expected) reads and writes PKCS12, although explicit JKS no longer reads PKCS12. But if you do need to convert with Java9 for some reason, you now need to specify -deststoretype jks but no longer need to specify -srcstoretype pkcs12.

这篇关于HAProxy SSL终止+客户端证书验证+ curl/Java客户端的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆