From c643dc1d535f41951ebf6849063478df3973b78d Mon Sep 17 00:00:00 2001 From: akshya96 <87045294+akshya96@users.noreply.github.com> Date: Fri, 17 Sep 2021 11:03:47 -0700 Subject: [PATCH] Add Custom metadata field to alias (#12502) * adding changes * removing q.Q * removing empty lines * testing * checking tests * fixing tests * adding changes * added requested changes * added requested changes * added policy templating changes and fixed tests * adding proto changes * making changes * adding unit tests * using suggested function --- changelog/12502.txt | 3 + helper/forwarding/types.pb.go | 2 +- helper/identity/identity.go | 13 +- helper/identity/mfa/types.pb.go | 2 +- helper/identity/types.pb.go | 84 +++++++----- helper/identity/types.proto | 3 + helper/storagepacker/types.pb.go | 2 +- physical/raft/types.pb.go | 2 +- sdk/database/dbplugin/database.pb.go | 2 +- sdk/database/dbplugin/v5/proto/database.pb.go | 2 +- sdk/helper/identitytpl/templating.go | 11 +- sdk/helper/identitytpl/templating_test.go | 107 ++++++++++++---- sdk/logical/identity.pb.go | 44 +++++-- sdk/logical/identity.proto | 3 + sdk/logical/plugin.pb.go | 2 +- sdk/plugin/pb/backend.pb.go | 2 +- vault/activity/activity_log.pb.go | 2 +- vault/identity_store_aliases.go | 121 +++++++++++++++--- vault/identity_store_aliases_test.go | 31 +++-- vault/identity_store_util.go | 7 +- vault/request_forwarding_service.pb.go | 2 +- 21 files changed, 335 insertions(+), 112 deletions(-) create mode 100644 changelog/12502.txt diff --git a/changelog/12502.txt b/changelog/12502.txt new file mode 100644 index 000000000..4d24e7af5 --- /dev/null +++ b/changelog/12502.txt @@ -0,0 +1,3 @@ +```release-note:feature +core: adds custom_metadata field for aliases +``` \ No newline at end of file diff --git a/helper/forwarding/types.pb.go b/helper/forwarding/types.pb.go index be61f311a..b7ffa7056 100644 --- a/helper/forwarding/types.pb.go +++ b/helper/forwarding/types.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0 +// protoc-gen-go v1.27.1 // protoc v3.17.3 // source: helper/forwarding/types.proto diff --git a/helper/identity/identity.go b/helper/identity/identity.go index c50dec268..4f8eb6d42 100644 --- a/helper/identity/identity.go +++ b/helper/identity/identity.go @@ -75,12 +75,13 @@ func ToSDKAlias(a *Alias) *logical.Alias { } return &logical.Alias{ - Name: a.Name, - ID: a.ID, - MountAccessor: a.MountAccessor, - MountType: a.MountType, - Metadata: metadata, - NamespaceID: a.NamespaceID, + Name: a.Name, + ID: a.ID, + MountAccessor: a.MountAccessor, + MountType: a.MountType, + Metadata: metadata, + NamespaceID: a.NamespaceID, + CustomMetadata: a.CustomMetadata, } } diff --git a/helper/identity/mfa/types.pb.go b/helper/identity/mfa/types.pb.go index 5230f4a1b..19724c2ee 100644 --- a/helper/identity/mfa/types.pb.go +++ b/helper/identity/mfa/types.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0 +// protoc-gen-go v1.27.1 // protoc v3.17.3 // source: helper/identity/mfa/types.proto diff --git a/helper/identity/types.pb.go b/helper/identity/types.pb.go index a5bd81f8d..ce8431c01 100644 --- a/helper/identity/types.pb.go +++ b/helper/identity/types.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0 +// protoc-gen-go v1.27.1 // protoc v3.17.3 // source: helper/identity/types.proto @@ -405,6 +405,8 @@ type Alias struct { // NamespaceID is the identifier of the namespace to which this alias // belongs. NamespaceID string `sentinel:"" protobuf:"bytes,11,opt,name=namespace_id,json=namespaceID,proto3" json:"namespace_id,omitempty"` + // Custom Metadata represents the custom data tied to this alias + CustomMetadata map[string]string `sentinel:"" protobuf:"bytes,12,rep,name=customMetadata,proto3" json:"customMetadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (x *Alias) Reset() { @@ -516,6 +518,13 @@ func (x *Alias) GetNamespaceID() string { return "" } +func (x *Alias) GetCustomMetadata() map[string]string { + if x != nil { + return x.CustomMetadata + } + return nil +} + // Deprecated. Retained for backwards compatibility. type EntityStorageEntry struct { state protoimpl.MessageState @@ -842,7 +851,7 @@ var file_helper_identity_types_proto_rawDesc = []byte{ 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x21, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x6d, 0x66, 0x61, 0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x90, 0x04, 0x0a, 0x05, 0x41, 0x6c, 0x69, 0x61, + 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xa0, 0x05, 0x0a, 0x05, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63, @@ -871,8 +880,17 @@ var file_helper_identity_types_proto_rawDesc = []byte{ 0x28, 0x09, 0x52, 0x16, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x43, 0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x1a, 0x3b, 0x0a, - 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, + 0x52, 0x0b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x4b, 0x0a, + 0x0e, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, + 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x2e, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x2e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0e, 0x63, 0x75, 0x73, 0x74, + 0x6f, 0x6d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x41, 0x0a, 0x13, 0x43, 0x75, 0x73, 0x74, 0x6f, + 0x6d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x88, 0x05, 0x0a, 0x12, 0x45, @@ -966,7 +984,7 @@ func file_helper_identity_types_proto_rawDescGZIP() []byte { return file_helper_identity_types_proto_rawDescData } -var file_helper_identity_types_proto_msgTypes = make([]protoimpl.MessageInfo, 12) +var file_helper_identity_types_proto_msgTypes = make([]protoimpl.MessageInfo, 13) var file_helper_identity_types_proto_goTypes = []interface{}{ (*Group)(nil), // 0: identity.Group (*Entity)(nil), // 1: identity.Entity @@ -977,40 +995,42 @@ var file_helper_identity_types_proto_goTypes = []interface{}{ nil, // 6: identity.Entity.MetadataEntry nil, // 7: identity.Entity.MFASecretsEntry nil, // 8: identity.Alias.MetadataEntry - nil, // 9: identity.EntityStorageEntry.MetadataEntry - nil, // 10: identity.EntityStorageEntry.MFASecretsEntry - nil, // 11: identity.PersonaIndexEntry.MetadataEntry - (*timestamppb.Timestamp)(nil), // 12: google.protobuf.Timestamp - (*mfa.Secret)(nil), // 13: mfa.Secret + nil, // 9: identity.Alias.CustomMetadataEntry + nil, // 10: identity.EntityStorageEntry.MetadataEntry + nil, // 11: identity.EntityStorageEntry.MFASecretsEntry + nil, // 12: identity.PersonaIndexEntry.MetadataEntry + (*timestamppb.Timestamp)(nil), // 13: google.protobuf.Timestamp + (*mfa.Secret)(nil), // 14: mfa.Secret } var file_helper_identity_types_proto_depIDxs = []int32{ 5, // 0: identity.Group.metadata:type_name -> identity.Group.MetadataEntry - 12, // 1: identity.Group.creation_time:type_name -> google.protobuf.Timestamp - 12, // 2: identity.Group.last_update_time:type_name -> google.protobuf.Timestamp + 13, // 1: identity.Group.creation_time:type_name -> google.protobuf.Timestamp + 13, // 2: identity.Group.last_update_time:type_name -> google.protobuf.Timestamp 2, // 3: identity.Group.alias:type_name -> identity.Alias 2, // 4: identity.Entity.aliases:type_name -> identity.Alias 6, // 5: identity.Entity.metadata:type_name -> identity.Entity.MetadataEntry - 12, // 6: identity.Entity.creation_time:type_name -> google.protobuf.Timestamp - 12, // 7: identity.Entity.last_update_time:type_name -> google.protobuf.Timestamp + 13, // 6: identity.Entity.creation_time:type_name -> google.protobuf.Timestamp + 13, // 7: identity.Entity.last_update_time:type_name -> google.protobuf.Timestamp 7, // 8: identity.Entity.mfa_secrets:type_name -> identity.Entity.MFASecretsEntry 8, // 9: identity.Alias.metadata:type_name -> identity.Alias.MetadataEntry - 12, // 10: identity.Alias.creation_time:type_name -> google.protobuf.Timestamp - 12, // 11: identity.Alias.last_update_time:type_name -> google.protobuf.Timestamp - 4, // 12: identity.EntityStorageEntry.personas:type_name -> identity.PersonaIndexEntry - 9, // 13: identity.EntityStorageEntry.metadata:type_name -> identity.EntityStorageEntry.MetadataEntry - 12, // 14: identity.EntityStorageEntry.creation_time:type_name -> google.protobuf.Timestamp - 12, // 15: identity.EntityStorageEntry.last_update_time:type_name -> google.protobuf.Timestamp - 10, // 16: identity.EntityStorageEntry.mfa_secrets:type_name -> identity.EntityStorageEntry.MFASecretsEntry - 11, // 17: identity.PersonaIndexEntry.metadata:type_name -> identity.PersonaIndexEntry.MetadataEntry - 12, // 18: identity.PersonaIndexEntry.creation_time:type_name -> google.protobuf.Timestamp - 12, // 19: identity.PersonaIndexEntry.last_update_time:type_name -> google.protobuf.Timestamp - 13, // 20: identity.Entity.MFASecretsEntry.value:type_name -> mfa.Secret - 13, // 21: identity.EntityStorageEntry.MFASecretsEntry.value:type_name -> mfa.Secret - 22, // [22:22] is the sub-list for method output_type - 22, // [22:22] is the sub-list for method input_type - 22, // [22:22] is the sub-list for extension type_name - 22, // [22:22] is the sub-list for extension extendee - 0, // [0:22] is the sub-list for field type_name + 13, // 10: identity.Alias.creation_time:type_name -> google.protobuf.Timestamp + 13, // 11: identity.Alias.last_update_time:type_name -> google.protobuf.Timestamp + 9, // 12: identity.Alias.customMetadata:type_name -> identity.Alias.CustomMetadataEntry + 4, // 13: identity.EntityStorageEntry.personas:type_name -> identity.PersonaIndexEntry + 10, // 14: identity.EntityStorageEntry.metadata:type_name -> identity.EntityStorageEntry.MetadataEntry + 13, // 15: identity.EntityStorageEntry.creation_time:type_name -> google.protobuf.Timestamp + 13, // 16: identity.EntityStorageEntry.last_update_time:type_name -> google.protobuf.Timestamp + 11, // 17: identity.EntityStorageEntry.mfa_secrets:type_name -> identity.EntityStorageEntry.MFASecretsEntry + 12, // 18: identity.PersonaIndexEntry.metadata:type_name -> identity.PersonaIndexEntry.MetadataEntry + 13, // 19: identity.PersonaIndexEntry.creation_time:type_name -> google.protobuf.Timestamp + 13, // 20: identity.PersonaIndexEntry.last_update_time:type_name -> google.protobuf.Timestamp + 14, // 21: identity.Entity.MFASecretsEntry.value:type_name -> mfa.Secret + 14, // 22: identity.EntityStorageEntry.MFASecretsEntry.value:type_name -> mfa.Secret + 23, // [23:23] is the sub-list for method output_type + 23, // [23:23] is the sub-list for method input_type + 23, // [23:23] is the sub-list for extension type_name + 23, // [23:23] is the sub-list for extension extendee + 0, // [0:23] is the sub-list for field type_name } func init() { file_helper_identity_types_proto_init() } @@ -1086,7 +1106,7 @@ func file_helper_identity_types_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_helper_identity_types_proto_rawDesc, NumEnums: 0, - NumMessages: 12, + NumMessages: 13, NumExtensions: 0, NumServices: 0, }, diff --git a/helper/identity/types.proto b/helper/identity/types.proto index 8fed73343..d48b776e9 100644 --- a/helper/identity/types.proto +++ b/helper/identity/types.proto @@ -172,6 +172,9 @@ message Alias { // NamespaceID is the identifier of the namespace to which this alias // belongs. string namespace_id = 11; + + // Custom Metadata represents the custom data tied to this alias + map customMetadata = 12; } // Deprecated. Retained for backwards compatibility. diff --git a/helper/storagepacker/types.pb.go b/helper/storagepacker/types.pb.go index ba00547df..7763a09b5 100644 --- a/helper/storagepacker/types.pb.go +++ b/helper/storagepacker/types.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0 +// protoc-gen-go v1.27.1 // protoc v3.17.3 // source: helper/storagepacker/types.proto diff --git a/physical/raft/types.pb.go b/physical/raft/types.pb.go index 07a5a30ec..98dc72982 100644 --- a/physical/raft/types.pb.go +++ b/physical/raft/types.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0 +// protoc-gen-go v1.27.1 // protoc v3.17.3 // source: physical/raft/types.proto diff --git a/sdk/database/dbplugin/database.pb.go b/sdk/database/dbplugin/database.pb.go index 2bd3b2ffc..436719342 100644 --- a/sdk/database/dbplugin/database.pb.go +++ b/sdk/database/dbplugin/database.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0 +// protoc-gen-go v1.27.1 // protoc v3.17.3 // source: sdk/database/dbplugin/database.proto diff --git a/sdk/database/dbplugin/v5/proto/database.pb.go b/sdk/database/dbplugin/v5/proto/database.pb.go index 9f72fda53..ce4e2ca03 100644 --- a/sdk/database/dbplugin/v5/proto/database.pb.go +++ b/sdk/database/dbplugin/v5/proto/database.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0 +// protoc-gen-go v1.27.1 // protoc v3.17.3 // source: sdk/database/dbplugin/v5/proto/database.proto diff --git a/sdk/helper/identitytpl/templating.go b/sdk/helper/identitytpl/templating.go index 85166bf4f..6d84df824 100644 --- a/sdk/helper/identitytpl/templating.go +++ b/sdk/helper/identitytpl/templating.go @@ -178,6 +178,15 @@ func performTemplating(input string, p *PopulateStringInput) (string, error) { case strings.HasPrefix(trimmed, "metadata."): split := strings.SplitN(trimmed, ".", 2) return p.templateHandler(alias.Metadata, split[1]) + + case trimmed == "custom_metadata": + return p.templateHandler(alias.CustomMetadata) + + case strings.HasPrefix(trimmed, "custom_metadata."): + + split := strings.SplitN(trimmed, ".", 2) + return p.templateHandler(alias.CustomMetadata, split[1]) + } return "", ErrTemplateValueNotFound @@ -222,7 +231,7 @@ func performTemplating(input string, p *PopulateStringInput) (string, error) { } // An empty alias is sufficient for generating defaults - alias = &logical.Alias{Metadata: make(map[string]string)} + alias = &logical.Alias{Metadata: make(map[string]string), CustomMetadata: make(map[string]string)} } return performAliasTemplating(split[1], alias) } diff --git a/sdk/helper/identitytpl/templating_test.go b/sdk/helper/identitytpl/templating_test.go index 41362da9e..15bfc8123 100644 --- a/sdk/helper/identitytpl/templating_test.go +++ b/sdk/helper/identitytpl/templating_test.go @@ -17,23 +17,24 @@ var testNow = time.Now().Add(100 * time.Hour) func TestPopulate_Basic(t *testing.T) { tests := []struct { - mode int - name string - input string - output string - err error - entityName string - metadata map[string]string - aliasAccessor string - aliasID string - aliasName string - nilEntity bool - validityCheckOnly bool - aliasMetadata map[string]string - groupName string - groupMetadata map[string]string - groupMemberships []string - now time.Time + mode int + name string + input string + output string + err error + entityName string + metadata map[string]string + aliasAccessor string + aliasID string + aliasName string + nilEntity bool + validityCheckOnly bool + aliasMetadata map[string]string + aliasCustomMetadata map[string]string + groupName string + groupMetadata map[string]string + groupMemberships []string + now time.Time }{ // time.* tests. Keep tests with time.Now() at the front to avoid false // positives due to the second changing during the test @@ -329,6 +330,53 @@ func TestPopulate_Basic(t *testing.T) { aliasMetadata: map[string]string{"foo": "bar", "color": "green"}, output: `{}`, }, + { + mode: JSONTemplating, + name: "one alias custom metadata key", + input: "{{identity.entity.aliases.aws_123.custom_metadata.foo}}", + aliasAccessor: "aws_123", + aliasCustomMetadata: map[string]string{"foo": "abc", "bar": "123"}, + output: `"abc"`, + }, + { + mode: JSONTemplating, + name: "one alias custom metadata key not found", + input: "{{identity.entity.aliases.aws_123.custom_metadata.size}}", + aliasAccessor: "aws_123", + aliasCustomMetadata: map[string]string{"foo": "abc", "bar": "123"}, + output: `""`, + }, + { + mode: JSONTemplating, + name: "one alias custom metadata, accessor not found", + input: "{{identity.entity.aliases.aws_123.custom_metadata.size}}", + aliasAccessor: "not_gonna_match", + aliasCustomMetadata: map[string]string{"foo": "abc", "bar": "123"}, + output: `""`, + }, + { + mode: JSONTemplating, + name: "all alias custom metadata", + input: "{{identity.entity.aliases.aws_123.custom_metadata}}", + aliasAccessor: "aws_123", + aliasCustomMetadata: map[string]string{"foo": "abc", "bar": "123"}, + output: `{"bar":"123","foo":"abc"}`, + }, + { + mode: JSONTemplating, + name: "null alias custom metadata", + input: "{{identity.entity.aliases.aws_123.custom_metadata}}", + aliasAccessor: "aws_123", + output: `{}`, + }, + { + mode: JSONTemplating, + name: "all alias custom metadata, accessor not found", + input: "{{identity.entity.aliases.aws_123.custom_metadata}}", + aliasAccessor: "not_gonna_match", + aliasCustomMetadata: map[string]string{"foo": "abc", "bar": "123"}, + output: `{}`, + }, } for _, test := range tests { @@ -343,10 +391,11 @@ func TestPopulate_Basic(t *testing.T) { if test.aliasAccessor != "" { entity.Aliases = []*logical.Alias{ { - MountAccessor: test.aliasAccessor, - ID: test.aliasID, - Name: test.aliasName, - Metadata: test.aliasMetadata, + MountAccessor: test.aliasAccessor, + ID: test.aliasID, + Name: test.aliasName, + Metadata: test.aliasMetadata, + CustomMetadata: test.aliasCustomMetadata, }, } } @@ -436,6 +485,10 @@ func TestPopulate_FullObject(t *testing.T) { "service": "ec2", "region": "west", }, + CustomMetadata: map[string]string{ + "foo": "abc", + "bar": "123", + }, }, }, } @@ -458,7 +511,11 @@ func TestPopulate_FullObject(t *testing.T) { "one not found alias metadata key": {{identity.entity.aliases.blahblah.metadata.service}}, "group names": {{identity.entity.groups.names}}, "group ids": {{identity.entity.groups.ids}}, - "repeated and": {"nested element": {{identity.entity.name}}} + "repeated and": {"nested element": {{identity.entity.name}}}, + "alias custom metadata": {{identity.entity.aliases.aws_123.custom_metadata}}, + "alias not found custom metadata": {{identity.entity.aliases.blahblah.custom_metadata}}, + "one alias custom metadata key": {{identity.entity.aliases.aws_123.custom_metadata.foo}}, + "one not found alias custom metadata key": {{identity.entity.aliases.blahblah.custom_metadata.foo}}, }` expected := ` @@ -474,7 +531,11 @@ func TestPopulate_FullObject(t *testing.T) { "one not found alias metadata key": "", "group names": ["g1","g2"], "group ids": ["a08b0c02","239bef91"], - "repeated and": {"nested element": "Entity Name"} + "repeated and": {"nested element": "Entity Name"}, + "alias custom metadata": {"bar":"123","foo":"abc"}, + "alias not found custom metadata": {}, + "one alias custom metadata key": "abc", + "one not found alias custom metadata key": "", }` input := PopulateStringInput{ diff --git a/sdk/logical/identity.pb.go b/sdk/logical/identity.pb.go index 0a99bc74e..3d1adc90a 100644 --- a/sdk/logical/identity.pb.go +++ b/sdk/logical/identity.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0 +// protoc-gen-go v1.27.1 // protoc v3.17.3 // source: sdk/logical/identity.proto @@ -138,6 +138,8 @@ type Alias struct { // NamespaceID is the identifier of the namespace to which this alias // belongs. NamespaceID string `sentinel:"" protobuf:"bytes,6,opt,name=namespace_id,json=namespaceID,proto3" json:"namespace_id,omitempty"` + // Custom Metadata represents the custom data tied to this alias + CustomMetadata map[string]string `sentinel:"" protobuf:"bytes,7,rep,name=custom_metadata,json=customMetadata,proto3" json:"custom_metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (x *Alias) Reset() { @@ -214,6 +216,13 @@ func (x *Alias) GetNamespaceID() string { return "" } +func (x *Alias) GetCustomMetadata() map[string]string { + if x != nil { + return x.CustomMetadata + } + return nil +} + type Group struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -312,7 +321,7 @@ var file_sdk_logical_identity_proto_rawDesc = []byte{ 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x8b, 0x02, 0x0a, 0x05, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x12, + 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x9b, 0x03, 0x0a, 0x05, 0x41, 0x6c, 0x69, 0x61, 0x73, 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, 0x25, 0x0a, 0x0e, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, @@ -325,7 +334,16 @@ var file_sdk_logical_identity_proto_rawDesc = []byte{ 0x61, 0x74, 0x61, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x12, 0x21, 0x0a, 0x0c, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6e, 0x61, 0x6d, 0x65, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x4b, 0x0a, 0x0f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, + 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x22, 0x2e, 0x6c, 0x6f, 0x67, 0x69, 0x63, 0x61, 0x6c, 0x2e, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x2e, + 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x0e, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, + 0x1a, 0x41, 0x0a, 0x13, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, @@ -359,25 +377,27 @@ func file_sdk_logical_identity_proto_rawDescGZIP() []byte { return file_sdk_logical_identity_proto_rawDescData } -var file_sdk_logical_identity_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_sdk_logical_identity_proto_msgTypes = make([]protoimpl.MessageInfo, 7) var file_sdk_logical_identity_proto_goTypes = []interface{}{ (*Entity)(nil), // 0: logical.Entity (*Alias)(nil), // 1: logical.Alias (*Group)(nil), // 2: logical.Group nil, // 3: logical.Entity.MetadataEntry nil, // 4: logical.Alias.MetadataEntry - nil, // 5: logical.Group.MetadataEntry + nil, // 5: logical.Alias.CustomMetadataEntry + nil, // 6: logical.Group.MetadataEntry } var file_sdk_logical_identity_proto_depIDxs = []int32{ 1, // 0: logical.Entity.aliases:type_name -> logical.Alias 3, // 1: logical.Entity.metadata:type_name -> logical.Entity.MetadataEntry 4, // 2: logical.Alias.metadata:type_name -> logical.Alias.MetadataEntry - 5, // 3: logical.Group.metadata:type_name -> logical.Group.MetadataEntry - 4, // [4:4] is the sub-list for method output_type - 4, // [4:4] is the sub-list for method input_type - 4, // [4:4] is the sub-list for extension type_name - 4, // [4:4] is the sub-list for extension extendee - 0, // [0:4] is the sub-list for field type_name + 5, // 3: logical.Alias.custom_metadata:type_name -> logical.Alias.CustomMetadataEntry + 6, // 4: logical.Group.metadata:type_name -> logical.Group.MetadataEntry + 5, // [5:5] is the sub-list for method output_type + 5, // [5:5] is the sub-list for method input_type + 5, // [5:5] is the sub-list for extension type_name + 5, // [5:5] is the sub-list for extension extendee + 0, // [0:5] is the sub-list for field type_name } func init() { file_sdk_logical_identity_proto_init() } @@ -429,7 +449,7 @@ func file_sdk_logical_identity_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_sdk_logical_identity_proto_rawDesc, NumEnums: 0, - NumMessages: 6, + NumMessages: 7, NumExtensions: 0, NumServices: 0, }, diff --git a/sdk/logical/identity.proto b/sdk/logical/identity.proto index 78c3758f8..9e07bd648 100644 --- a/sdk/logical/identity.proto +++ b/sdk/logical/identity.proto @@ -50,6 +50,9 @@ message Alias { // NamespaceID is the identifier of the namespace to which this alias // belongs. string namespace_id = 6; + + // Custom Metadata represents the custom data tied to this alias + map custom_metadata = 7; } message Group { diff --git a/sdk/logical/plugin.pb.go b/sdk/logical/plugin.pb.go index 539e0579a..46de77666 100644 --- a/sdk/logical/plugin.pb.go +++ b/sdk/logical/plugin.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0 +// protoc-gen-go v1.27.1 // protoc v3.17.3 // source: sdk/logical/plugin.proto diff --git a/sdk/plugin/pb/backend.pb.go b/sdk/plugin/pb/backend.pb.go index 9b550a0c5..ca67fc343 100644 --- a/sdk/plugin/pb/backend.pb.go +++ b/sdk/plugin/pb/backend.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0 +// protoc-gen-go v1.27.1 // protoc v3.17.3 // source: sdk/plugin/pb/backend.proto diff --git a/vault/activity/activity_log.pb.go b/vault/activity/activity_log.pb.go index 3c94d2bbd..3b5c90dba 100644 --- a/vault/activity/activity_log.pb.go +++ b/vault/activity/activity_log.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0 +// protoc-gen-go v1.27.1 // protoc v3.17.3 // source: vault/activity/activity_log.proto diff --git a/vault/identity_store_aliases.go b/vault/identity_store_aliases.go index 422e25a97..db827a33c 100644 --- a/vault/identity_store_aliases.go +++ b/vault/identity_store_aliases.go @@ -6,13 +6,21 @@ import ( "strings" "github.com/golang/protobuf/ptypes" + "github.com/hashicorp/go-multierror" + "github.com/hashicorp/go-secure-stdlib/strutil" "github.com/hashicorp/vault/helper/identity" "github.com/hashicorp/vault/helper/namespace" "github.com/hashicorp/vault/helper/storagepacker" "github.com/hashicorp/vault/sdk/framework" "github.com/hashicorp/vault/sdk/logical" + "github.com/mitchellh/mapstructure" ) +const maxCustomMetadataKeys = 64 +const maxCustomMetadataKeyLength = 128 +const maxCustomMetadataValueLength = 512 +const customMetadataValidationErrorPrefix = "custom_metadata validation failed" + // aliasPaths returns the API endpoints to operate on aliases. // Following are the paths supported: // entity-alias - To register/modify an alias @@ -44,6 +52,10 @@ This field is deprecated, use canonical_id.`, Type: framework.TypeString, Description: "Name of the alias; unused for a modify", }, + "custom_metadata": { + Type: framework.TypeKVPairs, + Description: "User provided key-value pairs", + }, }, Callbacks: map[logical.Operation]framework.OperationFunc{ logical.UpdateOperation: i.handleAliasCreateUpdate(), @@ -77,6 +89,10 @@ This field is deprecated, use canonical_id.`, Type: framework.TypeString, Description: "(Unused)", }, + "custom_metadata": { + Type: framework.TypeKVPairs, + Description: "User provided key-value pairs", + }, }, Callbacks: map[logical.Operation]framework.OperationFunc{ logical.UpdateOperation: i.handleAliasCreateUpdate(), @@ -118,6 +134,16 @@ func (i *IdentityStore) handleAliasCreateUpdate() framework.OperationFunc { // Get ID, if any id := d.Get("id").(string) + // Get custom metadata, if any + customMetadata := make(map[string]string) + data, customMetadataExists := d.GetOk("custom_metadata") + if customMetadataExists { + err = mapstructure.Decode(data, &customMetadata) + if err != nil { + return nil, err + } + } + // Get entity id canonicalID := d.Get("canonical_id").(string) if canonicalID == "" { @@ -125,6 +151,15 @@ func (i *IdentityStore) handleAliasCreateUpdate() framework.OperationFunc { canonicalID = d.Get("entity_id").(string) } + //validate customMetadata if provided + if len(customMetadata) != 0 { + + err := validateCustomMetadata(customMetadata) + if err != nil { + return nil, err + } + } + i.lock.Lock() defer i.lock.Unlock() @@ -143,31 +178,31 @@ func (i *IdentityStore) handleAliasCreateUpdate() framework.OperationFunc { if alias.NamespaceID != ns.ID { return logical.ErrorResponse("cannot modify aliases across namespaces"), logical.ErrPermissionDenied } - switch { - case mountAccessor == "" && name == "": + case mountAccessor == "" && name == "" && len(customMetadata) == 0: // Just a canonical ID update, maybe if canonicalID == "" { // Nothing to do, so be idempotent return nil, nil } - name = alias.Name mountAccessor = alias.MountAccessor + customMetadata = alias.CustomMetadata case mountAccessor == "": // No change to mount accessor mountAccessor = alias.MountAccessor - case name == "": // No change to mount name name = alias.Name + case len(customMetadata) == 0: + // No change to custom metadata + customMetadata = alias.CustomMetadata default: - // Both provided + // mountAccessor, name and customMetadata provided } - - return i.handleAliasUpdate(ctx, req, canonicalID, name, mountAccessor, alias) + return i.handleAliasUpdate(ctx, req, canonicalID, name, mountAccessor, alias, customMetadata) } } @@ -196,24 +231,25 @@ func (i *IdentityStore) handleAliasCreateUpdate() framework.OperationFunc { return logical.ErrorResponse("cannot modify aliases across namespaces"), logical.ErrPermissionDenied } - return i.handleAliasUpdate(ctx, req, alias.CanonicalID, name, mountAccessor, alias) + return i.handleAliasUpdate(ctx, req, alias.CanonicalID, name, mountAccessor, alias, customMetadata) } - // At this point we know it's a new creation request - return i.handleAliasCreate(ctx, req, canonicalID, name, mountAccessor) + return i.handleAliasCreate(ctx, req, canonicalID, name, mountAccessor, customMetadata) } } -func (i *IdentityStore) handleAliasCreate(ctx context.Context, req *logical.Request, canonicalID, name, mountAccessor string) (*logical.Response, error) { +func (i *IdentityStore) handleAliasCreate(ctx context.Context, req *logical.Request, canonicalID, name, mountAccessor string, customMetadata map[string]string) (*logical.Response, error) { ns, err := namespace.FromContext(ctx) if err != nil { return nil, err } alias := &identity.Alias{ - MountAccessor: mountAccessor, - Name: name, + MountAccessor: mountAccessor, + Name: name, + CustomMetadata: customMetadata, } + entity := &identity.Entity{} // If a canonical ID is provided pull up the entity and make sure we're in @@ -266,10 +302,10 @@ func (i *IdentityStore) handleAliasCreate(ctx context.Context, req *logical.Requ }, nil } -func (i *IdentityStore) handleAliasUpdate(ctx context.Context, req *logical.Request, canonicalID, name, mountAccessor string, alias *identity.Alias) (*logical.Response, error) { +func (i *IdentityStore) handleAliasUpdate(ctx context.Context, req *logical.Request, canonicalID, name, mountAccessor string, alias *identity.Alias, customMetadata map[string]string) (*logical.Response, error) { if name == alias.Name && mountAccessor == alias.MountAccessor && - (canonicalID == alias.CanonicalID || canonicalID == "") { + (canonicalID == alias.CanonicalID || canonicalID == "") && (strutil.EqualStringMaps(customMetadata, alias.CustomMetadata)) { // Nothing to do; return nil to be idempotent return nil, nil } @@ -279,7 +315,7 @@ func (i *IdentityStore) handleAliasUpdate(ctx context.Context, req *logical.Requ // If we're changing one or the other or both of these, make sure that // there isn't a matching alias already, and make sure it's in the same // namespace. - if name != alias.Name || mountAccessor != alias.MountAccessor { + if name != alias.Name || mountAccessor != alias.MountAccessor || !strutil.EqualStringMaps(customMetadata, alias.CustomMetadata) { // Check here to see if such an alias already exists, if so bail mountEntry := i.router.MatchingMountByAccessor(mountAccessor) if mountEntry == nil { @@ -296,6 +332,7 @@ func (i *IdentityStore) handleAliasUpdate(ctx context.Context, req *logical.Requ if err != nil { return nil, err } + // Bail unless it's just a case change if existingAlias != nil && !strings.EqualFold(existingAlias.Name, name) { return logical.ErrorResponse("alias with combination of mount accessor and name already exists"), nil @@ -304,8 +341,8 @@ func (i *IdentityStore) handleAliasUpdate(ctx context.Context, req *logical.Requ // Update the values in the alias alias.Name = name alias.MountAccessor = mountAccessor + alias.CustomMetadata = customMetadata } - // Get our current entity, which may be the same as the new one if the // canonical ID hasn't changed currentEntity, err := i.MemDBEntityByAliasID(alias.ID, true) @@ -373,6 +410,55 @@ func (i *IdentityStore) handleAliasUpdate(ctx context.Context, req *logical.Requ }, nil } +func validateCustomMetadata(customMetadata map[string]string) error { + var errs *multierror.Error + + if keyCount := len(customMetadata); keyCount > maxCustomMetadataKeys { + errs = multierror.Append(errs, fmt.Errorf("%s: payload must contain at most %d keys, provided %d", + customMetadataValidationErrorPrefix, + maxCustomMetadataKeys, + keyCount)) + + return errs.ErrorOrNil() + } + + // Perform validation on each key and value and return ALL errors + for key, value := range customMetadata { + if keyLen := len(key); 0 == keyLen || keyLen > maxCustomMetadataKeyLength { + errs = multierror.Append(errs, fmt.Errorf("%s: length of key %q is %d but must be 0 < len(key) <= %d", + customMetadataValidationErrorPrefix, + key, + keyLen, + maxCustomMetadataKeyLength)) + } + + if valueLen := len(value); 0 == valueLen || valueLen > maxCustomMetadataValueLength { + errs = multierror.Append(errs, fmt.Errorf("%s: length of value for key %q is %d but must be 0 < len(value) <= %d", + customMetadataValidationErrorPrefix, + key, + valueLen, + maxCustomMetadataValueLength)) + } + + if !strutil.Printable(key) { + // Include unquoted format (%s) to also include the string without the unprintable + // characters visible to allow for easier debug and key identification + errs = multierror.Append(errs, fmt.Errorf("%s: key %q (%s) contains unprintable characters", + customMetadataValidationErrorPrefix, + key, + key)) + } + + if !strutil.Printable(value) { + errs = multierror.Append(errs, fmt.Errorf("%s: value for key %q contains unprintable characters", + customMetadataValidationErrorPrefix, + key)) + } + } + + return errs.ErrorOrNil() +} + // pathAliasIDRead returns the properties of an alias for a given // alias ID func (i *IdentityStore) pathAliasIDRead() framework.OperationFunc { @@ -409,6 +495,7 @@ func (i *IdentityStore) handleAliasReadCommon(ctx context.Context, alias *identi respData["canonical_id"] = alias.CanonicalID respData["mount_accessor"] = alias.MountAccessor respData["metadata"] = alias.Metadata + respData["custom_metadata"] = alias.CustomMetadata respData["name"] = alias.Name respData["merged_from_canonical_ids"] = alias.MergedFromCanonicalIDs respData["namespace_id"] = alias.NamespaceID diff --git a/vault/identity_store_aliases_test.go b/vault/identity_store_aliases_test.go index a0779c68a..bf70e4010 100644 --- a/vault/identity_store_aliases_test.go +++ b/vault/identity_store_aliases_test.go @@ -375,10 +375,13 @@ func TestIdentityStore_AliasUpdate(t *testing.T) { t.Fatalf("err:%v resp:%#v", err, resp) } aliasID := resp.Data["id"].(string) + customMetadata := make(map[string]string) + customMetadata["foo"] = "abc" updateData := map[string]interface{}{ - "name": "updatedaliasname", - "mount_accessor": githubAccessor, + "name": "updatedaliasname", + "mount_accessor": githubAccessor, + "custom_metadata": customMetadata, } aliasReq.Data = updateData @@ -397,6 +400,9 @@ func TestIdentityStore_AliasUpdate(t *testing.T) { if resp.Data["name"] != "updatedaliasname" { t.Fatalf("failed to update alias information; \n response data: %#v\n", resp.Data) } + if !reflect.DeepEqual(resp.Data["custom_metadata"], customMetadata) { + t.Fatalf("failed to update alias information; \n response data: %#v\n", resp.Data) + } } func TestIdentityStore_AliasUpdate_ByID(t *testing.T) { @@ -425,9 +431,12 @@ func TestIdentityStore_AliasUpdate_ByID(t *testing.T) { t.Fatalf("expected an error due to invalid alias id") } + customMetadata := make(map[string]string) + customMetadata["foo"] = "abc" registerData := map[string]interface{}{ - "name": "testaliasname", - "mount_accessor": githubAccessor, + "name": "testaliasname", + "mount_accessor": githubAccessor, + "custom_metadata": customMetadata, } registerReq := &logical.Request{ @@ -468,6 +477,9 @@ func TestIdentityStore_AliasUpdate_ByID(t *testing.T) { if resp.Data["name"] != "updatedaliasname" { t.Fatalf("failed to update alias information; \n response data: %#v\n", resp.Data) } + if !reflect.DeepEqual(resp.Data["custom_metadata"], customMetadata) { + t.Fatalf("failed to update alias information; \n response data: %#v\n", resp.Data) + } delete(registerReq.Data, "name") @@ -498,10 +510,13 @@ func TestIdentityStore_AliasReadDelete(t *testing.T) { ctx := namespace.RootContext(nil) is, githubAccessor, _ := testIdentityStoreWithGithubAuth(ctx, t) + customMetadata := make(map[string]string) + customMetadata["foo"] = "abc" registerData := map[string]interface{}{ - "name": "testaliasname", - "mount_accessor": githubAccessor, - "metadata": []string{"organization=hashicorp", "team=vault"}, + "name": "testaliasname", + "mount_accessor": githubAccessor, + "metadata": []string{"organization=hashicorp", "team=vault"}, + "custom_metadata": customMetadata, } registerReq := &logical.Request{ @@ -537,7 +552,7 @@ func TestIdentityStore_AliasReadDelete(t *testing.T) { if resp.Data["id"].(string) == "" || resp.Data["canonical_id"].(string) == "" || resp.Data["name"].(string) != registerData["name"] || - resp.Data["mount_type"].(string) != "github" { + resp.Data["mount_type"].(string) != "github" || !reflect.DeepEqual(resp.Data["custom_metadata"], customMetadata) { t.Fatalf("bad: alias read response; \nexpected: %#v \nactual: %#v\n", registerData, resp.Data) } diff --git a/vault/identity_store_util.go b/vault/identity_store_util.go index 99e556ac9..53b347f4e 100644 --- a/vault/identity_store_util.go +++ b/vault/identity_store_util.go @@ -2080,9 +2080,10 @@ func (i *IdentityStore) handleAliasListCommon(ctx context.Context, groupAlias bo alias := raw.(*identity.Alias) aliasIDs = append(aliasIDs, alias.ID) aliasInfoEntry := map[string]interface{}{ - "name": alias.Name, - "canonical_id": alias.CanonicalID, - "mount_accessor": alias.MountAccessor, + "name": alias.Name, + "canonical_id": alias.CanonicalID, + "mount_accessor": alias.MountAccessor, + "custom_metadata": alias.CustomMetadata, } mi, ok := mountAccessorMap[alias.MountAccessor] diff --git a/vault/request_forwarding_service.pb.go b/vault/request_forwarding_service.pb.go index ecf5e0da9..40f696dad 100644 --- a/vault/request_forwarding_service.pb.go +++ b/vault/request_forwarding_service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0 +// protoc-gen-go v1.27.1 // protoc v3.17.3 // source: vault/request_forwarding_service.proto