Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove dynamic keys from SSH Secrets Engine #18874

Merged
merged 6 commits into from
Jan 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions builtin/logical/ssh/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ func Backend(conf *logical.BackendConfig) (*backend, error) {

Paths: []*framework.Path{
pathConfigZeroAddress(&b),
pathKeys(&b),
pathListRoles(&b),
pathRoles(&b),
pathCredsCreate(&b),
Expand All @@ -66,7 +65,6 @@ func Backend(conf *logical.BackendConfig) (*backend, error) {
},

Secrets: []*framework.Secret{
secretDynamicKey(&b),
secretOTP(&b),
},

Expand Down Expand Up @@ -112,8 +110,8 @@ const backendHelp = `
The SSH backend generates credentials allowing clients to establish SSH
connections to remote hosts.

There are three variants of the backend, which generate different types of
credentials: dynamic keys, One-Time Passwords (OTPs) and certificate authority. The desired behavior
There are two variants of the backend, which generate different types of
credentials: One-Time Passwords (OTPs) and certificate authority. The desired behavior
is role-specific and chosen at role creation time with the 'key_type'
parameter.

Expand Down
193 changes: 14 additions & 179 deletions builtin/logical/ssh/backend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,15 @@ import (
)

const (
testIP = "127.0.0.1"
testUserName = "vaultssh"
testMultiUserName = "vaultssh,otherssh"
testAdminUser = "vaultssh"
testCaKeyType = "ca"
testOTPKeyType = "otp"
testDynamicKeyType = "dynamic"
testCIDRList = "127.0.0.1/32"
testAtRoleName = "test@RoleName"
testDynamicRoleName = "testDynamicRoleName"
testOTPRoleName = "testOTPRoleName"
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"
// 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
Expand Down Expand Up @@ -537,36 +535,22 @@ func TestSSHBackend_Lookup(t *testing.T) {
"default_user": testUserName,
"cidr_list": testCIDRList,
}
testDynamicRoleData := map[string]interface{}{
"key_type": testDynamicKeyType,
"key": testKeyName,
"admin_user": testAdminUser,
"default_user": testAdminUser,
"cidr_list": testCIDRList,
}
data := map[string]interface{}{
"ip": testIP,
}
resp1 := []string(nil)
resp2 := []string{testOTPRoleName}
resp3 := []string{testDynamicRoleName, testOTPRoleName}
resp4 := []string{testDynamicRoleName}
resp5 := []string{testAtRoleName}
resp3 := []string{testAtRoleName}
logicaltest.Test(t, logicaltest.TestCase{
LogicalFactory: newTestingFactory(t),
Steps: []logicaltest.TestStep{
testLookupRead(t, data, resp1),
testRoleWrite(t, testOTPRoleName, testOTPRoleData),
testLookupRead(t, data, resp2),
testNamedKeysWrite(t, testKeyName, testSharedPrivateKey),
testRoleWrite(t, testDynamicRoleName, testDynamicRoleData),
testLookupRead(t, data, resp3),
testRoleDelete(t, testOTPRoleName),
testLookupRead(t, data, resp4),
testRoleDelete(t, testDynamicRoleName),
testLookupRead(t, data, resp1),
testRoleWrite(t, testAtRoleName, testDynamicRoleData),
testLookupRead(t, data, resp5),
testRoleWrite(t, testAtRoleName, testOTPRoleData),
testLookupRead(t, data, resp3),
testRoleDelete(t, testAtRoleName),
testLookupRead(t, data, resp1),
},
Expand Down Expand Up @@ -615,39 +599,6 @@ func TestSSHBackend_RoleList(t *testing.T) {
})
}

func TestSSHBackend_DynamicKeyCreate(t *testing.T) {
cleanup, sshAddress := prepareTestContainer(t, "", "")
defer cleanup()

host, port, err := net.SplitHostPort(sshAddress)
if err != nil {
t.Fatal(err)
}

testDynamicRoleData := map[string]interface{}{
"key_type": testDynamicKeyType,
"key": testKeyName,
"admin_user": testAdminUser,
"default_user": testAdminUser,
"cidr_list": host + "/32",
"port": port,
}
data := map[string]interface{}{
"username": testUserName,
"ip": host,
}
logicaltest.Test(t, logicaltest.TestCase{
LogicalFactory: newTestingFactory(t),
Steps: []logicaltest.TestStep{
testNamedKeysWrite(t, testKeyName, testSharedPrivateKey),
testRoleWrite(t, testDynamicRoleName, testDynamicRoleData),
testCredsWrite(t, testDynamicRoleName, data, false, sshAddress),
testRoleWrite(t, testAtRoleName, testDynamicRoleData),
testCredsWrite(t, testAtRoleName, data, false, sshAddress),
},
})
}

func TestSSHBackend_OTPRoleCrud(t *testing.T) {
testOTPRoleData := map[string]interface{}{
"key_type": testOTPKeyType,
Expand Down Expand Up @@ -675,50 +626,6 @@ func TestSSHBackend_OTPRoleCrud(t *testing.T) {
})
}

func TestSSHBackend_DynamicRoleCrud(t *testing.T) {
testDynamicRoleData := map[string]interface{}{
"key_type": testDynamicKeyType,
"key": testKeyName,
"admin_user": testAdminUser,
"default_user": testAdminUser,
"cidr_list": testCIDRList,
}
respDynamicRoleData := map[string]interface{}{
"cidr_list": testCIDRList,
"port": 22,
"install_script": DefaultPublicKeyInstallScript,
"key_bits": 1024,
"key": testKeyName,
"admin_user": testUserName,
"default_user": testUserName,
"key_type": testDynamicKeyType,
}
logicaltest.Test(t, logicaltest.TestCase{
LogicalFactory: newTestingFactory(t),
Steps: []logicaltest.TestStep{
testNamedKeysWrite(t, testKeyName, testSharedPrivateKey),
testRoleWrite(t, testDynamicRoleName, testDynamicRoleData),
testRoleRead(t, testDynamicRoleName, respDynamicRoleData),
testRoleDelete(t, testDynamicRoleName),
testRoleRead(t, testDynamicRoleName, nil),
testRoleWrite(t, testAtRoleName, testDynamicRoleData),
testRoleRead(t, testAtRoleName, respDynamicRoleData),
testRoleDelete(t, testAtRoleName),
testRoleRead(t, testAtRoleName, nil),
},
})
}

func TestSSHBackend_NamedKeysCrud(t *testing.T) {
logicaltest.Test(t, logicaltest.TestCase{
LogicalFactory: newTestingFactory(t),
Steps: []logicaltest.TestStep{
testNamedKeysWrite(t, testKeyName, testSharedPrivateKey),
testNamedKeysDelete(t),
},
})
}

func TestSSHBackend_OTPCreate(t *testing.T) {
cleanup, sshAddress := prepareTestContainer(t, "", "")
defer func() {
Expand Down Expand Up @@ -772,24 +679,14 @@ func TestSSHBackend_ConfigZeroAddressCRUD(t *testing.T) {
"default_user": testUserName,
"cidr_list": testCIDRList,
}
testDynamicRoleData := map[string]interface{}{
"key_type": testDynamicKeyType,
"key": testKeyName,
"admin_user": testAdminUser,
"default_user": testAdminUser,
"cidr_list": testCIDRList,
}
req1 := map[string]interface{}{
"roles": testOTPRoleName,
}
resp1 := map[string]interface{}{
"roles": []string{testOTPRoleName},
}
req2 := map[string]interface{}{
"roles": fmt.Sprintf("%s,%s", testOTPRoleName, testDynamicRoleName),
}
resp2 := map[string]interface{}{
"roles": []string{testOTPRoleName, testDynamicRoleName},
"roles": []string{testOTPRoleName},
}
resp3 := map[string]interface{}{
"roles": []string{},
Expand All @@ -801,11 +698,7 @@ func TestSSHBackend_ConfigZeroAddressCRUD(t *testing.T) {
testRoleWrite(t, testOTPRoleName, testOTPRoleData),
testConfigZeroAddressWrite(t, req1),
testConfigZeroAddressRead(t, resp1),
testNamedKeysWrite(t, testKeyName, testSharedPrivateKey),
testRoleWrite(t, testDynamicRoleName, testDynamicRoleData),
testConfigZeroAddressWrite(t, req2),
testConfigZeroAddressRead(t, resp2),
testRoleDelete(t, testDynamicRoleName),
testConfigZeroAddressRead(t, resp1),
testRoleDelete(t, testOTPRoleName),
testConfigZeroAddressRead(t, resp3),
Expand Down Expand Up @@ -839,43 +732,6 @@ func TestSSHBackend_CredsForZeroAddressRoles_otp(t *testing.T) {
})
}

func TestSSHBackend_CredsForZeroAddressRoles_dynamic(t *testing.T) {
cleanup, sshAddress := prepareTestContainer(t, "", "")
defer cleanup()

host, port, err := net.SplitHostPort(sshAddress)
if err != nil {
t.Fatal(err)
}

dynamicRoleData := map[string]interface{}{
"key_type": testDynamicKeyType,
"key": testKeyName,
"admin_user": testAdminUser,
"default_user": testAdminUser,
"port": port,
}
data := map[string]interface{}{
"username": testUserName,
"ip": host,
}
req2 := map[string]interface{}{
"roles": testDynamicRoleName,
}
logicaltest.Test(t, logicaltest.TestCase{
LogicalFactory: newTestingFactory(t),
Steps: []logicaltest.TestStep{
testNamedKeysWrite(t, testKeyName, testSharedPrivateKey),
testRoleWrite(t, testDynamicRoleName, dynamicRoleData),
testCredsWrite(t, testDynamicRoleName, data, true, sshAddress),
testConfigZeroAddressWrite(t, req2),
testCredsWrite(t, testDynamicRoleName, data, false, sshAddress),
testConfigZeroAddressDelete(t),
testCredsWrite(t, testDynamicRoleName, data, true, sshAddress),
},
})
}

func TestSSHBackend_CA(t *testing.T) {
testCases := []struct {
name string
Expand Down Expand Up @@ -2414,23 +2270,6 @@ func testVerifyWrite(t *testing.T, data map[string]interface{}, expected map[str
}
}

func testNamedKeysWrite(t *testing.T, name, key string) logicaltest.TestStep {
return logicaltest.TestStep{
Operation: logical.UpdateOperation,
Path: fmt.Sprintf("keys/%s", name),
Data: map[string]interface{}{
"key": key,
},
}
}

func testNamedKeysDelete(t *testing.T) logicaltest.TestStep {
return logicaltest.TestStep{
Operation: logical.DeleteOperation,
Path: fmt.Sprintf("keys/%s", testKeyName),
}
}

func testLookupRead(t *testing.T, data map[string]interface{}, expected []string) logicaltest.TestStep {
return logicaltest.TestStep{
Operation: logical.UpdateOperation,
Expand Down Expand Up @@ -2495,10 +2334,6 @@ func testRoleRead(t *testing.T, roleName string, expected map[string]interface{}
if d.KeyType != expected["key_type"] || d.DefaultUser != expected["default_user"] || d.CIDRList != expected["cidr_list"] {
return fmt.Errorf("data mismatch. bad: %#v", resp)
}
case "dynamic":
if d.AdminUser != expected["admin_user"] || d.CIDRList != expected["cidr_list"] || d.KeyName != expected["key"] || d.KeyType != expected["key_type"] {
return fmt.Errorf("data mismatch. bad: %#v", resp)
}
default:
return fmt.Errorf("unknown key type. bad: %#v", resp)
}
Expand Down Expand Up @@ -2539,7 +2374,7 @@ func testCredsWrite(t *testing.T, roleName string, data map[string]interface{},
}
return nil
}
if roleName == testDynamicRoleName || roleName == testAtRoleName {
if roleName == testAtRoleName {
var d struct {
Key string `mapstructure:"key"`
}
Expand Down
Loading