@@ -31,6 +31,7 @@ type keyWriter interface {
31
31
type cloudProvider struct {
32
32
Name string
33
33
Project string
34
+ Self string
34
35
}
35
36
36
37
//datadog type
@@ -92,6 +93,7 @@ type googleAuthProvider struct {
92
93
tokenSource oauth2.TokenSource
93
94
}
94
95
96
+ //rotationCandidate type
95
97
type rotationCandidate struct {
96
98
key keys.Key
97
99
keyLocation keyLocations
@@ -160,7 +162,7 @@ func keyProviders(c config) (keyProviders []keys.Provider) {
160
162
//validateFlags returns an error that's not nil if provided string values fail
161
163
// a set of validation rules
162
164
func validateFlags (account , provider , project string ) (err error ) {
163
- if ( len (account ) > 0 && len (provider ) == 0 ) || ( len ( account ) == 0 && len ( provider ) > 0 ) {
165
+ if len (account ) > 0 && len (provider ) == 0 {
164
166
err = errors .New ("Both account AND provider flags must be set" )
165
167
return
166
168
}
@@ -171,6 +173,16 @@ func validateFlags(account, provider, project string) (err error) {
171
173
return
172
174
}
173
175
176
+ //keysOfProviders returns keys from all the configured providers that have passed
177
+ // through filtering
178
+ func keysOfProviders (c config ) (accountKeys []keys.Key , err error ) {
179
+ if accountKeys , err = keys .Keys (keyProviders (c )); err != nil {
180
+ return
181
+ }
182
+ logger .Infof ("Found %d keys in total" , len (accountKeys ))
183
+ return filterKeys (accountKeys , c , account )
184
+ }
185
+
174
186
func rotate () (err error ) {
175
187
defer logger .Sync ()
176
188
var c config
@@ -180,21 +192,18 @@ func rotate() (err error) {
180
192
if err = validateFlags (account , provider , project ); err != nil {
181
193
return
182
194
}
183
- var accountKeys []keys.Key
184
- if accountKeys , err = keys . Keys ( keyProviders ( c ) ); err != nil {
195
+ var providerKeys []keys.Key
196
+ if providerKeys , err = keysOfProviders ( c ); err != nil {
185
197
return
186
198
}
187
- logger .Infof ("Found %d keys in total" , len (accountKeys ))
188
- if accountKeys , err = filterKeys (accountKeys , c , account ); err != nil {
189
- return
190
- }
191
- logger .Infof ("Filtered down to %d keys based on current app config" , len (accountKeys ))
199
+ logger .Infof ("Filtered down to %d keys based on current app config" , len (providerKeys ))
192
200
if ! c .RotationMode {
193
- postMetric (accountKeys , c .DatadogAPIKey , c .Datadog )
201
+ postMetric (providerKeys , c .DatadogAPIKey , c .Datadog )
194
202
return
195
203
}
196
204
var rc []rotationCandidate
197
- if rc , err = rotationCandidates (accountKeys , c .AccountKeyLocations , c .Credentials , c .DefaultRotationAgeThresholdMins ); err != nil {
205
+ if rc , err = rotationCandidates (providerKeys , c .AccountKeyLocations ,
206
+ c .Credentials , c .DefaultRotationAgeThresholdMins ); err != nil {
198
207
return
199
208
}
200
209
logger .Infof ("Finalised %d keys that are candidates for rotation" , len (rc ))
@@ -350,6 +359,8 @@ func accountKeyLocation(account string,
350
359
return
351
360
}
352
361
362
+ //locationsToUpdate return a slice of structs that implement the keyWriter
363
+ // interface, based on the keyLocations supplied
353
364
func locationsToUpdate (keyLocation keyLocations ) (kws []keyWriter ) {
354
365
355
366
// read locations
@@ -395,6 +406,8 @@ func updateKeyLocation(keyLocations keyLocations, keyID, key, keyProvider string
395
406
return
396
407
}
397
408
409
+ //encryptedServiceAccountKey uses github.com/ovotech/mantle to encrypt the
410
+ // key string that's passed in
398
411
func encryptedServiceAccountKey (key , kmsKey string ) (encKey []byte , err error ) {
399
412
const singleLine = false
400
413
const disableValidation = true
@@ -407,27 +420,62 @@ func encryptedServiceAccountKey(key, kmsKey string) (encKey []byte, err error) {
407
420
return enc .CipherBytesFromPrimitives ([]byte (decodedKey ), singleLine , disableValidation , "" , "" , "" , "" , kmsKey ), nil
408
421
}
409
422
423
+ //validKey returns a bool reflecting whether the key is deemed to be valid, based
424
+ // on a number of provider-specific rules. E.g., if the provider is AWS, and
425
+ // not configured to include user keys, is the key a user key (and hence invalid)?
426
+ func validKey (key keys.Key , config config ) bool {
427
+ if key .Provider .Provider == "aws" {
428
+ return validAwsKey (key , config )
429
+ }
430
+ return true
431
+ }
432
+
410
433
//filterKeys returns a keys.Key slice created by filtering the provided
411
434
// keys.Key slice based on specific rules for each provider
412
- func filterKeys (keys []keys.Key , config config , account string ) (filteredKeys []keys.Key , err error ) {
413
- for _ , key := range keys {
435
+ func filterKeys (keysToFilter []keys.Key , config config , account string ) (filteredKeys []keys.Key , err error ) {
436
+ var selfKeys []keys.Key
437
+ for _ , key := range keysToFilter {
414
438
//valid bool is used to filter out keys early, e.g. if config says don't
415
439
//include AWS user keys, and the current key happens to be a user key
416
- valid := true
417
- if key .Provider .Provider == "aws" {
418
- valid = validAwsKey (key , config )
440
+ if ! validKey (key , config ) {
441
+ continue
419
442
}
420
443
var eligible bool
421
444
if eligible , err = filterKey (account , config , key ); err != nil {
422
445
return
423
446
}
424
- if valid && eligible {
425
- filteredKeys = append (filteredKeys , key )
447
+ if eligible {
448
+ //don't add the key to filteredKeys yet if it's deemed to be a 'self' key
449
+ // (i.e. the key belongs to the process performing this rotation)
450
+ if isSelf (config , key ) {
451
+ logger .Infow ("Key has been identified as a cloud-rotator key, so will be processed last" ,
452
+ "keyProvider" , key .Provider ,
453
+ "account" , key .Account )
454
+ selfKeys = append (selfKeys , key )
455
+ } else {
456
+ filteredKeys = append (filteredKeys , key )
457
+ }
426
458
}
427
459
}
460
+ //now add the 'self' keys
461
+ filteredKeys = append (filteredKeys , selfKeys ... )
428
462
return
429
463
}
430
464
465
+ //isSelf returns true iff the key provided matches the 'self' defined in the
466
+ // config.cloudProvider. This means the key is the one being used in the
467
+ // rotation process, and should probably be rotated last.
468
+ func isSelf (config config , key keys.Key ) bool {
469
+ for _ , cloudProvider := range config .CloudProviders {
470
+ if cloudProvider .Name == key .Provider .Provider &&
471
+ cloudProvider .Project == key .Provider .GcpProject &&
472
+ cloudProvider .Self == key .Account {
473
+ return true
474
+ }
475
+ }
476
+ return false
477
+ }
478
+
431
479
//filterKey returns a bool indicating whether the key is eligible for 'use'
432
480
func filterKey (account string , config config , key keys.Key ) (eligible bool , err error ) {
433
481
if len (account ) > 0 {
@@ -548,10 +596,7 @@ func commitSignKey(name, email, passphrase string) (entity *openpgp.Entity,
548
596
return
549
597
}
550
598
var reader * os.File
551
- // if reader, err = os.Open("/etc/cloud-key-rotator/akr.asc"); err != nil {
552
- // return
553
- // }
554
- if reader , err = os .Open ("./akr.asc" ); err != nil {
599
+ if reader , err = os .Open ("/etc/cloud-key-rotator/akr.asc" ); err != nil {
555
600
return
556
601
}
557
602
var entityList openpgp.EntityList
0 commit comments