Last active
March 2, 2022 15:23
-
-
Save hanserya/43b00162741fa3022481301db60e8acd to your computer and use it in GitHub Desktop.
Use Mounted Volume for SSH Key-Based Authentication in Dockerized Spring Cloud Config Server
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This is only needed if you want to run the server on your machine without setting environment variables. | |
spring: | |
cloud: | |
config: | |
server: | |
git: | |
uri: ssh://your-repo |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@EnableConfigServer | |
@SpringBootApplication | |
@Import(SshLocationOverrideConfiguration.class) | |
public class ConfigServerApplication { | |
public static void main(String[] args) { | |
SpringApplication.run(ConfigServiceApplication.class, args) | |
.start(); //<-- THIS IS IMPORTANT! | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
version: '3.4' | |
services: | |
config-server: | |
image: config-server | |
container_name: config-server | |
environment: | |
spring.cloud.config.server.git.uri: ssh://your-repo | |
SPRING_CLOUD_CONFIG_SERVER_GIT_SSHLOCATION: /var/ssh-config | |
build: | |
context: . | |
dockerfile: ./Dockerfile | |
target: app | |
args: | |
sourceCodeLocation: '.' | |
settingsFile: 'maven-settings.xml' | |
volumes: | |
- <redirectedSshLocation>:/var/ssh-config:ro | |
ports: | |
- "8888:8080" | |
- "4000:4000" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
FROM maven:3.2-jdk-8 AS build | |
ARG sourceCodeLocation=. | |
ARG settingsFile=settings.xml | |
COPY ${sourceCodeLocation} /src | |
COPY ${settingsFile} /root/.m2/settings.xml | |
WORKDIR /src | |
RUN mvn package | |
FROM openjdk:8 AS app | |
COPY --from=build /<app.target directory>/<yourModuleName>*.jar /usr/app/server.jar | |
ADD https://github.com/ufoscout/docker-compose-wait/releases/download/2.4.0/wait /wait | |
RUN chmod +x /wait | |
ENTRYPOINT /wait && java -jar $JAVA_OPTS /usr/app/server.jar |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//This class may or may not be needed in your implementation. The Spring Boot application was not starting the same way from | |
// my IDE as it was within the Docker container. The inconsistency led to a situation where the invocation of | |
// JGitEnvironmentRepository.afterPropertiesSet was overriding my attempt to inject the RedirectedSshKeyLocationSessionFactory. | |
//The end result was the the first call to the config server running within the Docker container always failed | |
// with an ssh authenticatin exception. This "hack" resolves that problem. | |
//I actually have a .NET background and am unsure of whether or not there is another way that I can accomplish this without such | |
// an ugly implementation - but it works =\ | |
public class RedirectedSshKeyLocationContextStartedListener implements ApplicationListener<ContextStartedEvent> { | |
@Override | |
public void onApplicationEvent(ContextStartedEvent contextStartedEvent) { | |
String sshKeyLocation = contextStartedEvent.getApplicationContext().getEnvironment().getProperty("spring.cloud.config.server.git.sshLocation"); | |
if(isBlank(sshKeyLocation)) { | |
return; | |
} | |
JschConfigSessionFactory sessionFactory = (JschConfigSessionFactory) SshSessionFactory.getInstance(); | |
if(sessionFactory.getClass() != OverriddenSshKeyLocationSessionFactory.class) { | |
SshSessionFactory sessionFactoryDecorator = new OverriddenSshKeyLocationSessionFactory(sshKeyLocation, sessionFactory); | |
SshSessionFactory.setInstance(sessionFactoryDecorator); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class RedirectedSshKeyLocationSessionFactory extends JschConfigSessionFactory { | |
private final String sshKeyLocation; | |
private final BiConsumer<OpenSshConfig.Host, Session> configureInvoker; | |
RedirectedSshKeyLocationSessionFactory(String sshKeyLocation, JschConfigSessionFactory decoratedSessionFactory) { | |
this.sshKeyLocation = sshKeyLocation; | |
this.configureInvoker = createConfigureInvoker(decoratedSessionFactory); | |
} | |
@Override | |
protected void configure(OpenSshConfig.Host host, Session session) { | |
configureInvoker.accept(host, session); | |
} | |
@Override | |
protected JSch getJSch(OpenSshConfig.Host hc, FS fs) { | |
try { | |
String identity = getFileAbsolutePath("id_rsa"); | |
String knownHosts = getFileAbsolutePath("known_hosts"); | |
JSch jsch = super.getJSch(hc, fs); | |
jsch.removeAllIdentity(); | |
jsch.addIdentity(identity); | |
jsch.setKnownHosts(knownHosts); | |
return jsch; | |
} catch (Exception ex) { | |
throw new RuntimeException("Unable to redirect the Jsch identity provider to the specified key location due to an unexpected exception.", ex); | |
} | |
} | |
private String getFileAbsolutePath(String fileName) { | |
return Paths | |
.get(sshKeyLocation, fileName) | |
.toAbsolutePath() | |
.toString(); | |
} | |
private BiConsumer<OpenSshConfig.Host, Session> createConfigureInvoker(final JschConfigSessionFactory decoratedSessionFactory) { | |
return (host, session) -> { | |
try { | |
Class<?> parentClass = decoratedSessionFactory.getClass(); | |
Method configureMethod = parentClass.getDeclaredMethod("configure", OpenSshConfig.Host.class, Session.class); | |
configureMethod.setAccessible(true); | |
configureMethod.invoke(decoratedSessionFactory, host, session); | |
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { | |
e.printStackTrace(); | |
} | |
}; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class RedirectedSshLocationTransportConfigCallback extends FileBasedSshTransportConfigCallback { | |
private final String sshLocation; | |
RedirectedSshLocationTransportConfigCallback(MultipleJGitEnvironmentProperties environmentProperties, String sshKeyLocation) { | |
super(environmentProperties); | |
this.sshKeyLocation = sshKeyLocation; | |
} | |
@Override | |
public void configure(Transport transport) { | |
super.configure(transport); | |
JschConfigSessionFactory sessionFactory = (JschConfigSessionFactory) SshSessionFactory.getInstance(); | |
SshSessionFactory sessionFactoryDecorator = new RedirectedSshKeyLocationSessionFactory(sshKeyLocation, sessionFactory); | |
SshSessionFactory.setInstance(sessionFactoryDecorator); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
org.springframework.context.ApplicationListener=\ | |
<fully qualified package>.RedirectedSshKeyLocationContextStartedListener |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Configuration | |
@AutoConfigureBefore(ConfigServerConfiguration.class) | |
@ConditionalOnProperty("spring.cloud.config.server.git.sshLocation") | |
public class SshLocationOverrideConfiguration { | |
@Bean | |
public TransportConfigCallback customTransportCallback( | |
MultipleJGitEnvironmentProperties environmentProperties, | |
@Value("${spring.cloud.config.server.git.sshLocation}") String sshKeyLocation) { | |
Path path = Paths.get(sshKeyLocation); | |
if(Files.notExists(path)) { | |
throw new RuntimeException("The ssh location does not exist!"); | |
} | |
path = Paths.get(sshKeyLocation, "id_rsa"); | |
if(Files.notExists(path) && !Files.isReadable(path)) { | |
throw new RuntimeException("The private key does not exist within the specified ssh directory!"); | |
} | |
path = Paths.get(sshKeyLocation, "known_hosts"); | |
if(Files.notExists(path) && !Files.isReadable(path)) { | |
throw new RuntimeException("The known hosts file does not exist within the specified ssh directory!"); | |
} | |
return new RedirectedSshLocationTransportConfigCallback(environmentProperties, sshKeyLocation); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment