From 00e57b20a2b9624c33ea3f1afd8b89feb1fe7bda Mon Sep 17 00:00:00 2001 From: Timothy Messier Date: Wed, 6 Apr 2022 15:36:08 -0400 Subject: [PATCH] feat(credentiallibrary): Classify resources for audit events --- Makefile | 2 + .../services/credential_library_service.pb.go | 12 +- .../v1/credential_library.proto | 26 +-- .../v1/credential_library_service.proto | 12 +- .../credentiallibrary_classification_test.go | 201 ++++++++++++++++++ .../credential_library.pb.go | 26 +-- 6 files changed, 241 insertions(+), 38 deletions(-) create mode 100644 internal/tests/api/credentiallibraries/credentiallibrary_classification_test.go diff --git a/Makefile b/Makefile index 1b92557d73..64c262fb36 100644 --- a/Makefile +++ b/Makefile @@ -171,6 +171,8 @@ protobuild: @protoc-go-inject-tag -input=./internal/gen/controller/api/services/managed_group_service.pb.go @protoc-go-inject-tag -input=./sdk/pbs/controller/api/resources/groups/group.pb.go @protoc-go-inject-tag -input=./internal/gen/controller/api/services/group_service.pb.go + @protoc-go-inject-tag -input=./sdk/pbs/controller/api/resources/credentiallibraries/credential_library.pb.go + @protoc-go-inject-tag -input=./internal/gen/controller/api/services/credential_library_service.pb.go # these protos, services and openapi artifacts are purely for testing purposes @protoc-go-inject-tag -input=./internal/gen/testing/event/event.pb.go diff --git a/internal/gen/controller/api/services/credential_library_service.pb.go b/internal/gen/controller/api/services/credential_library_service.pb.go index e181dd7748..30a19ff6cd 100644 --- a/internal/gen/controller/api/services/credential_library_service.pb.go +++ b/internal/gen/controller/api/services/credential_library_service.pb.go @@ -30,7 +30,7 @@ type GetCredentialLibraryRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty" class:"public"` // @gotags: `class:"public"` } func (x *GetCredentialLibraryRequest) Reset() { @@ -124,8 +124,8 @@ type ListCredentialLibrariesRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - CredentialStoreId string `protobuf:"bytes,1,opt,name=credential_store_id,json=scope_id,proto3" json:"credential_store_id,omitempty"` - Filter string `protobuf:"bytes,30,opt,name=filter,proto3" json:"filter,omitempty"` + CredentialStoreId string `protobuf:"bytes,1,opt,name=credential_store_id,json=scope_id,proto3" json:"credential_store_id,omitempty" class:"public"` // @gotags: `class:"public"` + Filter string `protobuf:"bytes,30,opt,name=filter,proto3" json:"filter,omitempty" class:"public"` // @gotags: `class:"public"` } func (x *ListCredentialLibrariesRequest) Reset() { @@ -273,7 +273,7 @@ type CreateCredentialLibraryResponse struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Uri string `protobuf:"bytes,1,opt,name=uri,proto3" json:"uri,omitempty"` + Uri string `protobuf:"bytes,1,opt,name=uri,proto3" json:"uri,omitempty" class:"public"` // @gotags: `class:"public"` Item *credentiallibraries.CredentialLibrary `protobuf:"bytes,2,opt,name=item,proto3" json:"item,omitempty"` } @@ -328,7 +328,7 @@ type UpdateCredentialLibraryRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty" class:"public"` // @gotags: `class:"public"` Item *credentiallibraries.CredentialLibrary `protobuf:"bytes,2,opt,name=item,proto3" json:"item,omitempty"` UpdateMask *fieldmaskpb.FieldMask `protobuf:"bytes,3,opt,name=update_mask,proto3" json:"update_mask,omitempty"` } @@ -438,7 +438,7 @@ type DeleteCredentialLibraryRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty" class:"public"` // @gotags: `class:"public"` } func (x *DeleteCredentialLibraryRequest) Reset() { diff --git a/internal/proto/controller/api/resources/credentiallibraries/v1/credential_library.proto b/internal/proto/controller/api/resources/credentiallibraries/v1/credential_library.proto index d9f1229dc0..fcb2c2463d 100644 --- a/internal/proto/controller/api/resources/credentiallibraries/v1/credential_library.proto +++ b/internal/proto/controller/api/resources/credentiallibraries/v1/credential_library.proto @@ -14,35 +14,35 @@ import "controller/custom_options/v1/options.proto"; // CredentialLibrary contains all fields related to an Credential Library resource message CredentialLibrary { // Output only. The ID of the Credential Library. - string id = 10; + string id = 10; // @gotags: `class:"public"` // The ID of the Credential Store of which this Credential Library is a part. string credential_store_id = 20 [ json_name = "credential_store_id", (controller.custom_options.v1.subtype_source_id) = true - ]; + ]; // @gotags: `class:"public"` // Output only. Scope information for this Credential Library. resources.scopes.v1.ScopeInfo scope = 30; // Optional name for identification purposes. - google.protobuf.StringValue name = 40 [(custom_options.v1.generate_sdk_option) = true, (custom_options.v1.mask_mapping) = { this: "name" that: "Name" }]; + google.protobuf.StringValue name = 40 [(custom_options.v1.generate_sdk_option) = true, (custom_options.v1.mask_mapping) = { this: "name" that: "Name" }]; // @gotags: `class:"public"` // Optional user-set description for identification purposes. - google.protobuf.StringValue description = 50 [(custom_options.v1.generate_sdk_option) = true, (custom_options.v1.mask_mapping) = { this: "description" that: "Description" }]; + google.protobuf.StringValue description = 50 [(custom_options.v1.generate_sdk_option) = true, (custom_options.v1.mask_mapping) = { this: "description" that: "Description" }]; // @gotags: `class:"public"` // Output only. The time this resource was created. - google.protobuf.Timestamp created_time = 60 [json_name = "created_time"]; + google.protobuf.Timestamp created_time = 60 [json_name = "created_time"]; // @gotags: `class:"public"` // Output only. The time this resource was last updated. - google.protobuf.Timestamp updated_time = 70 [json_name = "updated_time"]; + google.protobuf.Timestamp updated_time = 70 [json_name = "updated_time"]; // @gotags: `class:"public"` // Version is used in mutation requests, after the initial creation, to ensure this resource has not changed. // The mutation will fail if the version does not match the latest known good version. - uint32 version = 80; + uint32 version = 80; // @gotags: `class:"public"` // The Credential Library type. - string type = 90; + string type = 90; // @gotags: `class:"public"` oneof attrs { // The attributes that are applicable for the specific Credential Library type. @@ -58,10 +58,10 @@ message CredentialLibrary { } // Output only. The available actions on this resource for this user. - repeated string authorized_actions = 300 [json_name = "authorized_actions"]; + repeated string authorized_actions = 300 [json_name = "authorized_actions"]; // @gotags: `class:"public"` // The type of credential this library will issue, defaults to Unspecified - string credential_type = 310 [json_name = "credential_type", (custom_options.v1.generate_sdk_option) = true]; + string credential_type = 310 [json_name = "credential_type", (custom_options.v1.generate_sdk_option) = true]; // @gotags: `class:"public"` // The credential mapping overrides google.protobuf.Struct credential_mapping_overrides = 320 [json_name = "credential_mapping_overrides", (custom_options.v1.generate_sdk_option) = true]; @@ -70,11 +70,11 @@ message CredentialLibrary { // The attributes of a vault typed Credential Library. message VaultCredentialLibraryAttributes { // The path in Vault to request credentials from. - google.protobuf.StringValue path = 10 [(custom_options.v1.generate_sdk_option) = true, (custom_options.v1.mask_mapping) = { this: "attributes.path" that: "VaultPath" }]; + google.protobuf.StringValue path = 10 [(custom_options.v1.generate_sdk_option) = true, (custom_options.v1.mask_mapping) = { this: "attributes.path" that: "VaultPath" }]; // @gotags: `class:"public"` // The HTTP method the library uses to communicate with Vault. - google.protobuf.StringValue http_method = 20 [json_name = "http_method", (custom_options.v1.generate_sdk_option) = true, (custom_options.v1.mask_mapping) = { this: "attributes.http_method" that: "HttpMethod" }]; + google.protobuf.StringValue http_method = 20 [json_name = "http_method", (custom_options.v1.generate_sdk_option) = true, (custom_options.v1.mask_mapping) = { this: "attributes.http_method" that: "HttpMethod" }]; // @gotags: `class:"public"` // The body of the HTTP request the library sends to vault. When set http_method must be "POST" - google.protobuf.StringValue http_request_body = 30 [json_name = "http_request_body", (custom_options.v1.generate_sdk_option) = true, (custom_options.v1.mask_mapping) = { this: "attributes.http_request_body" that: "HttpRequestBody" }]; + google.protobuf.StringValue http_request_body = 30 [json_name = "http_request_body", (custom_options.v1.generate_sdk_option) = true, (custom_options.v1.mask_mapping) = { this: "attributes.http_request_body" that: "HttpRequestBody" }]; // @gotags: `class:"secret"` } diff --git a/internal/proto/controller/api/services/v1/credential_library_service.proto b/internal/proto/controller/api/services/v1/credential_library_service.proto index 35f13c9b8a..c031900e54 100644 --- a/internal/proto/controller/api/services/v1/credential_library_service.proto +++ b/internal/proto/controller/api/services/v1/credential_library_service.proto @@ -86,7 +86,7 @@ service CredentialLibraryService { } message GetCredentialLibraryRequest { - string id = 1; + string id = 1; // @gotags: `class:"public"` } message GetCredentialLibraryResponse { @@ -94,8 +94,8 @@ message GetCredentialLibraryResponse { } message ListCredentialLibrariesRequest { - string credential_store_id = 1 [json_name = "scope_id"]; - string filter = 30 [json_name = "filter"]; + string credential_store_id = 1 [json_name = "scope_id"]; // @gotags: `class:"public"` + string filter = 30 [json_name = "filter"]; // @gotags: `class:"public"` } message ListCredentialLibrariesResponse { @@ -107,12 +107,12 @@ message CreateCredentialLibraryRequest { } message CreateCredentialLibraryResponse { - string uri = 1; + string uri = 1; // @gotags: `class:"public"` resources.credentiallibraries.v1.CredentialLibrary item = 2; } message UpdateCredentialLibraryRequest { - string id = 1; + string id = 1; // @gotags: `class:"public"` resources.credentiallibraries.v1.CredentialLibrary item = 2; google.protobuf.FieldMask update_mask = 3 [json_name = "update_mask"]; } @@ -122,7 +122,7 @@ message UpdateCredentialLibraryResponse { } message DeleteCredentialLibraryRequest { - string id = 1; + string id = 1; // @gotags: `class:"public"` } message DeleteCredentialLibraryResponse {} diff --git a/internal/tests/api/credentiallibraries/credentiallibrary_classification_test.go b/internal/tests/api/credentiallibraries/credentiallibrary_classification_test.go new file mode 100644 index 0000000000..13556c29d5 --- /dev/null +++ b/internal/tests/api/credentiallibraries/credentiallibrary_classification_test.go @@ -0,0 +1,201 @@ +package credentiallibraries_test + +import ( + "context" + "encoding/json" + "testing" + "time" + + "github.com/hashicorp/boundary/sdk/pbs/controller/api" + pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/credentiallibraries" + "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/scopes" + "github.com/hashicorp/boundary/sdk/wrapper" + "github.com/hashicorp/eventlogger" + "github.com/hashicorp/eventlogger/filters/encrypt" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/types/known/structpb" + "google.golang.org/protobuf/types/known/timestamppb" + "google.golang.org/protobuf/types/known/wrapperspb" +) + +func TestCredentialLibraryClassification(t *testing.T) { + ctx := context.Background() + now := time.Now() + pbNow := timestamppb.Now() + wrapper := wrapper.TestWrapper(t) + testEncryptingFilter := api.NewEncryptFilter(t, wrapper) + + cases := []struct { + name string + in *eventlogger.Event + want *eventlogger.Event + }{ + { + "Vault", + &eventlogger.Event{ + Type: "test", + CreatedAt: now, + Payload: &pb.CredentialLibrary{ + Id: "id", + CredentialStoreId: "credential-store-id", + Scope: &scopes.ScopeInfo{ + Id: "scope-id", + Type: "scope-type", + Name: "scope-name", + Description: "scope-descriptione", + ParentScopeId: "scope-parent-scope-id", + }, + Name: &wrapperspb.StringValue{Value: "name"}, + Description: &wrapperspb.StringValue{Value: "description"}, + CreatedTime: pbNow, + UpdatedTime: pbNow, + Version: 1, + Type: "vault", + Attrs: &pb.CredentialLibrary_VaultCredentialLibraryAttributes{ + VaultCredentialLibraryAttributes: &pb.VaultCredentialLibraryAttributes{ + Path: &wrapperspb.StringValue{Value: "/path"}, + HttpMethod: &wrapperspb.StringValue{Value: "POST"}, + HttpRequestBody: &wrapperspb.StringValue{Value: `{"request": "body-secret"}`}, + }, + }, + AuthorizedActions: []string{"action-1", "action-2"}, + CredentialType: "credential-type", + CredentialMappingOverrides: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "override-1": structpb.NewStringValue("one"), + "override-2": structpb.NewStringValue("two"), + }, + }, + }, + }, + &eventlogger.Event{ + Type: "test", + CreatedAt: now, + Payload: &pb.CredentialLibrary{ + Id: "id", + CredentialStoreId: "credential-store-id", + Scope: &scopes.ScopeInfo{ + Id: "scope-id", + Type: "scope-type", + Name: "scope-name", + Description: "scope-descriptione", + ParentScopeId: "scope-parent-scope-id", + }, + Name: &wrapperspb.StringValue{Value: "name"}, + Description: &wrapperspb.StringValue{Value: "description"}, + CreatedTime: pbNow, + UpdatedTime: pbNow, + Version: 1, + Type: "vault", + Attrs: &pb.CredentialLibrary_VaultCredentialLibraryAttributes{ + VaultCredentialLibraryAttributes: &pb.VaultCredentialLibraryAttributes{ + Path: &wrapperspb.StringValue{Value: "/path"}, + HttpMethod: &wrapperspb.StringValue{Value: "POST"}, + HttpRequestBody: &wrapperspb.StringValue{Value: encrypt.RedactedData}, + }, + }, + AuthorizedActions: []string{"action-1", "action-2"}, + CredentialType: "credential-type", + CredentialMappingOverrides: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "override-1": structpb.NewStringValue(encrypt.RedactedData), + "override-2": structpb.NewStringValue(encrypt.RedactedData), + }, + }, + }, + }, + }, + { + "Default", + &eventlogger.Event{ + Type: "test", + CreatedAt: now, + Payload: &pb.CredentialLibrary{ + Id: "id", + CredentialStoreId: "credential-store-id", + Scope: &scopes.ScopeInfo{ + Id: "scope-id", + Type: "scope-type", + Name: "scope-name", + Description: "scope-descriptione", + ParentScopeId: "scope-parent-scope-id", + }, + Name: &wrapperspb.StringValue{Value: "name"}, + Description: &wrapperspb.StringValue{Value: "description"}, + CreatedTime: pbNow, + UpdatedTime: pbNow, + Version: 1, + Type: "default", + Attrs: &pb.CredentialLibrary_Attributes{ + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "field1": structpb.NewStringValue("vaule1"), + "field2": structpb.NewStringValue("vaule2"), + }, + }, + }, + AuthorizedActions: []string{"action-1", "action-2"}, + CredentialType: "credential-type", + CredentialMappingOverrides: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "override-1": structpb.NewStringValue("one"), + "override-2": structpb.NewStringValue("two"), + }, + }, + }, + }, + &eventlogger.Event{ + Type: "test", + CreatedAt: now, + Payload: &pb.CredentialLibrary{ + Id: "id", + CredentialStoreId: "credential-store-id", + Scope: &scopes.ScopeInfo{ + Id: "scope-id", + Type: "scope-type", + Name: "scope-name", + Description: "scope-descriptione", + ParentScopeId: "scope-parent-scope-id", + }, + Name: &wrapperspb.StringValue{Value: "name"}, + Description: &wrapperspb.StringValue{Value: "description"}, + CreatedTime: pbNow, + UpdatedTime: pbNow, + Version: 1, + Type: "default", + Attrs: &pb.CredentialLibrary_Attributes{ + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "field1": structpb.NewStringValue(encrypt.RedactedData), + "field2": structpb.NewStringValue(encrypt.RedactedData), + }, + }, + }, + AuthorizedActions: []string{"action-1", "action-2"}, + CredentialType: "credential-type", + CredentialMappingOverrides: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "override-1": structpb.NewStringValue(encrypt.RedactedData), + "override-2": structpb.NewStringValue(encrypt.RedactedData), + }, + }, + }, + }, + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + wantJSON, err := json.Marshal(tc.want) + require.NoError(t, err) + + got, err := testEncryptingFilter.Process(ctx, tc.in) + require.NoError(t, err) + require.NotNil(t, got) + gotJSON, err := json.Marshal(got) + require.NoError(t, err) + assert.JSONEq(t, string(wantJSON), string(gotJSON)) + }) + } +} diff --git a/sdk/pbs/controller/api/resources/credentiallibraries/credential_library.pb.go b/sdk/pbs/controller/api/resources/credentiallibraries/credential_library.pb.go index bf95c4be78..29bf4d2348 100644 --- a/sdk/pbs/controller/api/resources/credentiallibraries/credential_library.pb.go +++ b/sdk/pbs/controller/api/resources/credentiallibraries/credential_library.pb.go @@ -33,32 +33,32 @@ type CredentialLibrary struct { unknownFields protoimpl.UnknownFields // Output only. The ID of the Credential Library. - Id string `protobuf:"bytes,10,opt,name=id,proto3" json:"id,omitempty"` + Id string `protobuf:"bytes,10,opt,name=id,proto3" json:"id,omitempty" class:"public"` // @gotags: `class:"public"` // The ID of the Credential Store of which this Credential Library is a part. - CredentialStoreId string `protobuf:"bytes,20,opt,name=credential_store_id,proto3" json:"credential_store_id,omitempty"` + CredentialStoreId string `protobuf:"bytes,20,opt,name=credential_store_id,proto3" json:"credential_store_id,omitempty" class:"public"` // @gotags: `class:"public"` // Output only. Scope information for this Credential Library. Scope *scopes.ScopeInfo `protobuf:"bytes,30,opt,name=scope,proto3" json:"scope,omitempty"` // Optional name for identification purposes. - Name *wrapperspb.StringValue `protobuf:"bytes,40,opt,name=name,proto3" json:"name,omitempty"` + Name *wrapperspb.StringValue `protobuf:"bytes,40,opt,name=name,proto3" json:"name,omitempty" class:"public"` // @gotags: `class:"public"` // Optional user-set description for identification purposes. - Description *wrapperspb.StringValue `protobuf:"bytes,50,opt,name=description,proto3" json:"description,omitempty"` + Description *wrapperspb.StringValue `protobuf:"bytes,50,opt,name=description,proto3" json:"description,omitempty" class:"public"` // @gotags: `class:"public"` // Output only. The time this resource was created. - CreatedTime *timestamppb.Timestamp `protobuf:"bytes,60,opt,name=created_time,proto3" json:"created_time,omitempty"` + CreatedTime *timestamppb.Timestamp `protobuf:"bytes,60,opt,name=created_time,proto3" json:"created_time,omitempty" class:"public"` // @gotags: `class:"public"` // Output only. The time this resource was last updated. - UpdatedTime *timestamppb.Timestamp `protobuf:"bytes,70,opt,name=updated_time,proto3" json:"updated_time,omitempty"` + UpdatedTime *timestamppb.Timestamp `protobuf:"bytes,70,opt,name=updated_time,proto3" json:"updated_time,omitempty" class:"public"` // @gotags: `class:"public"` // Version is used in mutation requests, after the initial creation, to ensure this resource has not changed. // The mutation will fail if the version does not match the latest known good version. - Version uint32 `protobuf:"varint,80,opt,name=version,proto3" json:"version,omitempty"` + Version uint32 `protobuf:"varint,80,opt,name=version,proto3" json:"version,omitempty" class:"public"` // @gotags: `class:"public"` // The Credential Library type. - Type string `protobuf:"bytes,90,opt,name=type,proto3" json:"type,omitempty"` + Type string `protobuf:"bytes,90,opt,name=type,proto3" json:"type,omitempty" class:"public"` // @gotags: `class:"public"` // Types that are assignable to Attrs: // *CredentialLibrary_Attributes // *CredentialLibrary_VaultCredentialLibraryAttributes Attrs isCredentialLibrary_Attrs `protobuf_oneof:"attrs"` // Output only. The available actions on this resource for this user. - AuthorizedActions []string `protobuf:"bytes,300,rep,name=authorized_actions,proto3" json:"authorized_actions,omitempty"` + AuthorizedActions []string `protobuf:"bytes,300,rep,name=authorized_actions,proto3" json:"authorized_actions,omitempty" class:"public"` // @gotags: `class:"public"` // The type of credential this library will issue, defaults to Unspecified - CredentialType string `protobuf:"bytes,310,opt,name=credential_type,proto3" json:"credential_type,omitempty"` + CredentialType string `protobuf:"bytes,310,opt,name=credential_type,proto3" json:"credential_type,omitempty" class:"public"` // @gotags: `class:"public"` // The credential mapping overrides CredentialMappingOverrides *structpb.Struct `protobuf:"bytes,320,opt,name=credential_mapping_overrides,proto3" json:"credential_mapping_overrides,omitempty"` } @@ -224,11 +224,11 @@ type VaultCredentialLibraryAttributes struct { unknownFields protoimpl.UnknownFields // The path in Vault to request credentials from. - Path *wrapperspb.StringValue `protobuf:"bytes,10,opt,name=path,proto3" json:"path,omitempty"` + Path *wrapperspb.StringValue `protobuf:"bytes,10,opt,name=path,proto3" json:"path,omitempty" class:"public"` // @gotags: `class:"public"` // The HTTP method the library uses to communicate with Vault. - HttpMethod *wrapperspb.StringValue `protobuf:"bytes,20,opt,name=http_method,proto3" json:"http_method,omitempty"` + HttpMethod *wrapperspb.StringValue `protobuf:"bytes,20,opt,name=http_method,proto3" json:"http_method,omitempty" class:"public"` // @gotags: `class:"public"` // The body of the HTTP request the library sends to vault. When set http_method must be "POST" - HttpRequestBody *wrapperspb.StringValue `protobuf:"bytes,30,opt,name=http_request_body,proto3" json:"http_request_body,omitempty"` + HttpRequestBody *wrapperspb.StringValue `protobuf:"bytes,30,opt,name=http_request_body,proto3" json:"http_request_body,omitempty" class:"secret"` // @gotags: `class:"secret"` } func (x *VaultCredentialLibraryAttributes) Reset() {