PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path

Bonjour,
dans le cadre de notre upgrade v5, j’ai un problème bloquant d’accès à des ressources exposées sur des serveurs (internes) dont la configuration https n’est pas conforme aux attendus par défaut du client http(s) intégré.
En l’occurrence, nous avons cette erreur bloquant lors des tentatives d’accès à de telles ressources :
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path.

N’ayant pas la main sur les sources concernées, est-il possible de débrayer ce mécanisme de protection globalement ? (nous sommes déployés en Intranet sécurisé et les sources concernées sont toutes internes donc le risque afférent à ces connexions chiffrées par des certificats auto-signés est acceptable - au moins en attendant de gérer cette dette convenablement en reconfigurant les sources identifiées).

Il y a toujours la possibilité d’ajouter des certificate authority (CA) “maison” à nos images Docker pour les mettre dans les trusted CA de Java de l’OS du container.

cf. Simplicité® documentation/90-operation/docker

Si tu as le certificat de la CA qui signe vos certificats SSL internes c’est la bonne approche. De mémoire c’est ce que vous faisiez jusqu’ici.

Merci beaucoup pour ton retour rapide.
Oui c’est déjà le cas dans nos Dockerfile:

COPY chain_bundle.pem /etc/pki/ca-trust/source/anchors/
RUN /bin/update-ca-trust extract

Mais le problème est à la source (des serveurs http/https qui embarquent des certificats auto-signés).

Sinon il est surement aussi possible de dire à Java de ne jamais vérifier aucun certificats (ex: via un -Dcom.sun.net.ssl.checkRevocation=false ou dans le genre => je n’ai jamais essayé, source: Is there a java setting for disabling certificate validation? - Stack Overflow)

Pour l’instant je n’arrive pas à le faire fonctionner…
J’ai comparé sur un environnement toujours en v4 en accédant à la même source https (auto-signée) et ça passe bien. C’est donc un comportement nouveau de la v5.

L’intégration de notre chaîne de certification se fait (comme indiqué dans mon post précédent) en recopiant un fichier PEM contenant toute la chaîne de certification interne dans /etc/pki/ca-trust/source/anchors/ puis en appelant /bin/update-ca-trust extract.

Cette procédure doit-elle évoluer dans le contexte de la V5?

Non pas de différence à ce niveau.

Mais les images par défaut récentes (y compris celles de la 4.0) sont buildées actuellement avec un OpenJDK 17 Eclipse Temurin (= Adoptium) car celui distribué sur le repo “epel” de CentOS est buggué à ce stade.

Si tu n’est pas à jour sur tes images 4.0 ça peut être une piste pour expliquer une différence sinon non.

Pour voir si c’est bien un pb de JVM 17 tu peux faire le test avec l’image utilisant le OpenJDK 11 standard de CentOS : simplicite/platform:5-latest-openjdk-11

Je confirme qu’avec cette image les calls http/https (re)fonctionnent bien.
Par contre, je n’ai plus aucun code qui compile car tous nos switch statements sont codés selon la nouvelle syntaxe introduite avec le JDK 13… :sob:

Notre production est actuellement sur le build Version=4.0.P25 BuiltOn=2021-09-28 22:59 (revision 680201342705438284ecf4de6c17600177b839b1) intégrant le JDK 16.

Y-a-t-il une image v5 fixée sur le JDK 16?

Les OpenJDK 12, 13, 14, 15 et 16 n’existent plus (en tout cas il ne sont plus distribué sur CentOS), on ne builde donc plus d’images avec cette JVM mais uniquement avec des JVM 11 (LTS) et 17.

Pour plus de détails => la situation actuelle fait que la 17 de CentOS n’est pas encore officiellement distribuée => elle n’est dispo que sur le répo “epel” en tant que “latest” (en remplacement de la 16 qui était la “latest” jusque là) => or cette version 17 “epel” pose de gros pbs, donc temporairement on utilise un OpenJDK Eclipse Temurin qui ne pose pas ces pbs.

On ne peut pas revenir sur la 16 qui n’est plus distribuée donc la seule autre option que tu as c’est les images basées sur la 11 (qui elle est dans le repo “base” de CentOS).

On attend avec impatience que la 17 arrive (sans bugs) dans le repos “base” de CentOS, car là la situation est bancale

OK je comprends… :sob: :speech_balloon:

Mais sur le fond je ne sais pas si ton pb est liée à la JVM Eclipse Temurin => je pense car il doit avoir son propre store de certificats et ne regarde pas dans le store “standard” de l’OS

Il n’y a qu’en testant avec la JVM 11 “standard” qu’on le saura avec certitude. Il y a 99% de chances que ton code spécifique soit compatible 11 (le moteur Simplicité version 5 est compilé avec un JDK 11).

En attendant je vais regarder comment accéder au store d’une JVM non gérée par l’OS, sachant que cela ne sera plus d’actualité quand le JDK 17 sera officiellement distribué

Ok merci bcp…
J’avais commencé à modifier les sections de code pour le rendre compatible JDK 11 mais comme on a utilisé les propositions d’optimisation d’IntelliJ un peu partout, ça concerne une masse significative d’instructions concernées.

OK tant pis pour la JVM 11 alors…

Le Dockerfile à utiliser pour les images avec une JVM autre qu’une JVM “standard” de CentOS est du genre:

