Fix entropy sourcing on Vault Enterprise (#20684)

Note the three overlapping scenarios discussed in the comments. In the
future, when this interface is more broadly supported, we should likely
add the interface directly to SystemView and implement it over the GRPC
interface, removing this nasty layering of already complex SystemView
implementations.

Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
This commit is contained in:
Alexander Scheel 2023-05-19 14:15:43 -04:00 committed by GitHub
parent f551f4e5ba
commit 9d2af72bde
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 87 additions and 13 deletions

View File

@ -13,34 +13,103 @@ import (
"time" "time"
"github.com/hashicorp/vault/sdk/logical" "github.com/hashicorp/vault/sdk/logical"
"github.com/hashicorp/go-kms-wrapping/entropy/v2"
) )
// See comment in command/format.go // See comment in command/format.go
const hopeDelim = "♨" const hopeDelim = "♨"
type acmeBillingSystemViewImpl struct { // acmeBillingImpl is the (single) implementation of the actual client
extendedSystemView // counting interface. It needs a reference to core (as per discussions
logical.ManagedKeySystemView // with Mike, in the future the activityLog reference will no longer be
// static but may be replaced throughout the lifecycle of a core instance)
// and a reference to the mount that is being counted.
type acmeBillingImpl struct {
core *Core core *Core
entry *MountEntry entry *MountEntry
} }
var _ logical.ACMEBillingSystemView = (*acmeBillingSystemViewImpl)(nil) var _ logical.ACMEBillingSystemView = (*acmeBillingImpl)(nil)
func (c *Core) NewAcmeBillingSystemView(sysView interface{}, managed logical.ManagedKeySystemView) *acmeBillingSystemViewImpl { // Due to unfortunate layering of system view interfaces, there are three
// possible sets of interfaces we need to layer with this ACME interface:
//
// 1. Everything: a managed key system view, an entropy sourcer, and an
// extended system view.
// 2. Managed keys without an entropy sourcer.
// 3. Just extended system view.
//
// Unfortunately, just using acmeBillingSystemViewImpl is not sufficient:
// because of the embedded interfaces, even when these are nil, the
// implementation will claim to support these interfaces, (thus, their cast
// being accepted by the toolchain), but when the caller goes to use the new
// value, they are hit with a nil panic.
//
// This is unfortunate.
//
// To avoid this, we create three possible implementations and use the lowest
// common denominator of the caller of NewAcmeBillingSystemView(...) to assume
// it is _just_ an extendedSystemView implementation.
// Scenario 1 above.
type acmeBillingSystemViewImpl struct {
extendedSystemView
logical.ManagedKeySystemView
entropy.Sourcer
acmeBillingImpl
}
var (
_ logical.ACMEBillingSystemView = (*acmeBillingSystemViewImpl)(nil)
_ extendedSystemView = (*acmeBillingSystemViewImpl)(nil)
_ logical.ManagedKeySystemView = (*acmeBillingSystemViewImpl)(nil)
_ entropy.Sourcer = (*acmeBillingSystemViewImpl)(nil)
)
// Scenario 2 above.
type acmeBillingSystemViewImplNoSourcer struct {
extendedSystemView
logical.ManagedKeySystemView
acmeBillingImpl
}
var (
_ logical.ACMEBillingSystemView = (*acmeBillingSystemViewImplNoSourcer)(nil)
_ extendedSystemView = (*acmeBillingSystemViewImplNoSourcer)(nil)
_ logical.ManagedKeySystemView = (*acmeBillingSystemViewImplNoSourcer)(nil)
)
// Scenario 3 above.
type acmeBillingSystemViewImplNoManagedKeys struct {
extendedSystemView
acmeBillingImpl
}
var (
_ logical.ACMEBillingSystemView = (*acmeBillingSystemViewImplNoManagedKeys)(nil)
_ extendedSystemView = (*acmeBillingSystemViewImplNoManagedKeys)(nil)
)
// NewAcmeBillingSystemView creates the appropriate implementation based on
// the passed arguments, mapping them to the above scenarios. We further
// restrict sysView to have a dynamicSystemView implementation, to get the
// mount entry out of.
func (c *Core) NewAcmeBillingSystemView(sysView interface{}) extendedSystemView {
es := sysView.(extendedSystemViewImpl) es := sysView.(extendedSystemViewImpl)
des := es.dynamicSystemView des := es.dynamicSystemView
return &acmeBillingSystemViewImpl{ // Scenario 3.
extendedSystemView: es, return &acmeBillingSystemViewImplNoManagedKeys{
ManagedKeySystemView: managed, extendedSystemView: es,
core: c, acmeBillingImpl: acmeBillingImpl{
entry: des.mountEntry, core: c,
entry: des.mountEntry,
},
} }
} }
func (a *acmeBillingSystemViewImpl) CreateActivityCountEventForIdentifiers(ctx context.Context, identifiers []string) error { func (a *acmeBillingImpl) CreateActivityCountEventForIdentifiers(ctx context.Context, identifiers []string) error {
// Fake our clientID from the identifiers, but ensure it is // Fake our clientID from the identifiers, but ensure it is
// independent of ordering. // independent of ordering.
// //

View File

@ -64,5 +64,10 @@ func (c *Core) mountEntrySysView(entry *MountEntry) extendedSystemView {
}, },
} }
return c.NewAcmeBillingSystemView(esi, nil /* managed keys system view */) // Due to complexity in the ACME interface, only return it when we
// are a PKI plugin that needs it.
if entry.Type != "pki" {
return esi
}
return c.NewAcmeBillingSystemView(esi)
} }