The problem/use-case that the feature addresses
Redis TLS cannot currently be used with ACME certificates
Description of the feature
A flag to pass in with TLS config to indicate a ACME certificate will be passed - in this scenario, the ca.crt is not needed as these certificates pass the full cert chain within the tls.crt. Scripts can then handle obtaining the necessary certificates from the cert chain to enable TLS.
Alternatives you've considered
Could be change downstream (at cert-manager for our install) to separate the ca.crt and include it with the certificate secret - cert-manager has made it clear they do not plan on implementing this.
We could manually break out this somewhere on our cluster & place within a new secret prior to passing to redis (rough logic). However, we believe that redis should follow suit with other applications to natively accept these ACME based certificates.
Comment From: zuiderkwast
Hello.
Scripts can then handle obtaining the necessary certificates from the cert chain to enable TLS.
What exactly would Redis need to do? Can we just allow CA certs to be absent and will then OpenSSL take them automatically from the cert file?
If you have a patch and it doesn't add a lot of complexity to redis, I think it's easier to get it in.
Comment From: slavak
@JDKnobloch Do you mean Redis would obtain the tls-ca-cert-file by extracting the intermediate certificate from a provided tls-cert-file?
Comment From: JDKnobloch
Sorry - forgot to return to this issue
@slavak precisely - our certs are provided to us fully within a single tls-cert-file via a cert chain. So we have the CA cert available, just not as cleanly as a standalone tls-ca-cert-file & it introduces an issue of extraction that we would prefer not to handle manually for this one application.
I would think could be a somewhat common issue for users implementing TLS as our ACME / lets-encrypt / cert-manager stack is fairly standard (at least not completely outlandish), so would be nice to have & could potentially mitigate future users winding up in a similar situation.
Comment From: slavak
I'm willing to give implementing this a shot, but I'd need your help, since I don't have any real certificates of this type to test with and couldn't find any spec that describes exactly how this works.
IIUC, it's basically a PEM file that contains a certificate bundle, from the leaf certificate up to a signing CA, and the algorithm would be to load this bundle and look for the first certificate in it that's a CA?
I wrote a small snippet of code that does this. Anyone more familiar with the OpenSSL API and/or ACME certificates that can tell me if this looks right?
````c X509 *ca_cert = NULL;
X509_STORE *ctx = X509_STORE_new(); assert(X509_STORE_load_locations(ctx, "/tmp/acme.pem", NULL));
STACK_OF(X509_OBJECT) sk = X509_STORE_get0_objects(ctx); for (int i = 0; i < sk_X509_OBJECT_num(sk); i++) { X509 c = X509_OBJECT_get0_X509(sk_X509_OBJECT_value(sk, i));; if (!c) continue; if (X509_check_ca(c)) { ca_cert = X509_dup(c); break; } }
X509_STORE_free(ctx);
Comment From: yossigo
@slavak @JDKnobloch Wouldn't we get the same effect if we point both tls-cert-file and tls-ca-cert-file to the same file that contains the whole chain?
This configuration might have undesired side effects, such as being overly permissive and accepting client certificates issued by any intermediate cert - but that would be the case also if we follow the original ask above.
Comment From: slavak
That's... a good question.
Comment From: JDKnobloch
@yossigo double checked git history to confirm and I indeed attempted this without success. Cannot remember the exact outcome but suffice to say it was unsuccessful - I believe pods failed to start.
@slavak that is correct as far as I understand. I can't find great documentation on the finer details on ACME certificate contents, but per cert-manager docs this is our current position:
When a certificate is issued by an intermediate CA and the Issuer can provide the issued certificate's chain, the contents of tls.crt will be the requested certificate followed by the certificate chain. Additionally, if the Certificate Authority is known, the corresponding CA certificate will be stored in the secret with key ca.crt. For example, with the ACME issuer, the CA is not known and ca.crt will not exist in acme-crt-secret.
We have the tls.crt containing the full chain as a PEM signed cert chain, but CA is not known
Comment From: yossigo
@JDKnobloch Can you provide sample PEM files to demonstrate / test this?
Comment From: JDKnobloch
@yossigo Sure - are you just looking for the general layout? Obviously I don't want to go pasting a cert chain that is in use around but I can provide that with dummy values if that suffices
Comment From: slavak
@JDKnobloch I think any kind of sample files that would allow us to reproduce the issue would be helpful. A (set of) certificate/private key file(s) that was generated for this purpose alone would work fine.
Comment From: nebed
@yossigo @slavak here is a dummy cert generated from the letsencrypt staging endpoint
-----BEGIN CERTIFICATE-----
MIIFGDCCBACgAwIBAgISK24uVWCpv0scvWDQMaCYhbNMMA0GCSqGSIb3DQEBCwUA
MFkxCzAJBgNVBAYTAlVTMSAwHgYDVQQKExcoU1RBR0lORykgTGV0J3MgRW5jcnlw
dDEoMCYGA1UEAxMfKFNUQUdJTkcpIEFydGlmaWNpYWwgQXByaWNvdCBSMzAeFw0y
NDAxMjkxMTE3MzFaFw0yNDA0MjgxMTE3MzBaMBgxFjAUBgNVBAMTDXRlc3QubmVi
ZWQuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCiNexx6i7jZtm1
G99EV4iOOOEFDp+IqG4DTYhXzbQNHmSmz0cg7Ny1/VX5Xt3Yr9R7K2HhGJHIGy7p
vL8mW6Eb5ri9QhWlZKwCMFFnn/HYuY7WY/Hw1lsStTLEp5gi1nD93mC6B3DBr8TE
uTERih5LJQBGwutDI9ZD4jkl+XyyW9hrTgj5D0KECUwGHC+1JicT735HoId0RXVe
AyJTlTeGfgS9/h4b7AtcH5DQ8fcfugMT8G8vHnzgakh/0FGR/Yb3y5AXfRlLkX8d
oRGjcdCfeJZ7+I4EFVHPrwahiDpz0SkHLwiO0ZPtYtqTRLLdYENV8odlsWUX73r1
gA4SuuVzAgMBAAGjggIZMIICFTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYI
KwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFDaUVESZ
d36jhVHhmTE+wTcf+fFxMB8GA1UdIwQYMBaAFN5yekjfMcOmUN+fhSPfVzdLXS5l
MF0GCCsGAQUFBwEBBFEwTzAlBggrBgEFBQcwAYYZaHR0cDovL3N0Zy1yMy5vLmxl
bmNyLm9yZzAmBggrBgEFBQcwAoYaaHR0cDovL3N0Zy1yMy5pLmxlbmNyLm9yZy8w
GAYDVR0RBBEwD4INdGVzdC5uZWJlZC5pbzATBgNVHSAEDDAKMAgGBmeBDAECATCC
AQYGCisGAQQB1nkCBAIEgfcEgfQA8gB3AKpssMXJ9MSdjY6pDDkX4NcK2SIQvwV/
QVCTgsw1DJhGAAABjVUnPQkAAAQDAEgwRgIhAPZqf55Bmlai8WhdHD3CZCQ4fjiE
sPReJKTsGBVaZyjaAiEAvLRqRNdeTWpv6hKJqOnZj5qu1REQ3vw1A7ZVeTgIUvkA
dwCwzIPlpfl9a698CcwoSQSHKsfoixMsY1C3xv0m4WxsdwAAAY1VJz0EAAAEAwBI
MEYCIQDvCEy72izdCMgu1O0yhuMuUew6InaQjrjBitT/WocTiAIhAOyvxZuZDNTm
RhaRxmTQqTztNVE70MMaj1+nkDjklOmzMA0GCSqGSIb3DQEBCwUAA4IBAQClgVwL
25821VNs9M9IjlYmwg7QtguTKsvEoXgc8WmZwyOBc/nVikfnMwh1jTyO+jA/G3+T
0lw5dSpt1BZ5SaT9rihTqWWU8lcNcLryqcsmXvqqrOKA2nH4dtsaXCuSQgYWiolE
zPBwcI0bVPVLcfIYFDXZ/7I4kMDHF7cQUOdcc+grTywS/TtzuY6GhGnlDjGqAWa0
eaRUG7r6n2FRpfZeKbNnr8siz1PhxLeUOGkr1lVF/Jbx4H2nudlpKXNShEEd8KYE
YfXiXh4ocBt+DKd0WngTG5ZXeZOhQzICNIrIc/lr8kV0p15H7XY1f9MXKu4XIP4L
JHXM8WmNUKGbKDv0
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFWzCCA0OgAwIBAgIQTfQrldHumzpMLrM7jRBd1jANBgkqhkiG9w0BAQsFADBm
MQswCQYDVQQGEwJVUzEzMDEGA1UEChMqKFNUQUdJTkcpIEludGVybmV0IFNlY3Vy
aXR5IFJlc2VhcmNoIEdyb3VwMSIwIAYDVQQDExkoU1RBR0lORykgUHJldGVuZCBQ
ZWFyIFgxMB4XDTIwMDkwNDAwMDAwMFoXDTI1MDkxNTE2MDAwMFowWTELMAkGA1UE
BhMCVVMxIDAeBgNVBAoTFyhTVEFHSU5HKSBMZXQncyBFbmNyeXB0MSgwJgYDVQQD
Ex8oU1RBR0lORykgQXJ0aWZpY2lhbCBBcHJpY290IFIzMIIBIjANBgkqhkiG9w0B
AQEFAAOCAQ8AMIIBCgKCAQEAu6TR8+74b46mOE1FUwBrvxzEYLck3iasmKrcQkb+
gy/z9Jy7QNIAl0B9pVKp4YU76JwxF5DOZZhi7vK7SbCkK6FbHlyU5BiDYIxbbfvO
L/jVGqdsSjNaJQTg3C3XrJja/HA4WCFEMVoT2wDZm8ABC1N+IQe7Q6FEqc8NwmTS
nmmRQm4TQvr06DP+zgFK/MNubxWWDSbSKKTH5im5j2fZfg+j/tM1bGaczFWw8/lS
nukyn5J2L+NJYnclzkXoh9nMFnyPmVbfyDPOc4Y25aTzVoeBKXa/cZ5MM+WddjdL
biWvm19f1sYn1aRaAIrkppv7kkn83vcth8XCG39qC2ZvaQIDAQABo4IBEDCCAQww
DgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAS
BgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBTecnpI3zHDplDfn4Uj31c3S10u
ZTAfBgNVHSMEGDAWgBS182Xy/rAKkh/7PH3zRKCsYyXDFDA2BggrBgEFBQcBAQQq
MCgwJgYIKwYBBQUHMAKGGmh0dHA6Ly9zdGcteDEuaS5sZW5jci5vcmcvMCsGA1Ud
HwQkMCIwIKAeoByGGmh0dHA6Ly9zdGcteDEuYy5sZW5jci5vcmcvMCIGA1UdIAQb
MBkwCAYGZ4EMAQIBMA0GCysGAQQBgt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCN
DLam9yN0EFxxn/3p+ruWO6n/9goCAM5PT6cC6fkjMs4uas6UGXJjr5j7PoTQf3C1
vuxiIGRJC6qxV7yc6U0X+w0Mj85sHI5DnQVWN5+D1er7mp13JJA0xbAbHa3Rlczn
y2Q82XKui8WHuWra0gb2KLpfboYj1Ghgkhr3gau83pC/WQ8HfkwcvSwhIYqTqxoZ
Uq8HIf3M82qS9aKOZE0CEmSyR1zZqQxJUT7emOUapkUN9poJ9zGc+FgRZvdro0XB
yphWXDaqMYph0DxW/10ig5j4xmmNDjCRmqIKsKoWA52wBTKKXK1na2ty/lW5dhtA
xkz5rVZFd4sgS4J0O+zm6d5GRkWsNJ4knotGXl8vtS3X40KXeb3A5+/3p0qaD215
Xq8oSNORfB2oI1kQuyEAJ5xvPTdfwRlyRG3lFYodrRg6poUBD/8fNTXMtzydpRgy
zUQZh/18F6B/iW6cbiRN9r2Hkh05Om+q0/6w0DdZe+8YrNpfhSObr/1eVZbKGMIY
qKmyZbBNu5ysENIK5MPc14mUeKmFjpN840VR5zunoU52lqpLDua/qIM8idk86xGW
xx2ml43DO/Ya/tVZVok0mO0TUjzJIfPqyvr455IsIut4RlCR9Iq0EDTve2/ZwCuG
hSjpTUFGSiQrR2JK2Evp+o6AETUkBCO1aw0PpQBPDQ==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFVDCCBDygAwIBAgIRAO1dW8lt+99NPs1qSY3Rs8cwDQYJKoZIhvcNAQELBQAw
cTELMAkGA1UEBhMCVVMxMzAxBgNVBAoTKihTVEFHSU5HKSBJbnRlcm5ldCBTZWN1
cml0eSBSZXNlYXJjaCBHcm91cDEtMCsGA1UEAxMkKFNUQUdJTkcpIERvY3RvcmVk
IER1cmlhbiBSb290IENBIFgzMB4XDTIxMDEyMDE5MTQwM1oXDTI0MDkzMDE4MTQw
M1owZjELMAkGA1UEBhMCVVMxMzAxBgNVBAoTKihTVEFHSU5HKSBJbnRlcm5ldCBT
ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEiMCAGA1UEAxMZKFNUQUdJTkcpIFByZXRl
bmQgUGVhciBYMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALbagEdD
Ta1QgGBWSYkyMhscZXENOBaVRTMX1hceJENgsL0Ma49D3MilI4KS38mtkmdF6cPW
nL++fgehT0FbRHZgjOEr8UAN4jH6omjrbTD++VZneTsMVaGamQmDdFl5g1gYaigk
kmx8OiCO68a4QXg4wSyn6iDipKP8utsE+x1E28SA75HOYqpdrk4HGxuULvlr03wZ
GTIf/oRt2/c+dYmDoaJhge+GOrLAEQByO7+8+vzOwpNAPEx6LW+crEEZ7eBXih6V
P19sTGy3yfqK5tPtTdXXCOQMKAp+gCj/VByhmIr+0iNDC540gtvV303WpcbwnkkL
YC0Ft2cYUyHtkstOfRcRO+K2cZozoSwVPyB8/J9RpcRK3jgnX9lujfwA/pAbP0J2
UPQFxmWFRQnFjaq6rkqbNEBgLy+kFL1NEsRbvFbKrRi5bYy2lNms2NJPZvdNQbT/
2dBZKmJqxHkxCuOQFjhJQNeO+Njm1Z1iATS/3rts2yZlqXKsxQUzN6vNbD8KnXRM
EeOXUYvbV4lqfCf8mS14WEbSiMy87GB5S9ucSV1XUrlTG5UGcMSZOBcEUpisRPEm
QWUOTWIoDQ5FOia/GI+Ki523r2ruEmbmG37EBSBXdxIdndqrjy+QVAmCebyDx9eV
EGOIpn26bW5LKerumJxa/CFBaKi4bRvmdJRLAgMBAAGjgfEwge4wDgYDVR0PAQH/
BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFLXzZfL+sAqSH/s8ffNE
oKxjJcMUMB8GA1UdIwQYMBaAFAhX2onHolN5DE/d4JCPdLriJ3NEMDgGCCsGAQUF
BwEBBCwwKjAoBggrBgEFBQcwAoYcaHR0cDovL3N0Zy1kc3QzLmkubGVuY3Iub3Jn
LzAtBgNVHR8EJjAkMCKgIKAehhxodHRwOi8vc3RnLWRzdDMuYy5sZW5jci5vcmcv
MCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQBgt8TAQEBMA0GCSqGSIb3DQEB
CwUAA4IBAQB7tR8B0eIQSS6MhP5kuvGth+dN02DsIhr0yJtk2ehIcPIqSxRRmHGl
4u2c3QlvEpeRDp2w7eQdRTlI/WnNhY4JOofpMf2zwABgBWtAu0VooQcZZTpQruig
F/z6xYkBk3UHkjeqxzMN3d1EqGusxJoqgdTouZ5X5QTTIee9nQ3LEhWnRSXDx7Y0
ttR1BGfcdqHopO4IBqAhbkKRjF5zj7OD8cG35omywUbZtOJnftiI0nFcRaxbXo0v
oDfLD0S6+AC2R3tKpqjkNX6/91hrRFglUakyMcZU/xleqbv6+Lr3YD8PsBTub6lI
oZ2lS38fL18Aon458fbc0BPHtenfhKj5
-----END CERTIFICATE-----
there are 3 certificate fields and according to them the middle certificate is the intermediate CA certificate
Comment From: garry-t
this ticket will solve big pain in ass and will give ability to use letsencrypt out of the box. isn't it?
Comment From: zuiderkwast
The certificate chain we get with the ACME protocol is described in the RFC under 7.4.2. Downloading the Certificate. What you get is of MIME-type application/pem-certificate-chain, which is describe like this:
A file of this type contains one or more certificates encoded with the PEM textual encoding
(...)
In order to provide easy interoperation with TLS, the first certificate MUST be an end-entity certificate. Each following certificate SHOULD directly certify the one preceding it. Because certificate validation requires that trust anchors be distributed independently, a certificate that represents a trust anchor MAY be omitted from the chain, provided that supported peers are known to possess any omitted certificates.
In tls.c, we use SSL_CTX_use_certificate_chain_file() to load the cert file, so I would suppose we already accept a cert chain in the cert file. The OpenSSL manual describes the function like this:
SSL_CTX_use_certificate_chain_file() loads a certificate chain from file into ctx. The certificates must be in PEM format and must be sorted starting with the subject's certificate (actual client or server certificate), followed by intermediate CA certificates if applicable, and ending at the highest level (root) CA. SSL_use_certificate_chain_file() is similar except it loads the certificate chain into ssl.
@nebed's certificate chain (posted above) contains these certificates:
-
Common Name: test.nebed.io \ Issuer: (STAGING) Artificial Apricot R3, (STAGING) Let's Encrypt
-
Common Name: (STAGING) Artificial Apricot R3 \ Issuer: (STAGING) Pretend Pear X1, (STAGING) Internet Security Research Group
-
Common Name: (STAGING) Pretend Pear X1 \ Issuer: (STAGING) Doctored Durian Root CA X3, (STAGING) Internet Security Research Group
Apart from the "STAGING" marks, it looks like Let's Encrypt's certificate hierarchy which is
DST Root CA X3 ==> ISRG X1 ==> R3 ==> Subscriber certificates
The root certificate is not included in the cert chain, so I guess you need to provide it in your CA certificates.
In my system (Debian) the trusted CA certificates are installed under /usr/share/ca-certificates/ and I found the DST Root CA X3 in the file /usr/share/ca-certificates/mozilla/DST_Root_CA_X3.crt.
So my conclusion is that you should be able to put the cert chain in the tls-cert-file and put your systems's ca certificates directory in tls-ca-cert-dir.
Has anyone tried that?
Comment From: nebed
you're a genius @zuiderkwast ! that works!
$ redis-cli -h redis-qa-master.k8s-dev.xxxxxx.xxxxxxx.com -p 6380 --tls -a "xxxxxxxxx"
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
redis-qa-master.k8s-dev.xxxxx.xxxxxx:6380> HELLO
1) "server"
2) "redis"
3) "version"
4) "7.2.3"
5) "proto"
6) (integer) 2
7) "id"
8) (integer) 382
9) "mode"
10) "standalone"
11) "role"
12) "master"
13) "modules"
14) (empty array)
let me see if I can create a PR to the bitnami/redis chart to support this
Comment From: nebed
created an issue on the bitnami/redis container to add a new environment variable for this config in redis.conf - https://github.com/bitnami/containers/issues/56361 would make the chart update easier.
Comment From: zuiderkwast
It's great that it works! So we don't need any new implementation in redis then, right?
If you can't set CA dir, maybe you can set CA file to the file containing "DST Root CA X3"?
Comment From: nebed
Yes, it works perfectly, I don't think there's anything to be done from Redis' side. I can currently set the CA dir in redis.conf, it would just be convenient from the bitnami/redis container to have it exposed as an environment variable. Thanks a lot for the help @zuiderkwast.
Comment From: zuiderkwast
Great. Maybe we could just improve documentation about this.
Comment From: garry-t
@zuiderkwast Dosent work for me .
I use certificates signed by sectigo.
tls-ca-cert-dir /usr/share/ca-certificates/mozilla/
Error condition on socket for SYNC: error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed
Comment From: zuiderkwast
@garry-t have you checked which certificates you have in the cert chain and that the bottom of those is signed by one of the certs in your ca dir? I pasted the pem contents in an online form like https://www.sslchecker.com/certdecoder or https://www.sslshopper.com/certificate-decoder.html
Comment From: garry-t
@zuiderkwast I found what CA certs used for my certificates here.
After that, I found another directory with ssl certs and use it in config, it started work.
Changed from:
tls-ca-cert-dir=/usr/share/ca-certificates/mozilla/
To
tls-ca-cert-dir=/etc/ssl/certs/
After that certificates was able to be validated. For now not sure what is the difference between two folders, but for Ubuntu 20.04 this path works : /etc/ssl/certs/. -> This is openssl compatible directory. see
In both folders I have same certificate COMODO_ECC_Certification_Authority, but with different extensions
openssl x509 -enddate -noout -in /usr/share/ca-certificates/mozilla/COMODO_RSA_Certification_Authority.crt
notAfter=Jan 18 23:59:59 2038 GMT
openssl x509 -enddate -noout -in /etc/ssl/certs/COMODO_RSA_Certification_Authority.pem
notAfter=Jan 18 23:59:59 2038 GMT
Comment From: zuiderkwast
Interesting. Yes, the CA cert store location seems to be different on every OS.
I found a list using the source code of an application that can find and use system's CA certs automatically. This is where it would look for a trusted CA cert bundle:
Linux: * "/etc/ssl/certs/ca-certificates.crt" (Debian, Ubuntu, Gentoo) * "/etc/pki/tls/certs/ca-bundle.crt" (Fedora, RHEL 6, Amazon Linux) * "/etc/ssl/ca-bundle.pem" (OpenSUSE) * "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem" (CentOS, RHEL 7) * "/etc/ssl/cert.pem" (Alpine Linux)
FreeBSD/OpenBSD/NetBSD:
- "/etc/ssl/cert.pem"
- "/etc/openssl/certs/cacert.pem" (netbsd (if installed))
- "/etc/openssl/certs/ca-certificates.crt"
- "/usr/local/share/certs/ca-root-nss.crt"
SunOS: * "/etc/certs/CA/" (Oracle Solaris, some older illumos distros) * "/etc/ssl/cacert.pem" (OmniOS)
MacOS doesn't seem to have the CA certs in the file system, but IIUC, OpenSSL can use MacOS key store API to get them, if it's compiled with that.
Comment From: zuiderkwast
If you have curl installed, curl-config --ca can tell you where the system CA bundle is located. I believe it's usually a good idea to use the system's CA certs (except if you're using your own self-signed CA certificates for clients and servers within your own network).