mirror of
https://github.com/hashicorp/vault.git
synced 2026-02-03 20:40:45 -05:00
Add cert metadata fields for tidy (#26867)
* add cert metadata fields for tidy * fix import * add missing fields to schema * add new fields to expected value * change error
This commit is contained in:
parent
eabb8e10a0
commit
a7b6f3490f
4 changed files with 86 additions and 1 deletions
|
|
@ -4108,6 +4108,7 @@ func TestBackend_RevokePlusTidy_Intermediate(t *testing.T) {
|
|||
"tidy_move_legacy_ca_bundle": false,
|
||||
"tidy_revocation_queue": false,
|
||||
"tidy_cross_cluster_revoked_certs": false,
|
||||
"tidy_cert_metadata": false,
|
||||
"pause_duration": "0s",
|
||||
"state": "Finished",
|
||||
"error": nil,
|
||||
|
|
@ -4129,6 +4130,7 @@ func TestBackend_RevokePlusTidy_Intermediate(t *testing.T) {
|
|||
"acme_account_revoked_count": json.Number("0"),
|
||||
"acme_account_deleted_count": json.Number("0"),
|
||||
"total_acme_account_count": json.Number("0"),
|
||||
"cert_metadata_deleted_count": json.Number("0"),
|
||||
}
|
||||
// Let's copy the times from the response so that we can use deep.Equal()
|
||||
timeStarted, ok := tidyStatus.Data["time_started"]
|
||||
|
|
|
|||
|
|
@ -579,6 +579,11 @@ the cross-cluster revoked certificate store. Only runs on the active
|
|||
primary node.`,
|
||||
}
|
||||
|
||||
fields["tidy_cert_metadata"] = &framework.FieldSchema{
|
||||
Type: framework.TypeBool,
|
||||
Description: `Set to true to enable tidying up certificate metadata`,
|
||||
}
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import (
|
|||
"errors"
|
||||
"math/big"
|
||||
|
||||
"github.com/hashicorp/go-hclog"
|
||||
"github.com/hashicorp/vault/builtin/logical/pki/issuing"
|
||||
"github.com/hashicorp/vault/sdk/logical"
|
||||
)
|
||||
|
|
@ -24,3 +25,7 @@ func storeMetadata(ctx context.Context, storage logical.Storage, issuerId issuin
|
|||
func GetCertificateMetadata(ctx context.Context, storage logical.Storage, serialNumber *big.Int) (*CertificateMetadata, error) {
|
||||
return nil, ErrMetadataIsEntOnly
|
||||
}
|
||||
|
||||
func (b *backend) doTidyCertMetadata(ctx context.Context, req *logical.Request, logger hclog.Logger, config *tidyConfig) error {
|
||||
return ErrMetadataIsEntOnly
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import (
|
|||
"github.com/hashicorp/go-hclog"
|
||||
"github.com/hashicorp/go-secure-stdlib/parseutil"
|
||||
"github.com/hashicorp/vault/builtin/logical/pki/issuing"
|
||||
"github.com/hashicorp/vault/helper/constants"
|
||||
"github.com/hashicorp/vault/sdk/framework"
|
||||
"github.com/hashicorp/vault/sdk/helper/consts"
|
||||
"github.com/hashicorp/vault/sdk/logical"
|
||||
|
|
@ -50,6 +51,7 @@ type tidyStatus struct {
|
|||
tidyRevocationQueue bool
|
||||
tidyCrossRevokedCerts bool
|
||||
tidyAcme bool
|
||||
tidyCertMetadata bool
|
||||
pauseDuration string
|
||||
|
||||
// Status
|
||||
|
|
@ -66,6 +68,7 @@ type tidyStatus struct {
|
|||
missingIssuerCertCount uint
|
||||
revQueueDeletedCount uint
|
||||
crossRevokedDeletedCount uint
|
||||
certMetadataDeletedCount uint
|
||||
|
||||
acmeAccountsCount uint
|
||||
acmeAccountsRevokedCount uint
|
||||
|
|
@ -87,6 +90,7 @@ type tidyConfig struct {
|
|||
RevocationQueue bool `json:"tidy_revocation_queue"`
|
||||
CrossRevokedCerts bool `json:"tidy_cross_cluster_revoked_certs"`
|
||||
TidyAcme bool `json:"tidy_acme"`
|
||||
CertMetadata bool `json:"tidy_cert_metadata"`
|
||||
|
||||
// Safety Buffers
|
||||
SafetyBuffer time.Duration `json:"safety_buffer"`
|
||||
|
|
@ -101,7 +105,7 @@ type tidyConfig struct {
|
|||
}
|
||||
|
||||
func (tc *tidyConfig) IsAnyTidyEnabled() bool {
|
||||
return tc.CertStore || tc.RevokedCerts || tc.IssuerAssocs || tc.ExpiredIssuers || tc.BackupBundle || tc.TidyAcme || tc.CrossRevokedCerts || tc.RevocationQueue
|
||||
return tc.CertStore || tc.RevokedCerts || tc.IssuerAssocs || tc.ExpiredIssuers || tc.BackupBundle || tc.TidyAcme || tc.CrossRevokedCerts || tc.RevocationQueue || tc.CertMetadata
|
||||
}
|
||||
|
||||
func (tc *tidyConfig) AnyTidyConfig() string {
|
||||
|
|
@ -126,6 +130,7 @@ var defaultTidyConfig = tidyConfig{
|
|||
RevocationQueue: false,
|
||||
QueueSafetyBuffer: 48 * time.Hour,
|
||||
CrossRevokedCerts: false,
|
||||
CertMetadata: false,
|
||||
}
|
||||
|
||||
func pathTidy(b *backend) *framework.Path {
|
||||
|
|
@ -217,6 +222,11 @@ func pathTidyCancel(b *backend) *framework.Path {
|
|||
Description: `Tidy expired issuers`,
|
||||
Required: false,
|
||||
},
|
||||
"tidy_cert_metadata": {
|
||||
Type: framework.TypeBool,
|
||||
Description: `Tidy cert metadata`,
|
||||
Required: false,
|
||||
},
|
||||
"pause_duration": {
|
||||
Type: framework.TypeString,
|
||||
Description: `Duration to pause between tidying certificates`,
|
||||
|
|
@ -321,6 +331,11 @@ func pathTidyCancel(b *backend) *framework.Path {
|
|||
Description: `The number of expired, unused acme orders removed`,
|
||||
Required: false,
|
||||
},
|
||||
"cert_metadata_deleted_count": {
|
||||
Type: framework.TypeInt,
|
||||
Description: `The number of metadata entries removed`,
|
||||
Required: false,
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
|
|
@ -399,6 +414,11 @@ func pathTidyStatus(b *backend) *framework.Path {
|
|||
Description: `Tidy Unused Acme Accounts, and Orders`,
|
||||
Required: true,
|
||||
},
|
||||
"tidy_cert_metadata": {
|
||||
Type: framework.TypeBool,
|
||||
Description: `Tidy cert metadata`,
|
||||
Required: true,
|
||||
},
|
||||
"pause_duration": {
|
||||
Type: framework.TypeString,
|
||||
Description: `Duration to pause between tidying certificates`,
|
||||
|
|
@ -499,6 +519,11 @@ func pathTidyStatus(b *backend) *framework.Path {
|
|||
Description: `The number of expired, unused acme orders removed`,
|
||||
Required: false,
|
||||
},
|
||||
"cert_metadata_deleted_count": {
|
||||
Type: framework.TypeInt,
|
||||
Description: `The number of metadata entries removed`,
|
||||
Required: false,
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
|
|
@ -587,6 +612,11 @@ available on the tidy-status endpoint.`,
|
|||
Description: `Tidy Unused Acme Accounts, and Orders`,
|
||||
Required: true,
|
||||
},
|
||||
"tidy_cert_metadata": {
|
||||
Type: framework.TypeBool,
|
||||
Description: `Tidy cert metadata`,
|
||||
Required: true,
|
||||
},
|
||||
"safety_buffer": {
|
||||
Type: framework.TypeInt,
|
||||
Description: `Safety buffer time duration`,
|
||||
|
|
@ -680,6 +710,11 @@ available on the tidy-status endpoint.`,
|
|||
Description: `Tidy Unused Acme Accounts, and Orders`,
|
||||
Required: true,
|
||||
},
|
||||
"tidy_cert_metadata": {
|
||||
Type: framework.TypeBool,
|
||||
Description: `Tidy cert metadata`,
|
||||
Required: true,
|
||||
},
|
||||
"safety_buffer": {
|
||||
Type: framework.TypeInt,
|
||||
Description: `Safety buffer time duration`,
|
||||
|
|
@ -753,6 +788,7 @@ func (b *backend) pathTidyWrite(ctx context.Context, req *logical.Request, d *fr
|
|||
tidyCrossRevokedCerts := d.Get("tidy_cross_cluster_revoked_certs").(bool)
|
||||
tidyAcme := d.Get("tidy_acme").(bool)
|
||||
acmeAccountSafetyBuffer := d.Get("acme_account_safety_buffer").(int)
|
||||
tidyCertMetadata := d.Get("tidy_cert_metadata").(bool)
|
||||
|
||||
if safetyBuffer < 1 {
|
||||
return logical.ErrorResponse("safety_buffer must be greater than zero"), nil
|
||||
|
|
@ -782,6 +818,10 @@ func (b *backend) pathTidyWrite(ctx context.Context, req *logical.Request, d *fr
|
|||
}
|
||||
}
|
||||
|
||||
if tidyCertMetadata && !constants.IsEnterprise {
|
||||
return logical.ErrorResponse("certificate metadata is only supported on Vault Enterprise"), nil
|
||||
}
|
||||
|
||||
bufferDuration := time.Duration(safetyBuffer) * time.Second
|
||||
issuerBufferDuration := time.Duration(issuerSafetyBuffer) * time.Second
|
||||
queueSafetyBufferDuration := time.Duration(queueSafetyBuffer) * time.Second
|
||||
|
|
@ -804,6 +844,7 @@ func (b *backend) pathTidyWrite(ctx context.Context, req *logical.Request, d *fr
|
|||
CrossRevokedCerts: tidyCrossRevokedCerts,
|
||||
TidyAcme: tidyAcme,
|
||||
AcmeAccountSafetyBuffer: acmeAccountSafetyBufferDuration,
|
||||
CertMetadata: tidyCertMetadata,
|
||||
}
|
||||
|
||||
if !atomic.CompareAndSwapUint32(b.tidyCASGuard, 0, 1) {
|
||||
|
|
@ -930,6 +971,17 @@ func (b *backend) startTidyOperation(req *logical.Request, config *tidyConfig) {
|
|||
}
|
||||
}
|
||||
|
||||
// Check for cancel before continuing.
|
||||
if atomic.CompareAndSwapUint32(b.tidyCancelCAS, 1, 0) {
|
||||
return tidyCancelledError
|
||||
}
|
||||
|
||||
if config.CertMetadata {
|
||||
if err := b.doTidyCertMetadata(ctx, req, logger, config); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -1647,6 +1699,7 @@ func (b *backend) pathTidyStatusRead(_ context.Context, _ *logical.Request, _ *f
|
|||
"tidy_revocation_queue": nil,
|
||||
"tidy_cross_cluster_revoked_certs": nil,
|
||||
"tidy_acme": nil,
|
||||
"tidy_cert_metadata": nil,
|
||||
"pause_duration": nil,
|
||||
"state": "Inactive",
|
||||
"error": nil,
|
||||
|
|
@ -1666,6 +1719,7 @@ func (b *backend) pathTidyStatusRead(_ context.Context, _ *logical.Request, _ *f
|
|||
"acme_account_revoked_count": nil,
|
||||
"acme_orders_deleted_count": nil,
|
||||
"acme_account_safety_buffer": nil,
|
||||
"cert_metadata_deleted_count": nil,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -1699,6 +1753,7 @@ func (b *backend) pathTidyStatusRead(_ context.Context, _ *logical.Request, _ *f
|
|||
resp.Data["tidy_revocation_queue"] = b.tidyStatus.tidyRevocationQueue
|
||||
resp.Data["tidy_cross_cluster_revoked_certs"] = b.tidyStatus.tidyCrossRevokedCerts
|
||||
resp.Data["tidy_acme"] = b.tidyStatus.tidyAcme
|
||||
resp.Data["tidy_cert_metadata"] = b.tidyStatus.tidyCertMetadata
|
||||
resp.Data["pause_duration"] = b.tidyStatus.pauseDuration
|
||||
resp.Data["time_started"] = b.tidyStatus.timeStarted
|
||||
resp.Data["message"] = b.tidyStatus.message
|
||||
|
|
@ -1714,6 +1769,7 @@ func (b *backend) pathTidyStatusRead(_ context.Context, _ *logical.Request, _ *f
|
|||
resp.Data["acme_account_revoked_count"] = b.tidyStatus.acmeAccountsRevokedCount
|
||||
resp.Data["acme_orders_deleted_count"] = b.tidyStatus.acmeOrdersDeletedCount
|
||||
resp.Data["acme_account_safety_buffer"] = b.tidyStatus.acmeAccountSafetyBuffer
|
||||
resp.Data["cert_metadata_deleted_count"] = b.tidyStatus.certMetadataDeletedCount
|
||||
|
||||
switch b.tidyStatus.state {
|
||||
case tidyStatusStarted:
|
||||
|
|
@ -1839,6 +1895,14 @@ func (b *backend) pathConfigAutoTidyWrite(ctx context.Context, req *logical.Requ
|
|||
}
|
||||
}
|
||||
|
||||
if tidyCertMetadataRaw, ok := d.GetOk("tidy_cert_metadata"); ok {
|
||||
config.CertMetadata = tidyCertMetadataRaw.(bool)
|
||||
|
||||
if config.CertMetadata && !constants.IsEnterprise {
|
||||
return logical.ErrorResponse("certificate metadata is only supported on Vault Enterprise"), nil
|
||||
}
|
||||
}
|
||||
|
||||
if config.Enabled && !config.IsAnyTidyEnabled() {
|
||||
return logical.ErrorResponse("Auto-tidy enabled but no tidy operations were requested. Enable at least one tidy operation to be run (" + config.AnyTidyConfig() + ")."), nil
|
||||
}
|
||||
|
|
@ -1881,6 +1945,7 @@ func (b *backend) tidyStatusStart(config *tidyConfig) {
|
|||
tidyRevocationQueue: config.RevocationQueue,
|
||||
tidyCrossRevokedCerts: config.CrossRevokedCerts,
|
||||
tidyAcme: config.TidyAcme,
|
||||
tidyCertMetadata: config.CertMetadata,
|
||||
pauseDuration: config.PauseDuration.String(),
|
||||
|
||||
state: tidyStatusStarted,
|
||||
|
|
@ -1983,6 +2048,13 @@ func (b *backend) tidyStatusIncDelAcmeOrderCount() {
|
|||
b.tidyStatus.acmeOrdersDeletedCount++
|
||||
}
|
||||
|
||||
func (b *backend) tidyStatusIncCertMetadataCount() {
|
||||
b.tidyStatusLock.Lock()
|
||||
defer b.tidyStatusLock.Unlock()
|
||||
|
||||
b.tidyStatus.certMetadataDeletedCount++
|
||||
}
|
||||
|
||||
const pathTidyHelpSyn = `
|
||||
Tidy up the backend by removing expired certificates, revocation information,
|
||||
or both.
|
||||
|
|
@ -2094,5 +2166,6 @@ func getTidyConfigData(config tidyConfig) map[string]interface{} {
|
|||
"tidy_revocation_queue": config.RevocationQueue,
|
||||
"revocation_queue_safety_buffer": int(config.QueueSafetyBuffer / time.Second),
|
||||
"tidy_cross_cluster_revoked_certs": config.CrossRevokedCerts,
|
||||
"tidy_cert_metadata": config.CertMetadata,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue