I’ve been working on a Groovy Spring Boot application using Snap and have been trying to get it to run as a service so that we can be sure it will run on startup.
It runs without issue as a normal command but when run as a service it throws an exception when it tries to open an SSL connection. Specifically when it calls javax.net.ssl.SSLContext.init() it throws a error like this:
java.security.KeyManagementException: java.security.KeyStoreException: initialization failed
at org.bouncycastle.jsse.provider.ProvSSLContextSpi.selectTrustManager(Unknown Source)
at org.bouncycastle.jsse.provider.ProvSSLContextSpi.engineInit(Unknown Source)
at javax.net.ssl.SSLContext.init(SSLContext.java:282)
at javax.net.ssl.SSLContext$init$0.call(Unknown Source)
...
Caused by: java.security.KeyStoreException: initialization failed
at org.bouncycastle.jsse.provider.ProvTrustManagerFactorySpi.engineInit(Unknown Source)
at javax.net.ssl.TrustManagerFactory.init(TrustManagerFactory.java:250)
...
Caused by: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty
at java.security.cert.PKIXParameters.setTrustAnchors(PKIXParameters.java:200)
at java.security.cert.PKIXParameters.<init>(PKIXParameters.java:120)
at java.security.cert.PKIXBuilderParameters.<init>(PKIXBuilderParameters.java:104)
at org.bouncycastle.jsse.provider.ProvX509TrustManagerImpl.<init>(Unknown Source)
...
Googling around after this error seems to suggest that it’s caused by missing ca certs:
https://stackoverflow.com/questions/6784463/error-trustanchors-parameter-must-be-non-empty
https://stackoverflow.com/questions/4764611/java-security-invalidalgorithmparameterexception-the-trustanchors-parameter-mus
But the cacerts file seem to be present in the snap directory after installation in multiple places:
etc/default/cacerts
etc/ssl/certs/java/cacerts
usr/lib/jvm/java-8-openjdk-armhf/jre/lib/security/cacerts
This seems to be picked up fine when the snap is run as a normal command, but when it’s running as a service it either doesn’t seem to be able to find them or it can’t read them.
Is there any difference in environment when running a snap as a service that would account for this?
Other info: My snapcraft.yml file is quite simple and looks like this:
name: foo
version: '1.1'
summary: bar
description: foobar
confinement: devmode
grade: devel
apps:
service:
command: java -Dspring.config.location=/config/dir/ -Dspring.config.name=foo -jar $SNAP/jar/foo-1.1.jar
daemon: simple
plugs:
- home
- network-bind
- network-observe
- serial-port
parts:
local:
plugin: gradle
source: .
gradle-options: [build]
The only difference with the non-service version of the project (that works fine) is “daemon: simple” line is removed from snapcraft.yml
We’re also setting the following ssl settings via the Spring Boot properties file:
server.port
server.ssl.enabled
server.ssl.key-store
server.ssl.key-store-password
server.ssl.key-password
server.ssl.key-alias
server.ssl.key-store-type
server.ssl.ciphers
It’s also probably worth noting that the environment it’s running in does not have its own Java runtime other than what is bundled in the snap.