Quarks docker run unable to find valid certification path to requested target - quarkus

i tried to build a container that runs my Quarkus application in JVM mode, i was able to run
./mvnw package
docker build -f src/main/docker/Dockerfile.jvm -t quarkus/myapp-jvm .
but when I ran
docker run -i --rm -p 8080:8080 quarkus/myapp-jvm
it failed with error:
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
I've already installed the certs
echo $GRAALVM_HOME
export JAVA_HOME=$GRAALVM_HOME
echo $JAVA_HOME
/Library/Java/JavaVirtualMachines/graalvm-ce-java17-22.0.0.2/Contents/Home
sudo keytool -importcert -file netskope-bundle.pem -alias netskope-bundle -keystore $JAVA_HOME/lib/security/cacerts
on my box i also have Java 13 installed and added the same certs there too
/Library/Java/JavaVirtualMachines/zulu-13.jdk/Contents/Home
my setup:
java -version
openjdk version "17.0.2" 2022-01-18
OpenJDK Runtime Environment GraalVM CE 22.0.0.2 (build 17.0.2+8-jvmci-22.0-b05)
OpenJDK 64-Bit Server VM GraalVM CE 22.0.0.2 (build 17.0.2+8-jvmci-22.0-b05, mixed mode, sharing)
mvn -version
Apache Maven 3.8.4 (9b656c72d54e5bacbed989b64718c159fe39b537)
Maven home: /usr/local/Cellar/maven/3.8.4/libexec
Java version: 17.0.2, vendor: GraalVM Community, runtime: /Library/Java/JavaVirtualMachines/graalvm-ce-java17-22.0.0.2/Contents/Home
Default locale: en_US, platform encoding: UTF-8
OS name: "mac os x", version: "10.15.7", arch: "x86_64", family: "mac"
why do i still get this error?

Add this to your application.properties file:
quarkus.tls.trust-all=true