FROM simplicite/platform:5-latest
COPY myca.pem /usr/local/tomcat
RUN dnf install -y openssl && dnf clean all && \
    openssl x509 -in myca.pem -inform pem -out myca.der -outform der && \
    /usr/local/jdk/bin/keytool -importcert -noprompt -cacerts -storepass changeit -alias myca -file myca.der

Plus tard je verrai pour “cabler” ça directement dans nos images pour rendre ça plus simple

1 Like

Dans les images buildées ce soir le package openssl est déjà installé, le Dockerfile se simplifie donc en:

FROM simplicite/platform:5-latest
COPY myca.pem /usr/local/tomcat
RUN openssl x509 -in myca.pem -inform pem -out myca.der -outform der && \
    /usr/local/jdk/bin/keytool -importcert -noprompt -cacerts -storepass changeit -alias myca -file myca.der

Merci beaucoup David, ça semble fonctionner sur les calls internes Simplicité (comme la comparaison de module via une url https fournie par exemple).

J’ai par contre de grandes difficultés à faire fonctionner nos appels ad-hoc implémentés sur les couches basses (pour configurer un proxy).

ça sort a priori du cadre du support Simplicité mais comme je sèche, je tente ma chance en sollicitant ton expertise. J’ai l’impression que je dois ajouter quelque-chose qui fait référence à la chaîne de certification insérée dans la nouvelle image mais je n’arrive pas à trouver quoi ni comment faire.

Voici comment j’ai codé la chose :

(extrait du code lançant un call)

HttpResponse httpResponse = buildHttpClient(url).execute(httpMethod);

(extrait du code partagé implémentant l’initialisation du client http et du contexte SSL)

public static HttpClient buildHttpClient(String url) throws NoSuchAlgorithmException, KeyStoreException, IOException, CertificateException, UnrecoverableKeyException, KeyManagementException {
		HttpClient httpClient;
		boolean needProxy = !url.startsWith(Grant.getSystemAdmin().getContextURL());
		if (needProxy) {
			String proxyData = Grant.getSystemAdmin().getParameter("RENAULT_PROXY");
			if (StringUtils.isNotBlank(proxyData)) {
				String[] proxyDataPart = proxyData.split(",");
				HttpHost proxy = new HttpHost(proxyDataPart[0].trim(), Integer.parseInt(proxyDataPart[1].trim()), proxyDataPart[2].trim());
				httpClient = HttpClientBuilder.create().setProxy(proxy).setSSLContext(buildSSLContext(new File(CERTIFICATE_PATH), CERTIFICATE_PASSWORD)).build();
			}  else {
				httpClient = new DefaultHttpClient();
			}
		} else {
			httpClient = HttpClientBuilder.create().setSSLContext(buildSSLContext(new File(CERTIFICATE_PATH), CERTIFICATE_PASSWORD)).setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).build();
		}
		return httpClient;
	}
	
	private static SSLContext buildSSLContext(File keyFile, String keyPassword) throws NoSuchAlgorithmException, KeyStoreException, IOException, CertificateException, UnrecoverableKeyException, KeyManagementException {
		KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
		KeyStore keyStore = KeyStore.getInstance("PKCS12");
		
		InputStream keyInput = new FileInputStream(keyFile);
		keyStore.load(keyInput, keyPassword.toCharArray());
		keyInput.close();
		
		keyManagerFactory.init(keyStore, keyPassword.toCharArray());
		
		SSLContext context = SSLContext.getInstance("TLS");
		context.init(keyManagerFactory.getKeyManagers(), null, new SecureRandom());
		
		return context;
	}

Bon, finalement, j’ai réussi en instanciant le httpclient comme ceci (j’ai restreint le cas aux contextes des sources internes connues et maîtrisées) :

httpClient = HttpClients.custom().setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, TrustAllStrategy.INSTANCE).build()).setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).build();

Je suis loin d’être un expert de ce genre de choses.

Je pense que l’ajout du certificat CA via keytool est valable pour l’ensemble des appels effectués depuis la JVM au moins pour ceux qui passent par les couches basses (java.net.*.) comme ceux de la classe helper HTTPTool (dans laquelle il y a des méthodes pour passer par un proxy avec authent, ex: HTTPTool)

Si tu passe par d’autres clients HTTP (ex: les clients Apache) il faut peut être ajouter les certificats (host et/ou CA) manuellement, je ne sais pas trop, mais à priori j’aurais tendance à penser que c’est inutile voire contre-productif.

PS: as tu essayé avec le client Unirest qu’on a embarqué (cf. Documentation - Unirest in Java: Simplified, lightweight HTTP client library.) ? Visiblement il a aussi des méthodes pour gérer des proxies avec authent (ex: Documentation - Unirest in Java: Simplified, lightweight HTTP client library.)

Merci de ton retour.
Je vais creuser cette piste et te te dis.

En fait, on est descendu d’une couche uniquement pour pouvoir faire un setProxy(…) sur le httpclient… donc on pourrait revenir au standard si le Tool.readUrl le prenait en charge.

Les Tool.readUrl ne sont que des cas particuliers d’utilisation des méthodes de HTTPTool => Si tu dois “descendre d’un étage” c’est plutôt dans HTTPTool qu’il faut aller.

Autant pour moi :slight_smile: je regarde ça asap…