2015-07-10 15:56:14 +00:00
package ssh
import (
2020-06-11 12:10:13 +00:00
"bytes"
2018-01-08 18:31:38 +00:00
"context"
2021-04-08 16:43:39 +00:00
"encoding/base64"
"errors"
2015-07-10 15:56:14 +00:00
"fmt"
2020-06-11 12:10:13 +00:00
"net"
2015-08-30 18:17:50 +00:00
"reflect"
2021-04-08 16:43:39 +00:00
"strings"
2015-07-10 15:56:14 +00:00
"testing"
2015-09-21 20:12:38 +00:00
"time"
2015-07-10 15:56:14 +00:00
2021-04-08 16:43:39 +00:00
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/sdk/logical"
2015-07-10 15:56:14 +00:00
2021-04-08 16:43:39 +00:00
"golang.org/x/crypto/ssh"
2017-03-02 21:37:03 +00:00
2021-05-13 21:37:22 +00:00
"github.com/hashicorp/vault/builtin/credential/userpass"
2020-06-11 12:10:13 +00:00
"github.com/hashicorp/vault/helper/testhelpers/docker"
2020-06-23 11:01:39 +00:00
logicaltest "github.com/hashicorp/vault/helper/testhelpers/logical"
2021-05-13 21:37:22 +00:00
vaulthttp "github.com/hashicorp/vault/http"
2015-07-10 22:18:02 +00:00
"github.com/hashicorp/vault/vault"
2015-07-10 15:56:14 +00:00
"github.com/mitchellh/mapstructure"
)
const (
2023-01-31 21:02:22 +00:00
testIP = "127.0.0.1"
testUserName = "vaultssh"
testMultiUserName = "vaultssh,otherssh"
testAdminUser = "vaultssh"
testCaKeyType = "ca"
testOTPKeyType = "otp"
testCIDRList = "127.0.0.1/32"
testAtRoleName = "test@RoleName"
testOTPRoleName = "testOTPRoleName"
2020-06-11 12:10:13 +00:00
// testKeyName is the name of the entry that will be written to SSHMOUNTPOINT/ssh/keys
testKeyName = "testKeyName"
// testSharedPrivateKey is the value of the entry that will be written to SSHMOUNTPOINT/ssh/keys
2015-07-10 22:18:02 +00:00
testSharedPrivateKey = `
2015-07-10 15:56:14 +00:00
-- -- - BEGIN RSA PRIVATE KEY -- -- -
2015-07-10 22:18:02 +00:00
MIIEogIBAAKCAQEAvYvoRcWRxqOim5VZnuM6wHCbLUeiND0yaM1tvOl + Fsrz55DG
A0OZp4RGAu1Fgr46E1mzxFz1 + zY4UbcEExg + u21fpa8YH8sytSWW1FyuD8ICib0A
/ l8slmDMw4BkkGOtSlEqgscpkpv / TWZD1NxJWkPcULk8z6c7TOETn2 / H9mL + v2RE
mbE6NDEwJKfD3MvlpIqCP7idR + 86 rNBAODjGOGgyUbtFLT + K01XmDRALkV3V / nh +
GltyjL4c6RU4zG2iRyV5RHlJtkml + UzUMkzr4IQnkCC32CC / wmtoo / IsAprpcHVe
nkBn3eFQ7uND70p5n6GhN / KOh2j519JFHJyokwIDAQABAoIBAHX7VOvBC3kCN9 / x
+ aPdup84OE7Z7MvpX6w + WlUhXVugnmsAAVDczhKoUc / WktLLx2huCGhsmKvyVuH +
MioUiE + vx75gm3qGx5xbtmOfALVMRLopjCnJYf6EaFA0ZeQ + NwowNW7Lu0PHmAU8
Z3JiX8IwxTz14DU82buDyewO7v + cEr97AnERe3PUcSTDoUXNaoNxjNpEJkKREY6h
4 hAY676RT / GsRcQ8tqe / rnCqPHNd7JGqL + 207 FK4tJw7daoBjQyijWuB7K5chSal
oPInylM6b13ASXuOAOT / 2 uSUBWmFVCZPDCmnZxy2SdnJGbsJAMl7Ma3MUlaGvVI +
Tfh1aQkCgYEA4JlNOabTb3z42wz6mz + Nz3JRwbawD + PJXOk5JsSnV7DtPtfgkK9y
6 FTQdhnozGWShAvJvc + C4QAihs9AlHXoaBY5bEU7R / 8 UK / pSqwzam + MmxmhVDV7G
IMQPV0FteoXTaJSikhZ88mETTegI2mik + zleBpVxvfdhE5TR + lq8Br0CgYEA2AwJ
CUD5CYUSj09PluR0HHqamWOrJkKPFPwa + 5 eiTTCzfBBxImYZh7nXnWuoviXC0sg2
AuvCW + uZ48ygv / D8gcz3j1JfbErKZJuV + TotK9rRtNIF5Ub7qysP7UjyI7zCssVM
kuDd9LfRXaB / qGAHNkcDA8NxmHW3gpln4CFdSY8CgYANs4xwfercHEWaJ1qKagAe
rZyrMpffAEhicJ / Z65lB0jtG4CiE6w8ZeUMWUVJQVcnwYD + 4 YpZbX4S7sJ0B8Ydy
AhkSr86D / 92 dKTIt2STk6aCN7gNyQ1vW198PtaAWH1 / cO2UHgHOy3ZUt5X / Uwxl9
cex4flln + 1 Viumts2GgsCQKBgCJH7psgSyPekK5auFdKEr5 + Gc / jB8I / Z3K9 + g4X
5 nH3G1PBTCJYLw7hRzw8W / 8 oALzvddqKzEFHphiGXK94Lqjt / A4q1OdbCrhiE68D
My21P / dAKB1UYRSs9Y8CNyHCjuZM9jSMJ8vv6vG / SOJPsnVDWVAckAbQDvlTHC9t
O98zAoGAcbW6uFDkrv0XMCpB9Su3KaNXOR0wzag + WIFQRXCcoTvxVi9iYfUReQPi
oOyBJU / HMVvBfv4g + OVFLVgSwwm6owwsouZ0 + D / LasbuHqYyqYqdyPJQYzWA2Y + F
+ B6f4RoPdSXj24JHPg / ioRxjaj094UXJxua2yfkcecGNEuBQHSs =
2015-07-10 15:56:14 +00:00
-- -- - END RSA PRIVATE KEY -- -- -
2016-12-26 14:03:27 +00:00
`
2020-06-11 12:10:13 +00:00
// Public half of `testCAPrivateKey`, identical to how it would be fed in from a file
testCAPublicKey = ` ssh - rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDArgK0ilRRfk8E7HIsjz5l3BuxmwpDd8DHRCVfOhbZ4gOSVxjEOOqBwWGjygdboBIZwFXmwDlU6sWX0hBJAgpQz0Cjvbjxtq / NjkvATrYPgnrXUhTaEn2eQO0PsqRNSFH46SK / oJfTp0q8 / WgojxWJ2L7FUV8PO8uIk49DzqAqPV7WXU63vFsjx + 3 WQOX / ILeQvHCvaqs3dWjjzEoDudRWCOdUqcHEOshV9azIzPrXlQVzRV3QAKl6u7pC + / Secorpwt6IHpMKoVPGiR0tMMuNOVH8zrAKzIxPGfy2WmNDpJopbXMTvSOGAqNcp49O4SKOQl9Fzfq2HEevJamKLrMB dummy @ example . com
2016-12-26 14:03:27 +00:00
`
publicKey2 = ` AAAAB3NzaC1yc2EAAAADAQABAAABAQDArgK0ilRRfk8E7HIsjz5l3BuxmwpDd8DHRCVfOhbZ4gOSVxjEOOqBwWGjygdboBIZwFXmwDlU6sWX0hBJAgpQz0Cjvbjxtq / NjkvATrYPgnrXUhTaEn2eQO0PsqRNSFH46SK / oJfTp0q8 / WgojxWJ2L7FUV8PO8uIk49DzqAqPV7WXU63vFsjx + 3 WQOX / ILeQvHCvaqs3dWjjzEoDudRWCOdUqcHEOshV9azIzPrXlQVzRV3QAKl6u7pC + / Secorpwt6IHpMKoVPGiR0tMMuNOVH8zrAKzIxPGfy2WmNDpJopbXMTvSOGAqNcp49O4SKOQl9Fzfq2HEevJamKLrMB
`
2019-02-11 18:03:26 +00:00
2022-02-17 20:36:56 +00:00
publicKey3072 = ` ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDlsMr3K1d0nzE1TjUULPRuVjEGETmOqHtWq4gVPq3HiuNVHE/e/BJnkXc40BoClQ2Z5ZZPJZ6izF9PnlzNDjpq8DrILUrn/6KrzCHvRwnkYMAXbfM/Br09z5QGptbOe1EMLeVe0b/udmUicbYAGPxMruZk+ljyr4vXkO+gOAIrxeSIQSdMVLU4g0pCPQuDCOx5IQpDYSlOB3091frpN8npfMueKPflNYzxnqqYgAVeDKAIqMCGOMOHUeIZJ7A7HuynEAVOsOkJwC9nesy9D6ppdWNduGl42IkzlwVdDMZtUAEznMUT/dnHNG1Krx9SuNZ/S9fGjxGVsT+jzUmizrWB9/6XIEHDxPBzcqlWFuwYTGz1OL8bfZ+HldOGPcnqZn9hKntWwjUc3whcvWt+NCmXpHSVLSxf+WN8pdmfEsCqn8mpvo2MXa+iJrtAVPX4i0u8AQUuqC3NuXHv4Cn0LNwtziBT544UjgbWkAZqzFZJREYA09OHscc3akEIrTnPehk= demo@example.com `
2019-02-11 18:03:26 +00:00
publicKey4096 = ` ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC54Oj4YCFDYxYv69Q9KfU6rWYtUB1eByQdUW0nXFi/vr98QUIV77sEeUVhaQzZcuCojAi/GrloW7ta0Z2DaEv5jOQMAnGpXBcqLJsz3KdrHbpvl93MPNdmNaGPU0GnUEsjBVuDVn9HdIUa8CNrxShvPu7/VqoaRHKLqphGgzFb37vi4qvnQ+5VYAO/TzyVYMD6qJX6I/9Pw8d74jCfEdOh2yGKkP7rXWOghreyIl8H2zTJKg9KoZuPq9F5M8nNt7Oi3rf+DwQiYvamzIqlDP4s5oFVTZW0E9lwWvYDpyiJnUrkQqksebBK/rcyfiFG3onb4qLo2WVWXeK3si8IhGik/TEzprScyAWIf9RviT8O+l5hTA2/c+ctn3MVCLRNfez2lKpdxCoprv1MbIcySGWblTJEcY6RA+aauVJpu7FMtRxHHtZKtMpep8cLu8GKbiP6Ifq2JXBtXtNxDeIgo2MkNoMh/NHAsACJniE/dqV/+u9HvhvgrTbJ69ell0nE4ivzA7O4kZgbR/4MHlLgLFvaqC8RrWRLY6BdFagPIMxghWha7Qw16zqoIjRnolvRzUWvSXanJVg8Z6ua1VxwgirNaAH1ivmJhUh2+4lNxCX6jmZyR3zjJsWY03gjJTairvI762opjjalF8fH6Xrs15mB14JiAlNbk6+5REQcvXlGqw== dummy@example.com `
2020-06-11 12:10:13 +00:00
testCAPrivateKey = ` -- -- - BEGIN RSA PRIVATE KEY -- -- -
2016-12-26 14:03:27 +00:00
MIIEowIBAAKCAQEAwK4CtIpUUX5PBOxyLI8 + ZdwbsZsKQ3fAx0QlXzoW2eIDklcY
xDjqgcFho8oHW6ASGcBV5sA5VOrFl9IQSQIKUM9Ao7248bavzY5LwE62D4J611IU
2 hJ9nkDtD7KkTUhR + Okiv6CX06dKvP1oKI8Vidi + xVFfDzvLiJOPQ86gKj1e1l1O
t7xbI8ft1kDl / yC3kLxwr2qrN3Vo48xKA7nUVgjnVKnBxDrIVfWsyMz615UFc0Vd
0 ACperu6Qvv0nnKK6cLeiB6TCqFTxokdLTDLjTlR / M6wCsyMTxn8tlpjQ6SaKW1z
E70jhgKjXKePTuEijkJfRc36thxHryWpii6zAQIDAQABAoIBAA / DrPD8iF2KigiL
F + RRa / eFhLaJStOuTpV / G9eotwnolgY5Hguf5H / tRIHUG7oBZLm6pMyWWZp7AuOj
CjYO9q0Z5939vc349nVI + SWoyviF4msPiik1bhWulja8lPjFu / 8 zg + ZNy15Dx7ei
vAzleAupMiKOv8pNSB / KguQ3WZ9a9bcQcoFQ2Foru6mXpLJ03kghVRlkqvQ7t5cA
n11d2Hiipq9mleESr0c + MUPKLBX / neaWfGA4xgJTjIYjZi6avmYc / Ox3sQ9aLq2J
tH0D4HVUZvaU28hn + jhbs64rRFbu ++ qQMe3vNvi / Q / iqcYU4b6tgDNzm / JFRTS / W
njiz4mkCgYEA44CnQVmonN6qQ0AgNNlBY5 + RX3wwBJZ1AaxpzwDRylAt2vlVUA0n
YY4RW4J4 + RMRKwHwjxK5RRmHjsIJx + nrpqihW3fte3ev5F2A9Wha4dzzEHxBY6IL
362 T / x2f + vYk6tV + uTZSUPHsuELH26mitbBVFNB / 00 nbMNdEc2bO5FMCgYEA2NCw
ubt + g2bRkkT / Qf8gIM8ZDpZbARt6onqxVcWkQFT16ZjbsBWUrH1Xi7alv9 + lwYLJ
ckY / XDX4KeU19HabeAbpyy6G9Q2uBSWZlJbjl7QNhdLeuzV82U1 / r8fy6Uu3gQnU
WSFx2GesRpSmZpqNKMs5ksqteZ9Yjg1EIgXdINsCgYBIn9REt1NtKGOf7kOZu1T1
cYXdvm4xuLoHW7u3OiK + e9P3mCqU0G4m5UxDMyZdFKohWZAqjCaamWi9uNGYgOMa
I7DG20TzaiS7OOIm9TY17eul8pSJMrypnealxRZB7fug / 6 Bhjaa / cktIEwFr7P4l
E / JFH73 + fBA9yipu0H3xQwKBgHmiwrLAZF6VrVcxDD9bQQwHA5iyc4Wwg + Fpkdl7
0 wUgZQHTdtRXlxwaCaZhJqX5c4WXuSo6DMvPn1TpuZZXgCsbPch2ZtJOBWXvzTSW
XkK6iaedQMWoYU2L8 + mK9FU73EwxVodWgwcUSosiVCRV6oGLWdZnjGEiK00uVh38
Si1nAoGBAL47wWinv1cDTnh5mm0mybz3oI2a6V9aIYCloQ / EFcvtahyR / gyB8qNF
lObH9Faf0WGdnACZvTz22U9gWhw79S0SpDV31tC5Kl8dXHFiZ09vYUKkYmSd / kms
SeKWrUkryx46LVf6NMhkyYmRqCEjBwfOozzezi5WbiJy6nn54GQt
-- -- - END RSA PRIVATE KEY -- -- -
2020-08-26 19:31:56 +00:00
`
testCAPublicKeyEd25519 = ` ssh - ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO1S6g5Bib7vT8eoFnvTl3dZSjOQL / GkH1nkRcDS9 ++ a ca
`
testCAPrivateKeyEd25519 = ` -- -- - BEGIN OPENSSH PRIVATE KEY -- -- -
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACDtUuoOQYm + 70 / HqBZ705d3WUozkC / xpB9Z5EXA0vfvmgAAAIhfRuszX0br
MwAAAAtzc2gtZWQyNTUxOQAAACDtUuoOQYm + 70 / HqBZ705d3WUozkC / xpB9Z5EXA0vfvmg
AAAEBQYa029SP / 7 AGPFQLmzwOc9eCoOZuwCq3iIf2C6fj9j + 1 S6g5Bib7vT8eoFnvTl3dZ
SjOQL / GkH1nkRcDS9 ++ aAAAAAmNhAQID
-- -- - END OPENSSH PRIVATE KEY -- -- -
2015-07-10 15:56:14 +00:00
`
2020-06-11 12:10:13 +00:00
2022-02-18 22:48:16 +00:00
publicKeyECDSA256 = ` ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJsfOouYIjJNI23QJqaDsFTGukm21fRAMeGvKZDB59i5jnX1EubMH1AEjjzz4fgySUlyWKo+TS31rxU8kX3DDM4= demo@example.com `
publicKeyECDSA521 = ` ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAEg73ORD4J3FV2CrL01gLSKREO2EHrZPlJCOeDL5OKD3M1GCHv3q8O452RW49Aw+8zFFFU5u6d1Ys3Qsj05zdaQwQDt/D3ceWLGVkWiKyLPQStfn0GGOZh3YFKEw5XmeW9jh6xudEHlKs4Pfv2FrroaUKZvM2SlxR/feOK0tCQyq3MN/g== demo@example.com `
2020-06-11 12:10:13 +00:00
// testPublicKeyInstall is the public key that is installed in the
// admin account's authorized_keys
testPublicKeyInstall = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC9i+hFxZHGo6KblVme4zrAcJstR6I0PTJozW286X4WyvPnkMYDQ5mnhEYC7UWCvjoTWbPEXPX7NjhRtwQTGD67bV+lrxgfyzK1JZbUXK4PwgKJvQD+XyyWYMzDgGSQY61KUSqCxymSm/9NZkPU3ElaQ9xQuTzPpztM4ROfb8f2Yv6/ZESZsTo0MTAkp8Pcy+WkioI/uJ1H7zqs0EA4OMY4aDJRu0UtP4rTVeYNEAuRXdX+eH4aW3KMvhzpFTjMbaJHJXlEeUm2SaX5TNQyTOvghCeQILfYIL/Ca2ij8iwCmulwdV6eQGfd4VDu40PvSnmfoaE38o6HaPnX0kUcnKiT"
2020-08-26 19:31:56 +00:00
dockerImageTagSupportsRSA1 = "8.1_p1-r0-ls20"
2021-05-06 15:57:54 +00:00
dockerImageTagSupportsNoRSA1 = "8.4_p1-r3-ls48"
2015-07-10 15:56:14 +00:00
)
2020-06-11 12:10:13 +00:00
func prepareTestContainer ( t * testing . T , tag , caPublicKeyPEM string ) ( func ( ) , string ) {
if tag == "" {
2020-08-26 19:31:56 +00:00
tag = dockerImageTagSupportsNoRSA1
2020-06-11 12:10:13 +00:00
}
2020-09-15 14:01:26 +00:00
runner , err := docker . NewServiceRunner ( docker . RunOptions {
ContainerName : "openssh" ,
2022-11-02 17:33:17 +00:00
ImageRepo : "docker.mirror.hashicorp.services/linuxserver/openssh-server" ,
2020-09-15 14:01:26 +00:00
ImageTag : tag ,
2020-06-11 12:10:13 +00:00
Env : [ ] string {
"DOCKER_MODS=linuxserver/mods:openssh-server-openssh-client" ,
"PUBLIC_KEY=" + testPublicKeyInstall ,
"SUDO_ACCESS=true" ,
"USER_NAME=vaultssh" ,
} ,
2020-09-15 14:01:26 +00:00
Ports : [ ] string { "2222/tcp" } ,
2020-06-11 12:10:13 +00:00
} )
if err != nil {
t . Fatalf ( "Could not start local ssh docker container: %s" , err )
}
2020-09-15 14:01:26 +00:00
svc , err := runner . StartService ( context . Background ( ) , func ( ctx context . Context , host string , port int ) ( docker . ServiceConfig , error ) {
ipaddr , err := net . ResolveIPAddr ( "ip" , host )
if err != nil {
return nil , err
}
sshAddress := fmt . Sprintf ( "%s:%d" , ipaddr . String ( ) , port )
2020-06-11 12:10:13 +00:00
2020-09-15 14:01:26 +00:00
signer , err := ssh . ParsePrivateKey ( [ ] byte ( testSharedPrivateKey ) )
if err != nil {
return nil , err
}
2020-06-11 12:10:13 +00:00
// Install util-linux for non-busybox flock that supports timeout option
2020-09-15 14:01:26 +00:00
err = testSSH ( "vaultssh" , sshAddress , ssh . PublicKeys ( signer ) , fmt . Sprintf ( `
2021-05-13 21:37:22 +00:00
set - e ;
2020-06-11 12:10:13 +00:00
sudo ln - s / config / home / vaultssh
sudo apk add util - linux ;
echo "LogLevel DEBUG" | sudo tee - a / config / ssh_host_keys / sshd_config ;
echo "TrustedUserCAKeys /config/ssh_host_keys/trusted-user-ca-keys.pem" | sudo tee - a / config / ssh_host_keys / sshd_config ;
kill - HUP $ ( cat / config / sshd . pid )
echo "%s" | sudo tee / config / ssh_host_keys / trusted - user - ca - keys . pem
` , caPublicKeyPEM ) )
2020-09-15 14:01:26 +00:00
if err != nil {
return nil , err
}
2020-06-11 12:10:13 +00:00
2020-09-15 14:01:26 +00:00
return docker . NewServiceHostPort ( ipaddr . String ( ) , port ) , nil
} )
if err != nil {
t . Fatalf ( "Could not start docker ssh server: %s" , err )
}
return svc . Cleanup , svc . Config . Address ( )
2020-06-11 12:10:13 +00:00
}
2020-09-15 14:01:26 +00:00
func testSSH ( user , host string , auth ssh . AuthMethod , command string ) error {
2020-06-11 12:10:13 +00:00
client , err := ssh . Dial ( "tcp" , host , & ssh . ClientConfig {
User : user ,
Auth : [ ] ssh . AuthMethod { auth } ,
HostKeyCallback : ssh . InsecureIgnoreHostKey ( ) ,
Timeout : 5 * time . Second ,
} )
if err != nil {
return fmt . Errorf ( "unable to dial sshd to host %q: %v" , host , err )
}
session , err := client . NewSession ( )
if err != nil {
return fmt . Errorf ( "unable to create sshd session to host %q: %v" , host , err )
}
var stderr bytes . Buffer
session . Stderr = & stderr
defer session . Close ( )
err = session . Run ( command )
if err != nil {
2020-09-15 14:01:26 +00:00
return fmt . Errorf ( "command %v failed, error: %v, stderr: %v" , command , err , stderr . String ( ) )
2020-06-11 12:10:13 +00:00
}
2021-10-19 00:29:47 +00:00
return nil
2020-06-11 12:10:13 +00:00
}
2021-10-19 22:00:15 +00:00
func TestBackend_AllowedUsers ( t * testing . T ) {
2016-05-30 07:01:47 +00:00
config := logical . TestBackendConfig ( )
config . StorageView = & logical . InmemStorage { }
2016-06-01 16:17:47 +00:00
b , err := Backend ( config )
2016-05-30 07:01:47 +00:00
if err != nil {
t . Fatal ( err )
}
2018-01-19 06:44:44 +00:00
err = b . Setup ( context . Background ( ) , config )
2016-05-30 07:01:47 +00:00
if err != nil {
t . Fatal ( err )
}
roleData := map [ string ] interface { } {
"key_type" : "otp" ,
"default_user" : "ubuntu" ,
"cidr_list" : "52.207.235.245/16" ,
"allowed_users" : "test" ,
}
roleReq := & logical . Request {
Operation : logical . UpdateOperation ,
Path : "roles/role1" ,
Storage : config . StorageView ,
Data : roleData ,
}
2018-01-08 18:31:38 +00:00
resp , err := b . HandleRequest ( context . Background ( ) , roleReq )
2016-05-30 07:01:47 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) || resp != nil {
t . Fatalf ( "failed to create role: resp:%#v err:%s" , resp , err )
}
credsData := map [ string ] interface { } {
"ip" : "52.207.235.245" ,
"username" : "ubuntu" ,
}
credsReq := & logical . Request {
Operation : logical . UpdateOperation ,
Storage : config . StorageView ,
Path : "creds/role1" ,
Data : credsData ,
}
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , credsReq )
2016-05-30 07:01:47 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) || resp == nil {
t . Fatalf ( "failed to create role: resp:%#v err:%s" , resp , err )
}
if resp . Data [ "key" ] == "" ||
resp . Data [ "key_type" ] != "otp" ||
resp . Data [ "ip" ] != "52.207.235.245" ||
resp . Data [ "username" ] != "ubuntu" {
t . Fatalf ( "failed to create credential: resp:%#v" , resp )
}
credsData [ "username" ] = "test"
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , credsReq )
2016-05-30 07:01:47 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) || resp == nil {
t . Fatalf ( "failed to create role: resp:%#v err:%s" , resp , err )
}
if resp . Data [ "key" ] == "" ||
resp . Data [ "key_type" ] != "otp" ||
resp . Data [ "ip" ] != "52.207.235.245" ||
resp . Data [ "username" ] != "test" {
t . Fatalf ( "failed to create credential: resp:%#v" , resp )
}
credsData [ "username" ] = "random"
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , credsReq )
2016-05-30 07:01:47 +00:00
if err != nil || resp == nil || ( resp != nil && ! resp . IsError ( ) ) {
t . Fatalf ( "expected failure: resp:%#v err:%s" , resp , err )
}
delete ( roleData , "allowed_users" )
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , roleReq )
2016-05-30 07:01:47 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) || resp != nil {
t . Fatalf ( "failed to create role: resp:%#v err:%s" , resp , err )
}
credsData [ "username" ] = "ubuntu"
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , credsReq )
2016-05-30 07:01:47 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) || resp == nil {
t . Fatalf ( "failed to create role: resp:%#v err:%s" , resp , err )
}
if resp . Data [ "key" ] == "" ||
resp . Data [ "key_type" ] != "otp" ||
resp . Data [ "ip" ] != "52.207.235.245" ||
resp . Data [ "username" ] != "ubuntu" {
t . Fatalf ( "failed to create credential: resp:%#v" , resp )
}
credsData [ "username" ] = "test"
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , credsReq )
2016-05-30 07:01:47 +00:00
if err != nil || resp == nil || ( resp != nil && ! resp . IsError ( ) ) {
t . Fatalf ( "expected failure: resp:%#v err:%s" , resp , err )
}
2016-05-30 07:12:43 +00:00
roleData [ "allowed_users" ] = "*"
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , roleReq )
2016-05-30 07:12:43 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) || resp != nil {
t . Fatalf ( "failed to create role: resp:%#v err:%s" , resp , err )
}
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , credsReq )
2016-05-30 07:12:43 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) || resp == nil {
t . Fatalf ( "failed to create role: resp:%#v err:%s" , resp , err )
}
if resp . Data [ "key" ] == "" ||
resp . Data [ "key_type" ] != "otp" ||
resp . Data [ "ip" ] != "52.207.235.245" ||
resp . Data [ "username" ] != "test" {
t . Fatalf ( "failed to create credential: resp:%#v" , resp )
}
2016-05-30 07:01:47 +00:00
}
2022-08-16 19:59:29 +00:00
func TestBackend_AllowedDomainsTemplate ( t * testing . T ) {
testAllowedDomainsTemplate := "{{ identity.entity.metadata.ssh_username }}.example.com"
expectedValidPrincipal := "foo." + testUserName + ".example.com"
testAllowedPrincipalsTemplate (
t , testAllowedDomainsTemplate ,
expectedValidPrincipal ,
map [ string ] string {
"ssh_username" : testUserName ,
} ,
map [ string ] interface { } {
"key_type" : testCaKeyType ,
"algorithm_signer" : "rsa-sha2-256" ,
"allow_host_certificates" : true ,
"allow_subdomains" : true ,
"allowed_domains" : testAllowedDomainsTemplate ,
"allowed_domains_template" : true ,
} ,
map [ string ] interface { } {
"cert_type" : "host" ,
"public_key" : testCAPublicKey ,
"valid_principals" : expectedValidPrincipal ,
} ,
)
}
2021-10-19 22:00:15 +00:00
func TestBackend_AllowedUsersTemplate ( t * testing . T ) {
testAllowedUsersTemplate ( t ,
"{{ identity.entity.metadata.ssh_username }}" ,
testUserName , map [ string ] string {
"ssh_username" : testUserName ,
} ,
)
}
2022-10-13 22:34:36 +00:00
func TestBackend_MultipleAllowedUsersTemplate ( t * testing . T ) {
testAllowedUsersTemplate ( t ,
"{{ identity.entity.metadata.ssh_username }}" ,
testUserName , map [ string ] string {
"ssh_username" : testMultiUserName ,
} ,
)
}
2021-10-19 22:00:15 +00:00
func TestBackend_AllowedUsersTemplate_WithStaticPrefix ( t * testing . T ) {
testAllowedUsersTemplate ( t ,
"ssh-{{ identity.entity.metadata.ssh_username }}" ,
"ssh-" + testUserName , map [ string ] string {
"ssh_username" : testUserName ,
} ,
)
}
2022-07-29 13:45:52 +00:00
func TestBackend_DefaultUserTemplate ( t * testing . T ) {
testDefaultUserTemplate ( t ,
"{{ identity.entity.metadata.ssh_username }}" ,
testUserName ,
map [ string ] string {
"ssh_username" : testUserName ,
} ,
)
}
func TestBackend_DefaultUserTemplate_WithStaticPrefix ( t * testing . T ) {
testDefaultUserTemplate ( t ,
"user-{{ identity.entity.metadata.ssh_username }}" ,
"user-" + testUserName ,
map [ string ] string {
"ssh_username" : testUserName ,
} ,
)
}
func TestBackend_DefaultUserTemplateFalse_AllowedUsersTemplateTrue ( t * testing . T ) {
cluster , userpassToken := getSshCaTestCluster ( t , testUserName )
defer cluster . Cleanup ( )
client := cluster . Cores [ 0 ] . Client
// set metadata "ssh_username" to userpass username
tokenLookupResponse , err := client . Logical ( ) . Write ( "/auth/token/lookup" , map [ string ] interface { } {
"token" : userpassToken ,
} )
if err != nil {
t . Fatal ( err )
}
entityID := tokenLookupResponse . Data [ "entity_id" ] . ( string )
_ , err = client . Logical ( ) . Write ( "/identity/entity/id/" + entityID , map [ string ] interface { } {
"metadata" : map [ string ] string {
"ssh_username" : testUserName ,
} ,
} )
if err != nil {
t . Fatal ( err )
}
_ , err = client . Logical ( ) . Write ( "ssh/roles/my-role" , map [ string ] interface { } {
"key_type" : testCaKeyType ,
"allow_user_certificates" : true ,
"default_user" : "{{identity.entity.metadata.ssh_username}}" ,
// disable user templating but not allowed_user_template and the request should fail
"default_user_template" : false ,
"allowed_users" : "{{identity.entity.metadata.ssh_username}}" ,
"allowed_users_template" : true ,
} )
if err != nil {
t . Fatal ( err )
}
// sign SSH key as userpass user
client . SetToken ( userpassToken )
_ , err = client . Logical ( ) . Write ( "ssh/sign/my-role" , map [ string ] interface { } {
"public_key" : testCAPublicKey ,
} )
if err == nil {
t . Errorf ( "signing request should fail when default_user is not in the allowed_users list, because allowed_users_template is true and default_user_template is not" )
}
expectedErrStr := "{{identity.entity.metadata.ssh_username}} is not a valid value for valid_principals"
if ! strings . Contains ( err . Error ( ) , expectedErrStr ) {
t . Errorf ( "expected error to include %q but it was: %q" , expectedErrStr , err . Error ( ) )
}
}
func TestBackend_DefaultUserTemplateFalse_AllowedUsersTemplateFalse ( t * testing . T ) {
cluster , userpassToken := getSshCaTestCluster ( t , testUserName )
defer cluster . Cleanup ( )
client := cluster . Cores [ 0 ] . Client
// set metadata "ssh_username" to userpass username
tokenLookupResponse , err := client . Logical ( ) . Write ( "/auth/token/lookup" , map [ string ] interface { } {
"token" : userpassToken ,
} )
if err != nil {
t . Fatal ( err )
}
entityID := tokenLookupResponse . Data [ "entity_id" ] . ( string )
_ , err = client . Logical ( ) . Write ( "/identity/entity/id/" + entityID , map [ string ] interface { } {
"metadata" : map [ string ] string {
"ssh_username" : testUserName ,
} ,
} )
if err != nil {
t . Fatal ( err )
}
_ , err = client . Logical ( ) . Write ( "ssh/roles/my-role" , map [ string ] interface { } {
"key_type" : testCaKeyType ,
"allow_user_certificates" : true ,
"default_user" : "{{identity.entity.metadata.ssh_username}}" ,
"default_user_template" : false ,
"allowed_users" : "{{identity.entity.metadata.ssh_username}}" ,
"allowed_users_template" : false ,
} )
if err != nil {
t . Fatal ( err )
}
// sign SSH key as userpass user
client . SetToken ( userpassToken )
signResponse , err := client . Logical ( ) . Write ( "ssh/sign/my-role" , map [ string ] interface { } {
"public_key" : testCAPublicKey ,
} )
if err != nil {
t . Fatal ( err )
}
// check for the expected valid principals of certificate
signedKey := signResponse . Data [ "signed_key" ] . ( string )
key , _ := base64 . StdEncoding . DecodeString ( strings . Split ( signedKey , " " ) [ 1 ] )
parsedKey , err := ssh . ParsePublicKey ( key )
if err != nil {
t . Fatal ( err )
}
actualPrincipals := parsedKey . ( * ssh . Certificate ) . ValidPrincipals
if len ( actualPrincipals ) < 1 {
t . Fatal (
fmt . Sprintf ( "No ValidPrincipals returned: should have been %v" ,
[ ] string { "{{identity.entity.metadata.ssh_username}}" } ) ,
)
}
if len ( actualPrincipals ) > 1 {
t . Error (
fmt . Sprintf ( "incorrect number ValidPrincipals, expected only 1: %v should be %v" ,
actualPrincipals , [ ] string { "{{identity.entity.metadata.ssh_username}}" } ) ,
)
}
if actualPrincipals [ 0 ] != "{{identity.entity.metadata.ssh_username}}" {
t . Fatal (
fmt . Sprintf ( "incorrect ValidPrincipals: %v should be %v" ,
actualPrincipals , [ ] string { "{{identity.entity.metadata.ssh_username}}" } ) ,
)
}
}
2020-06-11 12:10:13 +00:00
func newTestingFactory ( t * testing . T ) func ( ctx context . Context , conf * logical . BackendConfig ) ( logical . Backend , error ) {
return func ( ctx context . Context , conf * logical . BackendConfig ) ( logical . Backend , error ) {
defaultLeaseTTLVal := 2 * time . Minute
maxLeaseTTLVal := 10 * time . Minute
return Factory ( context . Background ( ) , & logical . BackendConfig {
Logger : vault . NewTestLogger ( t ) ,
StorageView : & logical . InmemStorage { } ,
System : & logical . StaticSystemView {
DefaultLeaseTTLVal : defaultLeaseTTLVal ,
MaxLeaseTTLVal : maxLeaseTTLVal ,
} ,
} )
}
2015-09-21 20:12:38 +00:00
}
2016-02-02 17:32:50 +00:00
func TestSSHBackend_Lookup ( t * testing . T ) {
testOTPRoleData := map [ string ] interface { } {
2015-08-03 20:18:14 +00:00
"key_type" : testOTPKeyType ,
"default_user" : testUserName ,
2015-08-13 15:46:55 +00:00
"cidr_list" : testCIDRList ,
2015-08-03 20:18:14 +00:00
}
2015-08-30 18:30:59 +00:00
data := map [ string ] interface { } {
"ip" : testIP ,
}
2015-09-03 22:43:53 +00:00
resp1 := [ ] string ( nil )
resp2 := [ ] string { testOTPRoleName }
2023-01-31 21:02:22 +00:00
resp3 := [ ] string { testAtRoleName }
2015-08-03 20:18:14 +00:00
logicaltest . Test ( t , logicaltest . TestCase {
2020-06-11 12:10:13 +00:00
LogicalFactory : newTestingFactory ( t ) ,
2015-08-03 20:18:14 +00:00
Steps : [ ] logicaltest . TestStep {
2015-09-03 22:43:53 +00:00
testLookupRead ( t , data , resp1 ) ,
2015-08-30 18:30:59 +00:00
testRoleWrite ( t , testOTPRoleName , testOTPRoleData ) ,
2015-09-03 22:43:53 +00:00
testLookupRead ( t , data , resp2 ) ,
2015-08-03 20:18:14 +00:00
testRoleDelete ( t , testOTPRoleName ) ,
2015-09-03 22:43:53 +00:00
testLookupRead ( t , data , resp1 ) ,
2023-01-31 21:02:22 +00:00
testRoleWrite ( t , testAtRoleName , testOTPRoleData ) ,
testLookupRead ( t , data , resp3 ) ,
2020-01-21 10:46:29 +00:00
testRoleDelete ( t , testAtRoleName ) ,
testLookupRead ( t , data , resp1 ) ,
2015-08-03 20:18:14 +00:00
} ,
} )
}
2017-11-03 21:12:03 +00:00
func TestSSHBackend_RoleList ( t * testing . T ) {
testOTPRoleData := map [ string ] interface { } {
"key_type" : testOTPKeyType ,
"default_user" : testUserName ,
"cidr_list" : testCIDRList ,
}
resp1 := map [ string ] interface { } { }
resp2 := map [ string ] interface { } {
"keys" : [ ] string { testOTPRoleName } ,
"key_info" : map [ string ] interface { } {
testOTPRoleName : map [ string ] interface { } {
"key_type" : testOTPKeyType ,
} ,
} ,
}
2020-01-21 10:46:29 +00:00
resp3 := map [ string ] interface { } {
"keys" : [ ] string { testAtRoleName , testOTPRoleName } ,
"key_info" : map [ string ] interface { } {
testOTPRoleName : map [ string ] interface { } {
"key_type" : testOTPKeyType ,
} ,
testAtRoleName : map [ string ] interface { } {
"key_type" : testOTPKeyType ,
} ,
} ,
}
2017-11-03 21:12:03 +00:00
logicaltest . Test ( t , logicaltest . TestCase {
2020-06-11 12:10:13 +00:00
LogicalFactory : newTestingFactory ( t ) ,
2017-11-03 21:12:03 +00:00
Steps : [ ] logicaltest . TestStep {
testRoleList ( t , resp1 ) ,
testRoleWrite ( t , testOTPRoleName , testOTPRoleData ) ,
testRoleList ( t , resp2 ) ,
2020-01-21 10:46:29 +00:00
testRoleWrite ( t , testAtRoleName , testOTPRoleData ) ,
testRoleList ( t , resp3 ) ,
testRoleDelete ( t , testAtRoleName ) ,
testRoleList ( t , resp2 ) ,
testRoleDelete ( t , testOTPRoleName ) ,
testRoleList ( t , resp1 ) ,
2017-11-03 21:12:03 +00:00
} ,
} )
}
2015-07-31 17:24:23 +00:00
func TestSSHBackend_OTPRoleCrud ( t * testing . T ) {
2016-02-02 17:32:50 +00:00
testOTPRoleData := map [ string ] interface { } {
"key_type" : testOTPKeyType ,
"default_user" : testUserName ,
"cidr_list" : testCIDRList ,
}
2015-09-10 14:44:26 +00:00
respOTPRoleData := map [ string ] interface { } {
"key_type" : testOTPKeyType ,
"port" : 22 ,
"default_user" : testUserName ,
"cidr_list" : testCIDRList ,
}
2015-07-31 19:17:40 +00:00
logicaltest . Test ( t , logicaltest . TestCase {
2020-06-11 12:10:13 +00:00
LogicalFactory : newTestingFactory ( t ) ,
2015-07-31 19:17:40 +00:00
Steps : [ ] logicaltest . TestStep {
2015-08-30 18:30:59 +00:00
testRoleWrite ( t , testOTPRoleName , testOTPRoleData ) ,
2015-09-10 14:44:26 +00:00
testRoleRead ( t , testOTPRoleName , respOTPRoleData ) ,
2015-07-31 19:17:40 +00:00
testRoleDelete ( t , testOTPRoleName ) ,
testRoleRead ( t , testOTPRoleName , nil ) ,
2020-01-21 10:46:29 +00:00
testRoleWrite ( t , testAtRoleName , testOTPRoleData ) ,
testRoleRead ( t , testAtRoleName , respOTPRoleData ) ,
testRoleDelete ( t , testAtRoleName ) ,
testRoleRead ( t , testAtRoleName , nil ) ,
2015-07-31 19:17:40 +00:00
} ,
} )
}
2015-08-03 23:04:07 +00:00
func TestSSHBackend_OTPCreate ( t * testing . T ) {
2020-06-11 12:10:13 +00:00
cleanup , sshAddress := prepareTestContainer ( t , "" , "" )
defer func ( ) {
if ! t . Failed ( ) {
cleanup ( )
}
} ( )
host , port , err := net . SplitHostPort ( sshAddress )
if err != nil {
t . Fatal ( err )
}
2016-02-02 17:32:50 +00:00
testOTPRoleData := map [ string ] interface { } {
"key_type" : testOTPKeyType ,
"default_user" : testUserName ,
2020-09-15 14:01:26 +00:00
"cidr_list" : host + "/32" ,
2020-06-11 12:10:13 +00:00
"port" : port ,
2016-02-02 17:32:50 +00:00
}
2015-09-03 22:11:04 +00:00
data := map [ string ] interface { } {
"username" : testUserName ,
2020-06-11 12:10:13 +00:00
"ip" : host ,
2015-09-03 22:11:04 +00:00
}
2015-08-03 23:04:07 +00:00
logicaltest . Test ( t , logicaltest . TestCase {
2020-06-11 12:10:13 +00:00
LogicalFactory : newTestingFactory ( t ) ,
2015-08-03 23:04:07 +00:00
Steps : [ ] logicaltest . TestStep {
2015-08-30 18:30:59 +00:00
testRoleWrite ( t , testOTPRoleName , testOTPRoleData ) ,
2020-06-11 12:10:13 +00:00
testCredsWrite ( t , testOTPRoleName , data , false , sshAddress ) ,
2015-08-03 23:04:07 +00:00
} ,
} )
}
2015-08-18 23:48:50 +00:00
func TestSSHBackend_VerifyEcho ( t * testing . T ) {
verifyData := map [ string ] interface { } {
"otp" : api . VerifyEchoRequest ,
}
expectedData := map [ string ] interface { } {
"message" : api . VerifyEchoResponse ,
}
logicaltest . Test ( t , logicaltest . TestCase {
2020-06-11 12:10:13 +00:00
LogicalFactory : newTestingFactory ( t ) ,
2015-08-18 23:48:50 +00:00
Steps : [ ] logicaltest . TestStep {
testVerifyWrite ( t , verifyData , expectedData ) ,
} ,
} )
}
2015-08-30 18:17:50 +00:00
func TestSSHBackend_ConfigZeroAddressCRUD ( t * testing . T ) {
2016-02-02 17:32:50 +00:00
testOTPRoleData := map [ string ] interface { } {
"key_type" : testOTPKeyType ,
"default_user" : testUserName ,
"cidr_list" : testCIDRList ,
}
2015-08-31 21:03:46 +00:00
req1 := map [ string ] interface { } {
2015-08-30 18:17:50 +00:00
"roles" : testOTPRoleName ,
}
2015-08-31 21:03:46 +00:00
resp1 := map [ string ] interface { } {
"roles" : [ ] string { testOTPRoleName } ,
}
resp2 := map [ string ] interface { } {
2023-01-31 21:02:22 +00:00
"roles" : [ ] string { testOTPRoleName } ,
2015-08-31 21:03:46 +00:00
}
resp3 := map [ string ] interface { } {
"roles" : [ ] string { } ,
2015-08-30 18:17:50 +00:00
}
logicaltest . Test ( t , logicaltest . TestCase {
2020-06-11 12:10:13 +00:00
LogicalFactory : newTestingFactory ( t ) ,
2015-08-30 18:17:50 +00:00
Steps : [ ] logicaltest . TestStep {
2015-08-30 18:30:59 +00:00
testRoleWrite ( t , testOTPRoleName , testOTPRoleData ) ,
2015-08-31 21:03:46 +00:00
testConfigZeroAddressWrite ( t , req1 ) ,
testConfigZeroAddressRead ( t , resp1 ) ,
testConfigZeroAddressRead ( t , resp2 ) ,
testConfigZeroAddressRead ( t , resp1 ) ,
2015-08-30 18:17:50 +00:00
testRoleDelete ( t , testOTPRoleName ) ,
2015-08-31 21:03:46 +00:00
testConfigZeroAddressRead ( t , resp3 ) ,
2015-08-30 18:17:50 +00:00
testConfigZeroAddressDelete ( t ) ,
} ,
} )
}
2018-04-13 14:18:06 +00:00
func TestSSHBackend_CredsForZeroAddressRoles_otp ( t * testing . T ) {
2015-09-10 15:55:07 +00:00
otpRoleData := map [ string ] interface { } {
"key_type" : testOTPKeyType ,
"default_user" : testUserName ,
}
data := map [ string ] interface { } {
"username" : testUserName ,
"ip" : testIP ,
}
req1 := map [ string ] interface { } {
"roles" : testOTPRoleName ,
}
2015-09-03 22:11:04 +00:00
logicaltest . Test ( t , logicaltest . TestCase {
2020-06-11 12:10:13 +00:00
LogicalFactory : newTestingFactory ( t ) ,
2015-09-03 22:11:04 +00:00
Steps : [ ] logicaltest . TestStep {
testRoleWrite ( t , testOTPRoleName , otpRoleData ) ,
2020-06-11 12:10:13 +00:00
testCredsWrite ( t , testOTPRoleName , data , true , "" ) ,
2015-09-10 15:55:07 +00:00
testConfigZeroAddressWrite ( t , req1 ) ,
2020-06-11 12:10:13 +00:00
testCredsWrite ( t , testOTPRoleName , data , false , "" ) ,
2018-04-13 14:18:06 +00:00
testConfigZeroAddressDelete ( t ) ,
2020-06-11 12:10:13 +00:00
testCredsWrite ( t , testOTPRoleName , data , true , "" ) ,
2018-04-13 14:18:06 +00:00
} ,
} )
}
2020-06-11 12:10:13 +00:00
func TestSSHBackend_CA ( t * testing . T ) {
testCases := [ ] struct {
2020-08-26 19:31:56 +00:00
name string
tag string
caPublicKey string
caPrivateKey string
algoSigner string
expectError bool
2020-06-11 12:10:13 +00:00
} {
2020-08-26 19:31:56 +00:00
{
"RSAKey_EmptyAlgoSigner_ImageSupportsRSA1" ,
dockerImageTagSupportsRSA1 ,
testCAPublicKey ,
testCAPrivateKey ,
"" ,
false ,
} ,
{
"RSAKey_EmptyAlgoSigner_ImageSupportsNoRSA1" ,
dockerImageTagSupportsNoRSA1 ,
testCAPublicKey ,
testCAPrivateKey ,
"" ,
2022-02-18 15:44:01 +00:00
false ,
} ,
{
"RSAKey_DefaultAlgoSigner_ImageSupportsRSA1" ,
dockerImageTagSupportsRSA1 ,
testCAPublicKey ,
testCAPrivateKey ,
"default" ,
false ,
} ,
{
"RSAKey_DefaultAlgoSigner_ImageSupportsNoRSA1" ,
dockerImageTagSupportsNoRSA1 ,
testCAPublicKey ,
testCAPrivateKey ,
"default" ,
false ,
2020-08-26 19:31:56 +00:00
} ,
{
"RSAKey_RSA1AlgoSigner_ImageSupportsRSA1" ,
dockerImageTagSupportsRSA1 ,
testCAPublicKey ,
testCAPrivateKey ,
ssh . SigAlgoRSA ,
false ,
} ,
2022-02-18 15:44:01 +00:00
{
"RSAKey_RSA1AlgoSigner_ImageSupportsNoRSA1" ,
dockerImageTagSupportsNoRSA1 ,
testCAPublicKey ,
testCAPrivateKey ,
ssh . SigAlgoRSA ,
true ,
} ,
2020-08-26 19:31:56 +00:00
{
"RSAKey_RSASHA2256AlgoSigner_ImageSupportsRSA1" ,
dockerImageTagSupportsRSA1 ,
testCAPublicKey ,
testCAPrivateKey ,
ssh . SigAlgoRSASHA2256 ,
false ,
} ,
{
"RSAKey_RSASHA2256AlgoSigner_ImageSupportsNoRSA1" ,
dockerImageTagSupportsNoRSA1 ,
testCAPublicKey ,
testCAPrivateKey ,
ssh . SigAlgoRSASHA2256 ,
false ,
} ,
{
"ed25519Key_EmptyAlgoSigner_ImageSupportsRSA1" ,
dockerImageTagSupportsRSA1 ,
testCAPublicKeyEd25519 ,
testCAPrivateKeyEd25519 ,
"" ,
false ,
} ,
{
"ed25519Key_EmptyAlgoSigner_ImageSupportsNoRSA1" ,
dockerImageTagSupportsNoRSA1 ,
testCAPublicKeyEd25519 ,
testCAPrivateKeyEd25519 ,
"" ,
false ,
} ,
{
"ed25519Key_RSA1AlgoSigner_ImageSupportsRSA1" ,
dockerImageTagSupportsRSA1 ,
testCAPublicKeyEd25519 ,
testCAPrivateKeyEd25519 ,
ssh . SigAlgoRSA ,
true ,
} ,
2020-06-11 12:10:13 +00:00
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
2020-08-26 19:31:56 +00:00
testSSHBackend_CA ( t , tc . tag , tc . caPublicKey , tc . caPrivateKey , tc . algoSigner , tc . expectError )
2020-06-11 12:10:13 +00:00
} )
}
}
2020-08-26 19:31:56 +00:00
func testSSHBackend_CA ( t * testing . T , dockerImageTag , caPublicKey , caPrivateKey , algorithmSigner string , expectError bool ) {
cleanup , sshAddress := prepareTestContainer ( t , dockerImageTag , caPublicKey )
2020-06-11 12:10:13 +00:00
defer cleanup ( )
config := logical . TestBackendConfig ( )
b , err := Factory ( context . Background ( ) , config )
if err != nil {
t . Fatalf ( "Cannot create backend: %s" , err )
}
testKeyToSignPrivate := ` -- -- - BEGIN OPENSSH PRIVATE KEY -- -- -
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
NhAAAAAwEAAQAAAQEAwn1V2xd / EgJXIY53fBTtc20k / ajekqQngvkpFSwNHW63XNEQK8Ll
FOCyGXoje9DUGxnYs3F / ohfsBBWkLNfU7fiENdSJL1pbkAgJ + 2 uhV9sLZjvYhikrXWoyJX
LDKfY12LjpcBS2HeLMT04laZ / xSJrOBEJHGzHyr2wUO0NUQUQPUODAFhnHKgvvA4Uu79UY
gcdThF4w83 + EAnE4JzBZMKPMjzy4u1C0R / LoD8DuapHwX6NGWdEUvUZZ + XRcIWeCOvR0ne
qGBRH35k1Mv7k65d7kkE0uvM5Z36erw3tdoszxPYf7AKnO1DpeU2uwMcym6xNwfwynKjhL
qL / Mgi4uRwAAA8iAsY0zgLGNMwAAAAdzc2gtcnNhAAABAQDCfVXbF38SAlchjnd8FO1zbS
T9qN6SpCeC + SkVLA0dbrdc0RArwuUU4LIZeiN70NQbGdizcX + iF + wEFaQs19Tt + IQ11Ikv
WluQCAn7a6FX2wtmO9iGKStdajIlcsMp9jXYuOlwFLYd4sxPTiVpn / FIms4EQkcbMfKvbB
Q7Q1RBRA9Q4MAWGccqC + 8 DhS7v1RiBx1OEXjDzf4QCcTgnMFkwo8yPPLi7ULRH8ugPwO5q
kfBfo0ZZ0RS9Rln5dFwhZ4I69HSd6oYFEffmTUy / uTrl3uSQTS68zlnfp6vDe12izPE9h /
sAqc7UOl5Ta7AxzKbrE3B / DKcqOEuov8yCLi5HAAAAAwEAAQAAAQABns2yT5XNbpuPOgKg
1 APObGBchKWmDxwNKUpAVOefEScR7OP3mV4TOHQDZlMZWvoJZ8O4av + nOA / NUOjXPs0VVn
azhBvIezY8EvUSVSk49Cg6J9F7 / KfR1WqpiTU7CkQUlCXNuz5xLUyKdJo3MQ / vjOqeenbh
MR9Wes4IWF1BVe4VOD6lxRsjwuIieIgmScW28FFh2rgsEfO2spzZ3AWOGExw + ih757hFz5
4 A2fhsQXP8m3r8m7iiqcjTLWXdxTUk4zot2kZEjbI4Avk0BL + wVeFq6f / y + G + g5edqSo7j
uuSgzbUQtA9PMnGxhrhU2Ob7n3VGdya7WbGZkaKP8zJhAAAAgQC3bJurmOSLIi3KVhp7lD
/ FfxwXHwVBFALCgq7EyNlkTz6RDoMFM4eOTRMDvsgWxT + bSB8R8eg1sfgY8rkHOuvTAVI5
3 oEYco3H7NWE9X8Zt0lyhO1uaE49EENNSQ8hY7R3UIw5becyI + 7 ZZxs9HkBgCQCZzSjzA +
SIyAoMKM261AAAAIEA + PCkcDRp3J0PaoiuetXSlWZ5WjP3CtwT2xrvEX9x + ZsDgXCDYQ5T
osxvEKOGSfIrHUUhzZbFGvqWyfrziPe9ypJrtCM7RJT / fApBXnbWFcDZzWamkQvohst + 0 w
XHYCmNoJ6 / Y + roLv3pzyFUmqRNcrQaohex7TZmsvHJT513UakAAACBAMgBXxH8DyNYdniX
mIXEto4GqMh4rXdNwCghfpyWdJE6vCyDt7g7bYMq7AQ2ynSKRtQDT / ZgQNfSbilUq3iXz7
xNZn5U9ndwFs90VmEpBup / PmhfX + Gwt5hQZLbkKZcgQ9XrhSKdMxVm1yy / fk0U457enlz5
cKumubUxOfFdy1ZvAAAAEm5jY0BtYnAudWJudC5sb2NhbA ==
-- -- - END OPENSSH PRIVATE KEY -- -- -
`
testKeyToSignPublic := ` ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDCfVXbF38SAlchjnd8FO1zbST9qN6SpCeC+SkVLA0dbrdc0RArwuUU4LIZeiN70NQbGdizcX+iF+wEFaQs19Tt+IQ11IkvWluQCAn7a6FX2wtmO9iGKStdajIlcsMp9jXYuOlwFLYd4sxPTiVpn/FIms4EQkcbMfKvbBQ7Q1RBRA9Q4MAWGccqC+8DhS7v1RiBx1OEXjDzf4QCcTgnMFkwo8yPPLi7ULRH8ugPwO5qkfBfo0ZZ0RS9Rln5dFwhZ4I69HSd6oYFEffmTUy/uTrl3uSQTS68zlnfp6vDe12izPE9h/sAqc7UOl5Ta7AxzKbrE3B/DKcqOEuov8yCLi5H `
roleOptions := map [ string ] interface { } {
"allow_user_certificates" : true ,
"allowed_users" : "*" ,
"default_extensions" : [ ] map [ string ] string {
{
"permit-pty" : "" ,
} ,
} ,
"key_type" : "ca" ,
"default_user" : testUserName ,
"ttl" : "30m0s" ,
}
if algorithmSigner != "" {
roleOptions [ "algorithm_signer" ] = algorithmSigner
}
testCase := logicaltest . TestCase {
LogicalBackend : b ,
Steps : [ ] logicaltest . TestStep {
2020-08-26 19:31:56 +00:00
configCaStep ( caPublicKey , caPrivateKey ) ,
2020-06-11 12:10:13 +00:00
testRoleWrite ( t , "testcarole" , roleOptions ) ,
2021-04-08 16:43:39 +00:00
{
2020-06-11 12:10:13 +00:00
Operation : logical . UpdateOperation ,
Path : "sign/testcarole" ,
ErrorOk : expectError ,
Data : map [ string ] interface { } {
"public_key" : testKeyToSignPublic ,
"valid_principals" : testUserName ,
} ,
Check : func ( resp * logical . Response ) error {
2020-08-26 19:31:56 +00:00
// Tolerate nil response if an error was expected
if expectError && resp == nil {
return nil
}
2020-06-11 12:10:13 +00:00
signedKey := strings . TrimSpace ( resp . Data [ "signed_key" ] . ( string ) )
if signedKey == "" {
return errors . New ( "no signed key in response" )
}
privKey , err := ssh . ParsePrivateKey ( [ ] byte ( testKeyToSignPrivate ) )
if err != nil {
return fmt . Errorf ( "error parsing private key: %v" , err )
}
parsedKey , _ , _ , _ , err := ssh . ParseAuthorizedKey ( [ ] byte ( signedKey ) )
if err != nil {
return fmt . Errorf ( "error parsing signed key: %v" , err )
}
certSigner , err := ssh . NewCertSigner ( parsedKey . ( * ssh . Certificate ) , privKey )
if err != nil {
return err
}
2020-09-15 14:01:26 +00:00
err = testSSH ( testUserName , sshAddress , ssh . PublicKeys ( certSigner ) , "date" )
2020-06-11 12:10:13 +00:00
if expectError && err == nil {
return fmt . Errorf ( "expected error but got none" )
}
if ! expectError && err != nil {
return err
}
return nil
} ,
} ,
} ,
}
logicaltest . Test ( t , testCase )
}
2020-08-26 19:31:56 +00:00
func TestSSHBackend_CAUpgradeAlgorithmSigner ( t * testing . T ) {
cleanup , sshAddress := prepareTestContainer ( t , dockerImageTagSupportsRSA1 , testCAPublicKey )
defer cleanup ( )
config := logical . TestBackendConfig ( )
b , err := Factory ( context . Background ( ) , config )
if err != nil {
t . Fatalf ( "Cannot create backend: %s" , err )
}
testKeyToSignPrivate := ` -- -- - BEGIN OPENSSH PRIVATE KEY -- -- -
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
NhAAAAAwEAAQAAAQEAwn1V2xd / EgJXIY53fBTtc20k / ajekqQngvkpFSwNHW63XNEQK8Ll
FOCyGXoje9DUGxnYs3F / ohfsBBWkLNfU7fiENdSJL1pbkAgJ + 2 uhV9sLZjvYhikrXWoyJX
LDKfY12LjpcBS2HeLMT04laZ / xSJrOBEJHGzHyr2wUO0NUQUQPUODAFhnHKgvvA4Uu79UY
gcdThF4w83 + EAnE4JzBZMKPMjzy4u1C0R / LoD8DuapHwX6NGWdEUvUZZ + XRcIWeCOvR0ne
qGBRH35k1Mv7k65d7kkE0uvM5Z36erw3tdoszxPYf7AKnO1DpeU2uwMcym6xNwfwynKjhL
qL / Mgi4uRwAAA8iAsY0zgLGNMwAAAAdzc2gtcnNhAAABAQDCfVXbF38SAlchjnd8FO1zbS
T9qN6SpCeC + SkVLA0dbrdc0RArwuUU4LIZeiN70NQbGdizcX + iF + wEFaQs19Tt + IQ11Ikv
WluQCAn7a6FX2wtmO9iGKStdajIlcsMp9jXYuOlwFLYd4sxPTiVpn / FIms4EQkcbMfKvbB
Q7Q1RBRA9Q4MAWGccqC + 8 DhS7v1RiBx1OEXjDzf4QCcTgnMFkwo8yPPLi7ULRH8ugPwO5q
kfBfo0ZZ0RS9Rln5dFwhZ4I69HSd6oYFEffmTUy / uTrl3uSQTS68zlnfp6vDe12izPE9h /
sAqc7UOl5Ta7AxzKbrE3B / DKcqOEuov8yCLi5HAAAAAwEAAQAAAQABns2yT5XNbpuPOgKg
1 APObGBchKWmDxwNKUpAVOefEScR7OP3mV4TOHQDZlMZWvoJZ8O4av + nOA / NUOjXPs0VVn
azhBvIezY8EvUSVSk49Cg6J9F7 / KfR1WqpiTU7CkQUlCXNuz5xLUyKdJo3MQ / vjOqeenbh
MR9Wes4IWF1BVe4VOD6lxRsjwuIieIgmScW28FFh2rgsEfO2spzZ3AWOGExw + ih757hFz5
4 A2fhsQXP8m3r8m7iiqcjTLWXdxTUk4zot2kZEjbI4Avk0BL + wVeFq6f / y + G + g5edqSo7j
uuSgzbUQtA9PMnGxhrhU2Ob7n3VGdya7WbGZkaKP8zJhAAAAgQC3bJurmOSLIi3KVhp7lD
/ FfxwXHwVBFALCgq7EyNlkTz6RDoMFM4eOTRMDvsgWxT + bSB8R8eg1sfgY8rkHOuvTAVI5
3 oEYco3H7NWE9X8Zt0lyhO1uaE49EENNSQ8hY7R3UIw5becyI + 7 ZZxs9HkBgCQCZzSjzA +
SIyAoMKM261AAAAIEA + PCkcDRp3J0PaoiuetXSlWZ5WjP3CtwT2xrvEX9x + ZsDgXCDYQ5T
osxvEKOGSfIrHUUhzZbFGvqWyfrziPe9ypJrtCM7RJT / fApBXnbWFcDZzWamkQvohst + 0 w
XHYCmNoJ6 / Y + roLv3pzyFUmqRNcrQaohex7TZmsvHJT513UakAAACBAMgBXxH8DyNYdniX
mIXEto4GqMh4rXdNwCghfpyWdJE6vCyDt7g7bYMq7AQ2ynSKRtQDT / ZgQNfSbilUq3iXz7
xNZn5U9ndwFs90VmEpBup / PmhfX + Gwt5hQZLbkKZcgQ9XrhSKdMxVm1yy / fk0U457enlz5
cKumubUxOfFdy1ZvAAAAEm5jY0BtYnAudWJudC5sb2NhbA ==
-- -- - END OPENSSH PRIVATE KEY -- -- -
`
testKeyToSignPublic := ` ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDCfVXbF38SAlchjnd8FO1zbST9qN6SpCeC+SkVLA0dbrdc0RArwuUU4LIZeiN70NQbGdizcX+iF+wEFaQs19Tt+IQ11IkvWluQCAn7a6FX2wtmO9iGKStdajIlcsMp9jXYuOlwFLYd4sxPTiVpn/FIms4EQkcbMfKvbBQ7Q1RBRA9Q4MAWGccqC+8DhS7v1RiBx1OEXjDzf4QCcTgnMFkwo8yPPLi7ULRH8ugPwO5qkfBfo0ZZ0RS9Rln5dFwhZ4I69HSd6oYFEffmTUy/uTrl3uSQTS68zlnfp6vDe12izPE9h/sAqc7UOl5Ta7AxzKbrE3B/DKcqOEuov8yCLi5H `
// Old role entries between 1.4.3 and 1.5.2 had algorithm_signer default to
// ssh-rsa if not provided.
roleOptionsOldEntry := map [ string ] interface { } {
"allow_user_certificates" : true ,
"allowed_users" : "*" ,
"default_extensions" : [ ] map [ string ] string {
{
"permit-pty" : "" ,
} ,
} ,
"key_type" : "ca" ,
"default_user" : testUserName ,
"ttl" : "30m0s" ,
"algorithm_signer" : ssh . SigAlgoRSA ,
}
// Upgrade entry by overwriting algorithm_signer with an empty value
roleOptionsUpgradedEntry := map [ string ] interface { } {
"allow_user_certificates" : true ,
"allowed_users" : "*" ,
"default_extensions" : [ ] map [ string ] string {
{
"permit-pty" : "" ,
} ,
} ,
"key_type" : "ca" ,
"default_user" : testUserName ,
"ttl" : "30m0s" ,
"algorithm_signer" : "" ,
}
testCase := logicaltest . TestCase {
LogicalBackend : b ,
Steps : [ ] logicaltest . TestStep {
configCaStep ( testCAPublicKey , testCAPrivateKey ) ,
testRoleWrite ( t , "testcarole" , roleOptionsOldEntry ) ,
testRoleWrite ( t , "testcarole" , roleOptionsUpgradedEntry ) ,
2021-04-08 16:43:39 +00:00
{
2020-08-26 19:31:56 +00:00
Operation : logical . UpdateOperation ,
Path : "sign/testcarole" ,
ErrorOk : false ,
Data : map [ string ] interface { } {
"public_key" : testKeyToSignPublic ,
"valid_principals" : testUserName ,
} ,
Check : func ( resp * logical . Response ) error {
signedKey := strings . TrimSpace ( resp . Data [ "signed_key" ] . ( string ) )
if signedKey == "" {
return errors . New ( "no signed key in response" )
}
privKey , err := ssh . ParsePrivateKey ( [ ] byte ( testKeyToSignPrivate ) )
if err != nil {
return fmt . Errorf ( "error parsing private key: %v" , err )
}
parsedKey , _ , _ , _ , err := ssh . ParseAuthorizedKey ( [ ] byte ( signedKey ) )
if err != nil {
return fmt . Errorf ( "error parsing signed key: %v" , err )
}
certSigner , err := ssh . NewCertSigner ( parsedKey . ( * ssh . Certificate ) , privKey )
if err != nil {
return err
}
2020-09-15 14:01:26 +00:00
err = testSSH ( testUserName , sshAddress , ssh . PublicKeys ( certSigner ) , "date" )
2020-08-26 19:31:56 +00:00
if err != nil {
return err
}
return nil
} ,
} ,
} ,
}
logicaltest . Test ( t , testCase )
}
2016-12-26 14:03:27 +00:00
func TestBackend_AbleToRetrievePublicKey ( t * testing . T ) {
config := logical . TestBackendConfig ( )
2018-01-19 06:44:44 +00:00
b , err := Factory ( context . Background ( ) , config )
2016-12-26 14:03:27 +00:00
if err != nil {
t . Fatalf ( "Cannot create backend: %s" , err )
}
testCase := logicaltest . TestCase {
2018-11-07 01:21:24 +00:00
LogicalBackend : b ,
2016-12-26 14:03:27 +00:00
Steps : [ ] logicaltest . TestStep {
2020-08-26 19:31:56 +00:00
configCaStep ( testCAPublicKey , testCAPrivateKey ) ,
2016-12-26 14:03:27 +00:00
2021-04-08 16:43:39 +00:00
{
2016-12-26 14:03:27 +00:00
Operation : logical . ReadOperation ,
Path : "public_key" ,
Unauthenticated : true ,
Check : func ( resp * logical . Response ) error {
key := string ( resp . Data [ "http_raw_body" ] . ( [ ] byte ) )
2020-06-11 12:10:13 +00:00
if key != testCAPublicKey {
return fmt . Errorf ( "public_key incorrect. Expected %v, actual %v" , testCAPublicKey , key )
2016-12-26 14:03:27 +00:00
}
return nil
} ,
} ,
} ,
}
logicaltest . Test ( t , testCase )
}
2017-03-02 09:32:50 +00:00
func TestBackend_AbleToAutoGenerateSigningKeys ( t * testing . T ) {
config := logical . TestBackendConfig ( )
2018-01-19 06:44:44 +00:00
b , err := Factory ( context . Background ( ) , config )
2017-03-02 09:32:50 +00:00
if err != nil {
t . Fatalf ( "Cannot create backend: %s" , err )
}
2020-06-11 12:10:13 +00:00
var expectedPublicKey string
2017-03-02 09:32:50 +00:00
testCase := logicaltest . TestCase {
2018-11-07 01:21:24 +00:00
LogicalBackend : b ,
2017-03-02 09:32:50 +00:00
Steps : [ ] logicaltest . TestStep {
2021-04-08 16:43:39 +00:00
{
2017-03-02 09:32:50 +00:00
Operation : logical . UpdateOperation ,
Path : "config/ca" ,
2020-06-11 12:10:13 +00:00
Check : func ( resp * logical . Response ) error {
if resp . Data [ "public_key" ] . ( string ) == "" {
return fmt . Errorf ( "public_key empty" )
}
expectedPublicKey = resp . Data [ "public_key" ] . ( string )
return nil
} ,
2017-03-02 09:32:50 +00:00
} ,
2021-04-08 16:43:39 +00:00
{
2017-03-02 09:32:50 +00:00
Operation : logical . ReadOperation ,
Path : "public_key" ,
Unauthenticated : true ,
Check : func ( resp * logical . Response ) error {
key := string ( resp . Data [ "http_raw_body" ] . ( [ ] byte ) )
if key == "" {
return fmt . Errorf ( "public_key empty. Expected not empty, actual %s" , key )
}
2020-06-11 12:10:13 +00:00
if key != expectedPublicKey {
return fmt . Errorf ( "public_key mismatch. Expected %s, actual %s" , expectedPublicKey , key )
}
2017-03-02 09:32:50 +00:00
return nil
} ,
} ,
} ,
}
logicaltest . Test ( t , testCase )
}
2016-12-26 14:03:27 +00:00
func TestBackend_ValidPrincipalsValidatedForHostCertificates ( t * testing . T ) {
config := logical . TestBackendConfig ( )
2018-01-19 06:44:44 +00:00
b , err := Factory ( context . Background ( ) , config )
2016-12-26 14:03:27 +00:00
if err != nil {
t . Fatalf ( "Cannot create backend: %s" , err )
}
testCase := logicaltest . TestCase {
2018-11-07 01:21:24 +00:00
LogicalBackend : b ,
2016-12-26 14:03:27 +00:00
Steps : [ ] logicaltest . TestStep {
2020-08-26 19:31:56 +00:00
configCaStep ( testCAPublicKey , testCAPrivateKey ) ,
2016-12-26 14:03:27 +00:00
createRoleStep ( "testing" , map [ string ] interface { } {
2017-03-02 21:37:03 +00:00
"key_type" : "ca" ,
2017-02-28 08:24:31 +00:00
"allow_host_certificates" : true ,
2017-03-02 21:37:03 +00:00
"allowed_domains" : "example.com,example.org" ,
"allow_subdomains" : true ,
2016-12-26 14:03:27 +00:00
"default_critical_options" : map [ string ] interface { } {
"option" : "value" ,
} ,
"default_extensions" : map [ string ] interface { } {
"extension" : "extended" ,
} ,
} ) ,
2017-03-16 15:14:17 +00:00
signCertificateStep ( "testing" , "vault-root-22608f5ef173aabf700797cb95c5641e792698ec6380e8e1eb55523e39aa5e51" , ssh . HostCert , [ ] string { "dummy.example.org" , "second.example.com" } , map [ string ] string {
2016-12-26 14:03:27 +00:00
"option" : "value" ,
} , map [ string ] string {
"extension" : "extended" ,
} ,
2 * time . Hour , map [ string ] interface { } {
"public_key" : publicKey2 ,
"ttl" : "2h" ,
"cert_type" : "host" ,
"valid_principals" : "dummy.example.org,second.example.com" ,
} ) ,
} ,
}
logicaltest . Test ( t , testCase )
}
func TestBackend_OptionsOverrideDefaults ( t * testing . T ) {
config := logical . TestBackendConfig ( )
2018-01-19 06:44:44 +00:00
b , err := Factory ( context . Background ( ) , config )
2016-12-26 14:03:27 +00:00
if err != nil {
t . Fatalf ( "Cannot create backend: %s" , err )
}
testCase := logicaltest . TestCase {
2018-11-07 01:21:24 +00:00
LogicalBackend : b ,
2016-12-26 14:03:27 +00:00
Steps : [ ] logicaltest . TestStep {
2020-08-26 19:31:56 +00:00
configCaStep ( testCAPublicKey , testCAPrivateKey ) ,
2016-12-26 14:03:27 +00:00
createRoleStep ( "testing" , map [ string ] interface { } {
2017-03-02 21:37:03 +00:00
"key_type" : "ca" ,
"allowed_users" : "tuber" ,
"default_user" : "tuber" ,
"allow_user_certificates" : true ,
2016-12-26 14:03:27 +00:00
"allowed_critical_options" : "option,secondary" ,
"allowed_extensions" : "extension,additional" ,
"default_critical_options" : map [ string ] interface { } {
"option" : "value" ,
} ,
"default_extensions" : map [ string ] interface { } {
"extension" : "extended" ,
} ,
} ) ,
2017-03-16 15:14:17 +00:00
signCertificateStep ( "testing" , "vault-root-22608f5ef173aabf700797cb95c5641e792698ec6380e8e1eb55523e39aa5e51" , ssh . UserCert , [ ] string { "tuber" } , map [ string ] string {
2016-12-26 14:03:27 +00:00
"secondary" : "value" ,
} , map [ string ] string {
"additional" : "value" ,
} , 2 * time . Hour , map [ string ] interface { } {
"public_key" : publicKey2 ,
"ttl" : "2h" ,
"critical_options" : map [ string ] interface { } {
"secondary" : "value" ,
} ,
"extensions" : map [ string ] interface { } {
"additional" : "value" ,
} ,
} ) ,
} ,
}
logicaltest . Test ( t , testCase )
}
2019-02-11 18:03:26 +00:00
func TestBackend_AllowedUserKeyLengths ( t * testing . T ) {
config := logical . TestBackendConfig ( )
b , err := Factory ( context . Background ( ) , config )
if err != nil {
t . Fatalf ( "Cannot create backend: %s" , err )
}
testCase := logicaltest . TestCase {
LogicalBackend : b ,
Steps : [ ] logicaltest . TestStep {
2020-08-26 19:31:56 +00:00
configCaStep ( testCAPublicKey , testCAPrivateKey ) ,
2019-02-11 18:03:26 +00:00
createRoleStep ( "weakkey" , map [ string ] interface { } {
"key_type" : "ca" ,
"allow_user_certificates" : true ,
"allowed_user_key_lengths" : map [ string ] interface { } {
2022-02-17 20:36:56 +00:00
"rsa" : 4096 ,
2019-02-11 18:03:26 +00:00
} ,
} ) ,
2021-04-08 16:43:39 +00:00
{
2019-02-11 18:03:26 +00:00
Operation : logical . UpdateOperation ,
Path : "sign/weakkey" ,
Data : map [ string ] interface { } {
2020-06-11 12:10:13 +00:00
"public_key" : testCAPublicKey ,
2019-02-11 18:03:26 +00:00
} ,
ErrorOk : true ,
Check : func ( resp * logical . Response ) error {
if resp . Data [ "error" ] != "public_key failed to meet the key requirements: key is of an invalid size: 2048" {
return errors . New ( "a smaller key (2048) was allowed, when the minimum was set for 4096" )
}
return nil
} ,
} ,
createRoleStep ( "stdkey" , map [ string ] interface { } {
"key_type" : "ca" ,
"allow_user_certificates" : true ,
"allowed_user_key_lengths" : map [ string ] interface { } {
2022-02-17 20:36:56 +00:00
"rsa" : 2048 ,
2019-02-11 18:03:26 +00:00
} ,
} ) ,
// Pass with 2048 key
2021-04-08 16:43:39 +00:00
{
2019-02-11 18:03:26 +00:00
Operation : logical . UpdateOperation ,
Path : "sign/stdkey" ,
Data : map [ string ] interface { } {
2020-06-11 12:10:13 +00:00
"public_key" : testCAPublicKey ,
2019-02-11 18:03:26 +00:00
} ,
} ,
// Fail with 4096 key
2021-04-08 16:43:39 +00:00
{
2019-02-11 18:03:26 +00:00
Operation : logical . UpdateOperation ,
Path : "sign/stdkey" ,
Data : map [ string ] interface { } {
"public_key" : publicKey4096 ,
} ,
ErrorOk : true ,
Check : func ( resp * logical . Response ) error {
if resp . Data [ "error" ] != "public_key failed to meet the key requirements: key is of an invalid size: 4096" {
return errors . New ( "a larger key (4096) was allowed, when the size was set for 2048" )
}
return nil
} ,
} ,
2022-02-17 20:36:56 +00:00
createRoleStep ( "multikey" , map [ string ] interface { } {
"key_type" : "ca" ,
"allow_user_certificates" : true ,
"allowed_user_key_lengths" : map [ string ] interface { } {
"rsa" : [ ] int { 2048 , 4096 } ,
} ,
} ) ,
// Pass with 2048-bit key
{
Operation : logical . UpdateOperation ,
Path : "sign/multikey" ,
Data : map [ string ] interface { } {
"public_key" : testCAPublicKey ,
} ,
} ,
// Pass with 4096-bit key
{
Operation : logical . UpdateOperation ,
Path : "sign/multikey" ,
Data : map [ string ] interface { } {
"public_key" : publicKey4096 ,
} ,
} ,
// Fail with 3072-bit key
{
Operation : logical . UpdateOperation ,
Path : "sign/multikey" ,
Data : map [ string ] interface { } {
"public_key" : publicKey3072 ,
} ,
ErrorOk : true ,
Check : func ( resp * logical . Response ) error {
if resp . Data [ "error" ] != "public_key failed to meet the key requirements: key is of an invalid size: 3072" {
return errors . New ( "a larger key (3072) was allowed, when the size was set for 2048" )
}
return nil
} ,
} ,
2022-02-18 22:48:16 +00:00
// Fail with ECDSA key
{
Operation : logical . UpdateOperation ,
Path : "sign/multikey" ,
Data : map [ string ] interface { } {
"public_key" : publicKeyECDSA256 ,
} ,
ErrorOk : true ,
Check : func ( resp * logical . Response ) error {
if resp . Data [ "error" ] != "public_key failed to meet the key requirements: key of type ecdsa is not allowed" {
return errors . New ( "an ECDSA key was allowed under RSA-only policy" )
}
return nil
} ,
} ,
createRoleStep ( "ectypes" , map [ string ] interface { } {
"key_type" : "ca" ,
"allow_user_certificates" : true ,
"allowed_user_key_lengths" : map [ string ] interface { } {
"ec" : [ ] int { 256 } ,
"ecdsa-sha2-nistp521" : 0 ,
} ,
} ) ,
// Pass with ECDSA P-256
{
Operation : logical . UpdateOperation ,
Path : "sign/ectypes" ,
Data : map [ string ] interface { } {
"public_key" : publicKeyECDSA256 ,
} ,
} ,
// Pass with ECDSA P-521
{
Operation : logical . UpdateOperation ,
Path : "sign/ectypes" ,
Data : map [ string ] interface { } {
"public_key" : publicKeyECDSA521 ,
} ,
} ,
// Fail with RSA key
{
Operation : logical . UpdateOperation ,
Path : "sign/ectypes" ,
Data : map [ string ] interface { } {
"public_key" : publicKey3072 ,
} ,
ErrorOk : true ,
Check : func ( resp * logical . Response ) error {
if resp . Data [ "error" ] != "public_key failed to meet the key requirements: key of type rsa is not allowed" {
return errors . New ( "an RSA key was allowed under ECDSA-only policy" )
}
return nil
} ,
} ,
2019-02-11 18:03:26 +00:00
} ,
}
logicaltest . Test ( t , testCase )
}
2017-06-29 03:05:06 +00:00
func TestBackend_CustomKeyIDFormat ( t * testing . T ) {
config := logical . TestBackendConfig ( )
2018-01-19 06:44:44 +00:00
b , err := Factory ( context . Background ( ) , config )
2017-06-29 03:05:06 +00:00
if err != nil {
t . Fatalf ( "Cannot create backend: %s" , err )
}
testCase := logicaltest . TestCase {
2018-11-07 01:21:24 +00:00
LogicalBackend : b ,
2017-06-29 03:05:06 +00:00
Steps : [ ] logicaltest . TestStep {
2020-08-26 19:31:56 +00:00
configCaStep ( testCAPublicKey , testCAPrivateKey ) ,
2017-06-29 03:05:06 +00:00
createRoleStep ( "customrole" , map [ string ] interface { } {
"key_type" : "ca" ,
"key_id_format" : "{{role_name}}-{{token_display_name}}-{{public_key_hash}}" ,
"allowed_users" : "tuber" ,
"default_user" : "tuber" ,
"allow_user_certificates" : true ,
"allowed_critical_options" : "option,secondary" ,
"allowed_extensions" : "extension,additional" ,
"default_critical_options" : map [ string ] interface { } {
"option" : "value" ,
} ,
"default_extensions" : map [ string ] interface { } {
"extension" : "extended" ,
} ,
} ) ,
signCertificateStep ( "customrole" , "customrole-root-22608f5ef173aabf700797cb95c5641e792698ec6380e8e1eb55523e39aa5e51" , ssh . UserCert , [ ] string { "tuber" } , map [ string ] string {
"secondary" : "value" ,
} , map [ string ] string {
"additional" : "value" ,
} , 2 * time . Hour , map [ string ] interface { } {
"public_key" : publicKey2 ,
"ttl" : "2h" ,
"critical_options" : map [ string ] interface { } {
"secondary" : "value" ,
} ,
"extensions" : map [ string ] interface { } {
"additional" : "value" ,
} ,
} ) ,
} ,
}
logicaltest . Test ( t , testCase )
}
func TestBackend_DisallowUserProvidedKeyIDs ( t * testing . T ) {
config := logical . TestBackendConfig ( )
2018-01-19 06:44:44 +00:00
b , err := Factory ( context . Background ( ) , config )
2017-06-29 03:05:06 +00:00
if err != nil {
t . Fatalf ( "Cannot create backend: %s" , err )
}
testCase := logicaltest . TestCase {
2018-11-07 01:21:24 +00:00
LogicalBackend : b ,
2017-06-29 03:05:06 +00:00
Steps : [ ] logicaltest . TestStep {
2020-08-26 19:31:56 +00:00
configCaStep ( testCAPublicKey , testCAPrivateKey ) ,
2017-06-29 03:05:06 +00:00
createRoleStep ( "testing" , map [ string ] interface { } {
"key_type" : "ca" ,
"allow_user_key_ids" : false ,
"allow_user_certificates" : true ,
} ) ,
2021-04-08 16:43:39 +00:00
{
2017-06-29 03:05:06 +00:00
Operation : logical . UpdateOperation ,
Path : "sign/testing" ,
Data : map [ string ] interface { } {
"public_key" : publicKey2 ,
"key_id" : "override" ,
} ,
ErrorOk : true ,
Check : func ( resp * logical . Response ) error {
if resp . Data [ "error" ] != "setting key_id is not allowed by role" {
2018-04-09 18:35:21 +00:00
return errors . New ( "custom user key id was allowed even when 'allow_user_key_ids' is false" )
2017-06-29 03:05:06 +00:00
}
return nil
} ,
} ,
} ,
}
logicaltest . Test ( t , testCase )
}
2021-05-13 21:37:22 +00:00
func TestBackend_DefExtTemplatingEnabled ( t * testing . T ) {
cluster , userpassToken := getSshCaTestCluster ( t , testUserName )
defer cluster . Cleanup ( )
client := cluster . Cores [ 0 ] . Client
// Get auth accessor for identity template.
2022-04-07 19:12:58 +00:00
auths , err := client . Sys ( ) . ListAuth ( )
2021-05-13 21:37:22 +00:00
if err != nil {
t . Fatal ( err )
}
userpassAccessor := auths [ "userpass/" ] . Accessor
// Write SSH role.
2022-04-07 19:12:58 +00:00
_ , err = client . Logical ( ) . Write ( "ssh/roles/test" , map [ string ] interface { } {
2021-05-13 21:37:22 +00:00
"key_type" : "ca" ,
"allowed_extensions" : "login@zipzap.com" ,
"allow_user_certificates" : true ,
"allowed_users" : "tuber" ,
"default_user" : "tuber" ,
"default_extensions_template" : true ,
"default_extensions" : map [ string ] interface { } {
"login@foobar.com" : "{{identity.entity.aliases." + userpassAccessor + ".name}}" ,
2022-06-17 15:06:17 +00:00
"login@foobar2.com" : "{{identity.entity.aliases." + userpassAccessor + ".name}}, " +
"{{identity.entity.aliases." + userpassAccessor + ".name}}_foobar" ,
2021-05-13 21:37:22 +00:00
} ,
} )
if err != nil {
t . Fatal ( err )
}
2021-10-19 00:29:47 +00:00
sshKeyID := "vault-userpass-" + testUserName + "-9bd0f01b7dfc50a13aa5e5cd11aea19276968755c8f1f9c98965d04147f30ed0"
2021-05-13 21:37:22 +00:00
// Issue SSH certificate with default extensions templating enabled, and no user-provided extensions
client . SetToken ( userpassToken )
2022-04-07 19:12:58 +00:00
resp , err := client . Logical ( ) . Write ( "ssh/sign/test" , map [ string ] interface { } {
2021-05-13 21:37:22 +00:00
"public_key" : publicKey4096 ,
} )
if err != nil {
t . Fatal ( err )
}
signedKey := resp . Data [ "signed_key" ] . ( string )
key , _ := base64 . StdEncoding . DecodeString ( strings . Split ( signedKey , " " ) [ 1 ] )
parsedKey , err := ssh . ParsePublicKey ( key )
if err != nil {
t . Fatal ( err )
}
defaultExtensionPermissions := map [ string ] string {
2022-06-17 15:06:17 +00:00
"login@foobar.com" : testUserName ,
"login@foobar2.com" : fmt . Sprintf ( "%s, %s_foobar" , testUserName , testUserName ) ,
2021-05-13 21:37:22 +00:00
}
err = validateSSHCertificate ( parsedKey . ( * ssh . Certificate ) , sshKeyID , ssh . UserCert , [ ] string { "tuber" } , map [ string ] string { } , defaultExtensionPermissions , 16 * time . Hour )
if err != nil {
t . Fatal ( err )
}
// Issue SSH certificate with default extensions templating enabled, and user-provided extensions
// The certificate should only have the user-provided extensions, and no templated extensions
userProvidedExtensionPermissions := map [ string ] string {
"login@zipzap.com" : "some_other_user_name" ,
}
2022-04-07 19:12:58 +00:00
resp , err = client . Logical ( ) . Write ( "ssh/sign/test" , map [ string ] interface { } {
2021-05-13 21:37:22 +00:00
"public_key" : publicKey4096 ,
"extensions" : userProvidedExtensionPermissions ,
} )
if err != nil {
t . Fatal ( err )
}
signedKey = resp . Data [ "signed_key" ] . ( string )
key , _ = base64 . StdEncoding . DecodeString ( strings . Split ( signedKey , " " ) [ 1 ] )
parsedKey , err = ssh . ParsePublicKey ( key )
if err != nil {
t . Fatal ( err )
}
err = validateSSHCertificate ( parsedKey . ( * ssh . Certificate ) , sshKeyID , ssh . UserCert , [ ] string { "tuber" } , map [ string ] string { } , userProvidedExtensionPermissions , 16 * time . Hour )
if err != nil {
t . Fatal ( err )
}
// Issue SSH certificate with default extensions templating enabled, and invalid user-provided extensions - it should fail
invalidUserProvidedExtensionPermissions := map [ string ] string {
"login@foobar.com" : "{{identity.entity.metadata}}" ,
}
2022-04-07 19:12:58 +00:00
resp , err = client . Logical ( ) . Write ( "ssh/sign/test" , map [ string ] interface { } {
2021-05-13 21:37:22 +00:00
"public_key" : publicKey4096 ,
"extensions" : invalidUserProvidedExtensionPermissions ,
} )
if err == nil {
t . Fatal ( "expected an error while attempting to sign a key with invalid permissions" )
}
}
2021-10-15 21:55:18 +00:00
func TestBackend_EmptyAllowedExtensionFailsClosed ( t * testing . T ) {
cluster , userpassToken := getSshCaTestCluster ( t , testUserName )
defer cluster . Cleanup ( )
client := cluster . Cores [ 0 ] . Client
// Get auth accessor for identity template.
2022-04-07 19:12:58 +00:00
auths , err := client . Sys ( ) . ListAuth ( )
2021-10-15 21:55:18 +00:00
if err != nil {
t . Fatal ( err )
}
userpassAccessor := auths [ "userpass/" ] . Accessor
// Write SSH role to test with no allowed extension. We also provide a templated default extension,
// to verify that it's not actually being evaluated
2022-04-07 19:12:58 +00:00
_ , err = client . Logical ( ) . Write ( "ssh/roles/test_allow_all_extensions" , map [ string ] interface { } {
2021-10-15 21:55:18 +00:00
"key_type" : "ca" ,
"allow_user_certificates" : true ,
"allowed_users" : "tuber" ,
"default_user" : "tuber" ,
"allowed_extensions" : "" ,
"default_extensions_template" : false ,
"default_extensions" : map [ string ] interface { } {
"login@foobar.com" : "{{identity.entity.aliases." + userpassAccessor + ".name}}" ,
} ,
} )
if err != nil {
t . Fatal ( err )
}
// Issue SSH certificate with default extensions templating disabled, and user-provided extensions
client . SetToken ( userpassToken )
userProvidedAnyExtensionPermissions := map [ string ] string {
"login@foobar.com" : "not_userpassname" ,
}
2022-04-07 19:12:58 +00:00
_ , err = client . Logical ( ) . Write ( "ssh/sign/test_allow_all_extensions" , map [ string ] interface { } {
2021-10-15 21:55:18 +00:00
"public_key" : publicKey4096 ,
"extensions" : userProvidedAnyExtensionPermissions ,
} )
if err == nil {
t . Fatal ( "Expected failure we should not have allowed specifying custom extensions" )
}
if ! strings . Contains ( err . Error ( ) , "are not on allowed list" ) {
t . Fatalf ( "Expected failure to contain 'are not on allowed list' but was %s" , err )
}
}
2021-05-13 21:37:22 +00:00
func TestBackend_DefExtTemplatingDisabled ( t * testing . T ) {
cluster , userpassToken := getSshCaTestCluster ( t , testUserName )
defer cluster . Cleanup ( )
client := cluster . Cores [ 0 ] . Client
// Get auth accessor for identity template.
2022-04-07 19:12:58 +00:00
auths , err := client . Sys ( ) . ListAuth ( )
2021-05-13 21:37:22 +00:00
if err != nil {
t . Fatal ( err )
}
userpassAccessor := auths [ "userpass/" ] . Accessor
// Write SSH role to test with any extension. We also provide a templated default extension,
// to verify that it's not actually being evaluated
2022-04-07 19:12:58 +00:00
_ , err = client . Logical ( ) . Write ( "ssh/roles/test_allow_all_extensions" , map [ string ] interface { } {
2021-05-13 21:37:22 +00:00
"key_type" : "ca" ,
"allow_user_certificates" : true ,
"allowed_users" : "tuber" ,
"default_user" : "tuber" ,
2021-10-15 21:55:18 +00:00
"allowed_extensions" : "*" ,
2021-05-13 21:37:22 +00:00
"default_extensions_template" : false ,
"default_extensions" : map [ string ] interface { } {
"login@foobar.com" : "{{identity.entity.aliases." + userpassAccessor + ".name}}" ,
} ,
} )
if err != nil {
t . Fatal ( err )
}
2021-10-19 00:29:47 +00:00
sshKeyID := "vault-userpass-" + testUserName + "-9bd0f01b7dfc50a13aa5e5cd11aea19276968755c8f1f9c98965d04147f30ed0"
2021-05-13 21:37:22 +00:00
2021-10-15 21:55:18 +00:00
// Issue SSH certificate with default extensions templating disabled, and no user-provided extensions
2021-05-13 21:37:22 +00:00
client . SetToken ( userpassToken )
defaultExtensionPermissions := map [ string ] string {
"login@foobar.com" : "{{identity.entity.aliases." + userpassAccessor + ".name}}" ,
"login@zipzap.com" : "some_other_user_name" ,
}
2022-04-07 19:12:58 +00:00
resp , err := client . Logical ( ) . Write ( "ssh/sign/test_allow_all_extensions" , map [ string ] interface { } {
2021-05-13 21:37:22 +00:00
"public_key" : publicKey4096 ,
"extensions" : defaultExtensionPermissions ,
} )
if err != nil {
t . Fatal ( err )
}
signedKey := resp . Data [ "signed_key" ] . ( string )
key , _ := base64 . StdEncoding . DecodeString ( strings . Split ( signedKey , " " ) [ 1 ] )
parsedKey , err := ssh . ParsePublicKey ( key )
if err != nil {
t . Fatal ( err )
}
err = validateSSHCertificate ( parsedKey . ( * ssh . Certificate ) , sshKeyID , ssh . UserCert , [ ] string { "tuber" } , map [ string ] string { } , defaultExtensionPermissions , 16 * time . Hour )
if err != nil {
t . Fatal ( err )
}
// Issue SSH certificate with default extensions templating disabled, and user-provided extensions
client . SetToken ( userpassToken )
userProvidedAnyExtensionPermissions := map [ string ] string {
"login@foobar.com" : "not_userpassname" ,
"login@zipzap.com" : "some_other_user_name" ,
}
2022-04-07 19:12:58 +00:00
resp , err = client . Logical ( ) . Write ( "ssh/sign/test_allow_all_extensions" , map [ string ] interface { } {
2021-05-13 21:37:22 +00:00
"public_key" : publicKey4096 ,
"extensions" : userProvidedAnyExtensionPermissions ,
} )
if err != nil {
t . Fatal ( err )
}
signedKey = resp . Data [ "signed_key" ] . ( string )
key , _ = base64 . StdEncoding . DecodeString ( strings . Split ( signedKey , " " ) [ 1 ] )
parsedKey , err = ssh . ParsePublicKey ( key )
if err != nil {
t . Fatal ( err )
}
err = validateSSHCertificate ( parsedKey . ( * ssh . Certificate ) , sshKeyID , ssh . UserCert , [ ] string { "tuber" } , map [ string ] string { } , userProvidedAnyExtensionPermissions , 16 * time . Hour )
if err != nil {
t . Fatal ( err )
}
}
2022-05-12 12:50:40 +00:00
func TestSSHBackend_ValidateNotBeforeDuration ( t * testing . T ) {
config := logical . TestBackendConfig ( )
b , err := Factory ( context . Background ( ) , config )
if err != nil {
t . Fatalf ( "Cannot create backend: %s" , err )
}
testCase := logicaltest . TestCase {
LogicalBackend : b ,
Steps : [ ] logicaltest . TestStep {
configCaStep ( testCAPublicKey , testCAPrivateKey ) ,
createRoleStep ( "testing" , map [ string ] interface { } {
"key_type" : "ca" ,
"allow_host_certificates" : true ,
"allowed_domains" : "example.com,example.org" ,
"allow_subdomains" : true ,
"default_critical_options" : map [ string ] interface { } {
"option" : "value" ,
} ,
"default_extensions" : map [ string ] interface { } {
"extension" : "extended" ,
} ,
"not_before_duration" : "300s" ,
} ) ,
signCertificateStep ( "testing" , "vault-root-22608f5ef173aabf700797cb95c5641e792698ec6380e8e1eb55523e39aa5e51" , ssh . HostCert , [ ] string { "dummy.example.org" , "second.example.com" } , map [ string ] string {
"option" : "value" ,
} , map [ string ] string {
"extension" : "extended" ,
} ,
2 * time . Hour + 5 * time . Minute - 30 * time . Second , map [ string ] interface { } {
"public_key" : publicKey2 ,
"ttl" : "2h" ,
"cert_type" : "host" ,
"valid_principals" : "dummy.example.org,second.example.com" ,
} ) ,
createRoleStep ( "testing" , map [ string ] interface { } {
"key_type" : "ca" ,
"allow_host_certificates" : true ,
"allowed_domains" : "example.com,example.org" ,
"allow_subdomains" : true ,
"default_critical_options" : map [ string ] interface { } {
"option" : "value" ,
} ,
"default_extensions" : map [ string ] interface { } {
"extension" : "extended" ,
} ,
"not_before_duration" : "2h" ,
} ) ,
signCertificateStep ( "testing" , "vault-root-22608f5ef173aabf700797cb95c5641e792698ec6380e8e1eb55523e39aa5e51" , ssh . HostCert , [ ] string { "dummy.example.org" , "second.example.com" } , map [ string ] string {
"option" : "value" ,
} , map [ string ] string {
"extension" : "extended" ,
} ,
4 * time . Hour - 30 * time . Second , map [ string ] interface { } {
"public_key" : publicKey2 ,
"ttl" : "2h" ,
"cert_type" : "host" ,
"valid_principals" : "dummy.example.org,second.example.com" ,
} ) ,
createRoleStep ( "testing" , map [ string ] interface { } {
"key_type" : "ca" ,
"allow_host_certificates" : true ,
"allowed_domains" : "example.com,example.org" ,
"allow_subdomains" : true ,
"default_critical_options" : map [ string ] interface { } {
"option" : "value" ,
} ,
"default_extensions" : map [ string ] interface { } {
"extension" : "extended" ,
} ,
"not_before_duration" : "30s" ,
} ) ,
signCertificateStep ( "testing" , "vault-root-22608f5ef173aabf700797cb95c5641e792698ec6380e8e1eb55523e39aa5e51" , ssh . HostCert , [ ] string { "dummy.example.org" , "second.example.com" } , map [ string ] string {
"option" : "value" ,
} , map [ string ] string {
"extension" : "extended" ,
} ,
2 * time . Hour , map [ string ] interface { } {
"public_key" : publicKey2 ,
"ttl" : "2h" ,
"cert_type" : "host" ,
"valid_principals" : "dummy.example.org,second.example.com" ,
} ) ,
} ,
}
logicaltest . Test ( t , testCase )
}
2022-06-10 13:48:19 +00:00
func TestSSHBackend_IssueSign ( t * testing . T ) {
config := logical . TestBackendConfig ( )
b , err := Factory ( context . Background ( ) , config )
if err != nil {
t . Fatalf ( "Cannot create backend: %s" , err )
}
testCase := logicaltest . TestCase {
LogicalBackend : b ,
Steps : [ ] logicaltest . TestStep {
configCaStep ( testCAPublicKey , testCAPrivateKey ) ,
createRoleStep ( "testing" , map [ string ] interface { } {
"key_type" : "otp" ,
"default_user" : "user" ,
} ) ,
// Key pair not issued with invalid role key type
issueSSHKeyPairStep ( "testing" , "rsa" , 0 , true , "role key type 'otp' not allowed to issue key pairs" ) ,
createRoleStep ( "testing" , map [ string ] interface { } {
"key_type" : "ca" ,
"allow_user_key_ids" : false ,
"allow_user_certificates" : true ,
"allowed_user_key_lengths" : map [ string ] interface { } {
"ssh-rsa" : [ ] int { 2048 , 3072 , 4096 } ,
"ecdsa-sha2-nistp521" : 0 ,
"ed25519" : 0 ,
} ,
} ) ,
// Key_type not in allowed_user_key_types_lengths
issueSSHKeyPairStep ( "testing" , "ec" , 256 , true , "provided key_type value not in allowed_user_key_types" ) ,
// Key_bits not in allowed_user_key_types_lengths for provided key_type
issueSSHKeyPairStep ( "testing" , "rsa" , 2560 , true , "provided key_bits value not in list of role's allowed_user_key_types" ) ,
// key_type `rsa` and key_bits `2048` successfully created
issueSSHKeyPairStep ( "testing" , "rsa" , 2048 , false , "" ) ,
// key_type `ed22519` and key_bits `0` successfully created
issueSSHKeyPairStep ( "testing" , "ed25519" , 0 , false , "" ) ,
} ,
}
logicaltest . Test ( t , testCase )
}
2021-05-13 21:37:22 +00:00
func getSshCaTestCluster ( t * testing . T , userIdentity string ) ( * vault . TestCluster , string ) {
coreConfig := & vault . CoreConfig {
CredentialBackends : map [ string ] logical . Factory {
"userpass" : userpass . Factory ,
} ,
LogicalBackends : map [ string ] logical . Factory {
"ssh" : Factory ,
} ,
}
cluster := vault . NewTestCluster ( t , coreConfig , & vault . TestClusterOptions {
HandlerFunc : vaulthttp . Handler ,
} )
cluster . Start ( )
client := cluster . Cores [ 0 ] . Client
// Write test policy for userpass auth method.
2022-04-07 19:12:58 +00:00
err := client . Sys ( ) . PutPolicy ( "test" , `
2021-05-13 21:37:22 +00:00
path "ssh/*" {
capabilities = [ "update" ]
} ` )
if err != nil {
t . Fatal ( err )
}
// Enable userpass auth method.
if err := client . Sys ( ) . EnableAuth ( "userpass" , "userpass" , "" ) ; err != nil {
t . Fatal ( err )
}
// Configure test role for userpass.
2022-04-07 19:12:58 +00:00
if _ , err := client . Logical ( ) . Write ( "auth/userpass/users/" + userIdentity , map [ string ] interface { } {
2021-05-13 21:37:22 +00:00
"password" : "test" ,
"policies" : "test" ,
} ) ; err != nil {
t . Fatal ( err )
}
// Login userpass for test role and keep client token.
2022-04-07 19:12:58 +00:00
secret , err := client . Logical ( ) . Write ( "auth/userpass/login/" + userIdentity , map [ string ] interface { } {
2021-05-13 21:37:22 +00:00
"password" : "test" ,
} )
if err != nil || secret == nil {
t . Fatal ( err )
}
userpassToken := secret . Auth . ClientToken
// Mount SSH.
2022-04-07 19:12:58 +00:00
err = client . Sys ( ) . Mount ( "ssh" , & api . MountInput {
2021-05-13 21:37:22 +00:00
Type : "ssh" ,
Config : api . MountConfigInput {
DefaultLeaseTTL : "16h" ,
MaxLeaseTTL : "60h" ,
} ,
} )
if err != nil {
t . Fatal ( err )
}
// Configure SSH CA.
2022-04-07 19:12:58 +00:00
_ , err = client . Logical ( ) . Write ( "ssh/config/ca" , map [ string ] interface { } {
2021-05-13 21:37:22 +00:00
"public_key" : testCAPublicKey ,
"private_key" : testCAPrivateKey ,
} )
if err != nil {
t . Fatal ( err )
}
return cluster , userpassToken
}
2022-07-29 13:45:52 +00:00
func testDefaultUserTemplate ( t * testing . T , testDefaultUserTemplate string ,
expectedValidPrincipal string , testEntityMetadata map [ string ] string ,
) {
cluster , userpassToken := getSshCaTestCluster ( t , testUserName )
defer cluster . Cleanup ( )
client := cluster . Cores [ 0 ] . Client
// set metadata "ssh_username" to userpass username
tokenLookupResponse , err := client . Logical ( ) . Write ( "/auth/token/lookup" , map [ string ] interface { } {
"token" : userpassToken ,
} )
if err != nil {
t . Fatal ( err )
}
entityID := tokenLookupResponse . Data [ "entity_id" ] . ( string )
_ , err = client . Logical ( ) . Write ( "/identity/entity/id/" + entityID , map [ string ] interface { } {
"metadata" : testEntityMetadata ,
} )
if err != nil {
t . Fatal ( err )
}
_ , err = client . Logical ( ) . Write ( "ssh/roles/my-role" , map [ string ] interface { } {
"key_type" : testCaKeyType ,
"allow_user_certificates" : true ,
"default_user" : testDefaultUserTemplate ,
"default_user_template" : true ,
"allowed_users" : testDefaultUserTemplate ,
"allowed_users_template" : true ,
} )
if err != nil {
t . Fatal ( err )
}
// sign SSH key as userpass user
client . SetToken ( userpassToken )
signResponse , err := client . Logical ( ) . Write ( "ssh/sign/my-role" , map [ string ] interface { } {
"public_key" : testCAPublicKey ,
} )
if err != nil {
t . Fatal ( err )
}
// check for the expected valid principals of certificate
signedKey := signResponse . Data [ "signed_key" ] . ( string )
key , _ := base64 . StdEncoding . DecodeString ( strings . Split ( signedKey , " " ) [ 1 ] )
parsedKey , err := ssh . ParsePublicKey ( key )
if err != nil {
t . Fatal ( err )
}
actualPrincipals := parsedKey . ( * ssh . Certificate ) . ValidPrincipals
if actualPrincipals [ 0 ] != expectedValidPrincipal {
t . Fatal (
fmt . Sprintf ( "incorrect ValidPrincipals: %v should be %v" ,
actualPrincipals , [ ] string { expectedValidPrincipal } ) ,
)
}
}
2022-08-16 19:59:29 +00:00
func testAllowedPrincipalsTemplate ( t * testing . T , testAllowedDomainsTemplate string ,
2022-06-10 13:48:19 +00:00
expectedValidPrincipal string , testEntityMetadata map [ string ] string ,
2022-09-08 00:31:20 +00:00
roleConfigPayload map [ string ] interface { } , signingPayload map [ string ] interface { } ,
) {
2021-10-19 22:00:15 +00:00
cluster , userpassToken := getSshCaTestCluster ( t , testUserName )
defer cluster . Cleanup ( )
client := cluster . Cores [ 0 ] . Client
// set metadata "ssh_username" to userpass username
2022-04-07 19:12:58 +00:00
tokenLookupResponse , err := client . Logical ( ) . Write ( "/auth/token/lookup" , map [ string ] interface { } {
2021-10-19 22:00:15 +00:00
"token" : userpassToken ,
} )
if err != nil {
t . Fatal ( err )
}
entityID := tokenLookupResponse . Data [ "entity_id" ] . ( string )
2022-04-07 19:12:58 +00:00
_ , err = client . Logical ( ) . Write ( "/identity/entity/id/" + entityID , map [ string ] interface { } {
2021-10-19 22:00:15 +00:00
"metadata" : testEntityMetadata ,
} )
if err != nil {
t . Fatal ( err )
}
2022-08-16 19:59:29 +00:00
_ , err = client . Logical ( ) . Write ( "ssh/roles/my-role" , roleConfigPayload )
2021-10-19 22:00:15 +00:00
if err != nil {
t . Fatal ( err )
}
// sign SSH key as userpass user
client . SetToken ( userpassToken )
2022-08-16 19:59:29 +00:00
signResponse , err := client . Logical ( ) . Write ( "ssh/sign/my-role" , signingPayload )
2021-10-19 22:00:15 +00:00
if err != nil {
t . Fatal ( err )
}
// check for the expected valid principals of certificate
signedKey := signResponse . Data [ "signed_key" ] . ( string )
key , _ := base64 . StdEncoding . DecodeString ( strings . Split ( signedKey , " " ) [ 1 ] )
parsedKey , err := ssh . ParsePublicKey ( key )
if err != nil {
t . Fatal ( err )
}
actualPrincipals := parsedKey . ( * ssh . Certificate ) . ValidPrincipals
if actualPrincipals [ 0 ] != expectedValidPrincipal {
t . Fatal (
fmt . Sprintf ( "incorrect ValidPrincipals: %v should be %v" ,
actualPrincipals , [ ] string { expectedValidPrincipal } ) ,
)
}
}
2022-08-16 19:59:29 +00:00
func testAllowedUsersTemplate ( t * testing . T , testAllowedUsersTemplate string ,
2022-09-08 00:31:20 +00:00
expectedValidPrincipal string , testEntityMetadata map [ string ] string ,
) {
2022-08-16 19:59:29 +00:00
testAllowedPrincipalsTemplate (
t , testAllowedUsersTemplate ,
expectedValidPrincipal , testEntityMetadata ,
map [ string ] interface { } {
"key_type" : testCaKeyType ,
"allow_user_certificates" : true ,
"allowed_users" : testAllowedUsersTemplate ,
"allowed_users_template" : true ,
} ,
map [ string ] interface { } {
"public_key" : testCAPublicKey ,
"valid_principals" : expectedValidPrincipal ,
} ,
)
}
2020-08-26 19:31:56 +00:00
func configCaStep ( caPublicKey , caPrivateKey string ) logicaltest . TestStep {
2016-12-26 14:03:27 +00:00
return logicaltest . TestStep {
Operation : logical . UpdateOperation ,
Path : "config/ca" ,
Data : map [ string ] interface { } {
2020-08-26 19:31:56 +00:00
"public_key" : caPublicKey ,
"private_key" : caPrivateKey ,
2016-12-26 14:03:27 +00:00
} ,
}
}
func createRoleStep ( name string , parameters map [ string ] interface { } ) logicaltest . TestStep {
return logicaltest . TestStep {
Operation : logical . CreateOperation ,
Path : "roles/" + name ,
Data : parameters ,
}
}
2017-03-02 21:37:03 +00:00
func signCertificateStep (
2019-02-11 18:03:26 +00:00
role , keyID string , certType int , validPrincipals [ ] string ,
2017-03-02 21:37:03 +00:00
criticalOptionPermissions , extensionPermissions map [ string ] string ,
ttl time . Duration ,
2022-06-10 13:48:19 +00:00
requestParameters map [ string ] interface { } ,
) logicaltest . TestStep {
2016-12-26 14:03:27 +00:00
return logicaltest . TestStep {
Operation : logical . UpdateOperation ,
Path : "sign/" + role ,
Data : requestParameters ,
Check : func ( resp * logical . Response ) error {
serialNumber := resp . Data [ "serial_number" ] . ( string )
if serialNumber == "" {
2018-04-09 18:35:21 +00:00
return errors . New ( "no serial number in response" )
2016-12-26 14:03:27 +00:00
}
signedKey := strings . TrimSpace ( resp . Data [ "signed_key" ] . ( string ) )
if signedKey == "" {
2018-04-09 18:35:21 +00:00
return errors . New ( "no signed key in response" )
2016-12-26 14:03:27 +00:00
}
key , _ := base64 . StdEncoding . DecodeString ( strings . Split ( signedKey , " " ) [ 1 ] )
parsedKey , err := ssh . ParsePublicKey ( key )
if err != nil {
return err
}
2019-02-11 18:03:26 +00:00
return validateSSHCertificate ( parsedKey . ( * ssh . Certificate ) , keyID , certType , validPrincipals , criticalOptionPermissions , extensionPermissions , ttl )
2016-12-26 14:03:27 +00:00
} ,
}
}
2022-06-10 13:48:19 +00:00
func issueSSHKeyPairStep ( role , keyType string , keyBits int , expectError bool , errorMsg string ) logicaltest . TestStep {
return logicaltest . TestStep {
Operation : logical . UpdateOperation ,
Path : "issue/" + role ,
Data : map [ string ] interface { } {
"key_type" : keyType ,
"key_bits" : keyBits ,
} ,
ErrorOk : true ,
Check : func ( resp * logical . Response ) error {
if expectError {
var err error
if resp . Data [ "error" ] != errorMsg {
err = fmt . Errorf ( "actual error message \"%s\" different from expected error message \"%s\"" , resp . Data [ "error" ] , errorMsg )
}
return err
}
if resp . IsError ( ) {
return fmt . Errorf ( "unexpected error response returned: %v" , resp . Error ( ) )
}
if resp . Data [ "private_key_type" ] != keyType {
return fmt . Errorf ( "response private_key_type (%s) does not match the provided key_type (%s)" , resp . Data [ "private_key_type" ] , keyType )
}
if resp . Data [ "signed_key" ] == "" {
return errors . New ( "certificate/signed_key should not be empty" )
}
return nil
} ,
}
}
2019-02-11 18:03:26 +00:00
func validateSSHCertificate ( cert * ssh . Certificate , keyID string , certType int , validPrincipals [ ] string , criticalOptionPermissions , extensionPermissions map [ string ] string ,
2022-01-27 18:06:34 +00:00
ttl time . Duration ,
) error {
2019-02-11 18:03:26 +00:00
if cert . KeyId != keyID {
return fmt . Errorf ( "incorrect KeyId: %v, wanted %v" , cert . KeyId , keyID )
2016-12-26 14:03:27 +00:00
}
if cert . CertType != uint32 ( certType ) {
2018-04-09 18:35:21 +00:00
return fmt . Errorf ( "incorrect CertType: %v" , cert . CertType )
2016-12-26 14:03:27 +00:00
}
if time . Unix ( int64 ( cert . ValidAfter ) , 0 ) . After ( time . Now ( ) ) {
2018-04-09 18:35:21 +00:00
return fmt . Errorf ( "incorrect ValidAfter: %v" , cert . ValidAfter )
2016-12-26 14:03:27 +00:00
}
if time . Unix ( int64 ( cert . ValidBefore ) , 0 ) . Before ( time . Now ( ) ) {
2018-04-09 18:35:21 +00:00
return fmt . Errorf ( "incorrect ValidBefore: %v" , cert . ValidBefore )
2016-12-26 14:03:27 +00:00
}
2019-02-11 18:03:26 +00:00
actualTTL := time . Unix ( int64 ( cert . ValidBefore ) , 0 ) . Add ( - 30 * time . Second ) . Sub ( time . Unix ( int64 ( cert . ValidAfter ) , 0 ) )
if actualTTL != ttl {
2021-05-13 21:37:22 +00:00
return fmt . Errorf ( "incorrect ttl: expected: %v, actual %v" , ttl , actualTTL )
2016-12-26 14:03:27 +00:00
}
if ! reflect . DeepEqual ( cert . ValidPrincipals , validPrincipals ) {
2018-04-09 18:35:21 +00:00
return fmt . Errorf ( "incorrect ValidPrincipals: expected: %#v actual: %#v" , validPrincipals , cert . ValidPrincipals )
2016-12-26 14:03:27 +00:00
}
publicSigningKey , err := getSigningPublicKey ( )
if err != nil {
return err
}
if ! reflect . DeepEqual ( cert . SignatureKey , publicSigningKey ) {
2018-04-09 18:35:21 +00:00
return fmt . Errorf ( "incorrect SignatureKey: %v" , cert . SignatureKey )
2016-12-26 14:03:27 +00:00
}
if cert . Signature == nil {
2018-04-09 18:35:21 +00:00
return fmt . Errorf ( "incorrect Signature: %v" , cert . Signature )
2016-12-26 14:03:27 +00:00
}
if ! reflect . DeepEqual ( cert . Permissions . Extensions , extensionPermissions ) {
2018-04-09 18:35:21 +00:00
return fmt . Errorf ( "incorrect Permissions.Extensions: Expected: %v, Actual: %v" , extensionPermissions , cert . Permissions . Extensions )
2016-12-26 14:03:27 +00:00
}
if ! reflect . DeepEqual ( cert . Permissions . CriticalOptions , criticalOptionPermissions ) {
2018-04-09 18:35:21 +00:00
return fmt . Errorf ( "incorrect Permissions.CriticalOptions: %v" , cert . Permissions . CriticalOptions )
2016-12-26 14:03:27 +00:00
}
return nil
}
func getSigningPublicKey ( ) ( ssh . PublicKey , error ) {
2020-06-11 12:10:13 +00:00
key , err := base64 . StdEncoding . DecodeString ( strings . Split ( testCAPublicKey , " " ) [ 1 ] )
2016-12-26 14:03:27 +00:00
if err != nil {
return nil , err
}
parsedKey , err := ssh . ParsePublicKey ( key )
if err != nil {
return nil , err
}
return parsedKey , nil
}
2015-08-30 18:17:50 +00:00
func testConfigZeroAddressDelete ( t * testing . T ) logicaltest . TestStep {
return logicaltest . TestStep {
Operation : logical . DeleteOperation ,
Path : "config/zeroaddress" ,
}
}
2015-09-03 22:50:44 +00:00
func testConfigZeroAddressWrite ( t * testing . T , data map [ string ] interface { } ) logicaltest . TestStep {
2015-08-30 18:17:50 +00:00
return logicaltest . TestStep {
2016-01-07 15:30:47 +00:00
Operation : logical . UpdateOperation ,
2015-08-30 18:17:50 +00:00
Path : "config/zeroaddress" ,
2015-09-03 22:50:44 +00:00
Data : data ,
2015-08-30 18:17:50 +00:00
}
}
func testConfigZeroAddressRead ( t * testing . T , expected map [ string ] interface { } ) logicaltest . TestStep {
return logicaltest . TestStep {
Operation : logical . ReadOperation ,
Path : "config/zeroaddress" ,
Check : func ( resp * logical . Response ) error {
var d zeroAddressRoles
if err := mapstructure . Decode ( resp . Data , & d ) ; err != nil {
return err
}
var ex zeroAddressRoles
if err := mapstructure . Decode ( expected , & ex ) ; err != nil {
return err
}
if ! reflect . DeepEqual ( d , ex ) {
return fmt . Errorf ( "Response mismatch:\nActual:%#v\nExpected:%#v" , d , ex )
}
return nil
} ,
}
}
2015-09-03 22:50:44 +00:00
func testVerifyWrite ( t * testing . T , data map [ string ] interface { } , expected map [ string ] interface { } ) logicaltest . TestStep {
2015-08-18 23:48:50 +00:00
return logicaltest . TestStep {
2016-01-07 15:30:47 +00:00
Operation : logical . UpdateOperation ,
2015-08-18 23:48:50 +00:00
Path : fmt . Sprintf ( "verify" ) ,
2015-09-03 22:50:44 +00:00
Data : data ,
2015-08-18 23:48:50 +00:00
Check : func ( resp * logical . Response ) error {
var ac api . SSHVerifyResponse
if err := mapstructure . Decode ( resp . Data , & ac ) ; err != nil {
return err
}
var ex api . SSHVerifyResponse
if err := mapstructure . Decode ( expected , & ex ) ; err != nil {
return err
}
2015-08-30 18:17:50 +00:00
if ! reflect . DeepEqual ( ac , ex ) {
2018-04-09 18:35:21 +00:00
return fmt . Errorf ( "invalid response" )
2015-08-18 23:48:50 +00:00
}
return nil
} ,
}
}
2015-09-03 22:43:53 +00:00
func testLookupRead ( t * testing . T , data map [ string ] interface { } , expected [ ] string ) logicaltest . TestStep {
2015-08-03 15:22:00 +00:00
return logicaltest . TestStep {
2016-01-07 15:30:47 +00:00
Operation : logical . UpdateOperation ,
2015-08-03 15:22:00 +00:00
Path : "lookup" ,
Data : data ,
Check : func ( resp * logical . Response ) error {
if resp . Data == nil || resp . Data [ "roles" ] == nil {
2018-04-09 18:35:21 +00:00
return fmt . Errorf ( "missing roles information" )
2015-08-03 15:22:00 +00:00
}
2015-09-03 22:43:53 +00:00
if ! reflect . DeepEqual ( resp . Data [ "roles" ] . ( [ ] string ) , expected ) {
return fmt . Errorf ( "Invalid response: \nactual:%#v\nexpected:%#v" , resp . Data [ "roles" ] . ( [ ] string ) , expected )
2015-08-03 15:22:00 +00:00
}
return nil
} ,
}
}
2015-07-31 19:17:40 +00:00
func testRoleWrite ( t * testing . T , name string , data map [ string ] interface { } ) logicaltest . TestStep {
2015-07-31 17:24:23 +00:00
return logicaltest . TestStep {
2016-01-07 15:30:47 +00:00
Operation : logical . UpdateOperation ,
2015-07-31 19:17:40 +00:00
Path : "roles/" + name ,
2015-07-31 17:24:23 +00:00
Data : data ,
}
}
2017-11-03 21:12:03 +00:00
func testRoleList ( t * testing . T , expected map [ string ] interface { } ) logicaltest . TestStep {
return logicaltest . TestStep {
Operation : logical . ListOperation ,
Path : "roles" ,
Check : func ( resp * logical . Response ) error {
if resp == nil {
return fmt . Errorf ( "nil response" )
}
if resp . Data == nil {
return fmt . Errorf ( "nil data" )
}
if ! reflect . DeepEqual ( resp . Data , expected ) {
return fmt . Errorf ( "Invalid response:\nactual:%#v\nexpected is %#v" , resp . Data , expected )
}
return nil
} ,
}
}
2015-09-10 14:44:26 +00:00
func testRoleRead ( t * testing . T , roleName string , expected map [ string ] interface { } ) logicaltest . TestStep {
2015-07-31 17:24:23 +00:00
return logicaltest . TestStep {
Operation : logical . ReadOperation ,
2015-09-10 14:44:26 +00:00
Path : "roles/" + roleName ,
2015-07-31 17:24:23 +00:00
Check : func ( resp * logical . Response ) error {
if resp == nil {
2015-09-10 14:44:26 +00:00
if expected == nil {
2015-07-31 17:24:23 +00:00
return nil
}
return fmt . Errorf ( "bad: %#v" , resp )
}
2015-07-31 19:17:40 +00:00
var d sshRole
2015-07-31 17:24:23 +00:00
if err := mapstructure . Decode ( resp . Data , & d ) ; err != nil {
2015-07-31 19:17:40 +00:00
return fmt . Errorf ( "error decoding response:%s" , err )
2015-07-31 17:24:23 +00:00
}
2020-01-21 10:46:29 +00:00
switch d . KeyType {
case "otp" :
2015-09-10 14:44:26 +00:00
if d . KeyType != expected [ "key_type" ] || d . DefaultUser != expected [ "default_user" ] || d . CIDRList != expected [ "cidr_list" ] {
2015-07-31 19:17:40 +00:00
return fmt . Errorf ( "data mismatch. bad: %#v" , resp )
}
2020-01-21 10:46:29 +00:00
default :
return fmt . Errorf ( "unknown key type. bad: %#v" , resp )
2015-07-31 17:24:23 +00:00
}
return nil
} ,
}
}
2015-07-31 19:17:40 +00:00
func testRoleDelete ( t * testing . T , name string ) logicaltest . TestStep {
2015-07-31 17:24:23 +00:00
return logicaltest . TestStep {
Operation : logical . DeleteOperation ,
2015-07-31 19:17:40 +00:00
Path : "roles/" + name ,
2015-07-31 17:24:23 +00:00
}
}
2020-06-11 12:10:13 +00:00
func testCredsWrite ( t * testing . T , roleName string , data map [ string ] interface { } , expectError bool , address string ) logicaltest . TestStep {
2015-07-10 15:56:14 +00:00
return logicaltest . TestStep {
2016-01-07 15:30:47 +00:00
Operation : logical . UpdateOperation ,
2015-09-03 22:11:04 +00:00
Path : fmt . Sprintf ( "creds/%s" , roleName ) ,
2015-09-03 22:50:44 +00:00
Data : data ,
2020-06-11 12:10:13 +00:00
ErrorOk : expectError ,
2015-07-10 15:56:14 +00:00
Check : func ( resp * logical . Response ) error {
2015-09-10 15:55:07 +00:00
if resp == nil {
return fmt . Errorf ( "response is nil" )
}
if resp . Data == nil {
return fmt . Errorf ( "data is nil" )
}
if expectError {
var e struct {
Error string ` mapstructure:"error" `
}
if err := mapstructure . Decode ( resp . Data , & e ) ; err != nil {
return err
}
if len ( e . Error ) == 0 {
2018-04-09 18:35:21 +00:00
return fmt . Errorf ( "expected error, but write succeeded" )
2015-09-10 15:55:07 +00:00
}
return nil
}
2023-01-31 21:02:22 +00:00
if roleName == testAtRoleName {
2015-09-03 22:11:04 +00:00
var d struct {
Key string ` mapstructure:"key" `
}
if err := mapstructure . Decode ( resp . Data , & d ) ; err != nil {
return err
}
if d . Key == "" {
2018-04-09 18:35:21 +00:00
return fmt . Errorf ( "generated key is an empty string" )
2015-09-03 22:11:04 +00:00
}
// Checking only for a parsable key
2020-06-11 12:10:13 +00:00
privKey , err := ssh . ParsePrivateKey ( [ ] byte ( d . Key ) )
2015-09-03 22:11:04 +00:00
if err != nil {
2018-04-09 18:35:21 +00:00
return fmt . Errorf ( "generated key is invalid" )
2015-09-03 22:11:04 +00:00
}
2020-09-15 14:01:26 +00:00
if err := testSSH ( data [ "username" ] . ( string ) , address , ssh . PublicKeys ( privKey ) , "date" ) ; err != nil {
2020-06-11 12:10:13 +00:00
return fmt . Errorf ( "unable to SSH with new key (%s): %w" , d . Key , err )
}
2015-09-03 22:11:04 +00:00
} else {
if resp . Data [ "key_type" ] != KeyTypeOTP {
2018-04-09 18:35:21 +00:00
return fmt . Errorf ( "incorrect key_type" )
2015-09-03 22:11:04 +00:00
}
if resp . Data [ "key" ] == nil {
2018-04-09 18:35:21 +00:00
return fmt . Errorf ( "invalid key" )
2015-09-03 22:11:04 +00:00
}
2015-07-10 15:56:14 +00:00
}
return nil
} ,
}
}