diff --git a/internal/auth/exports.go b/internal/auth/exports.go index f3dc523ade..abbed80abe 100644 --- a/internal/auth/exports.go +++ b/internal/auth/exports.go @@ -4,12 +4,38 @@ package auth import ( + "github.com/hashicorp/consul/internal/auth/internal/controllers" + "github.com/hashicorp/consul/internal/auth/internal/controllers/trafficpermissions" + "github.com/hashicorp/consul/internal/auth/internal/mappers/trafficpermissionsmapper" "github.com/hashicorp/consul/internal/auth/internal/types" + "github.com/hashicorp/consul/internal/controller" "github.com/hashicorp/consul/internal/resource" ) +var ( + // Controller statuses + + StatusKey = trafficpermissions.StatusKey + TrafficPermissionsConditionComputed = trafficpermissions.ConditionComputed + TrafficPermissionsConditionFailedToCompute = trafficpermissions.ConditionFailedToCompute +) + // RegisterTypes adds all resource types within the "catalog" API group // to the given type registry func RegisterTypes(r resource.Registry) { types.Register(r) } + +type ControllerDependencies = controllers.Dependencies + +func DefaultControllerDependencies() ControllerDependencies { + return ControllerDependencies{ + TrafficPermissionsMapper: trafficpermissionsmapper.New(), + } +} + +// RegisterControllers registers controllers for the auth types with +// the given controller manager. +func RegisterControllers(mgr *controller.Manager, deps ControllerDependencies) { + controllers.Register(mgr, deps) +} diff --git a/internal/auth/internal/controllers/register.go b/internal/auth/internal/controllers/register.go new file mode 100644 index 0000000000..03fc31c5bc --- /dev/null +++ b/internal/auth/internal/controllers/register.go @@ -0,0 +1,17 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package controllers + +import ( + "github.com/hashicorp/consul/internal/auth/internal/controllers/trafficpermissions" + "github.com/hashicorp/consul/internal/controller" +) + +type Dependencies struct { + TrafficPermissionsMapper trafficpermissions.TrafficPermissionsMapper +} + +func Register(mgr *controller.Manager, deps Dependencies) { + mgr.Register(trafficpermissions.Controller(deps.TrafficPermissionsMapper)) +} diff --git a/internal/auth/internal/controllers/trafficpermissions/controller.go b/internal/auth/internal/controllers/trafficpermissions/controller.go new file mode 100644 index 0000000000..530191f519 --- /dev/null +++ b/internal/auth/internal/controllers/trafficpermissions/controller.go @@ -0,0 +1,189 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package trafficpermissions + +import ( + "context" + + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/anypb" + + "github.com/hashicorp/consul/internal/controller" + "github.com/hashicorp/consul/internal/resource" + pbauth "github.com/hashicorp/consul/proto-public/pbauth/v2beta1" + "github.com/hashicorp/consul/proto-public/pbresource" +) + +// TrafficPermissionsMapper is used to map a watch event for a TrafficPermissions resource and translate +// it to a ComputedTrafficPermissions resource which contains the effective permissions +// from all referencing TrafficPermissions resources. +type TrafficPermissionsMapper interface { + // MapTrafficPermissions will take a TrafficPermission resource and return controller requests for all + // ComputedTrafficPermissions associated with that TrafficPermission. + MapTrafficPermissions(context.Context, controller.Runtime, *pbresource.Resource) ([]controller.Request, error) + + // UntrackTrafficPermissions instructs the Mapper to forget about the TrafficPermission. + UntrackTrafficPermissions(*pbresource.ID) + + // GetTrafficPermissionsForCTP returns the tracked TrafficPermissions that are used to create a CTP + GetTrafficPermissionsForCTP(*pbresource.ID) []*pbresource.Reference +} + +// Controller creates a controller for automatic ComputedTrafficPermissions management for +// updates to WorkloadIdentity or TrafficPermission resources. +func Controller(mapper TrafficPermissionsMapper) controller.Controller { + if mapper == nil { + panic("No TrafficPermissionsMapper was provided to the TrafficPermissionsController constructor") + } + + return controller.ForType(pbauth.ComputedTrafficPermissionsType). + WithWatch(pbauth.WorkloadIdentityType, controller.ReplaceType(pbauth.ComputedTrafficPermissionsType)). + WithWatch(pbauth.TrafficPermissionsType, mapper.MapTrafficPermissions). + WithReconciler(&reconciler{mapper: mapper}) +} + +type reconciler struct { + mapper TrafficPermissionsMapper +} + +// Reconcile will reconcile one ComputedTrafficPermission (CTP) in response to some event. +// Events include adding, modifying or deleting a WorkloadIdentity or TrafficPermission. +func (r *reconciler) Reconcile(ctx context.Context, rt controller.Runtime, req controller.Request) error { + rt.Logger = rt.Logger.With("resource-id", req.ID, "controller", StatusKey) + /* + * A CTP ID could come in for a variety of reasons. + * 1. workload identity create / delete: this results in the creation / deletion of a new CTP + * 2. traffic permission create / modify / delete: this results in a potential modification of an existing CTP + * + * Part 1: Handle Workload Identity changes: + * Check if the workload identity exists. If it doesn't we can stop here. + * CTPs are always generated from WorkloadIdentities, therefore the WI resource must already exist. + * If it is missing, that means it was deleted. + */ + ctpID := req.ID + wi := resource.ReplaceType(pbauth.WorkloadIdentityType, ctpID) + workloadIdentity, err := resource.GetDecodedResource[*pbauth.WorkloadIdentity](ctx, rt.Client, wi) + if err != nil { + rt.Logger.Error("error retrieving corresponding Workload Identity", "error", err) + return err + } + if workloadIdentity == nil || workloadIdentity.Resource == nil { + rt.Logger.Trace("workload identity has been deleted") + return nil + } + + // Check if CTP exists: + oldCTPData, err := resource.GetDecodedResource[*pbauth.ComputedTrafficPermissions](ctx, rt.Client, ctpID) + if err != nil { + rt.Logger.Error("error retrieving computed permissions", "error", err) + return err + } + var oldResource *pbresource.Resource + var owner *pbresource.ID + if oldCTPData == nil { + // CTP does not yet exist, so we need to make a new one + rt.Logger.Trace("creating new computed traffic permissions for workload identity") + owner = workloadIdentity.Resource.Id + } else { + oldResource = oldCTPData.Resource + owner = oldCTPData.Resource.Owner + } + + // Part 2: Recompute a CTP from TP create / modify / delete, or create a new CTP from existing TPs: + latestTrafficPermissions, err := computeNewTrafficPermissions(ctx, rt, r.mapper, ctpID, oldResource) + if err != nil { + rt.Logger.Error("error calculating computed permissions", "error", err) + return err + } + + if oldCTPData != nil && proto.Equal(oldCTPData.Data, latestTrafficPermissions) { + // there are no changes to the computed traffic permissions, and we can return early + rt.Logger.Trace("no new computed traffic permissions") + return nil + } + newCTPData, err := anypb.New(latestTrafficPermissions) + if err != nil { + rt.Logger.Error("error marshalling latest traffic permissions", "error", err) + writeFailedStatus(ctx, rt, oldResource, nil, err.Error()) + return err + } + rt.Logger.Trace("writing computed traffic permissions") + rsp, err := rt.Client.Write(ctx, &pbresource.WriteRequest{ + Resource: &pbresource.Resource{ + Id: req.ID, + Data: newCTPData, + Owner: owner, + }, + }) + if err != nil || rsp.Resource == nil { + rt.Logger.Error("error writing new computed traffic permissions", "error", err) + writeFailedStatus(ctx, rt, oldResource, nil, err.Error()) + return err + } else { + rt.Logger.Trace("new computed traffic permissions were successfully written") + } + newStatus := &pbresource.Status{ + ObservedGeneration: rsp.Resource.Generation, + Conditions: []*pbresource.Condition{ + ConditionComputed(req.ID.Name), + }, + } + _, err = rt.Client.WriteStatus(ctx, &pbresource.WriteStatusRequest{ + Id: rsp.Resource.Id, + Key: StatusKey, + Status: newStatus, + }) + return err +} + +func writeFailedStatus(ctx context.Context, rt controller.Runtime, ctp *pbresource.Resource, tp *pbresource.ID, errDetail string) error { + if ctp == nil { + return nil + } + newStatus := &pbresource.Status{ + ObservedGeneration: ctp.Generation, + Conditions: []*pbresource.Condition{ + ConditionFailedToCompute(ctp.Id.Name, tp.Name, errDetail), + }, + } + _, err := rt.Client.WriteStatus(ctx, &pbresource.WriteStatusRequest{ + Id: ctp.Id, + Key: StatusKey, + Status: newStatus, + }) + return err +} + +// computeNewTrafficPermissions will use all associated Traffic Permissions to create new ComputedTrafficPermissions data +func computeNewTrafficPermissions(ctx context.Context, rt controller.Runtime, wm TrafficPermissionsMapper, ctpID *pbresource.ID, ctp *pbresource.Resource) (*pbauth.ComputedTrafficPermissions, error) { + // Part 1: Get all TPs that apply to workload identity + // Get already associated WorkloadIdentities/CTPs for reconcile requests: + trackedTPs := wm.GetTrafficPermissionsForCTP(ctpID) + if len(trackedTPs) > 0 { + rt.Logger.Trace("got tracked traffic permissions for CTP", "tps:", trackedTPs) + } else { + rt.Logger.Trace("found no tracked traffic permissions for CTP") + } + ap := make([]*pbauth.Permission, 0) + dp := make([]*pbauth.Permission, 0) + for _, t := range trackedTPs { + rsp, err := resource.GetDecodedResource[*pbauth.TrafficPermissions](ctx, rt.Client, resource.IDFromReference(t)) + if err != nil { + rt.Logger.Error("error reading traffic permissions resource for computation", "error", err) + writeFailedStatus(ctx, rt, ctp, resource.IDFromReference(t), err.Error()) + return nil, err + } + if rsp == nil { + rt.Logger.Trace("untracking deleted TrafficPermissions", "traffic-permissions-name", t.Name) + wm.UntrackTrafficPermissions(resource.IDFromReference(t)) + continue + } + if rsp.Data.Action == pbauth.Action_ACTION_ALLOW { + ap = append(ap, rsp.Data.Permissions...) + } else { + dp = append(dp, rsp.Data.Permissions...) + } + } + return &pbauth.ComputedTrafficPermissions{AllowPermissions: ap, DenyPermissions: dp}, nil +} diff --git a/internal/auth/internal/controllers/trafficpermissions/controller_test.go b/internal/auth/internal/controllers/trafficpermissions/controller_test.go new file mode 100644 index 0000000000..5bfab242e2 --- /dev/null +++ b/internal/auth/internal/controllers/trafficpermissions/controller_test.go @@ -0,0 +1,617 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package trafficpermissions + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + + svctest "github.com/hashicorp/consul/agent/grpc-external/services/resource/testing" + "github.com/hashicorp/consul/internal/auth/internal/mappers/trafficpermissionsmapper" + "github.com/hashicorp/consul/internal/auth/internal/types" + "github.com/hashicorp/consul/internal/controller" + "github.com/hashicorp/consul/internal/resource" + rtest "github.com/hashicorp/consul/internal/resource/resourcetest" + pbauth "github.com/hashicorp/consul/proto-public/pbauth/v2beta1" + "github.com/hashicorp/consul/proto-public/pbresource" + "github.com/hashicorp/consul/proto/private/prototest" + "github.com/hashicorp/consul/sdk/testutil" +) + +type controllerSuite struct { + suite.Suite + ctx context.Context + client *rtest.Client + rt controller.Runtime + + mapper *trafficpermissionsmapper.TrafficPermissionsMapper + reconciler *reconciler +} + +func (suite *controllerSuite) SetupTest() { + suite.ctx = testutil.TestContext(suite.T()) + client := svctest.RunResourceService(suite.T(), types.Register) + suite.client = rtest.NewClient(client) + suite.rt = controller.Runtime{ + Client: suite.client, + Logger: testutil.Logger(suite.T()), + } + suite.mapper = trafficpermissionsmapper.New() + suite.reconciler = &reconciler{mapper: suite.mapper} +} + +func (suite *controllerSuite) requireTrafficPermissionsTracking(tp *pbresource.Resource, ids ...*pbresource.ID) { + reqs, err := suite.mapper.MapTrafficPermissions(suite.ctx, suite.rt, tp) + require.NoError(suite.T(), err) + require.Len(suite.T(), reqs, len(ids)) + for _, id := range ids { + prototest.AssertContainsElement(suite.T(), reqs, controller.Request{ID: id}) + } + for _, req := range reqs { + prototest.AssertContainsElement(suite.T(), ids, req.ID) + } +} + +func (suite *controllerSuite) requireCTP(resource *pbresource.Resource, allowExpected []*pbauth.Permission, denyExpected []*pbauth.Permission) { + var ctp pbauth.ComputedTrafficPermissions + require.NoError(suite.T(), resource.Data.UnmarshalTo(&ctp)) + require.Len(suite.T(), ctp.AllowPermissions, len(allowExpected)) + require.Len(suite.T(), ctp.DenyPermissions, len(denyExpected)) + prototest.AssertElementsMatch(suite.T(), allowExpected, ctp.AllowPermissions) + prototest.AssertElementsMatch(suite.T(), denyExpected, ctp.DenyPermissions) +} + +func (suite *controllerSuite) TestReconcile_CTPCreate_NoReferencingTrafficPermissionsExist() { + wi := rtest.Resource(pbauth.WorkloadIdentityType, "wi1").Write(suite.T(), suite.client) + require.NotNil(suite.T(), wi) + id := rtest.Resource(pbauth.ComputedTrafficPermissionsType, wi.Id.Name).WithTenancy(resource.DefaultNamespacedTenancy()).WithOwner(wi.Id).ID() + require.NotNil(suite.T(), id) + + err := suite.reconciler.Reconcile(suite.ctx, suite.rt, controller.Request{ID: id}) + require.NoError(suite.T(), err) + + // Ensure that the CTP was created + ctp := suite.client.RequireResourceExists(suite.T(), id) + suite.requireCTP(ctp, []*pbauth.Permission{}, []*pbauth.Permission{}) +} + +func (suite *controllerSuite) TestReconcile_CTPCreate_ReferencingTrafficPermissionsExist() { + // create dead-end traffic permissions + p1 := &pbauth.Permission{} + tp1 := rtest.Resource(pbauth.TrafficPermissionsType, "tp1").WithData(suite.T(), &pbauth.TrafficPermissions{ + Destination: &pbauth.Destination{ + IdentityName: "wi1", + }, + Action: pbauth.Action_ACTION_DENY, + Permissions: []*pbauth.Permission{p1}, + }).Write(suite.T(), suite.client) + wi1ID := &pbresource.ID{ + Name: "wi1", + Type: pbauth.ComputedTrafficPermissionsType, + Tenancy: tp1.Id.Tenancy, + } + suite.requireTrafficPermissionsTracking(tp1, wi1ID) + p2 := &pbauth.Permission{ + Sources: []*pbauth.Source{ + { + IdentityName: "wi2", + Namespace: "default", + Partition: "default", + Peer: "local", + }}, + } + tp2 := rtest.Resource(pbauth.TrafficPermissionsType, "tp2").WithData(suite.T(), &pbauth.TrafficPermissions{ + Destination: &pbauth.Destination{ + IdentityName: "wi1", + }, + Action: pbauth.Action_ACTION_ALLOW, + Permissions: []*pbauth.Permission{p2}, + }).Write(suite.T(), suite.client) + suite.requireTrafficPermissionsTracking(tp2, wi1ID) + + // create the workload identity that they reference + wi := rtest.Resource(pbauth.WorkloadIdentityType, "wi1").Write(suite.T(), suite.client) + id := rtest.Resource(pbauth.ComputedTrafficPermissionsType, wi.Id.Name).WithTenancy(resource.DefaultNamespacedTenancy()).WithOwner(wi.Id).ID() + + err := suite.reconciler.Reconcile(suite.ctx, suite.rt, controller.Request{ID: id}) + require.NoError(suite.T(), err) + + // Ensure that the CTP was created + ctp := suite.client.RequireResourceExists(suite.T(), id) + suite.requireCTP(ctp, []*pbauth.Permission{p2}, []*pbauth.Permission{p1}) + rtest.RequireOwner(suite.T(), ctp, wi.Id, true) +} + +func (suite *controllerSuite) TestReconcile_WorkloadIdentityDelete_ReferencingTrafficPermissionsExist() { + p1 := &pbauth.Permission{} + tp1 := rtest.Resource(pbauth.TrafficPermissionsType, "tp1").WithData(suite.T(), &pbauth.TrafficPermissions{ + Destination: &pbauth.Destination{ + IdentityName: "wi1", + }, + Action: pbauth.Action_ACTION_DENY, + Permissions: []*pbauth.Permission{p1}, + }).Write(suite.T(), suite.client) + wi1ID := &pbresource.ID{ + Name: "wi1", + Type: pbauth.ComputedTrafficPermissionsType, + Tenancy: tp1.Id.Tenancy, + } + suite.requireTrafficPermissionsTracking(tp1, wi1ID) + p2 := &pbauth.Permission{ + Sources: []*pbauth.Source{ + { + IdentityName: "wi2", + Namespace: "default", + Partition: "default", + Peer: "local", + }}, + } + tp2 := rtest.Resource(pbauth.TrafficPermissionsType, "tp2").WithData(suite.T(), &pbauth.TrafficPermissions{ + Destination: &pbauth.Destination{ + IdentityName: "wi1", + }, + Action: pbauth.Action_ACTION_ALLOW, + Permissions: []*pbauth.Permission{p2}, + }).Write(suite.T(), suite.client) + suite.requireTrafficPermissionsTracking(tp2, wi1ID) + + // create the workload identity that they reference + wi := rtest.Resource(pbauth.WorkloadIdentityType, "wi1").Write(suite.T(), suite.client) + id := rtest.Resource(pbauth.ComputedTrafficPermissionsType, wi.Id.Name).WithTenancy(resource.DefaultNamespacedTenancy()).WithOwner(wi.Id).ID() + + err := suite.reconciler.Reconcile(suite.ctx, suite.rt, controller.Request{ID: id}) + require.NoError(suite.T(), err) + + // delete the workload identity + suite.client.MustDelete(suite.T(), wi.Id) + + // re-reconcile: should untrack the CTP + err = suite.reconciler.Reconcile(suite.ctx, suite.rt, controller.Request{ID: id}) + require.NoError(suite.T(), err) +} + +func (suite *controllerSuite) TestReconcile_WorkloadIdentityDelete_NoReferencingTrafficPermissionsExist() { + // create the workload identity that they reference + wi := rtest.Resource(pbauth.WorkloadIdentityType, "wi1").Write(suite.T(), suite.client) + id := rtest.Resource(pbauth.ComputedTrafficPermissionsType, wi.Id.Name).WithTenancy(resource.DefaultNamespacedTenancy()).WithOwner(wi.Id).ID() + + err := suite.reconciler.Reconcile(suite.ctx, suite.rt, controller.Request{ID: id}) + require.NoError(suite.T(), err) + + // delete the workload identity + suite.client.MustDelete(suite.T(), wi.Id) + + // re-reconcile: should untrack the CTP + err = suite.reconciler.Reconcile(suite.ctx, suite.rt, controller.Request{ID: id}) + require.NoError(suite.T(), err) + + // there should not be any traffic permissions to compute + tps := suite.mapper.GetTrafficPermissionsForCTP(id) + require.Len(suite.T(), tps, 0) +} + +func (suite *controllerSuite) TestReconcile_TrafficPermissionsCreate_DestinationWorkloadIdentityExists() { + // create the workload identity to be referenced + wi := rtest.Resource(pbauth.WorkloadIdentityType, "wi1").Write(suite.T(), suite.client) + id := rtest.Resource(pbauth.ComputedTrafficPermissionsType, wi.Id.Name).WithTenancy(resource.DefaultNamespacedTenancy()).WithOwner(wi.Id).ID() + + err := suite.reconciler.Reconcile(suite.ctx, suite.rt, controller.Request{ID: id}) + require.NoError(suite.T(), err) + + // create traffic permissions + p1 := &pbauth.Permission{} + tp1 := rtest.Resource(pbauth.TrafficPermissionsType, "tp1").WithData(suite.T(), &pbauth.TrafficPermissions{ + Destination: &pbauth.Destination{ + IdentityName: "wi1", + }, + Action: pbauth.Action_ACTION_DENY, + Permissions: []*pbauth.Permission{p1}, + }).Write(suite.T(), suite.client) + suite.requireTrafficPermissionsTracking(tp1, id) + p2 := &pbauth.Permission{ + Sources: []*pbauth.Source{ + { + IdentityName: "wi2", + Namespace: "default", + Partition: "default", + Peer: "local", + }}, + } + tp2 := rtest.Resource(pbauth.TrafficPermissionsType, "tp2").WithData(suite.T(), &pbauth.TrafficPermissions{ + Destination: &pbauth.Destination{ + IdentityName: "wi1", + }, + Action: pbauth.Action_ACTION_ALLOW, + Permissions: []*pbauth.Permission{p2}, + }).Write(suite.T(), suite.client) + suite.requireTrafficPermissionsTracking(tp2, id) + + err = suite.reconciler.Reconcile(suite.ctx, suite.rt, controller.Request{ID: id}) + require.NoError(suite.T(), err) + + // Ensure that the CTP was updated + ctp := suite.client.RequireResourceExists(suite.T(), id) + suite.requireCTP(ctp, []*pbauth.Permission{p2}, []*pbauth.Permission{p1}) + rtest.RequireOwner(suite.T(), ctp, wi.Id, true) + + // Add another TP + p3 := &pbauth.Permission{ + Sources: []*pbauth.Source{ + { + IdentityName: "wi3", + Namespace: "default", + Partition: "default", + Peer: "local", + }}, + } + tp3 := rtest.Resource(pbauth.TrafficPermissionsType, "tp3").WithData(suite.T(), &pbauth.TrafficPermissions{ + Destination: &pbauth.Destination{ + IdentityName: "wi1", + }, + Action: pbauth.Action_ACTION_DENY, + Permissions: []*pbauth.Permission{p3}, + }).Write(suite.T(), suite.client) + suite.requireTrafficPermissionsTracking(tp3, id) + + err = suite.reconciler.Reconcile(suite.ctx, suite.rt, controller.Request{ID: id}) + require.NoError(suite.T(), err) + + // Ensure that the CTP was updated + ctp = suite.client.RequireResourceExists(suite.T(), id) + suite.requireCTP(ctp, []*pbauth.Permission{p2}, []*pbauth.Permission{p1, p3}) + rtest.RequireOwner(suite.T(), ctp, wi.Id, true) +} + +func (suite *controllerSuite) TestReconcile_TrafficPermissionsDelete_DestinationWorkloadIdentityExists() { + // create the workload identity to be referenced + wi := rtest.Resource(pbauth.WorkloadIdentityType, "wi1").Write(suite.T(), suite.client) + id := rtest.Resource(pbauth.ComputedTrafficPermissionsType, wi.Id.Name).WithTenancy(resource.DefaultNamespacedTenancy()).WithOwner(wi.Id).ID() + + err := suite.reconciler.Reconcile(suite.ctx, suite.rt, controller.Request{ID: id}) + require.NoError(suite.T(), err) + + // create traffic permissions + p1 := &pbauth.Permission{} + tp1 := rtest.Resource(pbauth.TrafficPermissionsType, "tp1").WithData(suite.T(), &pbauth.TrafficPermissions{ + Destination: &pbauth.Destination{ + IdentityName: "wi1", + }, + Action: pbauth.Action_ACTION_DENY, + Permissions: []*pbauth.Permission{p1}, + }).Write(suite.T(), suite.client) + suite.requireTrafficPermissionsTracking(tp1, id) + p2 := &pbauth.Permission{ + Sources: []*pbauth.Source{ + { + IdentityName: "wi2", + Namespace: "default", + Partition: "default", + Peer: "local", + }}, + } + tp2 := rtest.Resource(pbauth.TrafficPermissionsType, "tp2").WithData(suite.T(), &pbauth.TrafficPermissions{ + Destination: &pbauth.Destination{ + IdentityName: "wi1", + }, + Action: pbauth.Action_ACTION_ALLOW, + Permissions: []*pbauth.Permission{p2}, + }).Write(suite.T(), suite.client) + suite.requireTrafficPermissionsTracking(tp2, id) + + err = suite.reconciler.Reconcile(suite.ctx, suite.rt, controller.Request{ID: id}) + require.NoError(suite.T(), err) + + ctp := suite.client.RequireResourceExists(suite.T(), id) + suite.requireCTP(ctp, []*pbauth.Permission{p2}, []*pbauth.Permission{p1}) + rtest.RequireOwner(suite.T(), ctp, wi.Id, true) + + // Delete TP2 + suite.client.MustDelete(suite.T(), tp2.Id) + + err = suite.reconciler.Reconcile(suite.ctx, suite.rt, controller.Request{ID: id}) + require.NoError(suite.T(), err) + + // Ensure that the CTP was updated + ctp = suite.client.RequireResourceExists(suite.T(), id) + suite.requireCTP(ctp, []*pbauth.Permission{}, []*pbauth.Permission{p1}) + + // Ensure TP2 is untracked + newTps := suite.mapper.GetTrafficPermissionsForCTP(ctp.Id) + require.Len(suite.T(), newTps, 1) + require.Equal(suite.T(), newTps[0].Name, tp1.Id.Name) +} + +func (suite *controllerSuite) TestReconcile_TrafficPermissionsDelete_DestinationWorkloadIdentityDoesNotExist() { + // create traffic permissions + p1 := &pbauth.Permission{} + tp1 := rtest.Resource(pbauth.TrafficPermissionsType, "tp1").WithData(suite.T(), &pbauth.TrafficPermissions{ + Destination: &pbauth.Destination{ + IdentityName: "wi1", + }, + Action: pbauth.Action_ACTION_DENY, + Permissions: []*pbauth.Permission{p1}, + }).Write(suite.T(), suite.client) + wi1ID := &pbresource.ID{ + Name: "wi1", + Type: pbauth.ComputedTrafficPermissionsType, + Tenancy: tp1.Id.Tenancy, + } + suite.requireTrafficPermissionsTracking(tp1, wi1ID) + p2 := &pbauth.Permission{ + Sources: []*pbauth.Source{ + { + IdentityName: "wi2", + Namespace: "default", + Partition: "default", + Peer: "local", + }}, + } + tp2 := rtest.Resource(pbauth.TrafficPermissionsType, "tp2").WithData(suite.T(), &pbauth.TrafficPermissions{ + Destination: &pbauth.Destination{ + IdentityName: "wi1", + }, + Action: pbauth.Action_ACTION_ALLOW, + Permissions: []*pbauth.Permission{p2}, + }).Write(suite.T(), suite.client) + suite.requireTrafficPermissionsTracking(tp2, wi1ID) + + // Delete TP2 + suite.client.MustDelete(suite.T(), tp2.Id) + + // Ensure that no CTPs exist + rsp, err := suite.client.List(suite.ctx, &pbresource.ListRequest{ + Type: pbauth.ComputedTrafficPermissionsType, + Tenancy: resource.DefaultNamespacedTenancy(), + }) + require.NoError(suite.T(), err) + require.Empty(suite.T(), rsp.Resources) +} + +func (suite *controllerSuite) TestControllerBasic() { + // TODO: refactor this + // In this test we check basic operations for a workload identity and referencing traffic permission + mgr := controller.NewManager(suite.client, suite.rt.Logger) + mgr.Register(Controller(suite.mapper)) + mgr.SetRaftLeader(true) + go mgr.Run(suite.ctx) + + // Add a workload identity + workloadIdentity := rtest.Resource(pbauth.WorkloadIdentityType, "wi1").Write(suite.T(), suite.client) + + // Wait for the controller to record that the CTP has been computed + res := suite.client.WaitForReconciliation(suite.T(), resource.ReplaceType(pbauth.ComputedTrafficPermissionsType, workloadIdentity.Id), StatusKey) + // Check that the status was updated + rtest.RequireStatusCondition(suite.T(), res, StatusKey, ConditionComputed("wi1")) + + // Check that the CTP resource exists and contains no permissions + ctpID := rtest.Resource(pbauth.ComputedTrafficPermissionsType, "wi1").ID() + ctpObject := suite.client.RequireResourceExists(suite.T(), ctpID) + suite.requireCTP(ctpObject, nil, nil) + + // add a traffic permission that references wi1 + p1 := &pbauth.Permission{ + Sources: []*pbauth.Source{{ + IdentityName: "wi2", + Namespace: "default", + Partition: "default", + Peer: "local", + }}, + DestinationRules: nil, + } + tp1 := rtest.Resource(pbauth.TrafficPermissionsType, "tp1").WithData(suite.T(), &pbauth.TrafficPermissions{ + Destination: &pbauth.Destination{IdentityName: "wi1"}, + Action: pbauth.Action_ACTION_ALLOW, + Permissions: []*pbauth.Permission{p1}, + }).Write(suite.T(), suite.client) + suite.client.RequireResourceExists(suite.T(), tp1.Id) + // Wait for the controller to record that the CTP has been re-computed + res = suite.client.WaitForReconciliation(suite.T(), resource.ReplaceType(pbauth.ComputedTrafficPermissionsType, workloadIdentity.Id), StatusKey) + rtest.RequireStatusCondition(suite.T(), res, StatusKey, ConditionComputed("wi1")) + // Check that the ctp has been regenerated + ctpObject = suite.client.WaitForNewVersion(suite.T(), ctpID, ctpObject.Version) + // check wi1 + suite.requireCTP(ctpObject, []*pbauth.Permission{p1}, nil) + + // add a traffic permission that references wi2 + p2 := &pbauth.Permission{ + Sources: []*pbauth.Source{{ + IdentityName: "wi1", + Namespace: "default", + Partition: "default", + Peer: "local", + }}, + DestinationRules: nil, + } + tp2 := rtest.Resource(pbauth.TrafficPermissionsType, "tp2").WithData(suite.T(), &pbauth.TrafficPermissions{ + Destination: &pbauth.Destination{IdentityName: "wi2"}, + Action: pbauth.Action_ACTION_ALLOW, + Permissions: []*pbauth.Permission{p2}, + }).Write(suite.T(), suite.client) + suite.client.RequireResourceExists(suite.T(), tp2.Id) + // check wi1 is the same + ctpObject = suite.client.RequireResourceExists(suite.T(), ctpID) + suite.requireCTP(ctpObject, []*pbauth.Permission{p1}, nil) + // check no ctp2 + ctpID2 := rtest.Resource(pbauth.ComputedTrafficPermissionsType, "wi2").ID() + suite.client.RequireResourceNotFound(suite.T(), ctpID2) + + // delete tp1 + suite.client.MustDelete(suite.T(), tp1.Id) + suite.client.WaitForDeletion(suite.T(), tp1.Id) + // check wi1 has no permissions + ctpObject = suite.client.WaitForNewVersion(suite.T(), ctpID, ctpObject.Version) + suite.requireCTP(ctpObject, nil, nil) + + // edit tp2 to point to wi1 + rtest.Resource(pbauth.TrafficPermissionsType, "tp2").WithData(suite.T(), &pbauth.TrafficPermissions{ + Destination: &pbauth.Destination{IdentityName: "wi1"}, + Action: pbauth.Action_ACTION_ALLOW, + Permissions: []*pbauth.Permission{p2}, + }).Write(suite.T(), suite.client) + // check wi1 has tp2's permissions + ctpObject = suite.client.WaitForNewVersion(suite.T(), ctpID, ctpObject.Version) + suite.requireCTP(ctpObject, []*pbauth.Permission{p2}, nil) + // check no ctp2 + ctpID2 = rtest.Resource(pbauth.ComputedTrafficPermissionsType, "wi2").ID() + suite.client.RequireResourceNotFound(suite.T(), ctpID2) +} + +func (suite *controllerSuite) TestControllerMultipleTrafficPermissions() { + // TODO: refactor this, turn back on once timing flakes are understood + suite.T().Skip("flaky behavior observed") + // In this test we check operations for a workload identity and multiple referencing traffic permissions + mgr := controller.NewManager(suite.client, suite.rt.Logger) + mgr.Register(Controller(suite.mapper)) + mgr.SetRaftLeader(true) + go mgr.Run(suite.ctx) + + wi1ID := &pbresource.ID{ + Name: "wi1", + Type: pbauth.ComputedTrafficPermissionsType, + Tenancy: resource.DefaultNamespacedTenancy(), + } + // add tp1 and tp2 + p1 := &pbauth.Permission{ + Sources: []*pbauth.Source{{ + IdentityName: "wi2", + Namespace: "default", + Partition: "default", + Peer: "local", + }}, + DestinationRules: nil, + } + tp1 := rtest.Resource(pbauth.TrafficPermissionsType, "tp1").WithData(suite.T(), &pbauth.TrafficPermissions{ + Destination: &pbauth.Destination{IdentityName: "wi1"}, + Action: pbauth.Action_ACTION_ALLOW, + Permissions: []*pbauth.Permission{p1}, + }).Write(suite.T(), suite.client) + suite.client.RequireResourceExists(suite.T(), tp1.Id) + suite.requireTrafficPermissionsTracking(tp1, wi1ID) + p2 := &pbauth.Permission{ + Sources: []*pbauth.Source{{ + IdentityName: "wi3", + Namespace: "default", + Partition: "default", + Peer: "local", + }}, + DestinationRules: nil, + } + tp2 := rtest.Resource(pbauth.TrafficPermissionsType, "tp2").WithData(suite.T(), &pbauth.TrafficPermissions{ + Destination: &pbauth.Destination{IdentityName: "wi1"}, + Action: pbauth.Action_ACTION_ALLOW, + Permissions: []*pbauth.Permission{p2}, + }).Write(suite.T(), suite.client) + suite.client.RequireResourceExists(suite.T(), tp2.Id) + suite.requireTrafficPermissionsTracking(tp1, wi1ID) + + // Add a workload identity + workloadIdentity := rtest.Resource(pbauth.WorkloadIdentityType, "wi1").Write(suite.T(), suite.client) + ctpID := resource.ReplaceType(pbauth.ComputedTrafficPermissionsType, workloadIdentity.Id) + // Wait for the controller to record that the CTP has been computed + res := suite.client.WaitForReconciliation(suite.T(), ctpID, StatusKey) + rtest.RequireStatusCondition(suite.T(), res, StatusKey, ConditionComputed("wi1")) + // check ctp1 has tp1 and tp2 + ctpObject := suite.client.RequireResourceExists(suite.T(), res.Id) + suite.requireCTP(ctpObject, []*pbauth.Permission{p1, p2}, nil) + + // add tp3 + p3 := &pbauth.Permission{ + Sources: []*pbauth.Source{{ + IdentityName: "wi4", + Namespace: "default", + Partition: "default", + Peer: "local", + }}, + DestinationRules: nil, + } + tp3 := rtest.Resource(pbauth.TrafficPermissionsType, "tp3").WithData(suite.T(), &pbauth.TrafficPermissions{ + Destination: &pbauth.Destination{IdentityName: "wi1"}, + Action: pbauth.Action_ACTION_DENY, + Permissions: []*pbauth.Permission{p3}, + }).Write(suite.T(), suite.client) + suite.client.RequireResourceExists(suite.T(), tp3.Id) + // check ctp1 has tp3 + ctpObject = suite.client.WaitForReconciliation(suite.T(), ctpObject.Id, StatusKey) + ctpObject = suite.client.WaitForNewVersion(suite.T(), ctpObject.Id, ctpObject.Version) + suite.requireCTP(ctpObject, []*pbauth.Permission{p1, p2}, []*pbauth.Permission{p3}) + + // delete ctp + suite.client.MustDelete(suite.T(), ctpObject.Id) + suite.client.WaitForDeletion(suite.T(), ctpObject.Id) + // check ctp regenerated, has all permissions + res = suite.client.WaitForReconciliation(suite.T(), ctpID, StatusKey) + rtest.RequireStatusCondition(suite.T(), res, StatusKey, ConditionComputed("wi1")) + ctpObject = suite.client.RequireResourceExists(suite.T(), res.Id) + suite.requireCTP(ctpObject, []*pbauth.Permission{p1, p2}, []*pbauth.Permission{p3}) + + // delete wi1 + suite.client.MustDelete(suite.T(), workloadIdentity.Id) + suite.client.WaitForDeletion(suite.T(), workloadIdentity.Id) + + // recreate wi1 + rtest.Resource(pbauth.WorkloadIdentityType, "wi1").Write(suite.T(), suite.client) + // check ctp regenerated, has all permissions + res = suite.client.WaitForReconciliation(suite.T(), ctpID, StatusKey) + rtest.RequireStatusCondition(suite.T(), res, StatusKey, ConditionComputed("wi1")) + ctpObject = suite.client.RequireResourceExists(suite.T(), res.Id) + suite.requireCTP(ctpObject, []*pbauth.Permission{p1, p2}, []*pbauth.Permission{p3}) + + // delete tp3 + suite.client.MustDelete(suite.T(), tp3.Id) + suite.client.WaitForDeletion(suite.T(), tp3.Id) + suite.client.RequireResourceNotFound(suite.T(), tp3.Id) + // check ctp1 has tp1 and tp2, and not tp3 + res = suite.client.WaitForReconciliation(suite.T(), ctpObject.Id, StatusKey) + ctpObject = suite.client.WaitForNewVersion(suite.T(), res.Id, ctpObject.Version) + suite.requireCTP(ctpObject, []*pbauth.Permission{p1, p2}, nil) + + // add wi2 + workloadIdentity2 := rtest.Resource(pbauth.WorkloadIdentityType, "wi2").Write(suite.T(), suite.client) + // Wait for the controller to record that the CTP has been computed + res2 := suite.client.WaitForReconciliation(suite.T(), resource.ReplaceType(pbauth.ComputedTrafficPermissionsType, workloadIdentity2.Id), StatusKey) + rtest.RequireStatusCondition(suite.T(), res2, StatusKey, ConditionComputed("wi2")) + // check ctp2 has no permissions + ctpObject2 := suite.client.RequireResourceExists(suite.T(), res2.Id) + suite.requireCTP(ctpObject2, nil, nil) + + // edit all traffic permissions to point to wi2 + tp1 = rtest.Resource(pbauth.TrafficPermissionsType, "tp1").WithData(suite.T(), &pbauth.TrafficPermissions{ + Destination: &pbauth.Destination{IdentityName: "wi2"}, + Action: pbauth.Action_ACTION_ALLOW, + Permissions: []*pbauth.Permission{p1}, + }).Write(suite.T(), suite.client) + tp2 = rtest.Resource(pbauth.TrafficPermissionsType, "tp2").WithData(suite.T(), &pbauth.TrafficPermissions{ + Destination: &pbauth.Destination{IdentityName: "wi2"}, + Action: pbauth.Action_ACTION_ALLOW, + Permissions: []*pbauth.Permission{p2}, + }).Write(suite.T(), suite.client) + tp3 = rtest.Resource(pbauth.TrafficPermissionsType, "tp3").WithData(suite.T(), &pbauth.TrafficPermissions{ + Destination: &pbauth.Destination{IdentityName: "wi2"}, + Action: pbauth.Action_ACTION_DENY, + Permissions: []*pbauth.Permission{p3}, + }).Write(suite.T(), suite.client) + suite.client.RequireResourceExists(suite.T(), tp1.Id) + suite.client.RequireResourceExists(suite.T(), tp2.Id) + suite.client.RequireResourceExists(suite.T(), tp3.Id) + + // check wi2 has updated with all permissions after 6 reconciles + ctpObject2 = suite.client.WaitForReconciliation(suite.T(), ctpObject2.Id, StatusKey) + res2 = suite.client.WaitForReconciliation(suite.T(), ctpObject2.Id, StatusKey) + suite.client.WaitForResourceState(suite.T(), res2.Id, func(t rtest.T, res *pbresource.Resource) { + suite.requireCTP(res, []*pbauth.Permission{p1, p2}, []*pbauth.Permission{p3}) + }) + // check wi1 has no permissions after 6 reconciles + ctpObject = suite.client.WaitForReconciliation(suite.T(), ctpObject.Id, StatusKey) + res = suite.client.WaitForReconciliation(suite.T(), ctpObject.Id, StatusKey) + suite.client.WaitForResourceState(suite.T(), res.Id, func(t rtest.T, res *pbresource.Resource) { + suite.requireCTP(res, nil, nil) + }) +} + +func TestController(t *testing.T) { + suite.Run(t, new(controllerSuite)) +} diff --git a/internal/auth/internal/controllers/trafficpermissions/status.go b/internal/auth/internal/controllers/trafficpermissions/status.go new file mode 100644 index 0000000000..6baf4a1db7 --- /dev/null +++ b/internal/auth/internal/controllers/trafficpermissions/status.go @@ -0,0 +1,42 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package trafficpermissions + +import ( + "fmt" + + "github.com/hashicorp/consul/proto-public/pbresource" +) + +const ( + StatusKey = "consul.io/traffic-permissions" + StatusTrafficPermissionsComputed = "Traffic permissions have been computed" + StatusTrafficPermissionsNotComputed = "Traffic permissions have been computed" + ConditionPermissionsAppliedMsg = "Workload identity %s has new permission set" + ConditionPermissionsFailedMsg = "Unable to calculate new permission set for Workload identity %s" +) + +var ( + ConditionComputed = func(workloadIdentity string) *pbresource.Condition { + return &pbresource.Condition{ + Type: StatusTrafficPermissionsComputed, + State: pbresource.Condition_STATE_TRUE, + Message: fmt.Sprintf(ConditionPermissionsAppliedMsg, workloadIdentity), + } + } + ConditionFailedToCompute = func(workloadIdentity string, trafficPermissions string, errDetail string) *pbresource.Condition { + message := fmt.Sprintf(ConditionPermissionsFailedMsg, workloadIdentity) + if len(trafficPermissions) > 0 { + message = message + fmt.Sprintf(", traffic permission %s cannot be computed", trafficPermissions) + } + if len(errDetail) > 0 { + message = message + fmt.Sprintf(", error details: %s", errDetail) + } + return &pbresource.Condition{ + Type: StatusTrafficPermissionsNotComputed, + State: pbresource.Condition_STATE_FALSE, + Message: message, + } + } +) diff --git a/internal/auth/internal/mappers/trafficpermissionsmapper/traffic_permissions_mapper.go b/internal/auth/internal/mappers/trafficpermissionsmapper/traffic_permissions_mapper.go new file mode 100644 index 0000000000..be28126458 --- /dev/null +++ b/internal/auth/internal/mappers/trafficpermissionsmapper/traffic_permissions_mapper.go @@ -0,0 +1,73 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package trafficpermissionsmapper + +import ( + "context" + "sync" + + "github.com/hashicorp/consul/internal/auth/internal/types" + "github.com/hashicorp/consul/internal/controller" + "github.com/hashicorp/consul/internal/resource" + "github.com/hashicorp/consul/internal/resource/mappers/bimapper" + pbauth "github.com/hashicorp/consul/proto-public/pbauth/v2beta1" + "github.com/hashicorp/consul/proto-public/pbresource" +) + +type TrafficPermissionsMapper struct { + lock sync.Mutex + mapper *bimapper.Mapper +} + +func New() *TrafficPermissionsMapper { + return &TrafficPermissionsMapper{ + lock: sync.Mutex{}, + mapper: bimapper.New(pbauth.TrafficPermissionsType, pbauth.ComputedTrafficPermissionsType), + } +} + +// TrafficPermissionsMapper functions + +func (tm *TrafficPermissionsMapper) MapTrafficPermissions(_ context.Context, _ controller.Runtime, res *pbresource.Resource) ([]controller.Request, error) { + tm.lock.Lock() + defer tm.lock.Unlock() + var tp pbauth.TrafficPermissions + err := res.Data.UnmarshalTo(&tp) + if err != nil { + return nil, resource.NewErrDataParse(&tp, err) + } + // get new CTP associations based on destination + if len(tp.Destination.IdentityName) == 0 { + // this error should never happen if validation is working + return nil, types.ErrWildcardNotSupported + } + newCTP := &pbresource.ID{ + Name: tp.Destination.IdentityName, + Type: pbauth.ComputedTrafficPermissionsType, + Tenancy: res.Id.Tenancy, + } + requests := []controller.Request{{ID: newCTP}} + // add already associated WorkloadIdentities/CTPs for reconcile requests: + oldCTPs := tm.mapper.LinkIDsForItem(res.Id) + for _, mappedWI := range oldCTPs { + if mappedWI.Name != newCTP.Name { + requests = append(requests, controller.Request{ID: mappedWI}) + } + } + // re-map traffic permission to new CTP + tm.mapper.TrackItem(res.Id, []resource.ReferenceOrID{newCTP}) + return requests, nil +} + +func (tm *TrafficPermissionsMapper) UntrackTrafficPermissions(tp *pbresource.ID) { + tm.lock.Lock() + defer tm.lock.Unlock() + tm.mapper.UntrackItem(tp) +} + +func (tm *TrafficPermissionsMapper) GetTrafficPermissionsForCTP(ctp *pbresource.ID) []*pbresource.Reference { + tm.lock.Lock() + defer tm.lock.Unlock() + return tm.mapper.ItemRefsForLink(ctp) +} diff --git a/internal/auth/internal/types/errors.go b/internal/auth/internal/types/errors.go index 8bbf546df2..b79d7a3b98 100644 --- a/internal/auth/internal/types/errors.go +++ b/internal/auth/internal/types/errors.go @@ -6,9 +6,10 @@ package types import "errors" var ( - errInvalidAction = errors.New("action must be either allow or deny") - errSourcesTenancy = errors.New("permissions sources may not specify partitions, peers, and sameness_groups together") - errSourceWildcards = errors.New("permission sources may not have wildcard namespaces and explicit names.") - errSourceExcludes = errors.New("must be defined on wildcard sources") - errInvalidPrefixValues = errors.New("prefix values, regex values, and explicit names must not combined") + errInvalidAction = errors.New("action must be either allow or deny") + errSourcesTenancy = errors.New("permissions sources may not specify partitions, peers, and sameness_groups together") + errSourceWildcards = errors.New("permission sources may not have wildcard namespaces and explicit names.") + errSourceExcludes = errors.New("must be defined on wildcard sources") + errInvalidPrefixValues = errors.New("prefix values, regex values, and explicit names must not combined") + ErrWildcardNotSupported = errors.New("traffic permissions without explicit destinations are not yet supported") ) diff --git a/internal/resource/decode.go b/internal/resource/decode.go index 35ee088603..ba9abd87d6 100644 --- a/internal/resource/decode.go +++ b/internal/resource/decode.go @@ -44,9 +44,11 @@ func (d *DecodedResource[T]) GetData() T { func Decode[T proto.Message](res *pbresource.Resource) (*DecodedResource[T], error) { var zero T data := zero.ProtoReflect().New().Interface().(T) - - if err := res.Data.UnmarshalTo(data); err != nil { - return nil, NewErrDataParse(data, err) + // check that there is data to unmarshall + if res.Data != nil { + if err := res.Data.UnmarshalTo(data); err != nil { + return nil, NewErrDataParse(data, err) + } } return &DecodedResource[T]{ Resource: res, @@ -64,6 +66,5 @@ func GetDecodedResource[T proto.Message](ctx context.Context, client pbresource. case err != nil: return nil, err } - return Decode[T](rsp.Resource) } diff --git a/proto-public/pbauth/v2beta1/traffic_permissions.pb.go b/proto-public/pbauth/v2beta1/traffic_permissions.pb.go index 01c6676653..e803c20e9f 100644 --- a/proto-public/pbauth/v2beta1/traffic_permissions.pb.go +++ b/proto-public/pbauth/v2beta1/traffic_permissions.pb.go @@ -268,8 +268,7 @@ type Destination struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - IdentityName string `protobuf:"bytes,1,opt,name=identity_name,json=identityName,proto3" json:"identity_name,omitempty"` - IdentityPrefix string `protobuf:"bytes,2,opt,name=identity_prefix,json=identityPrefix,proto3" json:"identity_prefix,omitempty"` + IdentityName string `protobuf:"bytes,1,opt,name=identity_name,json=identityName,proto3" json:"identity_name,omitempty"` } func (x *Destination) Reset() { @@ -311,13 +310,6 @@ func (x *Destination) GetIdentityName() string { return "" } -func (x *Destination) GetIdentityPrefix() string { - if x != nil { - return x.IdentityPrefix - } - return "" -} - // permissions is a list of permissions to match on. type Permission struct { state protoimpl.MessageState @@ -881,120 +873,118 @@ var file_pbauth_v2beta1_traffic_permissions_proto_rawDesc = []byte{ 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, - 0x3a, 0x06, 0xa2, 0x93, 0x04, 0x02, 0x08, 0x02, 0x22, 0x5b, 0x0a, 0x0b, 0x44, 0x65, 0x73, 0x74, + 0x3a, 0x06, 0xa2, 0x93, 0x04, 0x02, 0x08, 0x02, 0x22, 0x32, 0x0a, 0x0b, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, - 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x27, 0x0a, 0x0f, - 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, - 0x72, 0x65, 0x66, 0x69, 0x78, 0x22, 0xaa, 0x01, 0x0a, 0x0a, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3f, 0x0a, 0x07, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, - 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x76, 0x32, - 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x07, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x5b, 0x0a, 0x11, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x2e, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, - 0x73, 0x75, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, - 0x2e, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, - 0x52, 0x10, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6c, - 0x65, 0x73, 0x22, 0xec, 0x01, 0x0a, 0x06, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x23, 0x0a, - 0x0d, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4e, 0x61, - 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, - 0x0a, 0x04, 0x70, 0x65, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x65, - 0x65, 0x72, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x61, 0x6d, 0x65, 0x6e, 0x65, 0x73, 0x73, 0x5f, 0x67, - 0x72, 0x6f, 0x75, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x61, 0x6d, 0x65, - 0x6e, 0x65, 0x73, 0x73, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x46, 0x0a, 0x07, 0x65, 0x78, 0x63, - 0x6c, 0x75, 0x64, 0x65, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x68, 0x61, 0x73, - 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x61, 0x75, - 0x74, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x45, 0x78, 0x63, 0x6c, 0x75, - 0x64, 0x65, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x07, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, - 0x65, 0x22, 0xab, 0x01, 0x0a, 0x0d, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x53, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x69, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x74, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, - 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x72, 0x74, 0x69, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x65, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x70, 0x65, 0x65, 0x72, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x61, 0x6d, 0x65, - 0x6e, 0x65, 0x73, 0x73, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0d, 0x73, 0x61, 0x6d, 0x65, 0x6e, 0x65, 0x73, 0x73, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x22, - 0xc7, 0x02, 0x0a, 0x0f, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x75, 0x6c, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x65, 0x78, 0x61, 0x63, - 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x74, 0x68, 0x45, 0x78, 0x61, - 0x63, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, - 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x61, 0x74, 0x68, 0x50, 0x72, 0x65, - 0x66, 0x69, 0x78, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x72, 0x65, 0x67, 0x65, - 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x74, 0x68, 0x52, 0x65, 0x67, - 0x65, 0x78, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x18, 0x04, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x12, 0x4c, 0x0a, 0x06, - 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x68, + 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0xaa, 0x01, 0x0a, + 0x0a, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3f, 0x0a, 0x07, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, - 0x61, 0x75, 0x74, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x44, 0x65, 0x73, - 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x48, 0x65, 0x61, 0x64, - 0x65, 0x72, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x6f, - 0x72, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, - 0x70, 0x6f, 0x72, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x4e, 0x0a, 0x07, 0x65, 0x78, 0x63, - 0x6c, 0x75, 0x64, 0x65, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x68, 0x61, 0x73, - 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x61, 0x75, - 0x74, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x45, 0x78, 0x63, 0x6c, 0x75, - 0x64, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, - 0x52, 0x07, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x22, 0xfd, 0x01, 0x0a, 0x15, 0x45, 0x78, - 0x63, 0x6c, 0x75, 0x64, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, - 0x75, 0x6c, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x65, 0x78, 0x61, 0x63, - 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x74, 0x68, 0x45, 0x78, 0x61, - 0x63, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, - 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x61, 0x74, 0x68, 0x50, 0x72, 0x65, - 0x66, 0x69, 0x78, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x72, 0x65, 0x67, 0x65, - 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x74, 0x68, 0x52, 0x65, 0x67, - 0x65, 0x78, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x18, 0x04, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x12, 0x4c, 0x0a, 0x06, - 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x68, - 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, - 0x61, 0x75, 0x74, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x44, 0x65, 0x73, - 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x48, 0x65, 0x61, 0x64, - 0x65, 0x72, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x6f, - 0x72, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, - 0x70, 0x6f, 0x72, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0xb9, 0x01, 0x0a, 0x15, 0x44, 0x65, - 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x48, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x65, 0x73, 0x65, - 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, - 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x78, 0x61, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x65, 0x78, 0x61, 0x63, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, - 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, - 0x16, 0x0a, 0x06, 0x73, 0x75, 0x66, 0x66, 0x69, 0x78, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x73, 0x75, 0x66, 0x66, 0x69, 0x78, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x65, 0x67, 0x65, 0x78, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x72, 0x65, 0x67, 0x65, 0x78, 0x12, 0x16, 0x0a, - 0x06, 0x69, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x69, - 0x6e, 0x76, 0x65, 0x72, 0x74, 0x2a, 0x43, 0x0a, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x16, 0x0a, 0x12, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, - 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x43, 0x54, 0x49, 0x4f, - 0x4e, 0x5f, 0x44, 0x45, 0x4e, 0x59, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x41, 0x43, 0x54, 0x49, - 0x4f, 0x4e, 0x5f, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x10, 0x02, 0x42, 0x98, 0x02, 0x0a, 0x21, 0x63, - 0x6f, 0x6d, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, - 0x73, 0x75, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, - 0x42, 0x17, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x43, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, - 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2d, 0x70, - 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2f, 0x70, 0x62, 0x61, 0x75, 0x74, 0x68, 0x2f, 0x76, 0x32, 0x62, - 0x65, 0x74, 0x61, 0x31, 0x3b, 0x61, 0x75, 0x74, 0x68, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, - 0xa2, 0x02, 0x03, 0x48, 0x43, 0x41, 0xaa, 0x02, 0x1d, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, - 0x72, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x2e, 0x56, - 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0xca, 0x02, 0x1d, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, - 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x41, 0x75, 0x74, 0x68, 0x5c, 0x56, - 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0xe2, 0x02, 0x29, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, - 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x41, 0x75, 0x74, 0x68, 0x5c, 0x56, - 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0xea, 0x02, 0x20, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x3a, 0x3a, - 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x3a, 0x3a, 0x41, 0x75, 0x74, 0x68, 0x3a, 0x3a, 0x56, 0x32, - 0x62, 0x65, 0x74, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x61, 0x75, 0x74, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x53, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x52, 0x07, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x5b, 0x0a, 0x11, + 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x75, 0x6c, 0x65, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, + 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, + 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x10, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x22, 0xec, 0x01, 0x0a, 0x06, 0x53, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x69, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, + 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, + 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x61, 0x72, 0x74, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x72, 0x74, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x65, 0x65, 0x72, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x65, 0x65, 0x72, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x61, 0x6d, + 0x65, 0x6e, 0x65, 0x73, 0x73, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0d, 0x73, 0x61, 0x6d, 0x65, 0x6e, 0x65, 0x73, 0x73, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x12, 0x46, 0x0a, 0x07, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x18, 0x06, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x2c, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, + 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, + 0x31, 0x2e, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, + 0x07, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x22, 0xab, 0x01, 0x0a, 0x0d, 0x45, 0x78, 0x63, + 0x6c, 0x75, 0x64, 0x65, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0c, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, + 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1c, 0x0a, + 0x09, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x70, + 0x65, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x65, 0x65, 0x72, 0x12, + 0x25, 0x0a, 0x0e, 0x73, 0x61, 0x6d, 0x65, 0x6e, 0x65, 0x73, 0x73, 0x5f, 0x67, 0x72, 0x6f, 0x75, + 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x61, 0x6d, 0x65, 0x6e, 0x65, 0x73, + 0x73, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x22, 0xc7, 0x02, 0x0a, 0x0f, 0x44, 0x65, 0x73, 0x74, 0x69, + 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, + 0x74, 0x68, 0x5f, 0x65, 0x78, 0x61, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x70, 0x61, 0x74, 0x68, 0x45, 0x78, 0x61, 0x63, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x61, 0x74, + 0x68, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, + 0x70, 0x61, 0x74, 0x68, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, + 0x74, 0x68, 0x5f, 0x72, 0x65, 0x67, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x70, 0x61, 0x74, 0x68, 0x52, 0x65, 0x67, 0x65, 0x78, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x74, + 0x68, 0x6f, 0x64, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x68, + 0x6f, 0x64, 0x73, 0x12, 0x4c, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, + 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, + 0x74, 0x61, 0x31, 0x2e, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x75, 0x6c, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, + 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, + 0x12, 0x4e, 0x0a, 0x07, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x18, 0x07, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x34, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, + 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, + 0x31, 0x2e, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x07, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, + 0x22, 0xfd, 0x01, 0x0a, 0x15, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x50, 0x65, 0x72, 0x6d, + 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, + 0x74, 0x68, 0x5f, 0x65, 0x78, 0x61, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x70, 0x61, 0x74, 0x68, 0x45, 0x78, 0x61, 0x63, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x61, 0x74, + 0x68, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, + 0x70, 0x61, 0x74, 0x68, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, + 0x74, 0x68, 0x5f, 0x72, 0x65, 0x67, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x70, 0x61, 0x74, 0x68, 0x52, 0x65, 0x67, 0x65, 0x78, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x74, + 0x68, 0x6f, 0x64, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x68, + 0x6f, 0x64, 0x73, 0x12, 0x4c, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, + 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, + 0x74, 0x61, 0x31, 0x2e, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x75, 0x6c, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, + 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, + 0x22, 0xb9, 0x01, 0x0a, 0x15, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x75, 0x6c, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, + 0x0a, 0x07, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x07, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x78, 0x61, 0x63, + 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x78, 0x61, 0x63, 0x74, 0x12, 0x16, + 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x75, 0x66, 0x66, 0x69, 0x78, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x75, 0x66, 0x66, 0x69, 0x78, 0x12, 0x14, + 0x0a, 0x05, 0x72, 0x65, 0x67, 0x65, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x72, + 0x65, 0x67, 0x65, 0x78, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x69, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x2a, 0x43, 0x0a, 0x06, + 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x12, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, + 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0f, + 0x0a, 0x0b, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x44, 0x45, 0x4e, 0x59, 0x10, 0x01, 0x12, + 0x10, 0x0a, 0x0c, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x10, + 0x02, 0x42, 0x98, 0x02, 0x0a, 0x21, 0x63, 0x6f, 0x6d, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, + 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, + 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x42, 0x17, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, + 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x50, 0x01, 0x5a, 0x43, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, + 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2d, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2f, 0x70, 0x62, 0x61, + 0x75, 0x74, 0x68, 0x2f, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x3b, 0x61, 0x75, 0x74, 0x68, + 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0xa2, 0x02, 0x03, 0x48, 0x43, 0x41, 0xaa, 0x02, 0x1d, + 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, + 0x2e, 0x41, 0x75, 0x74, 0x68, 0x2e, 0x56, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0xca, 0x02, 0x1d, + 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, + 0x5c, 0x41, 0x75, 0x74, 0x68, 0x5c, 0x56, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0xe2, 0x02, 0x29, + 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, + 0x5c, 0x41, 0x75, 0x74, 0x68, 0x5c, 0x56, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x5c, 0x47, 0x50, + 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x20, 0x48, 0x61, 0x73, 0x68, + 0x69, 0x63, 0x6f, 0x72, 0x70, 0x3a, 0x3a, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x3a, 0x3a, 0x41, + 0x75, 0x74, 0x68, 0x3a, 0x3a, 0x56, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/proto-public/pbauth/v2beta1/traffic_permissions.proto b/proto-public/pbauth/v2beta1/traffic_permissions.proto index 701709b2f1..9eab225026 100644 --- a/proto-public/pbauth/v2beta1/traffic_permissions.proto +++ b/proto-public/pbauth/v2beta1/traffic_permissions.proto @@ -50,7 +50,6 @@ message PartitionTrafficPermissions { // be in the same tenancy as the TrafficPermissions resource. message Destination { string identity_name = 1; - string identity_prefix = 2; } enum Action {