0

I have an Elasticsearch endpoint as a service (I have no access to config/server). The service provided me with a username and password, and a single "TLS certificate" file, which when decoded says that it is RSA Public-Key: (2048 bit)

I am running nginx and want to use it as a reverse proxy for this Elasticsearch endpoint. So I have to get nginx to handle the application of the certificate when it relays the request. Similar to this example config (from nginx docs):

location /upstream {
        proxy_pass                    https://backend.example.com;
        proxy_ssl_certificate         /etc/nginx/client.pem;
        proxy_ssl_certificate_key     /etc/nginx/client.key;
        proxy_ssl_protocols           TLSv1 TLSv1.1 TLSv1.2;
        proxy_ssl_ciphers             HIGH:!aNULL:!MD5;
        proxy_ssl_trusted_certificate /etc/nginx/trusted_ca_cert.crt;
        proxy_ssl_verify        on;
        proxy_ssl_verify_depth  2;
        proxy_ssl_session_reuse on;
    }

Any idea how I can generate the client.pem and client.key required (e.g. using openssl) -- when all I have to start with is a single public key file?

(edit)

Not sure if it helps, but this is how we are doing something similar with this public key, in a Java application. It takes the key file and builds an object that has a fully-formed x509 certificate, which gets sent to Elastic along with the request...and it works.

File caFile = new File("elastic_key_file.crt");
CertificateFactory fact = CertificateFactory.getInstance("X.509");
FileInputStream is = new FileInputStream(caFile);
X509Certificate cer = (X509Certificate) fact.generateCertificate(is);
KeyStore keystore = KeyStore.getInstance("JKS");
keystore.load(null, null);
keystore.setCertificateEntry("public", cer);

(edit)

Ended up being not related to SSL or that certificate Elastic gave me...which ended up being a point of confusion for me as I thought it was important. Here are the proxy settings in nginx that worked:

# Get the origin into a variable, for substitution into the header, below
map $http_origin $allow_origin {
    ~^https?://(.*\.)?incomingdomain.com(:\d+)?$ $http_origin;
    default "";
}

proxy_redirect off;
add_header 'Access-Control-Allow-Origin' $allow_origin;
add_header 'Access-Control-Allow-Methods' 'OPTIONS, HEAD, GET, POST, PUT, DELETE';
add_header 'Access-Control-Allow-Headers' 'X-Requested-With, Content-Type, Content-Length, Authorization';

location /ElasticSearch/someSearch {
    proxy_pass https://elasticdomain/_search;
}
C C
  • 423
  • 1
  • 4
  • 16
  • I'd comment, but I don't have enough reputation. You can't. You'll need the private key. – Necco Jan 06 '21 at 17:37

1 Answers1

0

This is impossible, you cannot create certificate and private key from a certificate. This would be a huge security problem if this was possible since the certificate is considered public and the private key should be kept secret.

... but this is how we are doing something similar with this public key ...

The code you show has nothing to do with your requirement. It just loads a certificate from a file (generateCertificate does not create a certificate, it just creates a certificate object from existing data). No private key is created here.

   proxy_ssl_certificate         /etc/nginx/client.pem;
   proxy_ssl_certificate_key     /etc/nginx/client.key;

I think you are on the wrong path in the first place. While you don't provide any useful details about the certificate you got, I assume that this certificate is the certificate of the Elasticsearch endpoint and you should use it to verify that the certificate is the expected one. In this case you would need to use the option proxy_ssl_trusted_certificate file and there is no private key needed for this.

What you instead try to do with proxy_ssl_certificate and proxy_ssl_certificate_key is to authenticate yourself against the server with the certificate, i.e. use it as a client certificate.

Steffen Ullrich
  • 13,227
  • 27
  • 39
  • thanks. So, maybe if I just generate a self-signed cert and use that along with the public key I got from Elastic as the ssl 'trusted certificate', it might work? – C C Jan 06 '21 at 18:16
  • @CC: see updated answer. I think you just try to use the wrong options in the first place. – Steffen Ullrich Jan 06 '21 at 18:21
  • Steffen, thank you. I will give that a shot. I'm sorry I didn't provide further details but literally what I got from the ES endpoint was "here is your certificate". I had to decode it to see that it is a public RSA keyed file. – C C Jan 06 '21 at 18:34
  • Unfortunately nothing seems to work. I can't get ES to accept the connection even with setting proxy_ssl_trusted_certificate (and also adding my own signed key) to the nginx reverse proxy. Looks like I will have to find another solution other than Elasticsearch... – C C Jan 06 '21 at 20:37
  • Turns out I was on a completely wrong path, largely due to my lack of understanding about the purpose for the certificate Elasticsearch provides. In the end, I got it to work and it was a very simply proxy_pass with nginx -- but with the added return headers for Access-Control-Allow-Origin, Access-Control-Allow-Methods and Access-Control-Allow-Headers. This 'tricks' the browser that made the request to the reverse proxy into allowing the pre-flight and POST to happen. I didn't even need the certificate at all. – C C Jan 07 '21 at 02:32