bug(vault): Correctly handle credential stores with expired tokens (#2399)

* bug(vault): Correctly handle credential stores with expired tokens

Boundary makes use of a database view to perform CRUD operations on
Vault credential stores and libraries. This view did not include
credential stores with tokens that have expired in Vault, causing
errors when attempting to perform any action against them.
This commit is contained in:
Louis Ruch authored and GitHub committed 2022-09-06 07:50:15 -07:00
1 parent ef4000fe08
commit d7c4c648ec
33 files changed
+965 -287

No files matched your search

@@ -675,6 +675,7 @@ func toProto(ctx context.Context, in credential.Store, opt ...handlers.Option) (
}
if vaultIn.Token() != nil {
attrs.TokenHmac = base64.RawURLEncoding.EncodeToString(vaultIn.Token().GetTokenHmac())
attrs.TokenStatus = vaultIn.Token().GetStatus()
}
if vaultIn.GetWorkerFilter() != "" {
if vaultWorkerFilterToProto {
@@ -96,6 +96,7 @@ func TestList(t *testing.T) {
VaultCredentialStoreAttributes: &pb.VaultCredentialStoreAttributes{
Address: wrapperspb.String(s.GetVaultAddress()),
TokenHmac: base64.RawURLEncoding.EncodeToString(s.Token().GetTokenHmac()),
TokenStatus: s.Token().GetStatus(),
ClientCertificate: wrapperspb.String(string(s.ClientCertificate().GetCertificate())),
ClientCertificateKeyHmac: base64.RawURLEncoding.EncodeToString(s.ClientCertificate().GetCertificateKeyHmac()),
// TODO: Add all fields including tls related fields, namespace, etc...
@@ -471,6 +472,7 @@ func TestCreateVault(t *testing.T) {
CaCert: wrapperspb.String(string(v.CaCert)),
Address: wrapperspb.String(v.Addr),
TokenHmac: "<hmac>",
TokenStatus: "current",
ClientCertificate: wrapperspb.String(string(v.ClientCert)),
ClientCertificateKeyHmac: "<hmac>",
},
@@ -512,6 +514,7 @@ func TestCreateVault(t *testing.T) {
CaCert: wrapperspb.String(string(v.CaCert)),
Address: wrapperspb.String(v.Addr),
TokenHmac: "<hmac>",
TokenStatus: "current",
ClientCertificate: wrapperspb.String(string(v.ClientCert)),
ClientCertificateKeyHmac: "<hmac>",
},
@@ -795,6 +798,7 @@ func TestGet(t *testing.T) {
VaultCredentialStoreAttributes: &pb.VaultCredentialStoreAttributes{
Address: wrapperspb.String(vaultStore.GetVaultAddress()),
TokenHmac: base64.RawURLEncoding.EncodeToString(vaultStore.Token().GetTokenHmac()),
TokenStatus: vaultStore.Token().GetStatus(),
ClientCertificate: wrapperspb.String(string(vaultStore.ClientCertificate().GetCertificate())),
ClientCertificateKeyHmac: base64.RawURLEncoding.EncodeToString(vaultStore.ClientCertificate().GetCertificateKeyHmac()),
},
@@ -1068,6 +1072,7 @@ func TestUpdateVault(t *testing.T) {
res: func(in *pb.CredentialStore) *pb.CredentialStore {
out := proto.Clone(in).(*pb.CredentialStore)
out.GetVaultCredentialStoreAttributes().TokenHmac = "<hmac>"
out.GetVaultCredentialStoreAttributes().TokenStatus = "current"
return out
},
},
@@ -3257,6 +3257,17 @@ func TestAuthorizeSession_Errors(t *testing.T) {
sec, tok := v.CreateToken(t, vault.WithPolicies([]string{"default", "database"}))
store := vault.TestCredentialStore(t, conn, wrapper, proj.GetPublicId(), v.Addr, tok, sec.Auth.Accessor)
sec1, tok1 := v.CreateToken(t, vault.WithPolicies([]string{"default", "database"}))
expiredStore := vault.TestCredentialStore(t, conn, wrapper, proj.GetPublicId(), v.Addr, tok1, sec1.Auth.Accessor)
// Set previous token to expired in the database and revoke in Vault to validate a
// credential store with an expired token is correctly returned over the API
num, err := rw.Exec(context.Background(), "update credential_vault_token set status = ? where store_id = ?",
[]interface{}{vault.ExpiredToken, expiredStore.PublicId})
require.NoError(t, err)
assert.Equal(t, 1, num)
v.RevokeToken(t, tok1)
workerExists := func(tar target.Target) (version uint32) {
server.TestKmsWorker(t, conn, wrapper)
return tar.GetVersion()
@@ -3356,6 +3367,30 @@ func TestAuthorizeSession_Errors(t *testing.T) {
return tr.GetItem().GetVersion()
}
expiredTokenLibrary := func(tar target.Target) (version uint32) {
credService, err := credentiallibraries.NewService(vaultCredRepoFn, iamRepoFn)
require.NoError(t, err)
clsResp, err := credService.CreateCredentialLibrary(ctx, &pbs.CreateCredentialLibraryRequest{Item: &credlibpb.CredentialLibrary{
CredentialStoreId: expiredStore.GetPublicId(),
Description: wrapperspb.String(fmt.Sprintf("Library Description for target %q", tar.GetName())),
Attrs: &credlibpb.CredentialLibrary_VaultCredentialLibraryAttributes{
VaultCredentialLibraryAttributes: &credlibpb.VaultCredentialLibraryAttributes{
Path: wrapperspb.String(path.Join("database", "creds", "opened")),
},
},
}})
require.NoError(t, err)
tr, err := s.AddTargetCredentialSources(ctx,
&pbs.AddTargetCredentialSourcesRequest{
Id: tar.GetPublicId(),
BrokeredCredentialSourceIds: []string{clsResp.GetItem().GetId()},
Version: tar.GetVersion(),
})
require.NoError(t, err)
return tr.GetItem().GetVersion()
}
cases := []struct {
name string
setup []func(target.Target) uint32
@@ -3386,6 +3421,11 @@ func TestAuthorizeSession_Errors(t *testing.T) {
setup: []func(tcpTarget target.Target) uint32{workerExists, hostExists, misConfiguredlibraryExists},
err: true,
},
{
name: "expired token library",
setup: []func(tcpTarget target.Target) uint32{workerExists, hostExists, expiredTokenLibrary},
err: true,
},
}
for i, tc := range cases {
t.Run(tc.name, func(t *testing.T) {