1- using Google . Api . Gax . ResourceNames ;
2- using Google . Cloud . SecretManager . V1 ;
1+ using Google . Api . Gax ;
2+ using Google . Api . Gax . ResourceNames ;
33using Google . Cloud . ResourceManager . V3 ;
4-
5- using Microsoft . Extensions . Logging ;
6-
4+ using Google . Cloud . SecretManager . V1 ;
5+ using Google . Protobuf . Collections ;
6+ using Google . Protobuf . WellKnownTypes ;
77using Keyfactor . Logging ;
8-
8+ using Microsoft . Extensions . Logging ;
99using System ;
1010using System . Collections . Generic ;
1111using System . Linq ;
12- using Google . Api . Gax ;
13- using System . Xml . Linq ;
12+ using System . Reflection ;
13+ using System . Reflection . Metadata ;
1414
1515namespace Keyfactor . Extensions . Orchestrator . GCPSecretManager
1616{
@@ -80,16 +80,26 @@ public List<string> GetSecretNames()
8080 return rtnSecrets ;
8181 }
8282
83- public string GetCertificateEntry ( string name )
83+ public SecretWithLabels GetCertificateEntry ( string name )
8484 {
8585 _logger . MethodEntry ( LogLevel . Debug ) ;
8686
87- string rtnValue ;
87+ SecretWithLabels rtnValue = new SecretWithLabels ( ) ;
8888
8989 try
9090 {
9191 AccessSecretVersionResponse version = Client . AccessSecretVersion ( new AccessSecretVersionRequest ( ) { Name = name + "/versions/latest" } ) ;
92- rtnValue = version . Payload . Data . ToStringUtf8 ( ) ;
92+ rtnValue . Secret = version . Payload . Data . ToStringUtf8 ( ) ;
93+ rtnValue . Labels = string . Empty ;
94+
95+ Secret secret = GetSecret ( name ) ;
96+ List < string > labelsString = new List < string > ( ) ;
97+ foreach ( var label in secret . Labels )
98+ {
99+ labelsString . Add ( $ "{ label . Key } :{ label . Value } ") ;
100+ }
101+ if ( labelsString . Count > 0 )
102+ rtnValue . Labels = string . Join ( "," , labelsString . ToArray ( ) ) ;
93103 }
94104 catch ( Exception ex )
95105 {
@@ -104,21 +114,19 @@ public string GetCertificateEntry(string name)
104114 return rtnValue ;
105115 }
106116
107- public string GetSecret ( string alias )
117+ public Secret GetSecret ( string alias )
108118 {
109119 _logger . MethodEntry ( LogLevel . Debug ) ;
110120 string rtnValue = string . Empty ;
111121
112122 try
113123 {
114- var secret = Client . GetSecret (
124+ return Client . GetSecret (
115125 new GetSecretRequest ( )
116126 {
117127 SecretName = SecretName . FromProjectSecret ( ProjectId , alias )
118128 }
119129 ) ;
120-
121- rtnValue = secret . Name ;
122130 }
123131 catch ( Exception ex )
124132 {
@@ -129,14 +137,14 @@ public string GetSecret(string alias)
129137 {
130138 _logger . MethodExit ( LogLevel . Debug ) ;
131139 }
132-
133- return rtnValue ;
134140 }
135141
136- public void AddSecret ( string alias , string secretContent , bool entryExists )
142+ public bool AddSecret ( string alias , string secretContent , bool entryExists , string labels = null , List < ReplicationRegion > replicationRegions = null , TimeSpan ? ttlDuration = null , TimeSpan ? versionDestroyTtlDuration = null )
137143 {
138144 _logger . MethodEntry ( LogLevel . Debug ) ;
139145
146+ bool rtnWarning = false ;
147+
140148 try
141149 {
142150 SecretName secretName = new SecretName ( ProjectId , alias ) ;
@@ -149,12 +157,38 @@ public void AddSecret(string alias, string secretContent, bool entryExists)
149157 CreateSecretRequest secretRequest = new CreateSecretRequest ( ) ;
150158 secretRequest . ParentAsProjectName = new ProjectName ( ProjectId ) ;
151159 secretRequest . SecretId = alias ;
152- secretRequest . Secret = new Secret { Replication = new Replication { Automatic = new Replication . Types . Automatic ( ) } } ;
160+
161+ secretRequest . Secret = new Secret ( ) ;
162+ if ( ttlDuration . HasValue ) secretRequest . Secret . Ttl = Duration . FromTimeSpan ( ttlDuration . Value ) ;
163+ if ( versionDestroyTtlDuration . HasValue ) secretRequest . Secret . VersionDestroyTtl = Duration . FromTimeSpan ( versionDestroyTtlDuration . Value ) ;
164+ if ( replicationRegions == null || replicationRegions . Count == 0 )
165+ {
166+ secretRequest . Secret . Replication = new Replication { Automatic = new Replication . Types . Automatic ( ) } ;
167+ }
168+ else
169+ {
170+ secretRequest . Secret . Replication = new Replication { UserManaged = new Replication . Types . UserManaged ( ) } ;
171+
172+ foreach ( ReplicationRegion replicationRegion in replicationRegions )
173+ {
174+ Replication . Types . UserManaged . Types . Replica replica = new Replication . Types . UserManaged . Types . Replica ( ) ;
175+ replica . Location = replicationRegion . Region ;
176+ if ( replicationRegion . KmsKeyPath != null )
177+ replica . CustomerManagedEncryption = new CustomerManagedEncryption ( ) { KmsKeyName = replicationRegion . KmsKeyPath } ;
178+
179+ secretRequest . Secret . Replication . UserManaged . Replicas . Add ( replica ) ;
180+ }
181+ }
182+
183+ AssignLabels ( labels , secretRequest . Secret . Labels ) ;
153184
154185 Secret secret = Client . CreateSecret ( secretRequest ) ;
155186 }
156187
157188 //create new version
189+ ClearSecretFields ( alias , labels != null , ttlDuration . HasValue , versionDestroyTtlDuration . HasValue ) ;
190+ UpdateSecretFields ( alias , labels , ttlDuration , versionDestroyTtlDuration ) ;
191+
158192 AddSecretVersionRequest secretVersionRequest = new AddSecretVersionRequest ( ) ;
159193 secretVersionRequest . ParentAsSecretName = secretName ;
160194 secretVersionRequest . Payload = new SecretPayload { Data = Google . Protobuf . ByteString . CopyFromUtf8 ( secretContent ) } ;
@@ -170,6 +204,8 @@ public void AddSecret(string alias, string secretContent, bool entryExists)
170204 {
171205 _logger . MethodExit ( LogLevel . Debug ) ;
172206 }
207+
208+ return rtnWarning ;
173209 }
174210
175211 public void DeleteCertificate ( string name )
@@ -317,10 +353,10 @@ public List<TagValue> GetTagValues(string tagName)
317353 return rtnValues ;
318354 }
319355
320- public Dictionary < string , object > GetSecretTags ( string secretResource )
356+ public string GetSecretTags ( string secretResource )
321357 {
322358 _logger . MethodEntry ( LogLevel . Debug ) ;
323- Dictionary < string , object > rtnValue = new Dictionary < string , object > ( ) ;
359+ string rtnValue = string . Empty ;
324360 List < string > tagPairs = new List < string > ( ) ;
325361
326362 ListTagBindingsRequest request = new ListTagBindingsRequest ( )
@@ -349,7 +385,7 @@ public Dictionary<string, object> GetSecretTags(string secretResource)
349385 }
350386
351387 if ( tagPairs . Count > 0 )
352- rtnValue . Add ( "tags" , string . Join ( "," , tagPairs ) ) ;
388+ rtnValue = string . Join ( "," , tagPairs ) ;
353389
354390 return rtnValue ;
355391 }
@@ -364,7 +400,7 @@ public void SetSecretTag(string alias, string tagValue)
364400 {
365401 TagBinding = new TagBinding ( )
366402 {
367- Parent = $ "{ ResourcePrefix } { GetSecret ( alias ) } ",
403+ Parent = $ "{ ResourcePrefix } { GetSecret ( alias ) . Name } ",
368404 TagValue = tagValue
369405 }
370406 } ) ;
@@ -380,14 +416,121 @@ public void SetSecretTag(string alias, string tagValue)
380416 }
381417 }
382418
419+ public void ClearSecretFields ( string alias , bool clearLabels , bool clearTtl , bool clearVersionDestroyTtl )
420+ {
421+ _logger . MethodEntry ( LogLevel . Debug ) ;
422+
423+ Secret secret = new Secret { SecretName = new SecretName ( ProjectId , alias ) } ;
424+
425+ FieldMask updateMask = new FieldMask ( ) ;
426+ if ( clearLabels )
427+ {
428+ updateMask . Paths . Add ( "labels" ) ;
429+ secret . Labels . Clear ( ) ;
430+ }
431+
432+ if ( clearTtl )
433+ {
434+ updateMask . Paths . Add ( "ttl" ) ;
435+ secret . Ttl = null ;
436+ }
437+
438+ if ( clearVersionDestroyTtl )
439+ {
440+ updateMask . Paths . Add ( "version_destroy_ttl" ) ;
441+ secret . VersionDestroyTtl = null ;
442+ }
443+
444+ try
445+ {
446+ var updatedSecret = Client . UpdateSecret ( secret , updateMask ) ;
447+ }
448+ catch ( Exception ex )
449+ {
450+ _logger . LogError ( ex . Message ) ;
451+ throw ;
452+ }
453+ finally
454+ {
455+ _logger . MethodExit ( LogLevel . Debug ) ;
456+ }
457+ }
458+
459+ public void UpdateSecretFields ( string alias , string labels , TimeSpan ? ttlDuration , TimeSpan ? versionDestroyTtlDuration )
460+ {
461+ _logger . MethodEntry ( LogLevel . Debug ) ;
462+
463+ Secret secret = new Secret { SecretName = new SecretName ( ProjectId , alias ) } ;
464+
465+ FieldMask updateMask = new FieldMask ( ) ;
466+ if ( ! string . IsNullOrEmpty ( labels ) )
467+ {
468+ updateMask . Paths . Add ( "labels" ) ;
469+ AssignLabels ( labels , secret . Labels ) ;
470+ }
471+
472+ if ( ttlDuration . HasValue )
473+ {
474+ updateMask . Paths . Add ( "ttl" ) ;
475+ secret . Ttl = Duration . FromTimeSpan ( ttlDuration . Value ) ;
476+ }
477+
478+ if ( versionDestroyTtlDuration . HasValue )
479+ {
480+ updateMask . Paths . Add ( "version_destroy_ttl" ) ;
481+ secret . VersionDestroyTtl = Duration . FromTimeSpan ( versionDestroyTtlDuration . Value ) ;
482+ }
483+
484+ try
485+ {
486+ var updatedSecret = Client . UpdateSecret ( secret , updateMask ) ;
487+ }
488+ catch ( Exception ex )
489+ {
490+ _logger . LogError ( ex . Message ) ;
491+ throw ;
492+ }
493+ finally
494+ {
495+ _logger . MethodExit ( LogLevel . Debug ) ;
496+ }
497+ }
498+
383499 private string GetOrganizationFromProject ( )
384500 {
501+ _logger . MethodEntry ( LogLevel . Debug ) ;
502+
385503 string organization = string . Empty ;
386504
387- Project project = ProjectsClient . GetProject ( new GetProjectRequest ( ) { ProjectName = ProjectName . FromProject ( ProjectId ) } ) ;
388- organization = project . Parent ;
505+ try
506+ {
507+ Project project = ProjectsClient . GetProject ( new GetProjectRequest ( ) { ProjectName = ProjectName . FromProject ( ProjectId ) } ) ;
508+ organization = project . Parent ;
509+ }
510+ catch ( Exception ex )
511+ {
512+ _logger . LogError ( ex . Message ) ;
513+ throw ;
514+ }
515+ finally
516+ {
517+ _logger . MethodExit ( LogLevel . Debug ) ;
518+ }
389519
390520 return organization . Substring ( organization . IndexOf ( "/" ) + 1 ) ;
391521 }
522+
523+ private void AssignLabels ( string labels , MapField < string , string > labelMap )
524+ {
525+ List < ( string , string ) > labelsList = labels != null ? null :
526+ labels . Split ( ',' , StringSplitOptions . RemoveEmptyEntries )
527+ . Select ( pair => pair . Split ( ':' , 2 ) )
528+ . Where ( parts => parts . Length == 2 )
529+ . Select ( parts => ( Key : parts [ 0 ] . Trim ( ) , Value : parts [ 1 ] . Trim ( ) ) )
530+ . ToList ( ) ;
531+
532+ foreach ( var label in labelsList )
533+ labelMap [ label . Item1 ] = label . Item2 ;
534+ }
392535 }
393536}
0 commit comments