英文:
Using self signed SSL Certificates
问题
我正在尝试在一个在nginx反向代理后面的InfluxDB REST端点和我用GoLang编写的简单客户端之间使用这个证书进行连接。
我开始使用使用openssl生成的SSL证书,使用这个链接上找到的教程,教程指导我创建和自签名证书。
但是,每次我尝试进行连接时,都会出现以下错误:
x509: 证书由未知的授权机构签名(可能是因为“x509: 无效的签名:父证书无法签署此类证书”而尝试验证候选授权证书“<我的证书名称>”)
我还没有找到解决这个问题的方法,但我会展示我认为相关的内容:
据我所知,InfluxDB的nginx规则相当容易编写,最终看起来像这样:
# InfluxDB
server {
ssl on;
ssl_protocols TLSV1.2 TLSV1.1 TLSV1;
ssl_certificate /etc/nginx/server.crt;
ssl_certificate_key /etc/nginx/server.key;
listen 8086;
access_log /var/log/nginx/influxdb.access.log;
error_log /var/log/nginx/influxdb.error.log;
location / {
include /etc/nginx/conf.d/options.conf.inc;
include /etc/nginx/conf.d/auth.conf.inc;
proxy_pass http://127.0.0.1:8087;
}
}
其中,options.conf.inc 文件内容如下:
if ($request_method = OPTIONS) {
add_header Access-Control-Allow-Origin $served_at;
add_header Access-Control-Allow-Methods "GET, OPTIONS";
add_header Access-Control-Allow-Headers "Authorization";
add_header Access-Control-Allow-Credentials "true";
add_header Content-Length 0;
add_header Content-Type text/plain;
return 200;
}
auto.conf.inc 文件内容如下:
add_header Access-Control-Allow-Headers "Authorization";
add_header Access-Control-Allow-Credentials "true";
auth_basic "Restricted";
auth_basic_user_file <pathTo>.htpasswd;
error_page 401 /401.html;
我的GoLang客户端代码如下:
func main() {
flag.Parse()
// Load client cert
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
log.Fatal(err)
}
// Load CA cert
caCert, err := ioutil.ReadFile(caFile)
if err != nil {
log.Fatal(err)
}
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
// Setup HTTPS client
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
RootCAs: caCertPool,
// InsecureSkipVerify: true,
}
//tlsConfig.BuildNameToCertificate()
transport := &http.Transport{TLSClientConfig: tlsConfig}
client := &http.Client{Transport: transport}
// Do GET something
resp, err := client.Get("https://fillerBasicAuthCredentials:password!1@192.168.223.128:8086/query?q=show+databases")
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
// Dump response
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
log.Println(string(data))
}
从我的GoLang代码中可以看到,我尝试使用tlsConfig对象上的InsecureSkipVerify
标志。将其设置为true可以使一切正常工作,但这似乎本质上是不好的,因为它破坏了使用证书的初衷。
我剩下的选择似乎是生成一个CA证书,并使用该证书签署我的常规证书,但这似乎比我应该需要做的更像是一种黑客行为。
编辑(解决方案):
在尝试创建自己的CA证书对其进行签名后,我成功解决了所有问题。现在我有一个CA证书,我将用它来签署其他证书,并将此CA证书安装在服务器上,以便它们知道这是一个受信任的证书。
在解决此问题时有帮助的一些要点:
我正在使用一个开源的InfluxDB客户端,我本来想避免使用它。它当前使用的是golang的net/http
包,而不是crypto
包,这意味着我无法像我的示例代码那样在代码中指定CA证书。我不得不将CA证书安装到我的服务器上,以便它能够正确识别。我在这个主题上找到了一篇有用的文章:这篇文章。
英文:
I am trying to use this certificate with a connection between an InfluxDB rest endpoint that is behind an nginx reverse-proxy and my simple client written in GoLang.
I started using SSL Certificates generated with openssl using the tutorial found at this link which runs me through creating and self-singing a certificate.
But I get this error every time I try to make this connection:
x509: certificate signed by unknown authority (possibly because of "x509: invalid signature: parent certificate cannot sign this kind of certificate" while trying to verify candidate authority certificate "<My Certificate Name>")
I have yet to find a way to get this resolved, but I'll show what I can see as relevant:
As far as I can tell, the nginx rules for InfluxDB were fairly easy to write and ended up looking like this:
# InfluxDB
server {
ssl on;
ssl_protocols TLSV1.2 TLSV1.1 TLSV1;
ssl_certificate /etc/nginx/server.crt;
ssl_certificate_key /etc/nginx/server.key;
listen 8086;
access_log /var/log/nginx/influxdb.access.log;
error_log /var/log/nginx/influxdb.error.log;
location / {
include /etc/nginx/conf.d/options.conf.inc;
include /etc/nginx/conf.d/auth.conf.inc;
proxy_pass http://127.0.0.1:8087;
}
}
Where options.conf.inc is:
if ($request_method = OPTIONS) {
add_header Access-Control-Allow-Origin $served_at;
add_header Access-Control-Allow-Methods "GET, OPTIONS";
add_header Access-Control-Allow-Headers "Authorization";
add_header Access-Control-Allow-Credentials "true";
add_header Content-Length 0;
add_header Content-Type text/plain;
return 200;
}
Where the auto.conf.inc is:
add_header Access-Control-Allow-Headers "Authorization";
add_header Access-Control-Allow-Credentials "true";
auth_basic "Restricted";
auth_basic_user_file <pathTo>.htpasswd;
error_page 401 /401.html;
My golang client looks like this:
func main() {
flag.Parse()
// Load client cert
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
log.Fatal(err)
}
// Load CA cert
caCert, err := ioutil.ReadFile(caFile)
if err != nil {
log.Fatal(err)
}
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
// Setup HTTPS client
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
RootCAs: caCertPool,
// InsecureSkipVerify: true,
}
//tlsConfig.BuildNameToCertificate()
transport := &http.Transport{TLSClientConfig: tlsConfig}
client := &http.Client{Transport: transport}
// Do GET something
resp, err := client.Get("https://fillerBasicAuthCredentials:password!1@192.168.223.128:8086/query?q=show+databases")
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
// Dump response
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
log.Println(string(data))
}
As you can see in my golang code, is that I have played with the InsecureSkipVerify
flag on the tlsConfig object. Setting this to true makes everything work, but seems inherently bad to do since it defeats a lot of the point of using the cert in the first place.
The options I have left, it seems, is to generate a CA cert and use THAT to sign my regular cert, but that also seems like more of a hack than I should be needing to do.
EDIT (Solution):
After exploring creating my own CA cert to sign these with I was able to get everything working. Now I have a CA cert that I will use to sign my other certs, and I will be installing this CA cert on the boxes so they know it is a trusted cert.
Pieces that were helpful in how I solved this:
I am using an open source influxdb client that I was trying to avoid using. It currently uses golang's net/http
package, and not the crypto
which means I can't specify my CA certs in-code like my example does. I had to install the CA cert onto my box so it was recognized properly. An article I found helpful on this topic is [this one]https://www.happyassassin.net/2015/01/14/trusting-additional-cas-in-fedora-rhel-centos-dont-append-to-etcpkitlscertsca-bundle-crt-or-etcpkitlscert-pem/
答案1
得分: 3
这个错误信息来自go的CheckSignatureFrom方法。看起来它要求在basicConstraints
中将CA标志设置为true,并且如果keyUsage
字段存在(在你提供的示例中是存在的,但在大多数使用自签名证书的指南中并不存在),它必须包含keyCertSign
值。
当我遇到类似的问题时,我会创建一个与服务器证书分开的CA。这需要更多的工作,但这不是一个“hack”;如果说有什么的话,将自签名证书正确地识别为自己的CA才是更“hack”的解决方案。
英文:
That error message is coming from go's CheckSignatureFrom method. It looks like it requires the CA flag in basicConstraints
to be set to true, and if the keyUsage
field is present (it is in the example you linked but it's not in most instructions I've seen for using self-signed certs) it must include the keyCertSign
value.
When I've faced similar problems I've created a CA that is separate from the server certificate. It's a little more work, but it's not a "hack"; if anything setting up the self-signed cert to be properly recognized as its own CA is the hackier solution.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论