vault/sdk/plugin/mock/path_config.go
kpcraig 8f522a2bca
add ce side code and stubs for rotation manager
* add ce side code and stubs

* add changelog

* style refactor

* try to use APIPath as mount point instead of request field

* fix linter

* return a response struct instead of a pure timestamp

* add issue time to response

* add ttl to GetRotationInformation response

* rename field for clarity

* update ttl to just seconds

* rename next and last rotation time field; describe what they are

* rename function

* catch up to ent PR

* fix patch merge mistake
2025-07-15 12:48:00 -04:00

153 lines
4.1 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package mock
import (
"context"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/helper/automatedrotationutil"
"github.com/hashicorp/vault/sdk/logical"
"github.com/hashicorp/vault/sdk/rotation"
)
// pathConfig is used to test auto rotation.
func pathConfig(b *backend) *framework.Path {
p := &framework.Path{
Pattern: "config",
Fields: map[string]*framework.FieldSchema{
"fail_rotate": {
Type: framework.TypeBool,
},
},
Callbacks: map[logical.Operation]framework.OperationFunc{
logical.CreateOperation: b.pathConfigUpdate,
logical.UpdateOperation: b.pathConfigUpdate,
logical.ReadOperation: b.pathConfigRead,
},
ExistenceCheck: b.pathConfigExistenceCheck,
}
automatedrotationutil.AddAutomatedRotationFields(p.Fields)
return p
}
func (b *backend) pathConfigUpdate(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
conf, err := b.configEntry(ctx, req.Storage)
if err != nil {
return nil, err
}
if conf == nil {
conf = &config{}
}
if failRotateRaw, ok := data.GetOk("fail_rotate"); ok {
conf.FailRotate = failRotateRaw.(bool)
}
if err := conf.ParseAutomatedRotationFields(data); err != nil {
return logical.ErrorResponse(err.Error()), nil
}
if conf.ShouldDeregisterRotationJob() {
deregisterReq := &rotation.RotationJobDeregisterRequest{
MountPoint: req.MountPoint,
ReqPath: req.Path,
}
b.Logger().Debug("Deregistering rotation job", "mount", req.MountPoint+req.Path)
if err := b.System().DeregisterRotationJob(ctx, deregisterReq); err != nil {
return logical.ErrorResponse("error deregistering rotation job: %s", err), nil
}
} else if conf.ShouldRegisterRotationJob() {
cfgReq := &rotation.RotationJobConfigureRequest{
MountPoint: req.MountPoint,
ReqPath: req.Path,
RotationSchedule: conf.RotationSchedule,
RotationWindow: conf.RotationWindow,
RotationPeriod: conf.RotationPeriod,
}
b.Logger().Debug("Registering rotation job", "mount", req.MountPoint+req.Path)
if _, err = b.System().RegisterRotationJob(ctx, cfgReq); err != nil {
return logical.ErrorResponse("error registering rotation job: %s", err), nil
}
}
entry, err := logical.StorageEntryJSON("config", conf)
if err != nil {
return nil, err
}
if err := req.Storage.Put(ctx, entry); err != nil {
return nil, err
}
return nil, nil
}
func (b *backend) pathConfigRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
conf, err := b.configEntry(ctx, req.Storage)
if err != nil {
return nil, err
}
if conf == nil {
return nil, nil
}
configData := map[string]interface{}{}
conf.PopulateAutomatedRotationData(configData)
if conf.HasNonzeroRotationValues() {
resp, err := b.System().GetRotationInformation(ctx, &rotation.RotationInfoRequest{ReqPath: req.Path})
if err != nil {
return nil, err
}
if resp != nil {
configData["expire_time"] = resp.NextVaultRotation.Unix()
configData["creation_time"] = resp.LastVaultRotation.Unix()
configData["ttl"] = int64(resp.TTL)
}
}
return &logical.Response{
Data: configData,
}, nil
}
func (b *backend) pathConfigDelete(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
if err := req.Storage.Delete(ctx, "config"); err != nil {
return nil, err
}
return nil, nil
}
func (b *backend) pathConfigExistenceCheck(ctx context.Context, req *logical.Request, data *framework.FieldData) (bool, error) {
entry, err := b.configEntry(ctx, req.Storage)
if err != nil {
return false, err
}
return entry != nil, nil
}
// Fetch the client configuration required to access the AWS API.
func (b *backend) configEntry(ctx context.Context, s logical.Storage) (*config, error) {
entry, err := s.Get(ctx, "config")
if err != nil {
return nil, err
}
if entry == nil {
return nil, nil
}
var result config
if err := entry.DecodeJSON(&result); err != nil {
return nil, err
}
return &result, nil
}
type config struct {
FailRotate bool
automatedrotationutil.AutomatedRotationParams
}