Skip to content

Commit

Permalink
Let allowed_users template mix templated and non-templated parts (#10388
Browse files Browse the repository at this point in the history
)
  • Loading branch information
phihos committed Mar 5, 2021
1 parent e7868e7 commit 0924ec0
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 1 deletion.
115 changes: 115 additions & 0 deletions builtin/logical/ssh/backend_test.go
Expand Up @@ -5,6 +5,8 @@ import (
"context"
"fmt"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/builtin/credential/userpass"
vaulthttp "github.com/hashicorp/vault/http"
"github.com/hashicorp/vault/sdk/logical"
"net"
"reflect"
Expand All @@ -29,6 +31,7 @@ const (
testIP = "127.0.0.1"
testUserName = "vaultssh"
testAdminUser = "vaultssh"
testCaKeyType = "ca"
testOTPKeyType = "otp"
testDynamicKeyType = "dynamic"
testCIDRList = "127.0.0.1/32"
Expand Down Expand Up @@ -316,6 +319,118 @@ func TestBackend_allowed_users(t *testing.T) {
}
}

func TestBackend_allowed_users_template(t *testing.T) {
testEntityID := "c65c8cff-5142-3d41-93d0-9d06286e7203"
testSshUsername := "testsshusername"
testEntityMetadata := map[string]string{
"ssh_username": testSshUsername,
}
testAllowedUsersTemplate := "ssh-{{ identity.entity.metadata.ssh_username }}"
expectedValidPrincipal := "ssh-" + testSshUsername

// Setup Vault cluster with a preexisting entity.
coreConfig := &vault.CoreConfig{
CredentialBackends: map[string]logical.Factory{
"userpass": userpass.Factory,
},
LogicalBackends: map[string]logical.Factory{
"ssh": 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,
EntityVal: &logical.Entity{
ID: testEntityID,
Name: "testentity",
Aliases: []*logical.Alias{},
Metadata: testEntityMetadata,
},
},
})
},
},
}
cluster := vault.NewTestCluster(t, coreConfig, &vault.TestClusterOptions{
HandlerFunc: vaulthttp.Handler,
})
cluster.Start()
defer cluster.Cleanup()
core := cluster.Cores[0]
client := core.Client
vault.TestWaitActive(t, core.Core)

// Create a policy allowing our test user to sign a SSH key.
err := client.Sys().PutPolicy("test", `
path "ssh/*" {
capabilities = ["update"]
}
`)
if err != nil {
t.Fatal(err)
}

// Init userpass auth with test user.
if err := client.Sys().EnableAuthWithOptions("userpass", &api.EnableAuthOptions{
Type: "userpass",
}); err != nil {
t.Fatal(err)
}
if _, err := client.Logical().Write("auth/userpass/users/userpassname", map[string]interface{}{
"password": "test",
"policies": "test",
}); err != nil {
t.Fatal(err)
}

// Init SSH secret engine with a signing role.
err = client.Sys().Mount("ssh", &api.MountInput{
Type: "ssh",
Config: api.MountConfigInput{
DefaultLeaseTTL: "16h",
MaxLeaseTTL: "60h",
},
})
if err != nil {
t.Fatal(err)
}
_, err = client.Logical().Write("ssh/config/ca", map[string]interface{}{
"generate_signing_key": true,
})
if err != nil {
t.Fatal(err)
}
_, err = client.Logical().Write("ssh/roles/my-role", map[string]interface{}{
"key_type": testCaKeyType,
"allow_user_certificates": true,
"allowed_users": testAllowedUsersTemplate,
"allowed_users_template": true,
})
if err != nil {
t.Fatal(err)
}

// Login test user and sign key with expected valid principal.
secret, err := client.Logical().Write("auth/userpass/login/userpassname", map[string]interface{}{
"password": "test",
})
if err != nil || secret == nil {
t.Fatal(err)
}
userpassToken := secret.Auth.ClientToken
client.SetToken(userpassToken)
_, err = client.Logical().Write("ssh/sign/my-role", map[string]interface{}{
"public_key": testCAPublicKey,
"valid_principals": expectedValidPrincipal,
})
if err != nil {
t.Fatal(err)
}
}

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
Expand Down
2 changes: 1 addition & 1 deletion builtin/logical/ssh/path_sign.go
Expand Up @@ -221,7 +221,7 @@ func (b *backend) calculateValidPrincipals(data *framework.FieldData, req *logic
for _, principal := range strutil.RemoveDuplicates(strutil.ParseStringSlice(principalsAllowedByRole, ","), false) {
if role.AllowedUsersTemplate {
// Look for templating markers {{ .* }}
matched, _ := regexp.MatchString(`^{{.+?}}$`, principal)
matched, _ := regexp.MatchString(`{{.+?}}`, principal)
if matched {
if req.EntityID != "" {
// Retrieve principal based on template + entityID from request.
Expand Down

0 comments on commit 0924ec0

Please sign in to comment.