Search code examples
securityjenkinsencryptionsshssh-keys

Is pasting a private key into the Jenkins web portal secure?


In Jenkins, I've only every seen one method for storing a private ssh key credential.

This method is recommended by everybody: Open the Jenkins server web portal in a web browser, go to Credentials, and under Add Credentials, select SSH Username with private key, paste the private key into the web page, and hit ok.

This, I assume, uses an HTML form to send the private key in a POST request over HTTPS to the Jenkins server, which then saves the private key locally on the server's disk.

The problem: The top voted answer to the question "How to securely send private keys?" states that a private ssh key can only be secured by not transmitting it at all.

My question: is pasting a private key into the Jenkins web portal and transmitting them over HTTPS actually secure? If not, what is the best way to get a private key into the Jenkins credentials?


Solution

  • in situ

    Using the web UI for this is probably secure enough for almost every use case, and is hard to beat with respect to convenience.

    Nevertheless, generating private keys where they are needed is certainly good advice, and is definitely possible with Jenkins. One approach:

    • SSH into the Jenkins server, and generate the keys
    • Run some groovy in the script console to create the Jenkins credential
    • Exfiltrate the public key
    • Delete the generated keys on the server

    In this example, on the Jenkins server both $HOME and $JENKINS_HOME point to /var/jenkins_home, and the keys are generated in ~/temp.


    Generate the key on Jenkins server

    ssh [email protected]
    mkdir ~/temp
    cd ~/temp
    ssh-keygen -t rsa -b 4096 -C "some-meaningful-label" -f "./my-in-situ-key"
    

    This creates my-in-situ-key and my-in-situ-key.pub in /var/jenkins_home/temp.


    Create the Jenkins credential

    In Jenkins script console:

    import com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey
    import com.cloudbees.plugins.credentials.CredentialsScope
    import com.cloudbees.plugins.credentials.domains.Domain
    
    def domain = Domain.global()
    
    def store = Jenkins.instance.getExtensionList('com.cloudbees.plugins.credentials.SystemCredentialsProvider')[0].getStore()
    
    def privateKeyString = new File('/var/jenkins_home/temp/my-in-situ-key').text
    def keySource = new BasicSSHUserPrivateKey.DirectEntryPrivateKeySource(privateKeyString)
    
    def privateKeyCredential = new BasicSSHUserPrivateKey(
        CredentialsScope.GLOBAL,
        "temp-stack-overflow-key",      // id
        "jenkins",                      // username
        keySource,                      // private key
        "",                             // passphrase
        "Temporary Demo Key"            // description
    )
    
    store.addCredentials(domain, privateKeyCredential)
    "Credential Added"
    

    Test the credential before cleaning up.


    Clean up

    Grab the public key and be sure to delete the private key on your way out the door.

    cat ~/temp/my-in-situ-key.pub
    rm -rf ~/temp
    

    Relevant Javadoc