add recognition of ssh key type to determine ssh file names

This commit is contained in:
az 2022-09-10 16:41:36 +02:00
parent 552c6e9445
commit a4bb1d228c
9 changed files with 71 additions and 21 deletions

View file

@ -2,11 +2,12 @@ package org.domaindrivenarchitecture.provs.desktop.domain
import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.KeyPairSource import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.KeyPairSource
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.SshKeyPairSource
@Serializable @Serializable
data class DesktopConfig( data class DesktopConfig(
val ssh: KeyPairSource? = null, val ssh: SshKeyPairSource? = null,
val gpg: KeyPairSource? = null, val gpg: KeyPairSource? = null,
val gitUserName: String? = null, val gitUserName: String? = null,
val gitEmail: String? = null, val gitEmail: String? = null,

View file

@ -7,6 +7,7 @@ import org.domaindrivenarchitecture.provs.framework.ubuntu.git.provisionGit
import org.domaindrivenarchitecture.provs.framework.ubuntu.install.base.aptInstall import org.domaindrivenarchitecture.provs.framework.ubuntu.install.base.aptInstall
import org.domaindrivenarchitecture.provs.framework.ubuntu.install.base.aptPurge import org.domaindrivenarchitecture.provs.framework.ubuntu.install.base.aptPurge
import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.KeyPair import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.KeyPair
import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.SshKeyPair
import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.base.gpgFingerprint import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.base.gpgFingerprint
import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.provisionKeys import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.provisionKeys
import org.domaindrivenarchitecture.provs.framework.ubuntu.user.base.currentUserCanSudo import org.domaindrivenarchitecture.provs.framework.ubuntu.user.base.currentUserCanSudo
@ -31,7 +32,7 @@ internal fun provisionDesktopCmd(prov: Prov, cmd: DesktopCliCommand) {
*/ */
internal fun Prov.provisionDesktop( internal fun Prov.provisionDesktop(
desktopType: DesktopType = DesktopType.BASIC, desktopType: DesktopType = DesktopType.BASIC,
ssh: KeyPair? = null, ssh: SshKeyPair? = null,
gpg: KeyPair? = null, gpg: KeyPair? = null,
gitUserName: String? = null, gitUserName: String? = null,
gitEmail: String? = null, gitEmail: String? = null,
@ -115,7 +116,7 @@ fun Prov.provisionOfficeDesktop(onlyModules: List<String>?) {
fun Prov.provisionBasicDesktop( fun Prov.provisionBasicDesktop(
gpg: KeyPair?, gpg: KeyPair?,
ssh: KeyPair?, ssh: SshKeyPair?,
gitUserName: String?, gitUserName: String?,
gitEmail: String?, gitEmail: String?,
onlyModules: List<String>? onlyModules: List<String>?

View file

@ -21,11 +21,19 @@ class KeyPairSource(val sourceType: SecretSourceType, val publicKey: String, val
} }
} }
@Serializable
class SshKeyPairSource(val sourceType: SecretSourceType, val publicKey: String, val privateKey: String) {
fun keyPair() : SshKeyPair {
val pub = sourceType.secret(publicKey)
val priv = sourceType.secret(privateKey)
return SshKeyPair(pub, priv)
}
}
/** /**
* provisions gpg and/or ssh keys for the current user * provisions gpg and/or ssh keys for the current user
*/ */
fun Prov.provisionKeys(gpgKeys: KeyPair? = null, sshKeys: KeyPair? = null) = task { fun Prov.provisionKeys(gpgKeys: KeyPair? = null, sshKeys: SshKeyPair? = null) = task {
gpgKeys?.let { configureGpgKeys(it, true) } gpgKeys?.let { configureGpgKeys(it, true) }
sshKeys?.let { configureSshKeys(it) } sshKeys?.let { configureSshKeys(it) }
ProvResult(true) // dummy ProvResult(true) // dummy

View file

@ -7,19 +7,18 @@ import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.check
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.createDir 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.createFile
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.createSecretFile import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.createSecretFile
import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.KeyPair import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.SshKeyPair
const val KNOWN_HOSTS_FILE = "~/.ssh/known_hosts" const val KNOWN_HOSTS_FILE = "~/.ssh/known_hosts"
/** /**
* installs ssh keys for active user * Installs ssh keys for active user; ssh filenames depend on the ssh key type, e.g. for public key file: "id_rsa.pub", "id_id_ed25519.pub", etc
*/ */
fun Prov.configureSshKeys(sshKeys: KeyPair) = task { fun Prov.configureSshKeys(sshKeys: SshKeyPair) = task {
createDir(".ssh", "~/") createDir(".ssh", "~/")
createSecretFile("~/.ssh/id_rsa.pub", sshKeys.publicKey, "644") createSecretFile("~/.ssh/id_${sshKeys.sshAlgorithmName}.pub", sshKeys.publicKey, "644")
createSecretFile("~/.ssh/id_rsa", sshKeys.privateKey, "600") createSecretFile("~/.ssh/id_${sshKeys.sshAlgorithmName}", sshKeys.privateKey, "600")
} }

View file

@ -2,7 +2,12 @@ package org.domaindrivenarchitecture.provs.framework.ubuntu.user
import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.KeyPairSource import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.KeyPairSource
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.SshKeyPairSource
@Serializable @Serializable
class UserConfig(val userName: String, val gitEmail: String? = null, val gpg: KeyPairSource? = null, val ssh: KeyPairSource? = null) class UserConfig(
val userName: String,
val gitEmail: String? = null,
val gpg: KeyPairSource? = null,
val ssh: SshKeyPairSource? = null)

View file

@ -17,7 +17,7 @@ internal class ProvisionKeysTest {
// when // when
val res = a.provisionKeys( val res = a.provisionKeys(
KeyPair(Secret(publicGPGSnakeoilKey()), Secret(privateGPGSnakeoilKey())), KeyPair(Secret(publicGPGSnakeoilKey()), Secret(privateGPGSnakeoilKey())),
KeyPair(Secret(publicSSHSnakeoilKey()), Secret(privateSSHSnakeoilKey())) SshKeyPair(Secret(publicSSHRSASnakeoilKey()), Secret(privateSSHRSASnakeoilKey()))
) )
// then // then

View file

@ -129,11 +129,11 @@ i+XV3Dazj3nq/DxUB0neLU/r1afAEiqZAkI=
-----END PGP PRIVATE KEY BLOCK-----""".trimIndent() -----END PGP PRIVATE KEY BLOCK-----""".trimIndent()
} }
fun publicSSHSnakeoilKey(): String { fun publicSSHRSASnakeoilKey(): String {
return """ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDOtQOq8a/Z7SdZVPrh+Icaq5rr+Qg1TZP4IPuRoFgfujUztQ2dy5DfTEbabJ0qHyo+PKwBDQorVohrW7CwvCEVQQh2NLuGgnukBN2ut5Lam7a/fZBoMjAyTvD4bXyEsUr/Bl5CLoBDkKM0elUxsc19ndzSofnDWeGyQjJIWlkNkVk/ybErAnIHVE+D+g3UxwA+emd7BF72RPqdVN39Eu4ntnxYzX0eepc8rkpFolVn6+Ai4CYHE4FaJ7bJ9WGPbwLuDl0pw/Cp3ps17cB+JlQfJ2spOq0tTVk+GcdGnt+mq0WaOnvVeQsGJ2O1HpY3VqQd1AsC2UOyHhAQ00pw7Pi9 snake@oil.com""" return """ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDOtQOq8a/Z7SdZVPrh+Icaq5rr+Qg1TZP4IPuRoFgfujUztQ2dy5DfTEbabJ0qHyo+PKwBDQorVohrW7CwvCEVQQh2NLuGgnukBN2ut5Lam7a/fZBoMjAyTvD4bXyEsUr/Bl5CLoBDkKM0elUxsc19ndzSofnDWeGyQjJIWlkNkVk/ybErAnIHVE+D+g3UxwA+emd7BF72RPqdVN39Eu4ntnxYzX0eepc8rkpFolVn6+Ai4CYHE4FaJ7bJ9WGPbwLuDl0pw/Cp3ps17cB+JlQfJ2spOq0tTVk+GcdGnt+mq0WaOnvVeQsGJ2O1HpY3VqQd1AsC2UOyHhAQ00pw7Pi9 snake@oil.com"""
} }
fun privateSSHSnakeoilKey(): String { fun privateSSHRSASnakeoilKey(): String {
return """ return """
-----BEGIN RSA PRIVATE KEY----- -----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAzrUDqvGv2e0nWVT64fiHGqua6/kINU2T+CD7kaBYH7o1M7UN MIIEowIBAAKCAQEAzrUDqvGv2e0nWVT64fiHGqua6/kINU2T+CD7kaBYH7o1M7UN
@ -163,4 +163,17 @@ fun privateSSHSnakeoilKey(): String {
OUxwE8Su4WnoQc7WjkTG0M3FECAu7TEcF9uqdcEsW+4+JMAhE5oo OUxwE8Su4WnoQc7WjkTG0M3FECAu7TEcF9uqdcEsW+4+JMAhE5oo
-----END RSA PRIVATE KEY----- -----END RSA PRIVATE KEY-----
""".trimIndent() """.trimIndent()
}
fun publicED25519SnakeOilKey(): String {
return """ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGL6JP3FhUZrVIfA9EzcJdlXwq3MHG6+QEFDFeNCxmOE snake@oil.com"""
}
fun privateED25519SnakeOilKey(): String {
return """-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACBi+iT9xYVGa1SHwPRM3CXZV8KtzBxuvkBBQxXjQsZjhAAAAJBoEaYdaBGm
HQAAAAtzc2gtZWQyNTUxOQAAACBi+iT9xYVGa1SHwPRM3CXZV8KtzBxuvkBBQxXjQsZjhA
AAAEB6dfLASdiUR6KzQVydw16iXN1ImqoLoe+I24G4K386J2L6JP3FhUZrVIfA9EzcJdlX
wq3MHG6+QEFDFeNCxmOEAAAACmVyaWtAbUtJREUBAgM=
-----END OPENSSH PRIVATE KEY-----""".trimIndent()
} }

View file

@ -1,25 +1,48 @@
package org.domaindrivenarchitecture.provs.framework.ubuntu.keys.base package org.domaindrivenarchitecture.provs.framework.ubuntu.keys.base
import org.domaindrivenarchitecture.provs.framework.core.Secret import org.domaindrivenarchitecture.provs.framework.core.Secret
import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.KeyPair import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.fileContent
import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.privateSSHSnakeoilKey import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.*
import org.domaindrivenarchitecture.provs.framework.ubuntu.keys.publicSSHSnakeoilKey
import org.domaindrivenarchitecture.provs.test.defaultTestContainer import org.domaindrivenarchitecture.provs.test.defaultTestContainer
import org.domaindrivenarchitecture.provs.test.tags.ContainerTest import org.domaindrivenarchitecture.provs.test.tags.ContainerTest
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.Assertions.assertTrue
internal class SshKtTest { internal class SshKtTest {
@ContainerTest @ContainerTest
fun configureSshKeys() { fun configureSshKeys_for_ssh_type_rsa() {
// given // given
val a = defaultTestContainer() val prov = defaultTestContainer()
// when // when
val res = a.configureSshKeys(KeyPair(Secret(publicSSHSnakeoilKey()), Secret(privateSSHSnakeoilKey()))) val res = prov.configureSshKeys(SshKeyPair(Secret(publicSSHRSASnakeoilKey()), Secret(privateSSHRSASnakeoilKey())))
// then // then
assertTrue(res.success) assertTrue(res.success)
val publicSshKeyFileContent = prov.fileContent("~/.ssh/id_rsa.pub")
assertEquals(publicSSHRSASnakeoilKey() + "\n", publicSshKeyFileContent)
val privateSshKeyFileContent = prov.fileContent("~/.ssh/id_rsa")
assertEquals(privateSSHRSASnakeoilKey() + "\n", privateSshKeyFileContent)
}
@ContainerTest
fun configureSshKeys_for_ssh_type_ed25519() {
// given
val prov = defaultTestContainer()
// when
val res = prov.configureSshKeys(SshKeyPair(Secret(publicED25519SnakeOilKey()), Secret(privateED25519SnakeOilKey())))
// then
assertTrue(res.success)
val publicSshKeyFileContent = prov.fileContent("~/.ssh/id_ed25519.pub")
assertEquals(publicED25519SnakeOilKey() + "\n", publicSshKeyFileContent)
val privateSshKeyFileContent = prov.fileContent("~/.ssh/id_ed25519")
assertEquals(privateED25519SnakeOilKey() + "\n", privateSshKeyFileContent)
} }
} }

View file

@ -29,7 +29,7 @@ internal class ProvisionUserKtTest {
"testuser", "testuser",
"test@mail.com", "test@mail.com",
KeyPairSource(SecretSourceType.PLAIN, publicGPGSnakeoilKey(), privateGPGSnakeoilKey()), KeyPairSource(SecretSourceType.PLAIN, publicGPGSnakeoilKey(), privateGPGSnakeoilKey()),
KeyPairSource(SecretSourceType.PLAIN, publicSSHSnakeoilKey(), privateSSHSnakeoilKey()) SshKeyPairSource(SecretSourceType.PLAIN, publicSSHRSASnakeoilKey(), privateSSHRSASnakeoilKey())
) )
) )