diff --git a/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/ubuntu/git/base/Git.kt b/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/ubuntu/git/base/Git.kt index 1ec684e..8f36731 100644 --- a/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/ubuntu/git/base/Git.kt +++ b/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/ubuntu/git/base/Git.kt @@ -2,13 +2,11 @@ package org.domaindrivenarchitecture.provs.framework.ubuntu.git.base import org.domaindrivenarchitecture.provs.framework.core.Prov import org.domaindrivenarchitecture.provs.framework.core.ProvResult -import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.base.isHostKnown -import org.domaindrivenarchitecture.provs.framework.core.echoCommandForText import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.* +import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.base.KNOWN_HOSTS_FILE +import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.base.trustHost import java.io.File -val knownHostsFile = "~/.ssh/known_hosts" - fun Prov.gitClone(repo: String, path: String, pullIfExisting: Boolean = true): ProvResult = task { val dir = cmdNoEval("basename $repo .git").out?.trim() @@ -49,68 +47,6 @@ fun Prov.trustGitlab() = task { gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9 gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY= """.trimIndent() - addTextToFile("\n" + gitlabFingerprints + "\n", File(knownHostsFile)) + addTextToFile("\n" + gitlabFingerprints + "\n", File(KNOWN_HOSTS_FILE)) } - -/** - * Adds ssh keys for specified host (which also can be an ip-address) to ssh-file "known_hosts" - * Either add the specified rsaFingerprints or - if null - add automatically retrieved keys. - * Note: adding keys automatically is vulnerable to a man-in-the-middle attack and not considered secure. - */ -// todo: consider making function public and moving to ssh package -private fun Prov.trustHost(host: String, fingerprintsOfKeysToBeAdded: Set?) = task { - if (isHostKnown(host)) { - return@task ProvResult(true, out = "Host already known") - } - if (!checkFile(knownHostsFile)) { - createDir(".ssh") - createFile(knownHostsFile, null) - } - if (fingerprintsOfKeysToBeAdded == null) { - // auto add keys - cmd("ssh-keyscan $host >> $knownHostsFile") - } else { - // logic based on https://serverfault.com/questions/447028/non-interactive-git-clone-ssh-fingerprint-prompt - val actualKeys = findSshKeys(host) - if (actualKeys == null || actualKeys.size == 0) { - return@task ProvResult(false, out = "No valid keys found for host: $host") - } - val actualFingerprints = getFingerprintsForKeys(actualKeys) - for (fingerprintToBeAdded in fingerprintsOfKeysToBeAdded) { - var indexOfKeyFound = -1 - - // search for fingerprint in actual fingerprints - for ((i, actualFingerprint) in actualFingerprints.withIndex()) { - if (actualFingerprint.contains(fingerprintToBeAdded)) { - indexOfKeyFound = i - break - } - } - if (indexOfKeyFound == -1) { - return@task ProvResult( - false, - err = "Fingerprint ($fingerprintToBeAdded) could not be found in actual fingerprints: $actualFingerprints" - ) - } - cmd(echoCommandForText(actualKeys.get(indexOfKeyFound) + "\n") + " >> $knownHostsFile") - } - ProvResult(true) - } -} - - -/** - * Returns a list of valid ssh keys for the given host (host can also be an ip address) - */ -private fun Prov.findSshKeys(host: String): List? { - return cmd("ssh-keyscan $host 2>/dev/null").out?.split("\n")?.filter { x -> "" != x } -} - - -/** - * Returns a list of fingerprints of the given sshKeys; the returning list has same size and order as the specified list of sshKeys - */ -private fun Prov.getFingerprintsForKeys(sshKeys: List): List { - return sshKeys.map { x -> cmd("echo \"$x\" | ssh-keygen -lf -").out ?: "" } -} diff --git a/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/ubuntu/keys/base/Ssh.kt b/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/ubuntu/keys/base/Ssh.kt index 16b047c..8745a7b 100644 --- a/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/ubuntu/keys/base/Ssh.kt +++ b/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/ubuntu/keys/base/Ssh.kt @@ -1,11 +1,18 @@ package org.domaindrivenarchitecture.provs.framework.ubuntu.keys.base import org.domaindrivenarchitecture.provs.framework.core.Prov +import org.domaindrivenarchitecture.provs.framework.core.ProvResult +import org.domaindrivenarchitecture.provs.framework.core.echoCommandForText +import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.checkFile import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.createDir +import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.createFile import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.createSecretFile import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.KeyPair +const val KNOWN_HOSTS_FILE = "~/.ssh/known_hosts" + + /** * installs ssh keys for active user */ @@ -16,19 +23,6 @@ fun Prov.configureSshKeys(sshKeys: KeyPair) = task { } -/** - * Specifies a host or Ip to be trusted - * - * ATTENTION: - * This method is NOT secure as a man-in-the-middle could compromise the connection. - * Don't use this for critical systems resp. environments - */ -@Suppress("unused") -fun Prov.trustServer(hostOrIp: String) = task { - cmd("ssh-keyscan $hostOrIp >> ~/.ssh/known_hosts") -} - - /** * Checks if the specified hostname or Ip is in a known_hosts file * @@ -38,3 +32,64 @@ fun Prov.isHostKnown(hostOrIp: String) : Boolean { return cmdNoEval("ssh-keygen -F $hostOrIp").out?.isNotEmpty() ?: false } + +/** + * Adds ssh keys for specified host (which also can be an ip-address) to ssh-file "known_hosts" + * Either add the specified rsaFingerprints or - if null - add automatically retrieved keys. + * Note: adding keys automatically is vulnerable to a man-in-the-middle attack, thus considered insecure and not recommended. + */ +fun Prov.trustHost(host: String, fingerprintsOfKeysToBeAdded: Set?) = task { + if (isHostKnown(host)) { + return@task ProvResult(true, out = "Host already known") + } + if (!checkFile(KNOWN_HOSTS_FILE)) { + createDir(".ssh") + createFile(KNOWN_HOSTS_FILE, null) + } + if (fingerprintsOfKeysToBeAdded == null) { + // auto add keys + cmd("ssh-keyscan $host >> $KNOWN_HOSTS_FILE") + } else { + // logic based on https://serverfault.com/questions/447028/non-interactive-git-clone-ssh-fingerprint-prompt + val actualKeys = findSshKeys(host) + if (actualKeys == null || actualKeys.size == 0) { + return@task ProvResult(false, out = "No valid keys found for host: $host") + } + val actualFingerprints = getFingerprintsForKeys(actualKeys) + for (fingerprintToBeAdded in fingerprintsOfKeysToBeAdded) { + var indexOfKeyFound = -1 + + // search for fingerprint in actual fingerprints + for ((i, actualFingerprint) in actualFingerprints.withIndex()) { + if (actualFingerprint.contains(fingerprintToBeAdded)) { + indexOfKeyFound = i + break + } + } + if (indexOfKeyFound == -1) { + return@task ProvResult( + false, + err = "Fingerprint ($fingerprintToBeAdded) could not be found in actual fingerprints: $actualFingerprints" + ) + } + cmd(echoCommandForText(actualKeys.get(indexOfKeyFound) + "\n") + " >> $KNOWN_HOSTS_FILE") + } + ProvResult(true) + } +} + + +/** + * Returns a list of valid ssh keys for the given host (host can also be an ip address) + */ +private fun Prov.findSshKeys(host: String): List? { + return cmd("ssh-keyscan $host 2>/dev/null").out?.split("\n")?.filter { x -> "" != x } +} + + +/** + * Returns a list of fingerprints of the given sshKeys; the returning list has same size and order as the specified list of sshKeys + */ +private fun Prov.getFingerprintsForKeys(sshKeys: List): List { + return sshKeys.map { x -> cmd("echo \"$x\" | ssh-keygen -lf -").out ?: "" } +}