The SSL/TLS communication occurs between the client (e.g., Artifactory) and the server (e.g., DockerHub or Red Hat CDN) in two ways.
In one way SSL, the server does not validate the identity of the client to start the secure communication. Here is the flow of events during the One-way SSL handshake process.
-
The client will say Hello to the server and request the resource over HTTPS protocol.
-
The server responds with its public certificate and public key by saying Hello.
-
The client checks the server's public certificate against its trust store and verifies the received server certificate, including the expiration date of the certificate, the common name, etc.
-
The client uses the server's public key to send a symmetric session key which can be decrypted by the server's private key.
-
The server decrypts the symmetric session key using its private certificate and sends back the encrypted session key to the client to establish secure communication.
Here is a sample demonstration for your reference.
curl -v https://testjpd.jfrog.io/artifactory/api/system/ping
* Trying X.X.X.X:443...
* Connected to testjpd.jfrog.io (X.X.X.X) port 443
* ALPN: curl offers h2,http/1.1
* (304) (OUT), TLS handshake, Client hello (1):
* CAfile: /etc/ssl/cert.pem
* CApath: none
* (304) (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN: server accepted http/1.1
* Server certificate:
* subject: CN=*.jfrog.io
* start date: Jan 17 00:00:00 2025 GMT
* expire date: Feb 16 23:59:59 2026 GMT
* subjectAltName: host "testjpd.jfrog.io" matched cert's "*.jfrog.io"
* issuer: C=US; O=DigiCert Inc; OU=www.digicert.com; CN=GeoTrust TLS RSA CA G1
* SSL certificate verify ok.
* using HTTP/1.1
> GET /artifactory/api/system/ping HTTP/1.1
> Host: testjpd.jfrog.io
> User-Agent: curl/8.4.0
> Accept: */*
>
< HTTP/1.1 200
< Date: Tue, 08 July 2025 06:55:55 GMT
< Content-Type: text/plain
< Transfer-Encoding: chunked
< Connection: keep-alive
< X-JFrog-Version: Artifactory/7.78.3 77803900
< X-Artifactory-Id: 5fd23443d0a231b74bfc50461aa513ef4dfcd619
< X-Artifactory-Node-Id: testjpd-artifactory-primary-2
< Strict-Transport-Security: max-age=31536000; includeSubDomains
< X-Request-ID: bd73946cf93ac6069e5cd438713ffa18
<
* Connection #0 to host testjpd.jfrog.io left intact
OK
In Two-Way SSL, the server also validates the identity of the client to start the secure communication. In Artifactory, the two-way SSL implementation can be seen if we configure a remote registry that requires certificate-based authentication (Ex: RedHat CDN).
For example, after importing the certificate, create a new RPM remote repository. Under URL pass the URL to the repository(e.g.https://cdn.redhat.com/content/dist/rhel/server/7/7Server/x86_64/sat-tools/6.5/os) and add the certificate by navigating to Advanced => Remote Authentication => SSL / TLS Certificate and select the certificate from the drop-down list.
If we perform the test connection on such types of remote repositories, the upstream registry requests a client certificate and validates it before establishing secure communication. In case the client certificate is invalid, we will encounter the “forbidden” error.
What is the best way to check if the certificate is present in the JVM keystore?
The Java JDK has an inbuilt tool(i.e. keytool) for checking the content of the JVM keystore. We can execute the following command.
/opt/jfrog/artifactory/app/third-party/java/bin/keytool -v -list -keystore /opt/jfrog/artifactory/app/third-party/java/lib/security/cacerts -storepass changeit
What is the best way to download the SSL/TLS certificate?
We can use the built-in OpenSSL tool available in the Linux operating system to download the certificate from the remote registry URLs. Here is the sample command for the reference.
openssl s_client -connect <secure authentication server IP and port> -showcerts < /dev/null > server.crt
You may refer to the following example commands.
RedHat CDN:
openssl s_client -connect cdn.redhat.com:443 -showcerts < /dev/null > redhat-server.crt
LDAP or Active Directory:
openssl s_client -connect the.ldap.server.net:636 -showcerts < /dev/null > ldap-server.crt
OAuth (Use the Authorization URL). For example, with GitHub:
openssl s_client -connect github.com:443 -showcerts < /dev/null > github-server.crt
How to view the SSL/TLS certificate content?
We can use OpenSSL to view the content of the SSL/TLS certificate. Here is the sample command for the reference.
openssl x509 -in server.crt -text
What is the process for importing SSL certificates into the JVM keystore?
If you wish to import SSL/TLS certificates to the Artifactory JVM keystore, we need to place them in $JFROG_HOME/artifactory/var/etc/security/keys/trusted directory. During every startup, the Artifactory Router loads the certificates from the trusted folder to the JVM keystore. If the certificate is already present in the keystore, then it will be skipped during the startup process. Here is a sample log entry for your reference.
2024-02-18T19:23:00.175Z [jfrou] [INFO ] [1c96451bef34e403] [trusted.go:56 ] [main ] [] - Following certificates were successfully loaded as trusted CAs for TLS communication:
[/opt/jfrog/artifactory/var/data/router/keys/trusted/access-root-ca.crt /opt/jfrog/artifactory/var/etc/security/keys/trusted/redhat-cdn-server.crt]
Alternatively, we can also add the certificate to each application's KeyStore. For example, to add a certificate to the JFrog Artifactory Keystore, you can add it directly to the host's JVM's trusted Keystore. We recommend referring to our documentation on Managing TLS certificates for detailed insights.
Note
When you modify/change the certificate (ex: expiry dates after the renewal) and for changes to take effect, we MUST change the file name or create a new file for the modified certificate. Otherwise, if we change the content of the certificate without modifying the name, Artifactory will skip it during the startup process and you will get an PKIX (certificate error)
SSL certificate issues from the Artifactory perspective:
While running the Artifactory instance, we may run into SSL/TLS issues in the following scenarios.
Debugging:
Upstream connection issues
If there is an SSL error in logs while connecting to the upstream Artifactory server(Ex: Dockerhub, RedHat CDN), enable the following debug logger. This logger will print entries when you perform the “Test Connection” on remote repository settings.
<logger name="org.artifactory.ui.rest.service.admin.configuration.repositories.util.RemoteRepositoryTestUrl">
<level value="debug"/>
</logger>
Note
Please remove this logger configuration once the troubleshooting process is complete.
If these debug loggers don’t help, add any one of the following debug loggers in the Artifactory system configuration file(system.yaml) to capture the JVM-level loggers.
-Djavax.net.debug=ssl,handshake
(or)
-Djavax.net.debug=all (This will print heavy logging, recommended for non-prod environment debugging)
Here is the sample configuration for your reference.
## ARTIFACTORY TEMPLATE
artifactory:
#port: 8081
## Artifactory Tomcat connector customization on the Artifactory port
tomcat:
## Artifactory connector settings
## Set up an HTTPS connector for artifactory.
## This opens a port in addition to the default HTTP connector.
httpsConnector:
## Enable connector with SSL/TLS
enabled: true
## Port to use for the HTTPS connector
port: 8443
## Certificate file to use
certificateFile: "$JFROG_HOME/artifactory/var/etc/artifactory/security/ssl/server.crt"
## Certificate key file to use.
certificateKeyFile: "$JFROG_HOME/artifactory/var/etc/artifactory/security/ssl/server.key"
## Extra configuration for the HTTPS connector.
## For example extraConfig: "SSLProtocol='TLSv1+TLSv1.1+TLSv1.2'"
#extraConfig: ""
In case of any misconfiguration of these parameters, Artifactory will not start or generate exceptions. We need to check the Tomcat’s Catalina logs and $JFROG_HOME/artifactory/app/artifactory/tomcat/conf
/server.xml file which gets generated on every Artifactory startup for further debugging.
Reverse proxy level SSL issues
In general, the SSL termination occurs at the reverse proxy layer if it is configured in front of Artifactory. Here are the sample configurations of two different third-party applications.
Apache:
<VirtualHost *:443>
SSLEngine on
SSLCertificateFile /etc/httpd/ssl/yourdomain.com.crt
SSLCertificateKeyFile /etc/httpd/yourdomain.com.key
SSLProxyEngine on
……
</VirtualHost>
Nginx:
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_certificate /etc/nginx/ssl/yourdomain.com.crt;
ssl_certificate_key /etc/nginx/ssl/yourdomain.com.key;
ssl_session_cache shared:SSL:1m;
ssl_prefer_server_ciphers on;
We need to make sure these certificates and keys are present in the respective paths with relevant permissions. There are a few cases where we may have to remove/block a few SSL protocols based on organizational requirements.
If there are any issues during the startup or while running the application, kindly check the reverse proxy logs for more details. In case the SSL certificates are about to expire, we need to get the new certificates and replace them. In such cases, a restart of the reverse proxy is required. No need to restart Artifactory since we are not making any changes in it.