I believe you are receiving this error because the certificates aren't in the cacerts of the JVM running inside your container.
I guess you only imported the certificates to the host machine.
In this project I added to the Dockerfile one instruction to copy the cert file and then another to import it to the JVM cacerts:
COPY certificates /tmp/ssl
RUN keytool -importcert -noprompt -keystore /etc/alternatives/jre/lib/security/cacerts -storepass changeit -file /tmp/ssl/b3-api.crt -alias "b3-api-root"
Complete Dockerfile
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.3
ARG JAVA_PACKAGE=java-11-openjdk-headless
ARG RUN_JAVA_VERSION=1.3.8
ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en'
# Install java and the run-java script
# Also set up permissions for user `1001`
RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \
&& microdnf update \
&& microdnf clean all \
&& mkdir /deployments \
&& chown 1001 /deployments \
&& chmod "g+rwX" /deployments \
&& chown 1001:root /deployments \
&& curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \
&& chown 1001 /deployments/run-java.sh \
&& chmod 540 /deployments/run-java.sh \
&& echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security
# Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size.
ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
# We make four distinct layers so if there are application changes the library layers can be re-used
COPY --chown=1001 target/quarkus-app/lib/ /deployments/lib/
COPY --chown=1001 target/quarkus-app/*.jar /deployments/
COPY --chown=1001 target/quarkus-app/app/ /deployments/app/
COPY --chown=1001 target/quarkus-app/quarkus/ /deployments/quarkus/
COPY certificates /tmp/ssl
RUN keytool -importcert -noprompt -keystore /etc/alternatives/jre/lib/security/cacerts -storepass changeit -file /tmp/ssl/b3-api.crt -alias "b3-api-root"
EXPOSE 8080
USER 1001
ENTRYPOINT [ "/deployments/run-java.sh" ]
Making sure the certificates are correct
If you imported the certificates correctly to the cacerts of the JVM of your host machine, running the application like this should work:
./mvnw quarkus:dev

Related

cannot run thinkorswim behind corporate firewall: "unable to find valid certification path to requested target"

In windows, when I install and run thinkorswim inside company network (with its own self-signed ssl cert), it cannot connect via https to tdameritrade's server. How do I update tos's java runtime with the self-signed cert?
open command prompt in windows and run the following command to install company's cacert into thinkorswim's jre:
cd C:\<thinkorswim-install-dir>\jre\bin\
keytool.exe -import -trustcacerts -noprompt -storepass changeit -alias mycertificate -keystore ..\lib\security\cacerts -file c:\mycert.cer
For MacOS
cd /Applications/thinkorswim/.install4j/jre.bundle/Contents/Home/jre/bin
./keytool -import -trustcacerts -noprompt -storepass changeit -alias mycertificate -keystore ../lib/security/cacerts -file /path/to/mycert.cer

Amazon Keyspace NoHostAvailableException

I am running a Spring Boot application and using Spring boot cassandra to connect to keyspace.
Following are the properties being used:
spring.data.cassandra.contact-points=cassandra.us-east-2.amazonaws.com
spring.data.cassandra.port=9142
spring.data.cassandra.ssl=true
I am passing cassandra truststore key as vm argument.
From my local dev environment it works perfectly fine without any issue.
When I created a docker image with exactly same cassandra configuration and deployed it in AWS cloud (using ECS) it fails every time with following exception
Invocation of init method failed; nested exception is com.datastax.driver.core.exceptions.NoHostAvailableException: All host(s) tried for query failed (tried: cassandra.us-east-2.amazonaws.com/3.12.23.159:9142 (com.datastax.driver.core.exceptions.TransportException: cassandra.us-east-2.amazonaws.com/3.12.23.159:9142 Cannot connect)-
Here also I am passing trustore key as vm argument and verified certificate as well by enabling log.
Can some one please help me with this issue.
Use the following container as a reference on how to setup a container
https://github.com/aws-samples/amazon-keyspaces-toolkit
For Java apps you may need to add the pem to the truststore with the additional info
RUN mkdir $CQLSHRC_HOME
RUN yum install -y openssl && \
yum install -y java-1.8.0-openjdk && \
yum install -y tar
#create jks truststore
RUN openssl x509 -outform der -in $CQLSHRC_HOME/AmazonRootCA1.pem -out temp_file.der && \
keytool -import -alias new-cassandra -keystore $CQLSHRC_HOME/cassandra_truststore.jks -file temp_file.der -storepass amazon -noprompt
ENV javax.net.ssl.trustStore=$CQLSHRC_HOME/cassandra_truststore.jks
ENV javax.net.ssl.trustStorePassword=amazon

How to install self signed certificate for Java in Docker/Kubernetes?

I am running a Spring Boot application in Docker with Kubernetes.
While downloading an image I am getting the below error:
sun.security.validator.ValidatorException: PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException: unable to
find valid certification path to requested target
How can I solve this problem?
Try adding the certificates to the docker image and installing them via keytool
After adding certificate to the docker now i am able to access the remote site.
Assure I need to download files or access abc.com over https
Add below lines to your Docker file
USER root
RUN cd $JAVA_HOME/lib/security && echo -n | openssl s_client -connect abc.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > abc.com.crt && keytool -keystore cacerts -keypass changeit -storepass changeit -noprompt -import -v -trustcacerts -alias abc.com -file abc.com.crt

Using a VPN for a travis deploy script

I'm using a corporate install of Travis-CI for CI. So far triggering a build through a commit and using encrypted values work well.
For deployment however I need to connect to a server that I only can reach via a VPN tunnel (OpenVPN based).
I'm looking for a sample .travis.yml file that has a VPN connection. So far my file looks like this:
language: java
addons:
ssh_known_hosts: some.host.in.vpn.org
git:
depth: 3
before_install:
- sudo apt-get install -qq rpm
- openssl aes-256-cbc -K $encrypted_fancynumber_key -iv $encrypted_fancynumber_iv -in supersecret_rsa.enc -out supersecret_rsa -d
before_deploy:
- eval "$(ssh-agent -s)"
- chmod 600 $TRAVIS_BUILD_DIR/supersecret_rsa
- ssh-add $TRAVIS_BUILD_DIR/supersecret_rsa
deploy:
provider: script
skip_cleanup: true
script: rsync -r --delete-after --quiet $TRAVIS_BUILD_DIR/build travisdeploy#some.host.in.vpn.org:/opt/coolapp/war
on:
branch: master
The script runs a maven script (language Java makes travis look for a pom.xml) and rsyncs the build directory onto a server. Works nice without the VPN inbetween.

Clojure Compojure Ring and https

I'm using Clojure (ring and compojure) to build a web app and I don't know where to start with https. I have a registration and login that will need to be secured, then once they're authenticated they'll need to stay in https.
I can't seem to find a good tutorial on setting up https in general or for a clojure app specifically.
I found this answer: How do you enable https and http->https redirects in ring / compojure
Does that mean I can write my compojure app as if there's no https and have nginx sit in front and take care of all that for me?
Yes, the standard procedure is to have nginx act as a reverse proxy in front of the ring based webapp. This is considered secure and it's easier to maintain because it's more standard. Every clojure based site I know about does it this way.
The reverse proxy approach does seem to be the most common option. However, as an 'experiment' I looked into using just ring, jetty compojure etc with https. It isn't that hard.
First you need to use keytool to generate a self signed certificate and install that into a new keystore. The keytool docs a pretty good and can walk you through this process. Note that if you use a self signed cert, you will need to add an exception rule with most browsers to say that you trust that certificate.
Copy the keystore file created into the root of your project tree
Update the jetty config parameters to specify ssl, ssl-port, keystore file and keystore password.
Add the ring/ring-defaults package to your project.clj
Add the wrap-defaults middleware with the secure-site-defaults configuration option to force https connections i.e. redirect http connections to https.
This is not the setup I would recommend for production use, but I found it simpler than also having to configure ngix when doing development etc. The hardest part was working through the keytool process. However, just following the docs and examples gives you enough provided you don't allow yoruself to be overwhelmed by all the options - just keep it simple.
Something like
keytool -genkeypair \
-keystore $SSL_DIR/$KS_NAME \
-keypass $PASSWORD \
-storepass $PASSWORD \
-keyalg RSA -keysize 2048 \
-alias root \
-ext bc:c \
-dname "$ROOT_CN"
echo "CA Key"
keytool -genkeypair \
-keystore $SSL_DIR/$KS_NAME \
-alias ca \
-ext bc:c \
-keypass $PASSWORD \
-keyalg RSA -keysize 2048 \
-storepass $PASSWORD \
-dname "$CA_CN"
echo "Server Key"
keytool -genkeypair \
-keystore $SSL_DIR/$KS_NAME \
-alias server \
-keypass $PASSWORD \
-storepass $PASSWORD \
-keyalg RSA -keysize 2048 \
-dname "$SERVER_CN"
echo "Root Cert"
keytool -keystore $SSL_DIR/$KS_NAME \
-storepass $PASSWORD \
-alias root \
-exportcert \
-rfc > $SSL_DIR/root.pem
echo "CA Cert"
keytool -storepass $PASSWORD \
-keystore $SSL_DIR/$KS_NAME \
-certreq \
-alias ca | keytool -storepass $PASSWORD \
-keystore $SSL_DIR/$KS_NAME \
-gencert \
-alias root \
-ext BC=0 \
-rfc > $SSL_DIR/ca.pem
echo "Import CA cert"
keytool -keystore $SSL_DIR/$KS_NAME \
-storepass $PASSWORD \
-importcert \
-alias ca \
-file $SSL_DIR/ca.pem
echo "Server Cert"
keytool -storepass $PASSWORD \
-keystore $SSL_DIR/$KS_NAME \
-certreq \
-alias server | keytool -storepass $PASSWORD \
-keystore $SSL_DIR/$KS_NAME \
-gencert \
-alias ca \
-rfc > $SSL_DIR/server.pem
echo "Import Server Cert"
cat $SSL_DIR/root.pem $SSL_DIR/ca.pem $SSL_DIR/server.pem | \
keytool -keystore $SSL_DIR/$KS_NAME \
-storepass $PASSWORD \
-keypass $PASSWORD \
-importcert \
-alias server
Usually application-level code does not care whether it's HTTPS or HTTP. Most often it's provided by application server or a proxy in front of it. If you're familiar, your choices are pretty much the same as in the Java world.
If you're using the Jetty adapter, it has ssl? and ssl-port options. See docs here and related blog post here.
You can run your Ring app in plain HTTP and place a proxy such as Nginx or Apache in front of it. Proxy would implement HTTPS and forward requests as plain HTTP to your app.
Another solution is to try nginx-clojure (http://nginx-clojure.github.io) by which you can deploy ring app on nginx directly. nginx can do https things more efficiently.
Here's an example about nginx.conf
http {
### jvm dynamic library path
jvm_path '/usr/lib/jvm/java-7-oracle/jre/lib/amd64/server/libjvm.so';
### my app jars e.g. clojure-1.5.1.jar , groovy-2.3.4.jar ,etc.
jvm_var my_other_jars 'my_jar_dir/clojure-1.5.1.jar';
### my app classpath, windows user should use ';' as the separator
jvm_options "-Djava.class.path=jars/nginx-clojure-0.3.0.jar:#{my_other_jars}";
server {
listen 80 default deferred;
server_name example.com;
###redirect to https
rewrite ^/(.+) https://example.com/$1 permanent;
}
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /opt/mycert/my-unified.crt;
ssl_certificate_key /opt/mycert/my.key;
location /myapp {
content_handler_name 'my/ringapp';
}
}
}
You can get more details about SSL server configurations from http://nginx.org/en/docs/http/configuring_https_servers.html
You can setup Ring middleware that will force all requests to use SSL. An easy way to do this is to use the ring-defaults library.
From the ring-defaults documentation:
There are four configurations included with the middleware
- api-defaults
- site-defaults
- secure-api-defaults
- secure-site-defaults
...
The "secure" defaults force SSL. Unencrypted HTTP URLs are redirected to the equivlant HTTPS URL, and various headers and flags are sent to prevent the browser sending sensitive information over insecure channels.
Also note:
In order to enable local development without SSL, you can set which ring-defaults set you use based on an environment variable. Environ helps with this.
In order to enable SSL to work behind a load balancer or proxy, you have to set :proxy to true in the ring-defaults map.
Here's the general idea:
(ns my-app
(:require [ring.middleware.defaults :refer :all]
[environ.core :refer [env]]))
(defroutes app-routes
(GET "/" [] "home page"))
(def app
(-> app-routes
(wrap-defaults (if (= (env :environment) "dev")
site-defaults
(assoc secure-site-defaults :proxy true))))
I don't know about nginx, but I have this working for an app deployed to Heroku.
Its very simple. If you want to enable HTTPS support in your web app, just do the following:
Generate a Java KeyStore(.jks) file using a linux tool called keytool.
In the ring map of your project.clj file, add the following:
{
:ssl? true
:ssl-port 8443
:keystore "path to the jks file"
:key-password "the keystore password"
}
Fire up the server. Now your web app is HTTPS enabled.
I had a similar problem while I was trying to test my Sign-In using Social Media code which obviously had to authenticate over HTTPS and this did the trick for me.

Resources