简体   繁体   English

HAProxy SSL终止+客户端证书验证+ curl / java客户端

[英]HAProxy SSL termination + client certificate validation + curl / java client

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. 我希望在HAProxy上使用我自己的自签名证书进行SSL终止,并使用我创建的客户端证书验证客户端访问。

I create the server (which is also the CA) certificates the following way: 我通过以下方式创建服务器(也是CA)证书:

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

and: 和:

cat ca.crt ca.key > haproxy.pem

at HAProxy, I configure: bind *:443 ssl crt /path/server.pem ca-file /path/ca.crt verify required crt-ignore-err all 在HAProxy,我配置:bind *:443 ssl crt /path/server.pem ca-file /path/ca.crt验证所需的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

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). 我的逻辑是:我正在创建一个客户端密钥,一个证书签名请求,然后我使用CA(它也是服务器证书,因此有一个服务器可识别的简单链)签名。

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

My question: 1) I would like to create a client certificate that this server will accpet, and test it using curl. 我的问题:1)我想创建一个客户端证书,该服务器将使用,并使用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. 2)我想使用keytool将此证书和CA导入新的Java密钥库/信任库,以便Java(Jersey客户端)代码可以访问相同的内容。

I have spent 2 days on 1/2. 我在1/2上花了2天。 I'm pretty sure someone that's done this before could answer this in 5m. 我很确定之前完成此操作的人可以在5米内回答这个问题。 Or so I hope. 或者我希望如此。 :) :)

Thanks! 谢谢!

1. create client cert 1.创建客户证书

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. 错误: openssl x509 -req -signkey创建一个自签名的证书,其定义是指证书(主题密钥)是相同的密钥,其私人一半标志证书的公共部分。 The documentation for the cert (not req) case is clear that it replaces the key previously in the cert with the signing key. cert(而不是req)情况的文档很明显,它使用签名密钥替换了以前在cert中的密钥。 The -req doc is less clear, but it does the same thing; -req doc不太清楚,但它做同样的事情; it puts in the cert the subject name from the CSR, also as the issuer, and the key from -signkey . 它将来自CSR的主题名称(也作为发行者)和来自-signkey的密钥-signkey You have used a CSR containing the client name, but a -signkey containing the CA key, producing an unusable chimera. 您使用了包含客户端名称的CSR,但使用了包含CA密钥的-signkey ,从而产生了无法使用的嵌合体。

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). 右:签署“儿童”(不是自签名)证书与x509 ,使用-CA并可能-CAkey如文档中描述的https://www.openssl.org/docs/apps/x509.html#SIGNING-选项 (或安装了openssl doc的任何Unix上的man [where] x509 )。 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(由其DN定义)有或将有多个子证书,请使用序列号文件方案自动方便地分配顺序序列号,或使用-set_serial手动分配唯一序列号(顺序是最简单的独特方式,但如果你更喜欢另一种方式,那就没关系)。

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 . 另外:对于自签名CA(和服务器?!)证书,您不需要单独的req -newx509 -req -signkey步骤,您可以在一个req -new -x509 See the doc/manpage for req . 有关req请参阅doc / manpage。 In fact you don't need a separate genrsa step, req -newkey [-nodes] -x509 can do that as well. 实际上你不需要单独的genrsa步骤, req -newkey [-nodes] -x509也可以这样做。 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 ); 需要注意的是:在OpenSSL 1.0.0+中,这会生成通用的PKCS#8格式密钥文件,而不是genrsa (和rsa )使用的“遗留”PKCS#1格式; all OpenSSL functions can accept either, but some other things might not. 所有OpenSSL函数都可以接受,但其他一些东西可能不接受。 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. 特别是最后我检查(不久前)使用服务器密钥为akRSA解密SSL / TLS的Wireshark选项(还有其他选项)仅接受PKCS#1而不是PKCS#8。

2. use in Java (Jersey). 2.在Java(泽西岛)中使用。 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. 请注意,执行客户端身份验证的任何 SSL / TLS客户端(包括Java)都需要证书和私钥 ,并且在大多数情况下,证书使用您还需要的“链”或“中间”证书。 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. 在另一方面信任库条目只需要证书,几乎总是只有 (CA)证书,通常必须只有证书。 Your situation where the same person operates the CA and server and client(s) is somewhat unusual for PKC. 您的情况是,同一个人操作CA 以及服务器客户端对于PKC来说有点不寻常。

2a. 2A。 maybe just convert to pkcs12. 也许只是转换为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). Java并不直接支持密钥的openssl格式,但Java和openssl都支持PKCS#12(微软,Mozilla,Apple以及其他公司也是如此)。 Since you combined client key and (leaf) cert in client.pem do 由于您在client.pem组合了客户端密钥和(叶)证书

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 crypto (JCE and JSSE) can use this PKCS#12 as a keystore, if you can configure the keystore "type" (as pkcs12). Java加密(JCE和JSSE)可以使用此PKCS#12作为密钥库, 如果您可以配置密钥库“类型”(作为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. 默认的SSLSocketFactory支持这一点,我使用的其他应用程序也是如此,但我不使用Jersey,也不知道它在这里做了什么。 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; PKCS#12通常不支持携带“单独”证书(没有私钥),但在您的情况下,客户端的CA证书也是服务器的证书,因此它也可以作为您的信任库使用; 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). 否则,您需要将服务器CA或服务器自签名证书(仅限cert而非私钥)导入JKS信任库(可能是JRE / lib / security / [jsse] cacerts中的缺省信任库)。

2b. 2B。 maybe further convert to JKS. 也许进一步转换为JKS。 If Jersey cannot use PKCS#12 directly, Java can convert it to JKS which any sane Java code can use, like: 如果Jersey不能直接使用PKCS#12,那么Java可以将它转换为任何理智的Java代码都可以使用的JKS,例如:

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

UPDATE 2018: after this answer was written Java support of PKCS12 increased, making it less often necessary to convert to JKS. 更新2018年:在写完这个答案后,PKCS12的Java支持增加,使得转换为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; 2017年秋季发布的8u60仍然默认为密钥库类型JKS,但作为一个特殊功能(?)类型JKS实际上可以读取(虽然不写)PKCS12; see the release notes and item keystore.type.compat in file JRE/lib/security/java.security . 请参阅文件JRE/lib/security/java.security 的发行说明和项目keystore.type.compat Java9 released 2017 makes the default keystore type PKCS12 which (as expected) reads and writes PKCS12, although explicit JKS no longer reads PKCS12. 2017发布的Java9使得默认密钥库类型PKCS12(正如预期的那样)读写PKCS12,尽管显式JKS不再读取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 . 但是如果由于某种原因确实需要使用Java9进行转换,那么现在需要指定-deststoretype jks但不再需要指定-srcstoretype pkcs12

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM