Search code examples
javaopenshiftssh-keys

Openshift: how to add ssh key to pod


I need an ssh key in my Openshift pod to access a server from inside my application logic (Java). My application tries to add a id_ed25519 file to the pod on startup:

String executeString = "mkdir ~/.ssh && echo $SSH_CERT > ~/.ssh/id_ed25519";
Process process = Runtime.getRuntime().exec(executeString);
...

$SSH_CERT is a OS secret string value.

This doesn't throw an error but also doesn't seem to work (ls ~/.ssh/ in the pods terminal doesn't list anything). Is ~/.ssh the right place for this file? Is there a different, easier way to add files to a pod?


Solution

  • I finally found a solution! :)

    There were two main problems that I had to solve:

    1. Permissions were wrong - the app couldn't create folders or edit the file
    2. The stdout and errors of a process aren't logged anywhere by default. Thus I didn't have any error logs that would have helped.

    1. How to solve permissions

    I added the directory and file inside my Dockerfile. Then I gave permissions to the newly created file. Security input: If you can, try not to give permissions to all users like I do (we have dynamic user ids...) but give it to least possible users.

    RUN mkdir -p ~/.ssh/
    RUN touch ~/.ssh/id_ed25519
    RUN chmod a+rw ~/.ssh/id_ed25519
    

    2. How to get proper output

    I added a method that looks like this:

    private void attachCommandOutputStreams(Process process) {
        InputStream inputStream = process.getInputStream();
        InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
    
        InputStream errorStream = process.getErrorStream();
        InputStreamReader errorStreamReader = new InputStreamReader(errorStream);
        BufferedReader errorBufferedReader = new BufferedReader(errorStreamReader);
    
        // Create a separate thread to read from the error stream
        Thread errorThread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    String line;
                    while ((line = errorBufferedReader.readLine()) != null) {
                        log.error(line);
                    }
                } catch (IOException e) {
                    log.error(e.toString());
                }
            }
        });
        errorThread.start();
    
        try {
    
            // Read from the standard output stream in the current thread
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                log.info("Standard output: " + line);
            }
    
            // Wait for the error thread to complete
            errorThread.join();
    
            // Close the readers
            bufferedReader.close();
            errorBufferedReader.close();
        } catch (InterruptedException | IOException e) {
            log.error("Error: ", e);
    
        }
    }
    

    Then it is called like this:

     Process process = Runtime.getRuntime().exec(new String[]{"sh", "-c", executeString});
     this.attachCommandOutputStreams(process);
    
     int exitCode = process.waitFor();
     assert exitCode == 0;