Jeff did a really good job explaining what I glossed over earlier. Assuming the site you are trying to reach doesn’t have a certificate that is signed by a known CA (for example, a company service that is only accessed from within the organization), you can follow these instructions to obtain the service’s certificate, put it in a new truststore, and configure NiFi. I concur with Jeff; adding custom certs to cacerts is a bad idea.
Let’s say your NiFi instance is hosted on “nifi.vic.com” and the service you want to connect to is “other.service.com” and running on port 443. From your command-line, run the following “openssl s_client -connect other.service.com:443 -showcerts”. This command will attempt to make a TLS connection to that service, and will print the provided certificates in PEM format. You should see an “issuer” and “subject” for each. A subject is “who am I” and the issuer is “who vouches for me”. At level 0 is the actual service certificate. That is the one you want to copy. However, if that cert could change (I.e. there is a pool of application servers, each with their own cert, or it’s a Docker container that gets a new cert every time it’s instantiated) you will want to get the signing cert (unlikely to change). Either way, there will be a section of output that looks like: -----BEGIN CERTIFICATE----- MIIDZTCCAk2gAwIBAgIKAWTeM3kDAAAAADANBgkqhkiG9w0BAQsFADAxMQ0wCwYD ... MDG+K3rCeieSBPOnGNrEC/PiA/CvaMXBEog+xPAw1SgYfuCz4rlM3BdRa54z3+oO lc8xbzd7w8Q3 -----END CERTIFICATE----- That is called the “PEM-encoded certificate”. It means it is in Base64 encoding. Copy all of that into a file named “service.pem”. Now you will import that certificate into a JKS truststore file. Follow the instructions here [1], starting at Step 2 (you already have the PEM file). This will create a truststore file with that trusted cert in it, which you can reference in your SSLContextService. There are more details on certificate formats here [2], but it’s not quite tailored to your use case, so you’ll have to patch things together. [1] https://docs.oracle.com/cd/E35976_01/server.740/es_admin/src/tadm_ssl_convert_pem_to_jks.html [2] https://nifi.apache.org/docs/nifi-docs/html/administration-guide.html#using-an-existing-intermediate-certificate-authority-ca Andy LoPresto [email protected] [email protected] PGP Fingerprint: 70EC B3E5 98A6 5A3F D3C4 BACE 3C6E F65B 2F7D EF69 > On Dec 26, 2018, at 11:14, Jeff <[email protected]> wrote: > > There was a bit of a grammar issue with my previous message... InvokeHTTP > should be *presented* with a cert that's signed by one of the CAs in cacerts. > You can use your browser to go to the website/URL that you've configured in > InvokeHTTP, and take a look at the certificate for the site. > > For example, going to www.google.com using Google Chrome, you can click on > the padlock icon next to the URL, and click on "Certificate", which should > show you information about the cert that was presented for www.google.com, > and you can see that the root CA is from "GlobalSign". The owner/issuer of > that "GlobalSign" root CA is: > CN=GlobalSign, O=GlobalSign, OU=GlobalSign Root CA - R2 > Then, you can look in your JDK's cacerts to see if that CA is included: > keytool -storepass changeit -keystore > /Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib/security/cacerts > -list -v | grep -i "GlobalSign" > You should see output similar to the following: > > Alias name: globalsignr2ca [jdk] > Owner: CN=GlobalSign, O=GlobalSign, OU=GlobalSign Root CA - R2 > Issuer: CN=GlobalSign, O=GlobalSign, OU=GlobalSign Root CA - R2 > [URIName: http://crl.globalsign.net/root-r2.crl] > Alias name: globalsigneccrootcar4 [jdk] > Owner: CN=GlobalSign, O=GlobalSign, OU=GlobalSign ECC Root CA - R4 > Issuer: CN=GlobalSign, O=GlobalSign, OU=GlobalSign ECC Root CA - R4 > Alias name: globalsignca [jdk] > Owner: CN=GlobalSign Root CA, OU=Root CA, O=GlobalSign nv-sa, C=BE > Issuer: CN=GlobalSign Root CA, OU=Root CA, O=GlobalSign nv-sa, C=BE > Alias name: globalsignr3ca [jdk] > Owner: CN=GlobalSign, O=GlobalSign, OU=GlobalSign Root CA - R3 > Issuer: CN=GlobalSign, O=GlobalSign, OU=GlobalSign Root CA - R3 > Alias name: globalsigneccrootcar5 [jdk] > Owner: CN=GlobalSign, O=GlobalSign, OU=GlobalSign ECC Root CA - R5 > Issuer: CN=GlobalSign, O=GlobalSign, OU=GlobalSign ECC Root CA - R5 > > You can see that the cert with an owner/issuer of "CN=GlobalSign, > O=GlobalSign, OU=GlobalSign Root CA - R2" is in the alias "globalsignr2ca > [jdk]" in the output, which should match the root CA with which > www.google.com's cert is signed. You can look at more details of that cert > with keytool: > > keytool -storepass changeit -keystore > /Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib/security/cacerts > -list -v -alias "globalsignr2ca [jdk]" > > I won't list that output here, but you can compare it with the detailed view > provided by your browser if you click on the root certificate. > > If the issuer of the cert presented by a website cannot be found in the > truststore of the SSLContextService that InvokeHTTP is using, you'll see that > "PKIX path" exception. This can happen with self-signed certs, if the > issuer's cert has not been added to the truststore. Not all public CAs are > present in the JDK's cacerts by default, and like self-signed certs, the CA > cert will need to be added to a truststore. I don't recommend adding certs > to cacerts, but Andy may have a different view on this. If you need to > access sites with certs that are not part of cacerts, and you trust the > issuer of the cert for the site being accessed, you should create a custom > truststore that contains the issuer's cert, and configure an > SSLContextService that uses the custom truststore. > > This isn't a comprehensive guide on CA certs, but I hope it helps you to work > through the issue. Please let us know if we can help further! > > - Jeff > > >> On Mon, Dec 24, 2018 at 9:34 AM l vic <[email protected]> wrote: >> Could you try using an explicit path to the cacerts provided by your >> JDK/JRE, instead of referring to $JAVA_HOME? >> Tried without success... >> Were you able to successfully start the SSLContextService after configuring >> it? >> Yes >> InvokeHTTP needs to present a certificate that is signed by a CA that is in >> the default cacerts >> Not sure how to identify one that is supposed to be presented >> >> >>> On Sun, Dec 23, 2018 at 1:32 PM Jeff <[email protected]> wrote: >>> Could you try using an explicit path to the cacerts provided by your >>> JDK/JRE, instead of referring to $JAVA_HOME? Andy gave an example of >>> "/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/jre/lib/security/cacerts", >>> which you would update with the path to the JDK you are using. >>> Referencing an environment variable (without using EL) will not work for a >>> NiFi property. It does not appear that EL is supported for the keystore >>> and truststore properties, as that could lead to security issues. Those >>> properties have validators that should also verify that the >>> keystore/truststore exists and is readable. Were you able to successfully >>> start the SSLContextService after configuring it? >>> >>> Also, as Andy mentioned, the URL you are using in InvokeHTTP needs to >>> present a certificate that is signed by a CA that is in the default >>> cacerts. Can you please verify this? You can get a list of what is >>> contained in cacerts by using keytool, and specifying the path to cacerts, >>> the password, and the list command. For example: >>> >>> keytool -storepass changeit -keystore >>> /Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib/security/cacerts >>> -list >>> >>> - Jeff >>> >>>> On Fri, Dec 21, 2018 at 2:55 PM l vic <[email protected]> wrote: >>>> I put "default" parameters for trust-store: >>>> Path: $JAVA_HOME/jre/lib/security/cacerts >>>> Password: changeit (default) >>>> Type: JKS >>>> and got "invalid path" exception ( see below) >>>> How does that missing cert file should look like? >>>> Thanks again... >>>> >>>> 2018-12-21 14:46:00,021 ERROR [Timer-Driven Process Thread-1] >>>> o.a.nifi.processors.standard.InvokeHTTP >>>> InvokeHTTP[id=0929346d-d742-1fd9-e41a-8e4324b73349] Yielding processor due >>>> to exception encountered as a source processor: >>>> javax.net.ssl.SSLHandshakeException: >>>> sun.security.validator.ValidatorException: PKIX path building failed: >>>> sun.security.provider.certpath.SunCertPathBuilderException: unable to find >>>> valid certification path to requested target: {} >>>> javax.net.ssl.SSLHandshakeException: >>>> sun.security.validator.ValidatorException: PKIX path building failed: >>>> sun.security.provider.certpath.SunCertPathBuilderException: unable to find >>>> valid certification path to requested target >>>> at sun.security.ssl.Alerts.getSSLException(Alerts.java:192) >>>> at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1964) >>>> at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:328) >>>> at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:322) >>>> at >>>> sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1614) >>>> at >>>> sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216) >>>> at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1052) >>>> at sun.security.ssl.Handshaker.process_record(Handshaker.java:987) >>>> at >>>> sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1072) >>>> at >>>> sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1385) >>>> at >>>> sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1413) >>>> at >>>> sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1397) >>>> at >>>> okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:267) >>>> at >>>> okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.java:237) >>>> at >>>> okhttp3.internal.connection.RealConnection.connect(RealConnection.java:148) >>>> at >>>> okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:186) >>>> at >>>> okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:121) >>>> at >>>> okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:100) >>>> at >>>> okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42) >>>> at >>>> okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92) >>>> at >>>> okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67) >>>> at >>>> okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93) >>>> at >>>> okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92) >>>> at >>>> okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67) >>>> at >>>> okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93) >>>> at >>>> okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92) >>>> at >>>> okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:120) >>>> at >>>> okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92) >>>> at >>>> okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67) >>>> at >>>> okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:179) >>>> at okhttp3.RealCall.execute(RealCall.java:63) >>>> at >>>> org.apache.nifi.processors.standard.InvokeHTTP.onTrigger(InvokeHTTP.java:709) >>>> at >>>> org.apache.nifi.processor.AbstractProcessor.onTrigger(AbstractProcessor.java:27) >>>> at >>>> org.apache.nifi.controller.StandardProcessorNode.onTrigger(StandardProcessorNode.java:1122) >>>> at >>>> org.apache.nifi.controller.tasks.ContinuallyRunProcessorTask.call(ContinuallyRunProcessorTask.java:147) >>>> at >>>> org.apache.nifi.controller.tasks.ContinuallyRunProcessorTask.call(ContinuallyRunProcessorTask.java:47) >>>> at >>>> org.apache.nifi.controller.scheduling.QuartzSchedulingAgent$2.run(QuartzSchedulingAgent.java:161) >>>> at >>>> java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) >>>> at java.util.concurrent.FutureTask.run(FutureTask.java:266) >>>> at >>>> java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) >>>> at >>>> java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) >>>> at >>>> java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) >>>> at >>>> java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) >>>> at java.lang.Thread.run(Thread.java:748) >>>> Caused by: sun.security.validator.ValidatorException: PKIX path building >>>> failed: sun.security.provider.certpath.SunCertPathBuilderException: unable >>>> to find valid certification path to requested target >>>> at >>>> sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:397) >>>> at >>>> sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:302) >>>> at sun.security.validator.Validator.validate(Validator.java:260) >>>> at >>>> sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324) >>>> at >>>> sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229) >>>> at >>>> sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124) >>>> at >>>> sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1596) >>>> ... 39 common frames omitted >>>> Caused by: sun.security.provider.certpath.SunCertPathBuilderException: >>>> unable to find valid certification path to requested target >>>> at >>>> sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141) >>>> at >>>> sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126) >>>> at >>>> java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280) >>>> at >>>> sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:392) >>>> ... 45 common frames omitted >>>> >>>> >>>> >>>> >>>>> On Thu, Dec 20, 2018 at 4:14 PM Andy LoPresto <[email protected]> >>>>> wrote: >>>>> You need to configure the truststore properties in the SSLContextService >>>>> — the keystore contains the private key and public certificate the >>>>> service (NiFi) uses to identify itself, but the truststore contains the >>>>> public certificate(s) of external services NiFi should trust. In this >>>>> case, in order to connect to another service at >>>>> https://service.external.com, you will need to have the public >>>>> certificate (pub1) of the External Service or one of the public >>>>> certificates in the chain that signed that pub1. If this is a site on the >>>>> public internet, you can probably use the JVM defaults, as it will likely >>>>> be signed by a known certificate authority. If not, you must obtain that >>>>> public certificate independently, put it in a JKS truststore, and >>>>> populate the controller service properties for it. >>>>> >>>>> JVM truststore: >>>>> >>>>> Path: $JAVA_HOME/jre/lib/security/cacerts (i.e. >>>>> /Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/jre/lib/security/cacerts) >>>>> Password: changeit (default) >>>>> Type: JKS >>>>> >>>>> >>>>> Andy LoPresto >>>>> [email protected] >>>>> [email protected] >>>>> PGP Fingerprint: 70EC B3E5 98A6 5A3F D3C4 BACE 3C6E F65B 2F7D EF69 >>>>> >>>>>> On Dec 20, 2018, at 2:31 PM, l vic <[email protected]> wrote: >>>>>> >>>>>> Hello, >>>>>> I am trying to perform "get" request over SSL from InvokeHTTP >>>>>> nifi-1.5.0-RC1; >>>>>> I configured SSL by the means of a StandardSSLContextService with jks >>>>>> certificate (see attached) >>>>>> When I try to execute processor, i see the following problem: >>>>>> Caused by: java.lang.IllegalStateException: TrustManagerFactoryImpl is >>>>>> not initialized >>>>>> at >>>>>> sun.security.ssl.TrustManagerFactoryImpl.engineGetTrustManagers(TrustManagerFactoryImpl.java:100) >>>>>> Do I have an error in my configuration, or is this bug? keystore >>>>>> file/password combination is valid - i can do that request from cli.... >>>>>> Can I do "insecure" SSL request ( like curl -k) with InvokeHTTP? >>>>>> Below is full stack trace >>>>>> >>>>>> 2018-12-20 14:53:41,116 ERROR [StandardProcessScheduler Thread-3] >>>>>> o.a.n.controller.StandardProcessorNode Failed to invoke @OnScheduled >>>>>> method due to java.lang.RuntimeException: Failed while executing one of >>>>>> processor's OnScheduled task. >>>>>> java.lang.RuntimeException: Failed while executing one of processor's >>>>>> OnScheduled task. >>>>>> at >>>>>> org.apache.nifi.controller.StandardProcessorNode.invokeTaskAsCancelableFuture(StandardProcessorNode.java:1504) >>>>>> at >>>>>> org.apache.nifi.controller.StandardProcessorNode.initiateStart(StandardProcessorNode.java:1330) >>>>>> at >>>>>> org.apache.nifi.controller.StandardProcessorNode.lambda$start$0(StandardProcessorNode.java:1315) >>>>>> at >>>>>> java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) >>>>>> at java.util.concurrent.FutureTask.run(FutureTask.java:266) >>>>>> at >>>>>> java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) >>>>>> at >>>>>> java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) >>>>>> at >>>>>> java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) >>>>>> at >>>>>> java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) >>>>>> at java.lang.Thread.run(Thread.java:748) >>>>>> Caused by: java.util.concurrent.ExecutionException: >>>>>> java.lang.reflect.InvocationTargetException >>>>>> at java.util.concurrent.FutureTask.report(FutureTask.java:122) >>>>>> at java.util.concurrent.FutureTask.get(FutureTask.java:206) >>>>>> at >>>>>> org.apache.nifi.controller.StandardProcessorNode.invokeTaskAsCancelableFuture(StandardProcessorNode.java:1487) >>>>>> ... 9 common frames omitted >>>>>> Caused by: java.lang.reflect.InvocationTargetException: null >>>>>> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) >>>>>> at >>>>>> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) >>>>>> at >>>>>> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) >>>>>> at java.lang.reflect.Method.invoke(Method.java:498) >>>>>> at >>>>>> org.apache.nifi.util.ReflectionUtils.invokeMethodsWithAnnotations(ReflectionUtils.java:137) >>>>>> at >>>>>> org.apache.nifi.util.ReflectionUtils.invokeMethodsWithAnnotations(ReflectionUtils.java:125) >>>>>> at >>>>>> org.apache.nifi.util.ReflectionUtils.invokeMethodsWithAnnotations(ReflectionUtils.java:70) >>>>>> at >>>>>> org.apache.nifi.util.ReflectionUtils.invokeMethodsWithAnnotation(ReflectionUtils.java:47) >>>>>> at >>>>>> org.apache.nifi.controller.StandardProcessorNode$1.call(StandardProcessorNode.java:1334) >>>>>> at >>>>>> org.apache.nifi.controller.StandardProcessorNode$1.call(StandardProcessorNode.java:1330) >>>>>> ... 6 common frames omitted >>>>>> Caused by: java.lang.IllegalStateException: TrustManagerFactoryImpl is >>>>>> not initialized >>>>>> at >>>>>> sun.security.ssl.TrustManagerFactoryImpl.engineGetTrustManagers(TrustManagerFactoryImpl.java:100) >>>>>> at >>>>>> javax.net.ssl.TrustManagerFactory.getTrustManagers(TrustManagerFactory.java:285) >>>>>> at >>>>>> org.apache.nifi.processors.standard.InvokeHTTP.setSslSocketFactory(InvokeHTTP.java:613) >>>>>> at >>>>>> org.apache.nifi.processors.standard.InvokeHTTP.setUpClient(InvokeHTTP.java:545) >>>>>> ... 16 common frames omitted >>>>>> <Screen Shot 2018-12-20 at 3.21.08 PM.png>
