diff --git a/builtin/credential/aws/backend.go b/builtin/credential/aws/backend.go index df5f7ec233..4bf4cd239d 100644 --- a/builtin/credential/aws/backend.go +++ b/builtin/credential/aws/backend.go @@ -199,6 +199,10 @@ func Backend(_ *logical.BackendConfig) (*backend, error) { InitializeFunc: b.initialize, BackendType: logical.TypeCredential, Clean: b.cleanup, + RotateCredential: func(ctx context.Context, request *logical.Request) error { + _, err := b.rotateRoot(ctx, request) + return err + }, } b.partitionToRegionMap = generatePartitionToRegionMap() diff --git a/builtin/credential/aws/backend_test.go b/builtin/credential/aws/backend_test.go index 5770b2c5ed..c4aba017af 100644 --- a/builtin/credential/aws/backend_test.go +++ b/builtin/credential/aws/backend_test.go @@ -34,6 +34,7 @@ func TestBackend_CreateParseVerifyRoleTag(t *testing.T) { config := logical.TestBackendConfig() storage := &logical.InmemStorage{} config.StorageView = storage + config.System = &testSystemView{} b, err := Backend(config) if err != nil { @@ -260,6 +261,7 @@ func TestBackend_ConfigTidyIdentities(t *testing.T) { config := logical.TestBackendConfig() storage := &logical.InmemStorage{} config.StorageView = storage + config.System = &testSystemView{} b, err := Backend(config) if err != nil { @@ -317,6 +319,7 @@ func TestBackend_ConfigTidyRoleTags(t *testing.T) { config := logical.TestBackendConfig() storage := &logical.InmemStorage{} config.StorageView = storage + config.System = &testSystemView{} b, err := Backend(config) if err != nil { @@ -374,6 +377,7 @@ func TestBackend_TidyIdentities(t *testing.T) { config := logical.TestBackendConfig() storage := &logical.InmemStorage{} config.StorageView = storage + config.System = &testSystemView{} b, err := Backend(config) if err != nil { @@ -424,6 +428,7 @@ func TestBackend_TidyRoleTags(t *testing.T) { config := logical.TestBackendConfig() storage := &logical.InmemStorage{} config.StorageView = storage + config.System = &testSystemView{} b, err := Backend(config) if err != nil { @@ -473,6 +478,7 @@ func TestBackend_ConfigClient(t *testing.T) { config := logical.TestBackendConfig() storage := &logical.InmemStorage{} config.StorageView = storage + config.System = &testSystemView{} b, err := Backend(config) if err != nil { @@ -614,6 +620,7 @@ func TestBackend_pathConfigCertificate(t *testing.T) { config := logical.TestBackendConfig() storage := &logical.InmemStorage{} config.StorageView = storage + config.System = &testSystemView{} b, err := Backend(config) if err != nil { @@ -771,6 +778,8 @@ func TestBackend_parseAndVerifyRoleTagValue(t *testing.T) { config := logical.TestBackendConfig() storage := &logical.InmemStorage{} config.StorageView = storage + config.System = &testSystemView{} + b, err := Backend(config) if err != nil { t.Fatal(err) @@ -853,6 +862,8 @@ func TestBackend_PathRoleTag(t *testing.T) { config := logical.TestBackendConfig() storage := &logical.InmemStorage{} config.StorageView = storage + config.System = &testSystemView{} + b, err := Backend(config) if err != nil { t.Fatal(err) @@ -920,6 +931,8 @@ func TestBackend_PathBlacklistRoleTag(t *testing.T) { storage := &logical.InmemStorage{} config := logical.TestBackendConfig() config.StorageView = storage + config.System = &testSystemView{} + b, err := Backend(config) if err != nil { t.Fatal(err) @@ -1379,6 +1392,8 @@ func TestBackend_pathStsConfig(t *testing.T) { config := logical.TestBackendConfig() storage := &logical.InmemStorage{} config.StorageView = storage + config.System = &testSystemView{} + b, err := Backend(config) if err != nil { t.Fatal(err) diff --git a/builtin/credential/aws/path_config_client.go b/builtin/credential/aws/path_config_client.go index b47cee617e..d6125bfa3d 100644 --- a/builtin/credential/aws/path_config_client.go +++ b/builtin/credential/aws/path_config_client.go @@ -14,9 +14,11 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/hashicorp/go-secure-stdlib/strutil" "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/helper/automatedrotationutil" "github.com/hashicorp/vault/sdk/helper/pluginidentityutil" "github.com/hashicorp/vault/sdk/helper/pluginutil" "github.com/hashicorp/vault/sdk/logical" + "github.com/hashicorp/vault/sdk/rotation" ) func (b *backend) pathConfigClient() *framework.Path { @@ -130,6 +132,7 @@ func (b *backend) pathConfigClient() *framework.Path { HelpDescription: pathConfigClientHelpDesc, } pluginidentityutil.AddPluginIdentityTokenFields(p.Fields) + automatedrotationutil.AddAutomatedRotationFields(p.Fields) return p } @@ -193,6 +196,7 @@ func (b *backend) pathConfigClientRead(ctx context.Context, req *logical.Request } clientConfig.PopulatePluginIdentityTokenData(configData) + clientConfig.PopulateAutomatedRotationData(configData) return &logical.Response{ Data: configData, }, nil @@ -363,6 +367,10 @@ func (b *backend) pathConfigClientCreateUpdate(ctx context.Context, req *logical return logical.ErrorResponse(err.Error()), nil } + if err := configEntry.ParseAutomatedRotationFields(data); err != nil { + return logical.ErrorResponse(err.Error()), nil + } + // handle mutual exclusivity if configEntry.IdentityTokenAudience != "" && configEntry.AccessKey != "" { return logical.ErrorResponse("only one of 'access_key' or 'identity_token_audience' can be set"), nil @@ -384,6 +392,36 @@ func (b *backend) pathConfigClientCreateUpdate(ctx context.Context, req *logical } } + var performedRotationManagerOpern string + if configEntry.ShouldDeregisterRotationJob() { + performedRotationManagerOpern = "deregistration" + // Disable Automated Rotation and Deregister credentials if required + 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 configEntry.ShouldRegisterRotationJob() { + performedRotationManagerOpern = "registration" + // Register the rotation job if it's required. + cfgReq := &rotation.RotationJobConfigureRequest{ + MountPoint: req.MountPoint, + ReqPath: req.Path, + RotationSchedule: configEntry.RotationSchedule, + RotationWindow: configEntry.RotationWindow, + RotationPeriod: configEntry.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 + } + } + // Since this endpoint supports both create operation and update operation, // the error checks for access_key and secret_key not being set are not present. // This allows calling this endpoint multiple times to provide the values. @@ -396,6 +434,10 @@ func (b *backend) pathConfigClientCreateUpdate(ctx context.Context, req *logical if changedCreds || changedOtherConfig || req.Operation == logical.CreateOperation { if err := req.Storage.Put(ctx, entry); err != nil { + if performedRotationManagerOpern != "" { + b.Logger().Error("write to storage failed but the rotation manager still succeeded.", + "operation", performedRotationManagerOpern, "mount", req.MountPoint, "path", req.Path) + } return nil, err } } @@ -424,6 +466,7 @@ func (b *backend) configClientToEntry(conf *clientConfig) (*logical.StorageEntry // interact with the AWS EC2 API. type clientConfig struct { pluginidentityutil.PluginIdentityTokenParams + automatedrotationutil.AutomatedRotationParams AccessKey string `json:"access_key"` SecretKey string `json:"secret_key"` diff --git a/builtin/credential/aws/path_config_client_test.go b/builtin/credential/aws/path_config_client_test.go index 7d5bd79202..70d3222249 100644 --- a/builtin/credential/aws/path_config_client_test.go +++ b/builtin/credential/aws/path_config_client_test.go @@ -7,9 +7,11 @@ import ( "context" "testing" + "github.com/hashicorp/vault/sdk/helper/automatedrotationutil" "github.com/hashicorp/vault/sdk/helper/pluginidentityutil" "github.com/hashicorp/vault/sdk/helper/pluginutil" "github.com/hashicorp/vault/sdk/logical" + "github.com/hashicorp/vault/sdk/rotation" "github.com/stretchr/testify/assert" ) @@ -17,6 +19,7 @@ func TestBackend_pathConfigClient(t *testing.T) { config := logical.TestBackendConfig() storage := &logical.InmemStorage{} config.StorageView = storage + config.System = &testSystemView{} b, err := Backend(config) if err != nil { @@ -176,3 +179,11 @@ type testSystemView struct { func (d testSystemView) GenerateIdentityToken(_ context.Context, _ *pluginutil.IdentityTokenRequest) (*pluginutil.IdentityTokenResponse, error) { return nil, pluginidentityutil.ErrPluginWorkloadIdentityUnsupported } + +func (d testSystemView) RegisterRotationJob(_ context.Context, _ *rotation.RotationJobConfigureRequest) (string, error) { + return "", automatedrotationutil.ErrRotationManagerUnsupported +} + +func (d testSystemView) DeregisterRotationJob(_ context.Context, _ *rotation.RotationJobDeregisterRequest) error { + return nil +} diff --git a/builtin/credential/aws/path_config_rotate_root.go b/builtin/credential/aws/path_config_rotate_root.go index 0a0e64fcb0..2e945fab2a 100644 --- a/builtin/credential/aws/path_config_rotate_root.go +++ b/builtin/credential/aws/path_config_rotate_root.go @@ -42,6 +42,10 @@ func (b *backend) pathConfigRotateRoot() *framework.Path { } func (b *backend) pathConfigRotateRootUpdate(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + return b.rotateRoot(ctx, req) +} + +func (b *backend) rotateRoot(ctx context.Context, req *logical.Request) (*logical.Response, error) { // First get the AWS key and secret and validate that we _can_ rotate them. // We need the read lock here to prevent anything else from mutating it while we're using it. b.configMutex.Lock() diff --git a/builtin/credential/aws/path_login_test.go b/builtin/credential/aws/path_login_test.go index b5b5679607..1541fea528 100644 --- a/builtin/credential/aws/path_login_test.go +++ b/builtin/credential/aws/path_login_test.go @@ -315,6 +315,8 @@ func TestBackend_pathLogin_NoClientConfig(t *testing.T) { storage := new(logical.InmemStorage) config := logical.TestBackendConfig() config.StorageView = storage + config.System = &testSystemView{} + b, err := Backend(config) if err != nil { t.Fatal(err) @@ -363,6 +365,8 @@ func TestBackend_pathLogin_IAMHeaders(t *testing.T) { storage := &logical.InmemStorage{} config := logical.TestBackendConfig() config.StorageView = storage + config.System = &testSystemView{} + b, err := Backend(config) if err != nil { t.Fatal(err) @@ -570,6 +574,8 @@ func TestBackend_pathLogin_IAMRoleResolution(t *testing.T) { storage := &logical.InmemStorage{} config := logical.TestBackendConfig() config.StorageView = storage + config.System = &testSystemView{} + b, err := Backend(config) if err != nil { t.Fatal(err) @@ -670,6 +676,8 @@ func TestBackend_defaultAliasMetadata(t *testing.T) { storage := &logical.InmemStorage{} config := logical.TestBackendConfig() config.StorageView = storage + config.System = &testSystemView{} + b, err := Backend(config) if err != nil { t.Fatal(err) diff --git a/builtin/logical/aws/backend.go b/builtin/logical/aws/backend.go index 2313561201..521ab5be09 100644 --- a/builtin/logical/aws/backend.go +++ b/builtin/logical/aws/backend.go @@ -10,8 +10,6 @@ import ( "sync" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/iam" "github.com/aws/aws-sdk-go/service/iam/iamiface" "github.com/aws/aws-sdk-go/service/sts/stsiface" "github.com/hashicorp/vault/sdk/framework" @@ -77,89 +75,8 @@ func Backend(_ *logical.BackendConfig) *backend { return nil }, RotateCredential: func(ctx context.Context, req *logical.Request) error { - // the following code is a modified version of the rotate-root method - client, err := b.clientIAM(ctx, req.Storage) - if err != nil { - return err - } - if client == nil { - return fmt.Errorf("nil IAM client") - } - - b.clientMutex.Lock() - defer b.clientMutex.Unlock() - - rawRootConfig, err := req.Storage.Get(ctx, "config/root") - if err != nil { - return err - } - if rawRootConfig == nil { - return fmt.Errorf("no configuration found for config/root") - } - var config rootConfig - if err := rawRootConfig.DecodeJSON(&config); err != nil { - return fmt.Errorf("error reading root configuration: %w", err) - } - - if config.AccessKey == "" || config.SecretKey == "" { - return fmt.Errorf("cannot call config/rotate-root when either access_key or secret_key is empty") - } - - var getUserInput iam.GetUserInput // empty input means get current user - getUserRes, err := client.GetUserWithContext(ctx, &getUserInput) - if err != nil { - return fmt.Errorf("error calling GetUser: %w", err) - } - if getUserRes == nil { - return fmt.Errorf("nil response from GetUser") - } - if getUserRes.User == nil { - return fmt.Errorf("nil user returned from GetUser") - } - if getUserRes.User.UserName == nil { - return fmt.Errorf("nil UserName returned from GetUser") - } - - createAccessKeyInput := iam.CreateAccessKeyInput{ - UserName: getUserRes.User.UserName, - } - createAccessKeyRes, err := client.CreateAccessKeyWithContext(ctx, &createAccessKeyInput) - if err != nil { - return fmt.Errorf("error calling CreateAccessKey: %w", err) - } - if createAccessKeyRes.AccessKey == nil { - return fmt.Errorf("nil response from CreateAccessKey") - } - if createAccessKeyRes.AccessKey.AccessKeyId == nil || createAccessKeyRes.AccessKey.SecretAccessKey == nil { - return fmt.Errorf("nil AccessKeyId or SecretAccessKey returned from CreateAccessKey") - } - - oldAccessKey := config.AccessKey - - config.AccessKey = *createAccessKeyRes.AccessKey.AccessKeyId - config.SecretKey = *createAccessKeyRes.AccessKey.SecretAccessKey - - newEntry, err := logical.StorageEntryJSON("config/root", config) - if err != nil { - return fmt.Errorf("error generating new config/root JSON: %w", err) - } - if err := req.Storage.Put(ctx, newEntry); err != nil { - return fmt.Errorf("error saving new config/root: %w", err) - } - - b.iamClient = nil - b.stsClient = nil - - deleteAccessKeyInput := iam.DeleteAccessKeyInput{ - AccessKeyId: aws.String(oldAccessKey), - UserName: getUserRes.User.UserName, - } - _, err = client.DeleteAccessKeyWithContext(ctx, &deleteAccessKeyInput) - if err != nil { - return fmt.Errorf("error deleting old access key: %w", err) - } - - return nil + _, err := b.rotateRoot(ctx, req) + return err }, BackendType: logical.TypeLogical, } diff --git a/builtin/logical/aws/backend_test.go b/builtin/logical/aws/backend_test.go index 56cd095a3b..11e479a23b 100644 --- a/builtin/logical/aws/backend_test.go +++ b/builtin/logical/aws/backend_test.go @@ -62,7 +62,9 @@ func (m *mockIAMClient) CreateUserWithContext(_ aws.Context, input *iam.CreateUs } func getBackend(t *testing.T) logical.Backend { - be, _ := Factory(context.Background(), logical.TestBackendConfig()) + cfg := logical.TestBackendConfig() + cfg.System = &testSystemView{} + be, _ := Factory(context.Background(), cfg) return be } diff --git a/builtin/logical/aws/path_config_root.go b/builtin/logical/aws/path_config_root.go index 5cd8d2775a..c2d57936ea 100644 --- a/builtin/logical/aws/path_config_root.go +++ b/builtin/logical/aws/path_config_root.go @@ -109,11 +109,11 @@ func (b *backend) pathConfigRootRead(ctx context.Context, req *logical.Request, b.clientMutex.RLock() defer b.clientMutex.RUnlock() - config, exists, err := getConfigFromStorage(ctx, req) + config, err := getConfigFromStorage(ctx, req) if err != nil { return nil, err } - if !exists { + if config == nil { return nil, nil } @@ -139,46 +139,90 @@ func (b *backend) pathConfigRootRead(ctx context.Context, req *logical.Request, } func (b *backend) pathConfigRootWrite(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { - region := data.Get("region").(string) - iamendpoint := data.Get("iam_endpoint").(string) - stsendpoint := data.Get("sts_endpoint").(string) - stsregion := data.Get("sts_region").(string) - maxretries := data.Get("max_retries").(int) - roleARN := data.Get("role_arn").(string) - usernameTemplate := data.Get("username_template").(string) - if usernameTemplate == "" { - usernameTemplate = defaultUserNameTemplate - } - - stsFallbackEndpoints := data.Get("sts_fallback_endpoints").([]string) - stsFallbackRegions := data.Get("sts_fallback_regions").([]string) - - if len(stsFallbackEndpoints) != len(stsFallbackRegions) { - return logical.ErrorResponse("fallback endpoints and fallback regions must be the same length"), nil - } - b.clientMutex.Lock() defer b.clientMutex.Unlock() // check for existing config - previousCfg, previousCfgExists, err := getConfigFromStorage(ctx, req) + rc, err := getConfigFromStorage(ctx, req) if err != nil { return nil, err } - rc := rootConfig{ - AccessKey: data.Get("access_key").(string), - SecretKey: data.Get("secret_key").(string), - IAMEndpoint: iamendpoint, - STSEndpoint: stsendpoint, - STSRegion: stsregion, - STSFallbackEndpoints: stsFallbackEndpoints, - STSFallbackRegions: stsFallbackRegions, - Region: region, - MaxRetries: maxretries, - UsernameTemplate: usernameTemplate, - RoleARN: roleARN, + if rc == nil { + // Baseline + rc = &rootConfig{} } + + if accessKey, ok := data.GetOk("access_key"); ok { + rc.AccessKey = accessKey.(string) + } else if req.Operation == logical.CreateOperation { + rc.AccessKey = data.Get("access_key").(string) + } + + if secretKey, ok := data.GetOk("secret_key"); ok { + rc.SecretKey = secretKey.(string) + } else if req.Operation == logical.CreateOperation { + rc.SecretKey = data.Get("secret_key").(string) + } + + if region, ok := data.GetOk("region"); ok { + rc.Region = region.(string) + } else if req.Operation == logical.CreateOperation { + rc.Region = data.Get("region").(string) + } + + if iamEndpoint, ok := data.GetOk("iam_endpoint"); ok { + rc.IAMEndpoint = iamEndpoint.(string) + } else if req.Operation == logical.CreateOperation { + rc.IAMEndpoint = data.Get("iam_endpoint").(string) + } + + if stsEndpoint, ok := data.GetOk("sts_endpoint"); ok { + rc.STSEndpoint = stsEndpoint.(string) + } else if req.Operation == logical.CreateOperation { + rc.STSEndpoint = data.Get("sts_endpoint").(string) + } + + if stsRegion, ok := data.GetOk("sts_region"); ok { + rc.STSRegion = stsRegion.(string) + } else if req.Operation == logical.CreateOperation { + rc.STSRegion = data.Get("sts_region").(string) + } + + if maxRetries, ok := data.GetOk("max_retries"); ok { + rc.MaxRetries = maxRetries.(int) + } else if req.Operation == logical.CreateOperation { + rc.MaxRetries = data.Get("max_retries").(int) + } + + if roleARN, ok := data.GetOk("role_arn"); ok { + rc.RoleARN = roleARN.(string) + } else if req.Operation == logical.CreateOperation { + rc.RoleARN = data.Get("role_arn").(string) + } + + if stsFallbackEndpoints, ok := data.GetOk("sts_fallback_endpoints"); ok { + rc.STSFallbackEndpoints = stsFallbackEndpoints.([]string) + } else if req.Operation == logical.CreateOperation { + rc.STSFallbackEndpoints = data.Get("sts_fallback_endpoints").([]string) + } + + if stsFallbackRegions, ok := data.GetOk("sts_fallback_regions"); ok { + rc.STSFallbackRegions = stsFallbackRegions.([]string) + } else if req.Operation == logical.CreateOperation { + rc.STSFallbackRegions = data.Get("sts_fallback_regions").([]string) + } + + usernameTemplate := data.Get("username_template").(string) + if usernameTemplate == "" { + usernameTemplate = defaultUserNameTemplate + } + rc.UsernameTemplate = usernameTemplate + + if len(rc.STSFallbackEndpoints) != len(rc.STSFallbackRegions) { + return logical.ErrorResponse("fallback endpoints and fallback regions must be the same length"), nil + } + if err := rc.ParsePluginIdentityTokenFields(data); err != nil { return logical.ErrorResponse(err.Error()), nil } @@ -206,48 +250,42 @@ func (b *backend) pathConfigRootWrite(ctx context.Context, req *logical.Request, } } - // Save the initial config only if it does not already exist - if !previousCfgExists { - if err := putConfigToStorage(ctx, req, &rc); err != nil { - return nil, err + var performedRotationManagerOpern string + if rc.ShouldDeregisterRotationJob() { + performedRotationManagerOpern = "deregistration" + // Disable Automated Rotation and Deregister credentials if required + deregisterReq := &rotation.RotationJobDeregisterRequest{ + MountPoint: req.MountPoint, + ReqPath: req.Path, } - } - // Now that the root config is set up, register the rotation job if it required - if rc.ShouldRegisterRotationJob() { + 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 rc.ShouldRegisterRotationJob() { + performedRotationManagerOpern = "registration" + // Register the rotation job if it's required. cfgReq := &rotation.RotationJobConfigureRequest{ - Name: rootRotationJobName, - MountType: req.MountType, + MountPoint: req.MountPoint, ReqPath: req.Path, RotationSchedule: rc.RotationSchedule, RotationWindow: rc.RotationWindow, RotationPeriod: rc.RotationPeriod, } - _, err = b.System().RegisterRotationJob(ctx, cfgReq) - if err != nil { + 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 } } - // Disable Automated Rotation and Deregister credentials if required - if rc.DisableAutomatedRotation { - // Ensure de-registering only occurs on updates and if - // a credential has actually been registered (rotation_period or rotation_schedule is set) - deregisterReq := &rotation.RotationJobDeregisterRequest{ - MountType: req.MountType, - ReqPath: req.Path, + // Save the config + if err := putConfigToStorage(ctx, req, rc); err != nil { + if performedRotationManagerOpern != "" { + b.Logger().Error("write to storage failed but the rotation manager still succeeded.", + "operation", performedRotationManagerOpern, "mount", req.MountPoint, "path", req.Path) } - if previousCfgExists && previousCfg.ShouldRegisterRotationJob() { - err := b.System().DeregisterRotationJob(ctx, deregisterReq) - if err != nil { - return logical.ErrorResponse("error de-registering rotation job: %s", err), nil - } - } - } - - // update config entry with rotation ID - if err := putConfigToStorage(ctx, req, &rc); err != nil { return nil, err } @@ -259,22 +297,22 @@ func (b *backend) pathConfigRootWrite(ctx context.Context, req *logical.Request, return nil, nil } -func getConfigFromStorage(ctx context.Context, req *logical.Request) (*rootConfig, bool, error) { +func getConfigFromStorage(ctx context.Context, req *logical.Request) (*rootConfig, error) { entry, err := req.Storage.Get(ctx, "config/root") if err != nil { - return nil, false, err + return nil, err } if entry == nil { - return nil, false, nil + return nil, nil } var config rootConfig if err := entry.DecodeJSON(&config); err != nil { - return nil, false, err + return nil, err } - return &config, true, nil + return &config, nil } func putConfigToStorage(ctx context.Context, req *logical.Request, rc *rootConfig) error { diff --git a/builtin/logical/aws/path_config_root_test.go b/builtin/logical/aws/path_config_root_test.go index 99d0eb038b..f26d876492 100644 --- a/builtin/logical/aws/path_config_root_test.go +++ b/builtin/logical/aws/path_config_root_test.go @@ -21,6 +21,7 @@ import ( func TestBackend_PathConfigRoot(t *testing.T) { config := logical.TestBackendConfig() config.StorageView = &logical.InmemStorage{} + config.System = &testSystemView{} b := Backend(config) if err := b.Setup(context.Background(), config); err != nil { @@ -280,8 +281,8 @@ func TestBackend_PathConfigRoot_RegisterRootRotation(t *testing.T) { configData := map[string]interface{}{ "access_key": "access-key", "secret_key": "secret-key", - "rotation_schedule": "*/30 * * * * *", - "rotation_window": 60, + "rotation_schedule": "*/1 * * * *", + "rotation_window": 120, } configReq := &logical.Request{ @@ -308,3 +309,7 @@ func (d testSystemView) GenerateIdentityToken(_ context.Context, _ *pluginutil.I func (d testSystemView) RegisterRotationJob(_ context.Context, _ *rotation.RotationJobConfigureRequest) (string, error) { return "", automatedrotationutil.ErrRotationManagerUnsupported } + +func (d testSystemView) DeregisterRotationJob(_ context.Context, _ *rotation.RotationJobDeregisterRequest) error { + return nil +} diff --git a/builtin/logical/aws/path_config_rotate_root.go b/builtin/logical/aws/path_config_rotate_root.go index 72f9c82e4d..371b03714b 100644 --- a/builtin/logical/aws/path_config_rotate_root.go +++ b/builtin/logical/aws/path_config_rotate_root.go @@ -37,6 +37,10 @@ func pathConfigRotateRoot(b *backend) *framework.Path { } func (b *backend) pathConfigRotateRootUpdate(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + return b.rotateRoot(ctx, req) +} + +func (b *backend) rotateRoot(ctx context.Context, req *logical.Request) (*logical.Response, error) { // have to get the client config first because that takes out a read lock client, err := b.clientIAM(ctx, req.Storage) if err != nil { diff --git a/builtin/logical/aws/secret_access_keys_test.go b/builtin/logical/aws/secret_access_keys_test.go index 8c6804d946..7a88a0e12e 100644 --- a/builtin/logical/aws/secret_access_keys_test.go +++ b/builtin/logical/aws/secret_access_keys_test.go @@ -120,6 +120,8 @@ func TestGenUsername(t *testing.T) { func TestReadConfig_DefaultTemplate(t *testing.T) { config := logical.TestBackendConfig() config.StorageView = &logical.InmemStorage{} + config.System = &testSystemView{} + b := Backend(config) if err := b.Setup(context.Background(), config); err != nil { t.Fatal(err) @@ -164,6 +166,8 @@ func TestReadConfig_DefaultTemplate(t *testing.T) { func TestReadConfig_CustomTemplate(t *testing.T) { config := logical.TestBackendConfig() config.StorageView = &logical.InmemStorage{} + config.System = &testSystemView{} + b := Backend(config) if err := b.Setup(context.Background(), config); err != nil { t.Fatal(err) diff --git a/changelog/29497.txt b/changelog/29497.txt new file mode 100644 index 0000000000..d6f2a321e8 --- /dev/null +++ b/changelog/29497.txt @@ -0,0 +1,5 @@ +```release-note:feature +**Automated Root Rotation**: Adds Automated Root Rotation capabilities to the AWS Auth, AWS Secrets +and DB Secrets plugins. This allows plugin users to automate their root credential rotations based +on configurable schedules/periods via the Rotation Manager. Note: Enterprise only. +``` \ No newline at end of file diff --git a/sdk/helper/automatedrotationutil/fields.go b/sdk/helper/automatedrotationutil/fields.go index 9adb3651bb..8bd1fce8cd 100644 --- a/sdk/helper/automatedrotationutil/fields.go +++ b/sdk/helper/automatedrotationutil/fields.go @@ -8,6 +8,7 @@ import ( "fmt" "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/rotation" ) var ( @@ -41,6 +42,14 @@ func (p *AutomatedRotationParams) ParseAutomatedRotationFields(d *framework.Fiel return ErrRotationMutuallyExclusiveFields } p.RotationSchedule = rotationScheduleRaw.(string) + + // parse schedule to ensure it is valid + if p.RotationSchedule != "" { + _, err := rotation.DefaultScheduler.Parse(p.RotationSchedule) + if err != nil { + return fmt.Errorf("failed to parse provided rotation_schedule: %w", err) + } + } } if windowOk { @@ -75,6 +84,10 @@ func (p *AutomatedRotationParams) ShouldRegisterRotationJob() bool { return p.RotationSchedule != "" || p.RotationPeriod != 0 } +func (p *AutomatedRotationParams) ShouldDeregisterRotationJob() bool { + return p.DisableAutomatedRotation || (p.RotationSchedule == "" && p.RotationPeriod == 0) +} + // AddAutomatedRotationFields adds plugin identity token fields to the given // field schema map. func AddAutomatedRotationFields(m map[string]*framework.FieldSchema) { diff --git a/sdk/helper/automatedrotationutil/fields_test.go b/sdk/helper/automatedrotationutil/fields_test.go index c960d49c9b..8e05ef9b80 100644 --- a/sdk/helper/automatedrotationutil/fields_test.go +++ b/sdk/helper/automatedrotationutil/fields_test.go @@ -41,13 +41,13 @@ func TestParseAutomatedRotationFields(t *testing.T) { name: "basic", data: &framework.FieldData{ Raw: map[string]interface{}{ - "rotation_schedule": "*/15 * * * * *", + "rotation_schedule": "*/15 * * * *", "rotation_window": 60, }, Schema: schemaMap, }, expectedParams: &AutomatedRotationParams{ - RotationSchedule: "*/15 * * * * *", + RotationSchedule: "*/15 * * * *", RotationWindow: 60, RotationPeriod: 0, DisableAutomatedRotation: false, @@ -57,7 +57,7 @@ func TestParseAutomatedRotationFields(t *testing.T) { name: "mutually-exclusive", data: &framework.FieldData{ Raw: map[string]interface{}{ - "rotation_schedule": "*/15 * * * * *", + "rotation_schedule": "*/15 * * * *", "rotation_period": 15, "rotation_window": 60, }, @@ -65,6 +65,16 @@ func TestParseAutomatedRotationFields(t *testing.T) { }, expectedError: ErrRotationMutuallyExclusiveFields.Error(), }, + { + name: "bad-schedule", + data: &framework.FieldData{ + Raw: map[string]interface{}{ + "rotation_schedule": "random string", + }, + Schema: schemaMap, + }, + expectedError: "failed to parse provided rotation_schedule", + }, { name: "incompatible-fields", data: &framework.FieldData{ @@ -82,13 +92,17 @@ func TestParseAutomatedRotationFields(t *testing.T) { t.Run(tt.name, func(t *testing.T) { p := &AutomatedRotationParams{} err := p.ParseAutomatedRotationFields(tt.data) - - if err != nil && !strings.Contains(err.Error(), tt.expectedError) { - t.Errorf("ParseAutomatedRotationFields() error = %v, expected %s", err, tt.expectedError) + if err != nil { + if tt.expectedError == "" { + t.Errorf("expected no error but received an error: %s", err) + } + if !strings.Contains(err.Error(), tt.expectedError) { + t.Errorf("ParseAutomatedRotationFields() error = %v, expected %s", err, tt.expectedError) + } } if err == nil && !reflect.DeepEqual(tt.expectedParams, p) { - t.Errorf("ParseAutomatedRotationFields() error comparing params; got %v, expected %v", tt.expectedParams, p) + t.Errorf("ParseAutomatedRotationFields() error comparing params; got %v, expected %v", p, tt.expectedParams) } }) } @@ -103,13 +117,13 @@ func TestPopulateAutomatedRotationData(t *testing.T) { { name: "basic", expected: map[string]interface{}{ - "rotation_schedule": "*/15 * * * * *", + "rotation_schedule": "*/15 * * * *", "rotation_window": 60, "rotation_period": 0, "disable_automated_rotation": false, }, inputParams: &AutomatedRotationParams{ - RotationSchedule: "*/15 * * * * *", + RotationSchedule: "*/15 * * * *", RotationWindow: 60, RotationPeriod: 0, DisableAutomatedRotation: false, @@ -129,3 +143,109 @@ func TestPopulateAutomatedRotationData(t *testing.T) { }) } } + +func TestShouldRegisterRotationJob(t *testing.T) { + tests := []struct { + name string + inputParams *AutomatedRotationParams + expected bool + }{ + { + name: "false", + expected: false, + inputParams: &AutomatedRotationParams{ + RotationSchedule: "", + RotationWindow: 60, + RotationPeriod: 0, + DisableAutomatedRotation: false, + }, + }, + { + name: "true-schedule", + expected: true, + inputParams: &AutomatedRotationParams{ + RotationSchedule: "*/15 * * * *", + RotationWindow: 0, + RotationPeriod: 0, + DisableAutomatedRotation: false, + }, + }, + { + name: "true-period", + expected: true, + inputParams: &AutomatedRotationParams{ + RotationSchedule: "", + RotationWindow: 0, + RotationPeriod: 5, + DisableAutomatedRotation: false, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + out := tt.inputParams.ShouldRegisterRotationJob() + if out != tt.expected { + t.Errorf("ShouldRegisterRotationJob() output = %v, expected: %v", out, tt.expected) + } + }) + } +} + +func TestShouldDeregisterRotationJob(t *testing.T) { + tests := []struct { + name string + inputParams *AutomatedRotationParams + expected bool + }{ + { + name: "zero out schedule and period", + expected: true, + inputParams: &AutomatedRotationParams{ + RotationSchedule: "", + RotationWindow: 60, + RotationPeriod: 0, + DisableAutomatedRotation: false, + }, + }, + { + name: "false-schedule set", + expected: false, + inputParams: &AutomatedRotationParams{ + RotationSchedule: "*/15 * * * *", + RotationWindow: 0, + RotationPeriod: 0, + DisableAutomatedRotation: false, + }, + }, + { + name: "false-period set", + expected: false, + inputParams: &AutomatedRotationParams{ + RotationSchedule: "", + RotationWindow: 0, + RotationPeriod: 5, + DisableAutomatedRotation: false, + }, + }, + { + name: "true-disable set", + expected: true, + inputParams: &AutomatedRotationParams{ + RotationSchedule: "*/15 * * * *", + RotationWindow: 0, + RotationPeriod: 0, + DisableAutomatedRotation: true, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + out := tt.inputParams.ShouldDeregisterRotationJob() + if out != tt.expected { + t.Errorf("ShouldRegisterRotationJob() output = %v, expected: %v", out, tt.expected) + } + }) + } +} diff --git a/sdk/plugin/grpc_system.go b/sdk/plugin/grpc_system.go index 727b1942fe..f2a666b150 100644 --- a/sdk/plugin/grpc_system.go +++ b/sdk/plugin/grpc_system.go @@ -231,7 +231,7 @@ func (s *gRPCSystemViewClient) RegisterRotationJob(ctx context.Context, req *rot cfgReq := &pb.RegisterRotationJobRequest{ Job: &pb.RotationJobInput{ Name: req.Name, - MountType: req.MountType, + MountPoint: req.MountPoint, Path: req.ReqPath, RotationSchedule: req.RotationSchedule, RotationWindow: int64(req.RotationWindow), @@ -248,8 +248,8 @@ func (s *gRPCSystemViewClient) RegisterRotationJob(ctx context.Context, req *rot func (s *gRPCSystemViewClient) DeregisterRotationJob(ctx context.Context, req *rotation.RotationJobDeregisterRequest) error { _, err := s.client.DeregisterRotationJob(ctx, &pb.DeregisterRotationJobRequest{ Req: &pb.DeregisterRotationRequestInput{ - MountType: req.MountType, - ReqPath: req.ReqPath, + MountPoint: req.MountPoint, + ReqPath: req.ReqPath, }, }) if err != nil { @@ -469,7 +469,7 @@ func (s *gRPCSystemViewServer) RegisterRotationJob(ctx context.Context, req *pb. cfgReq := &rotation.RotationJobConfigureRequest{ Name: req.Job.Name, - MountType: req.Job.MountType, + MountPoint: req.Job.MountPoint, ReqPath: req.Job.Path, RotationSchedule: req.Job.RotationSchedule, RotationWindow: int(req.Job.RotationWindow), @@ -493,8 +493,8 @@ func (s *gRPCSystemViewServer) DeregisterRotationJob(ctx context.Context, req *p } cfgReq := &rotation.RotationJobDeregisterRequest{ - MountType: req.Req.MountType, - ReqPath: req.Req.ReqPath, + MountPoint: req.Req.MountPoint, + ReqPath: req.Req.ReqPath, } err := s.impl.DeregisterRotationJob(ctx, cfgReq) diff --git a/sdk/plugin/pb/backend.pb.go b/sdk/plugin/pb/backend.pb.go index 080c668d9a..ae838ae69e 100644 --- a/sdk/plugin/pb/backend.pb.go +++ b/sdk/plugin/pb/backend.pb.go @@ -3310,7 +3310,7 @@ func (x *RegisterRotationJobResponse) GetErr() string { type RotationJobInput struct { state protoimpl.MessageState `protogen:"open.v1"` Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - MountType string `protobuf:"bytes,2,opt,name=mount_type,json=mountType,proto3" json:"mount_type,omitempty"` + MountPoint string `protobuf:"bytes,2,opt,name=mount_point,json=mountPoint,proto3" json:"mount_point,omitempty"` Path string `protobuf:"bytes,3,opt,name=path,proto3" json:"path,omitempty"` RotationSchedule string `protobuf:"bytes,4,opt,name=rotation_schedule,json=rotationSchedule,proto3" json:"rotation_schedule,omitempty"` RotationWindow int64 `protobuf:"varint,5,opt,name=rotation_window,json=rotationWindow,proto3" json:"rotation_window,omitempty"` @@ -3356,9 +3356,9 @@ func (x *RotationJobInput) GetName() string { return "" } -func (x *RotationJobInput) GetMountType() string { +func (x *RotationJobInput) GetMountPoint() string { if x != nil { - return x.MountType + return x.MountPoint } return "" } @@ -3393,7 +3393,7 @@ func (x *RotationJobInput) GetRotationPeriod() int64 { type DeregisterRotationRequestInput struct { state protoimpl.MessageState `protogen:"open.v1"` - MountType string `protobuf:"bytes,1,opt,name=mount_type,json=mountType,proto3" json:"mount_type,omitempty"` + MountPoint string `protobuf:"bytes,1,opt,name=mount_point,json=mountPoint,proto3" json:"mount_point,omitempty"` ReqPath string `protobuf:"bytes,2,opt,name=req_path,json=reqPath,proto3" json:"req_path,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -3429,9 +3429,9 @@ func (*DeregisterRotationRequestInput) Descriptor() ([]byte, []int) { return file_sdk_plugin_pb_backend_proto_rawDescGZIP(), []int{52} } -func (x *DeregisterRotationRequestInput) GetMountType() string { +func (x *DeregisterRotationRequestInput) GetMountPoint() string { if x != nil { - return x.MountType + return x.MountPoint } return "" } @@ -4241,198 +4241,198 @@ var file_sdk_plugin_pb_backend_proto_rawDesc = []byte{ 0x0a, 0x0b, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x65, 0x72, - 0x72, 0x22, 0xd8, 0x01, 0x0a, 0x10, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4a, 0x6f, + 0x72, 0x22, 0xda, 0x01, 0x0a, 0x10, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, - 0x75, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, - 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, - 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x2b, 0x0a, - 0x11, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, - 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x72, 0x6f, - 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x0e, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x57, 0x69, 0x6e, - 0x64, 0x6f, 0x77, 0x12, 0x27, 0x0a, 0x0f, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, - 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x72, 0x6f, - 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x22, 0x5a, 0x0a, 0x1e, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x6f, + 0x75, 0x6e, 0x74, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0a, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, + 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, + 0x2b, 0x0a, 0x11, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x63, 0x68, 0x65, + 0x64, 0x75, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x72, 0x6f, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x27, 0x0a, 0x0f, + 0x72, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x57, + 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x12, 0x27, 0x0a, 0x0f, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, + 0x72, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x22, 0x5c, + 0x0a, 0x1e, 0x44, 0x65, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x6f, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x6e, 0x70, 0x75, 0x74, + 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x6f, 0x69, 0x6e, + 0x74, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x65, 0x71, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x71, 0x50, 0x61, 0x74, 0x68, 0x22, 0x54, 0x0a, 0x1c, 0x44, 0x65, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x1d, - 0x0a, 0x0a, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x19, 0x0a, - 0x08, 0x72, 0x65, 0x71, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x72, 0x65, 0x71, 0x50, 0x61, 0x74, 0x68, 0x22, 0x54, 0x0a, 0x1c, 0x44, 0x65, 0x72, 0x65, + 0x6f, 0x6e, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x34, 0x0a, 0x03, + 0x72, 0x65, 0x71, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x62, 0x2e, 0x44, + 0x65, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x03, 0x72, + 0x65, 0x71, 0x22, 0x8e, 0x01, 0x0a, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x61, 0x64, 0x64, 0x72, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x41, 0x64, + 0x64, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x70, 0x6f, 0x72, + 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x50, + 0x6f, 0x72, 0x74, 0x12, 0x3e, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, + 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x22, 0xbb, 0x04, 0x0a, 0x0f, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x12, 0x2d, 0x0a, 0x12, 0x68, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x5f, 0x63, + 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x68, + 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, + 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x69, 0x64, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x64, 0x69, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x12, + 0x21, 0x0a, 0x0c, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x5f, 0x73, 0x75, 0x69, 0x74, 0x65, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x53, 0x75, 0x69, + 0x74, 0x65, 0x12, 0x2f, 0x0a, 0x13, 0x6e, 0x65, 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74, 0x65, 0x64, + 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x12, 0x6e, 0x65, 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x63, 0x6f, 0x6c, 0x12, 0x41, 0x0a, 0x1d, 0x6e, 0x65, 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74, 0x65, + 0x64, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x69, 0x73, 0x5f, 0x6d, 0x75, + 0x74, 0x75, 0x61, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x6e, 0x65, 0x67, 0x6f, + 0x74, 0x69, 0x61, 0x74, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x49, 0x73, + 0x4d, 0x75, 0x74, 0x75, 0x61, 0x6c, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x41, 0x0a, 0x11, 0x70, 0x65, 0x65, 0x72, 0x5f, + 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x52, 0x10, 0x70, 0x65, 0x65, 0x72, 0x43, 0x65, + 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x12, 0x3d, 0x0a, 0x0f, 0x76, 0x65, + 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x09, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x52, 0x0e, 0x76, 0x65, 0x72, 0x69, 0x66, + 0x69, 0x65, 0x64, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x73, 0x12, 0x42, 0x0a, 0x1d, 0x73, 0x69, 0x67, + 0x6e, 0x65, 0x64, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0c, + 0x52, 0x1b, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x73, 0x12, 0x23, 0x0a, + 0x0d, 0x6f, 0x63, 0x73, 0x70, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x0b, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x6f, 0x63, 0x73, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x6c, 0x73, 0x5f, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, + 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x74, 0x6c, 0x73, 0x55, 0x6e, 0x69, 0x71, 0x75, + 0x65, 0x22, 0x2a, 0x0a, 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, + 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x73, 0x6e, 0x31, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x08, 0x61, 0x73, 0x6e, 0x31, 0x44, 0x61, 0x74, 0x61, 0x22, 0x47, 0x0a, + 0x10, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x69, + 0x6e, 0x12, 0x33, 0x0a, 0x0c, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x65, 0x72, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x0c, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x22, 0x5b, 0x0a, 0x10, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x28, 0x0a, 0x05, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6c, 0x6f, 0x67, 0x69, 0x63, + 0x61, 0x6c, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x44, 0x61, 0x74, 0x61, 0x52, 0x05, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x32, 0xa5, 0x03, 0x0a, 0x07, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x12, + 0x3e, 0x0a, 0x0d, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x15, 0x2e, 0x70, 0x62, 0x2e, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x16, 0x2e, 0x70, 0x62, 0x2e, 0x48, 0x61, 0x6e, + 0x64, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, + 0x30, 0x0a, 0x0c, 0x53, 0x70, 0x65, 0x63, 0x69, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x73, 0x12, + 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x15, 0x2e, 0x70, 0x62, 0x2e, + 0x53, 0x70, 0x65, 0x63, 0x69, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x73, 0x52, 0x65, 0x70, 0x6c, + 0x79, 0x12, 0x53, 0x0a, 0x14, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x45, 0x78, 0x69, 0x73, 0x74, + 0x65, 0x6e, 0x63, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x1c, 0x2e, 0x70, 0x62, 0x2e, 0x48, + 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x45, 0x78, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x65, 0x43, 0x68, + 0x65, 0x63, 0x6b, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x1d, 0x2e, 0x70, 0x62, 0x2e, 0x48, 0x61, 0x6e, + 0x64, 0x6c, 0x65, 0x45, 0x78, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x65, 0x43, 0x68, 0x65, 0x63, + 0x6b, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1f, 0x0a, 0x07, 0x43, 0x6c, 0x65, 0x61, 0x6e, 0x75, + 0x70, 0x12, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x09, 0x2e, 0x70, + 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x31, 0x0a, 0x0d, 0x49, 0x6e, 0x76, 0x61, 0x6c, + 0x69, 0x64, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x15, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x6e, + 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x72, 0x67, 0x73, 0x1a, + 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x26, 0x0a, 0x05, 0x53, 0x65, + 0x74, 0x75, 0x70, 0x12, 0x0d, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x74, 0x75, 0x70, 0x41, 0x72, + 0x67, 0x73, 0x1a, 0x0e, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x74, 0x75, 0x70, 0x52, 0x65, 0x70, + 0x6c, 0x79, 0x12, 0x35, 0x0a, 0x0a, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, + 0x12, 0x12, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, + 0x41, 0x72, 0x67, 0x73, 0x1a, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, + 0x6c, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x20, 0x0a, 0x04, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0d, 0x2e, 0x70, + 0x62, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x32, 0xd5, 0x01, 0x0a, 0x07, + 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x31, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, + 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, + 0x41, 0x72, 0x67, 0x73, 0x1a, 0x14, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, + 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x2e, 0x0a, 0x03, 0x47, 0x65, + 0x74, 0x12, 0x12, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x47, 0x65, + 0x74, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, + 0x67, 0x65, 0x47, 0x65, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x2e, 0x0a, 0x03, 0x50, 0x75, + 0x74, 0x12, 0x12, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x50, 0x75, + 0x74, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, + 0x67, 0x65, 0x50, 0x75, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x37, 0x0a, 0x06, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x12, 0x15, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, + 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x16, 0x2e, 0x70, 0x62, + 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, + 0x70, 0x6c, 0x79, 0x32, 0xdd, 0x07, 0x0a, 0x0a, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x56, 0x69, + 0x65, 0x77, 0x12, 0x2a, 0x0a, 0x0f, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x4c, 0x65, 0x61, + 0x73, 0x65, 0x54, 0x54, 0x4c, 0x12, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x1a, 0x0c, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x54, 0x4c, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x26, + 0x0a, 0x0b, 0x4d, 0x61, 0x78, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x54, 0x54, 0x4c, 0x12, 0x09, 0x2e, + 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0c, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x54, + 0x4c, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x26, 0x0a, 0x07, 0x54, 0x61, 0x69, 0x6e, 0x74, 0x65, + 0x64, 0x12, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x10, 0x2e, 0x70, + 0x62, 0x2e, 0x54, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x36, + 0x0a, 0x0f, 0x43, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, + 0x64, 0x12, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x18, 0x2e, 0x70, + 0x62, 0x2e, 0x43, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, + 0x64, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x38, 0x0a, 0x10, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x09, 0x2e, 0x70, 0x62, 0x2e, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x19, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, + 0x12, 0x47, 0x0a, 0x10, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x57, 0x72, 0x61, 0x70, + 0x44, 0x61, 0x74, 0x61, 0x12, 0x18, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x57, 0x72, 0x61, 0x70, 0x44, 0x61, 0x74, 0x61, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x19, + 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x57, 0x72, 0x61, 0x70, + 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x30, 0x0a, 0x0c, 0x4d, 0x6c, 0x6f, + 0x63, 0x6b, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, + 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x15, 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x6c, 0x6f, 0x63, 0x6b, 0x45, + 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x2c, 0x0a, 0x0a, 0x4c, + 0x6f, 0x63, 0x61, 0x6c, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, + 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x4d, + 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x35, 0x0a, 0x0a, 0x45, 0x6e, 0x74, + 0x69, 0x74, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6e, 0x74, + 0x69, 0x74, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x13, 0x2e, 0x70, 0x62, + 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, + 0x12, 0x2a, 0x0a, 0x09, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x45, 0x6e, 0x76, 0x12, 0x09, 0x2e, + 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x6c, + 0x75, 0x67, 0x69, 0x6e, 0x45, 0x6e, 0x76, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x3f, 0x0a, 0x0f, + 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x46, 0x6f, 0x72, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, + 0x12, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x41, + 0x72, 0x67, 0x73, 0x1a, 0x18, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x46, + 0x6f, 0x72, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x68, 0x0a, + 0x1a, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, + 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x25, 0x2e, 0x70, 0x62, + 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, + 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, + 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x50, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x2e, 0x0a, 0x0b, 0x43, 0x6c, 0x75, 0x73, 0x74, + 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, + 0x79, 0x1a, 0x14, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x5c, 0x0a, 0x15, 0x47, 0x65, 0x6e, 0x65, 0x72, + 0x61, 0x74, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, + 0x12, 0x20, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x49, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, + 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x13, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, + 0x72, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4a, 0x6f, 0x62, 0x12, 0x1e, 0x2e, 0x70, + 0x62, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x70, + 0x62, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, + 0x15, 0x44, 0x65, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x6f, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x4a, 0x6f, 0x62, 0x12, 0x20, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4a, 0x6f, - 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x34, 0x0a, 0x03, 0x72, 0x65, 0x71, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x72, 0x65, 0x67, - 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x03, 0x72, 0x65, 0x71, 0x22, 0x8e, - 0x01, 0x0a, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, - 0x0b, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x41, 0x64, 0x64, 0x72, 0x12, 0x1f, - 0x0a, 0x0b, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x0a, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x12, - 0x3e, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, - 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x43, - 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x0f, - 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, - 0xbb, 0x04, 0x0a, 0x0f, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, - 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2d, 0x0a, - 0x12, 0x68, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, - 0x65, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x68, 0x61, 0x6e, 0x64, 0x73, - 0x68, 0x61, 0x6b, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x1d, 0x0a, 0x0a, - 0x64, 0x69, 0x64, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x09, 0x64, 0x69, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x63, - 0x69, 0x70, 0x68, 0x65, 0x72, 0x5f, 0x73, 0x75, 0x69, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x0b, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x53, 0x75, 0x69, 0x74, 0x65, 0x12, 0x2f, - 0x0a, 0x13, 0x6e, 0x65, 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x6e, 0x65, 0x67, - 0x6f, 0x74, 0x69, 0x61, 0x74, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, - 0x41, 0x0a, 0x1d, 0x6e, 0x65, 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x69, 0x73, 0x5f, 0x6d, 0x75, 0x74, 0x75, 0x61, 0x6c, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x6e, 0x65, 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74, - 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x49, 0x73, 0x4d, 0x75, 0x74, 0x75, - 0x61, 0x6c, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4e, - 0x61, 0x6d, 0x65, 0x12, 0x41, 0x0a, 0x11, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x63, 0x65, 0x72, 0x74, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, - 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, - 0x68, 0x61, 0x69, 0x6e, 0x52, 0x10, 0x70, 0x65, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x12, 0x3d, 0x0a, 0x0f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, - 0x65, 0x64, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x14, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, - 0x43, 0x68, 0x61, 0x69, 0x6e, 0x52, 0x0e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x43, - 0x68, 0x61, 0x69, 0x6e, 0x73, 0x12, 0x42, 0x0a, 0x1d, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, - 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x1b, 0x73, 0x69, - 0x67, 0x6e, 0x65, 0x64, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x54, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x6f, 0x63, 0x73, - 0x70, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x0c, 0x6f, 0x63, 0x73, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, - 0x0a, 0x0a, 0x74, 0x6c, 0x73, 0x5f, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x18, 0x0c, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x09, 0x74, 0x6c, 0x73, 0x55, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x22, 0x2a, 0x0a, - 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x1b, 0x0a, 0x09, - 0x61, 0x73, 0x6e, 0x31, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x08, 0x61, 0x73, 0x6e, 0x31, 0x44, 0x61, 0x74, 0x61, 0x22, 0x47, 0x0a, 0x10, 0x43, 0x65, 0x72, - 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x12, 0x33, 0x0a, - 0x0c, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x65, 0x52, 0x0c, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, - 0x65, 0x73, 0x22, 0x5b, 0x0a, 0x10, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, - 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x65, 0x76, 0x65, 0x6e, - 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x28, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6c, 0x6f, 0x67, 0x69, 0x63, 0x61, 0x6c, 0x2e, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x44, 0x61, 0x74, 0x61, 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x32, - 0xa5, 0x03, 0x0a, 0x07, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x12, 0x3e, 0x0a, 0x0d, 0x48, - 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x2e, 0x70, - 0x62, 0x2e, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, - 0x72, 0x67, 0x73, 0x1a, 0x16, 0x2e, 0x70, 0x62, 0x2e, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x30, 0x0a, 0x0c, 0x53, - 0x70, 0x65, 0x63, 0x69, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x73, 0x12, 0x09, 0x2e, 0x70, 0x62, - 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x15, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x70, 0x65, 0x63, - 0x69, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x53, 0x0a, - 0x14, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x45, 0x78, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x65, - 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x1c, 0x2e, 0x70, 0x62, 0x2e, 0x48, 0x61, 0x6e, 0x64, 0x6c, - 0x65, 0x45, 0x78, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x41, - 0x72, 0x67, 0x73, 0x1a, 0x1d, 0x2e, 0x70, 0x62, 0x2e, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x45, - 0x78, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x70, - 0x6c, 0x79, 0x12, 0x1f, 0x0a, 0x07, 0x43, 0x6c, 0x65, 0x61, 0x6e, 0x75, 0x70, 0x12, 0x09, 0x2e, - 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x12, 0x31, 0x0a, 0x0d, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, - 0x65, 0x4b, 0x65, 0x79, 0x12, 0x15, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, - 0x64, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x09, 0x2e, 0x70, 0x62, - 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x26, 0x0a, 0x05, 0x53, 0x65, 0x74, 0x75, 0x70, 0x12, - 0x0d, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x74, 0x75, 0x70, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x0e, - 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x74, 0x75, 0x70, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x35, - 0x0a, 0x0a, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x12, 0x12, 0x2e, 0x70, - 0x62, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x41, 0x72, 0x67, 0x73, - 0x1a, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, - 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x20, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, 0x2e, - 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0d, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x79, - 0x70, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x32, 0xd5, 0x01, 0x0a, 0x07, 0x53, 0x74, 0x6f, 0x72, - 0x61, 0x67, 0x65, 0x12, 0x31, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x13, 0x2e, 0x70, 0x62, - 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x72, 0x67, 0x73, - 0x1a, 0x14, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4c, 0x69, 0x73, - 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x2e, 0x0a, 0x03, 0x47, 0x65, 0x74, 0x12, 0x12, 0x2e, - 0x70, 0x62, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x47, 0x65, 0x74, 0x41, 0x72, 0x67, - 0x73, 0x1a, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x47, 0x65, - 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x2e, 0x0a, 0x03, 0x50, 0x75, 0x74, 0x12, 0x12, 0x2e, - 0x70, 0x62, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x50, 0x75, 0x74, 0x41, 0x72, 0x67, - 0x73, 0x1a, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x50, 0x75, - 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x37, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x12, 0x15, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x16, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x6f, - 0x72, 0x61, 0x67, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x32, - 0xdd, 0x07, 0x0a, 0x0a, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x56, 0x69, 0x65, 0x77, 0x12, 0x2a, - 0x0a, 0x0f, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x54, 0x54, - 0x4c, 0x12, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0c, 0x2e, 0x70, - 0x62, 0x2e, 0x54, 0x54, 0x4c, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x26, 0x0a, 0x0b, 0x4d, 0x61, - 0x78, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x54, 0x54, 0x4c, 0x12, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, - 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0c, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x54, 0x4c, 0x52, 0x65, 0x70, - 0x6c, 0x79, 0x12, 0x26, 0x0a, 0x07, 0x54, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x64, 0x12, 0x09, 0x2e, - 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x10, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x61, - 0x69, 0x6e, 0x74, 0x65, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x36, 0x0a, 0x0f, 0x43, 0x61, - 0x63, 0x68, 0x69, 0x6e, 0x67, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x09, 0x2e, - 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x18, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x61, - 0x63, 0x68, 0x69, 0x6e, 0x67, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, 0x65, 0x70, - 0x6c, 0x79, 0x12, 0x38, 0x0a, 0x10, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, - 0x79, 0x1a, 0x19, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x47, 0x0a, 0x10, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x57, 0x72, 0x61, 0x70, 0x44, 0x61, 0x74, 0x61, - 0x12, 0x18, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x57, 0x72, - 0x61, 0x70, 0x44, 0x61, 0x74, 0x61, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x19, 0x2e, 0x70, 0x62, 0x2e, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x57, 0x72, 0x61, 0x70, 0x44, 0x61, 0x74, 0x61, - 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x30, 0x0a, 0x0c, 0x4d, 0x6c, 0x6f, 0x63, 0x6b, 0x45, 0x6e, - 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, - 0x1a, 0x15, 0x2e, 0x70, 0x62, 0x2e, 0x4d, 0x6c, 0x6f, 0x63, 0x6b, 0x45, 0x6e, 0x61, 0x62, 0x6c, - 0x65, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x2c, 0x0a, 0x0a, 0x4c, 0x6f, 0x63, 0x61, 0x6c, - 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, - 0x1a, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x4d, 0x6f, 0x75, 0x6e, 0x74, - 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x35, 0x0a, 0x0a, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, - 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, - 0x6e, 0x66, 0x6f, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6e, 0x74, - 0x69, 0x74, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x2a, 0x0a, 0x09, - 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x45, 0x6e, 0x76, 0x12, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, - 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, - 0x45, 0x6e, 0x76, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x3f, 0x0a, 0x0f, 0x47, 0x72, 0x6f, 0x75, - 0x70, 0x73, 0x46, 0x6f, 0x72, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x12, 0x2e, 0x70, 0x62, - 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x41, 0x72, 0x67, 0x73, 0x1a, - 0x18, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x46, 0x6f, 0x72, 0x45, 0x6e, - 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x68, 0x0a, 0x1a, 0x47, 0x65, 0x6e, - 0x65, 0x72, 0x61, 0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x46, 0x72, 0x6f, - 0x6d, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x25, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x6e, - 0x65, 0x72, 0x61, 0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x46, 0x72, 0x6f, - 0x6d, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, - 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x50, 0x61, 0x73, 0x73, - 0x77, 0x6f, 0x72, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, - 0x70, 0x6c, 0x79, 0x12, 0x2e, 0x0a, 0x0b, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x6e, - 0x66, 0x6f, 0x12, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x14, 0x2e, - 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, - 0x70, 0x6c, 0x79, 0x12, 0x5c, 0x0a, 0x15, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x49, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x20, 0x2e, 0x70, - 0x62, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, - 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x49, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x74, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x56, 0x0a, 0x13, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x6f, 0x74, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4a, 0x6f, 0x62, 0x12, 0x1e, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, - 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4a, 0x6f, - 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, - 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4a, 0x6f, - 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x15, 0x44, 0x65, 0x72, - 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4a, - 0x6f, 0x62, 0x12, 0x20, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, - 0x65, 0x72, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x32, - 0x36, 0x0a, 0x06, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x2c, 0x0a, 0x09, 0x53, 0x65, 0x6e, - 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x65, 0x6e, 0x64, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x09, 0x2e, 0x70, - 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x2a, 0x5a, 0x28, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, - 0x76, 0x61, 0x75, 0x6c, 0x74, 0x2f, 0x73, 0x64, 0x6b, 0x2f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, - 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x32, 0x36, 0x0a, 0x06, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x2c, 0x0a, + 0x09, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x2e, 0x70, 0x62, 0x2e, + 0x53, 0x65, 0x6e, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x09, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x2a, 0x5a, 0x28, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, + 0x6f, 0x72, 0x70, 0x2f, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x2f, 0x73, 0x64, 0x6b, 0x2f, 0x70, 0x6c, + 0x75, 0x67, 0x69, 0x6e, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/sdk/plugin/pb/backend.proto b/sdk/plugin/pb/backend.proto index 57b856c43b..07c56c695f 100644 --- a/sdk/plugin/pb/backend.proto +++ b/sdk/plugin/pb/backend.proto @@ -618,7 +618,7 @@ message RegisterRotationJobResponse { message RotationJobInput { string name = 1; - string mount_type = 2; + string mount_point = 2; string path = 3; string rotation_schedule = 4; int64 rotation_window = 5; @@ -626,7 +626,7 @@ message RotationJobInput { } message DeregisterRotationRequestInput { - string mount_type = 1; + string mount_point = 1; string req_path = 2; } diff --git a/sdk/rotation/rotation_job.go b/sdk/rotation/rotation_job.go index 2eaecb7cd1..35ba234e06 100644 --- a/sdk/rotation/rotation_job.go +++ b/sdk/rotation/rotation_job.go @@ -26,13 +26,13 @@ type RotationJob struct { // For requests, this will always be blank. RotationID string `sentinel:""` Path string - MountType string + MountPoint string Name string } type RotationJobConfigureRequest struct { Name string - MountType string + MountPoint string ReqPath string RotationSchedule string RotationWindow int @@ -40,12 +40,23 @@ type RotationJobConfigureRequest struct { } type RotationJobDeregisterRequest struct { - MountType string - ReqPath string + MountPoint string + ReqPath string } func (s *RotationJob) Validate() error { - // TODO: validation? + if s.MountPoint == "" { + return fmt.Errorf("MountPoint is required") + } + + if s.Path == "" { + return fmt.Errorf("ReqPath is required") + } + + if s.Schedule.RotationSchedule == "" && s.Schedule.RotationPeriod == 0 { + return fmt.Errorf("RotationSchedule or RotationPeriod is required to set up rotation job") + } + return nil } @@ -72,9 +83,9 @@ func newRotationJob(configRequest *RotationJobConfigureRequest) (*RotationJob, e RotationOptions: RotationOptions{ Schedule: rs, }, - MountType: configRequest.MountType, - Path: configRequest.ReqPath, - Name: configRequest.Name, + MountPoint: configRequest.MountPoint, + Path: configRequest.ReqPath, + Name: configRequest.Name, }, nil } @@ -84,6 +95,11 @@ func ConfigureRotationJob(configRequest *RotationJobConfigureRequest) (*Rotation if err != nil { return nil, err } + + if err := rotationJob.Validate(); err != nil { + return nil, fmt.Errorf("error validating rotation job: %s", err) + } + // Expect rotation job to exist here if rotationJob == nil { return nil, fmt.Errorf("rotation credential was nil; expected non-nil value") diff --git a/sdk/rotation/rotation_job_test.go b/sdk/rotation/rotation_job_test.go new file mode 100644 index 0000000000..c0f5eca968 --- /dev/null +++ b/sdk/rotation/rotation_job_test.go @@ -0,0 +1,71 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package rotation + +import ( + "reflect" + "strings" + "testing" +) + +func TestConfigureRotationJob(t *testing.T) { + tests := []struct { + name string + req *RotationJobConfigureRequest + expected RotationJob + expectedError string + }{ + { + name: "no rotation params", + req: &RotationJobConfigureRequest{ + MountPoint: "aws", + ReqPath: "config/root", + RotationSchedule: "", + RotationWindow: 60, + RotationPeriod: 0, + }, + expectedError: "RotationSchedule or RotationPeriod is required to set up rotation job", + }, + { + name: "no mount point", + req: &RotationJobConfigureRequest{ + MountPoint: "", + ReqPath: "config/root", + RotationSchedule: "", + RotationWindow: 60, + RotationPeriod: 5, + }, + expectedError: "MountPoint is required", + }, + { + name: "no req path", + req: &RotationJobConfigureRequest{ + MountPoint: "aws", + ReqPath: "", + RotationSchedule: "", + RotationWindow: 60, + RotationPeriod: 5, + }, + expectedError: "ReqPath is required", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + out, err := ConfigureRotationJob(tt.req) + if err != nil { + if tt.expectedError == "" { + t.Errorf("expected no error but received an error: %s", err) + } + if !strings.Contains(err.Error(), tt.expectedError) { + t.Errorf("TestConfigureRotationJob() error = %v, expected %s", err, tt.expectedError) + } + } + + if err == nil && !reflect.DeepEqual(tt.expected, out) { + t.Errorf("TestConfigureRotationJob() error comparing params; got %v, expected %v", out, tt.expected) + } + }) + } +} diff --git a/sdk/rotation/schedule.go b/sdk/rotation/schedule.go index 7c35f3615e..8d4af151f7 100644 --- a/sdk/rotation/schedule.go +++ b/sdk/rotation/schedule.go @@ -13,7 +13,7 @@ import ( const ( // Minimum allowed value for rotation_window minRotationWindowSeconds = 3600 - parseOptions = cron.Second | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow + parseOptions = cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow ) // RotationSchedule holds the parsed and unparsed versions of the schedule, along with the projected next rotation time. diff --git a/vault/rotation_stubs_oss.go b/vault/rotation_stubs_oss.go index 746689ce28..2bbd1f0b31 100644 --- a/vault/rotation_stubs_oss.go +++ b/vault/rotation_stubs_oss.go @@ -29,5 +29,5 @@ func (c *Core) RegisterRotationJob(_ context.Context, _ *rotation.RotationJob) ( } func (c *Core) DeregisterRotationJob(_ context.Context, _ *rotation.RotationJobDeregisterRequest) error { - return automatedrotationutil.ErrRotationManagerUnsupported + return nil }