secret_config 0.9.1 → 0.10.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f21043b5cb86e83686e3e3cdb920c39bdd21c6c8e8dcfbd2d1cc34f81aef8e8c
4
- data.tar.gz: d932bca14ac864d3558e825ae226f227da60af5abe53f81dc601b05c2c51bfde
3
+ metadata.gz: 3379ac282a4a14c4b577024fbd417e94aaa498c974b5371026d5142515050810
4
+ data.tar.gz: f70b58807cfa0bbe3d668d975b1dba7ca4ee67126f7fe0b380a2b3b6e66c4cae
5
5
  SHA512:
6
- metadata.gz: d72ec54655bab806b3c1c7243fc033e529924f0024cae1c2f604904b3ea620e833e36744a1dfbbe8bb1b2d0c6d5fc0b644bb7477f7978c186fcbdca795596fb9
7
- data.tar.gz: cf24dc349803e4bd328fe471b0bcec0cd1f94b5b94b0261db990f4acab975494497b31044807f1fe87ba9d2ff5bb408db1674cedafad6676200c3de0904bc158
6
+ metadata.gz: 291fd4a292787ad879136b41511faebd7e9ad4e18caf071618d93c0b6ade144cfd4deab3e01313e81b130858d12037141a83bb99a9d516df316b57519beb12a9
7
+ data.tar.gz: 7eec020e42b794a3230dcff53bd6dde3ff67ae7bf4cc4dd8477d6ef13d7be4afead65cefaa337ac74abf8f85f1b9d30f1fb69c3821391c45e92aaa22b04c3a50
data/README.md CHANGED
@@ -5,834 +5,35 @@ Centralized Configuration and Secrets Management for Ruby and Rails applications
5
5
 
6
6
  Securely store configuration information centrally, supporting multiple tenants of the same application.
7
7
 
8
- ## v0.9 Upgrade Notes
9
-
10
- Note that the command line program name has changed from `secret_config` to `secret-config`.
11
- Be careful that the arguments have also changed. The arguments are now consistent across operations.
12
- The command line examples below have also been updated to reflect the changes.
13
-
14
- Please run `secret-config --help` to see the new arguments and updated operations.
15
-
16
- ## Overview
17
-
18
- Securely store centralized configuration information such as:
19
- * Settings
20
- * Passwords
21
- * Encryption keys and certificates
22
-
23
- ## Features
24
-
25
- Supports storing configuration information in:
26
- * File
27
- * Development and testing use.
28
- * Environment Variables
29
- * Environment Variables take precedence and can be used to override any setting.
30
- * AWS System Manager Parameter Store
31
- * Encrypt and securely store secrets such as passwords centrally.
32
-
33
- Since all values are stored as strings in the central directory or config file, the following type conversions
34
- are supported:
35
- * integer
36
- * float
37
- * string
38
- * boolean
39
- * symbol
40
- * json
41
-
42
- Supported conversions:
43
- * base64
44
-
45
- Arrays are also supported when the value contains a known separator by which to break down the values.
46
-
47
- ## Benefits
48
-
49
- Benefits of moving sensitive configuration information into AWS System Manager Parameter Store:
50
-
51
- * Hierarchical structure is maintained.
52
- * Environment variables force all config into a single level.
53
- * Reduces the number of environment variables.
54
- * In a large application the number of secrets can grow dramatically.
55
- * Replaces sensitive data stored in local yaml or configuration files.
56
- * Including securing and managing encryption keys.
57
- * When encryption keys change, such as during a key rotation, config files don't have to be changed.
58
- * Removes security concerns with placing passwords in the clear into environment variables.
59
- * AWS System Manager Parameter Store does not charge for parameters.
60
- * Still recommend using a custom KMS key that charges only $1 per month.
61
- * Amounts as of 4/2019. Confirm what AWS charges you for these services.
62
- * AWS Secrets Manager charges for every secret being managed, which can accumulate quickly with large projects.
63
- * Configure multiple distinct application instances to support multiple tenants.
64
- * For example, use separate databases with unique credentials for each tenant.
65
- * Separation of responsibilities is achieved since operations can manage production configuration.
66
- * Developers do not need to be involved with production configuration such as host names and passwords.
67
- * All values are encrypted by default when stored in the AWS Parameter Store.
68
- * Prevents accidentally not encrypting sensitive data.
69
-
70
- ## Introduction
71
-
72
- When Secret Config starts up it reads all configuration entries into memory for all keys under the configured path.
73
- This means that once Secret Config has initialized all calls to Secret Config are extremely fast.
74
-
75
- The in-memory copy of the registry can be refreshed at any time by calling `SecretConfig.refresh!`. It can be refreshed
76
- via a process signal, or by calling it through an event, or via a messaging system.
77
-
78
- It is suggested that any programmatic lookup to values stored in Secret Config are called every time a value is
79
- being used, rather than creating a local copy of the value. This ensures that a refresh of the registry will take effect
80
- immediately for any code reading from Secret Config.
81
-
82
- ## API
83
-
84
- When Secret Config starts up it reads all configuration entries immediately for all keys under the configured path.
85
- This means that once Secret Config has initialized all calls to Secret Config are extremely fast.
86
-
87
- Secret Config supports the following programmatic interface:
88
-
89
- ### Read values
90
-
91
- Fetch the value for the supplied key, returning nil if not found:
92
-
93
- ~~~ruby
94
- # Key is present:
95
- SecretConfig["logger/level"]
96
- # => "info"
97
-
98
- # Key is missing:
99
- SecretConfig["logger/blah"]
100
- # => nil
101
- ~~~
102
-
103
- Fetch the value for the supplied key, raising `SecretConfig::MissingMandatoryKey` if not found:
104
-
105
- ~~~ruby
106
- # Key is present:
107
- SecretConfig.fetch("logger/level")
108
- # => "info"
109
-
110
- # Key is missing:
111
- SecretConfig.fetch("logger/blah")
112
- # => SecretConfig::MissingMandatoryKey (Missing configuration value for /development/logger/blah)
113
- ~~~
114
-
115
- A default value can be supplied when the key is not found in the registry:
116
-
117
- ~~~ruby
118
- SecretConfig.fetch("logger/level", default: "info")
119
- # => "info"
120
- ~~~
121
-
122
- Since AWS SSM Parameter store and environment variables only support string values,
123
- it is neccessary to convert the string back to the type required by the program.
124
-
125
- The following types are supported:
126
- `:integer`
127
- `:float`
128
- `:string`
129
- `:boolean`
130
- `:symbol`
131
- `:json`
132
-
133
- ~~~ruby
134
- # Without type conversion:
135
- SecretConfig.fetch("symmetric_encryption/version")
136
- # => "0"
137
-
138
- # With type conversion:
139
- SecretConfig.fetch("symmetric_encryption/version", type: :integer)
140
- # => 0
141
- ~~~
142
-
143
- Sometimes it is useful to store arrays of values as a single key.
144
-
145
- ~~~ruby
146
- # Example: A list of host names could be stored as: "primary.example.net,secondary.example.net,backup.example.net"
147
- # To extract it as an array of strings:
148
- SecretConfig.fetch("address_services/hostnames", separator: ",")
149
- # => ["primary.example.net", "secondary.example.net", "backup.example.net"]
150
-
151
- # Example: A list of ports could be stored as: "12345,5343,26815"
152
- # To extract it as an array of Integers:
153
- SecretConfig.fetch("address_services/ports", type: :integer, separator: ",")
154
- # => [12345, 5343, 26815]
155
- ~~~
156
-
157
- When storing binary data, it should be encoded with strict base64 encoding. To automatically convert it back to binary
158
- specify the encoding as `:base64`
159
-
160
- ~~~ruby
161
- # Return a value that was stored in Base64 encoding format:
162
- SecretConfig.fetch("symmetric_encryption/iv")
163
- # => "FW+/wLubAYM+ZU0bWQj59Q=="
164
-
165
- # Base64 decode a value that was stored in Base64 encoding format:
166
- SecretConfig.fetch("symmetric_encryption/iv", encoding: :base64)
167
- # => "\x15o\xBF\xC0\xBB\x9B\x01\x83>eM\eY\b\xF9\xF5"
168
- ~~~
169
-
170
- ### Key presence
171
-
172
- Returns whether a key is present in the registry:
173
-
174
- ~~~ruby
175
- SecretConfig.key?("logger/level")
176
- # => true
177
- ~~~
178
-
179
- ### Write values
180
-
181
- When Secret Config is configured to use the AWS SSM Parameter store, its values can be modified:
182
-
183
- ~~~ruby
184
- SecretConfig["logger/level"] = "debug"
185
- ~~~
186
-
187
- ~~~ruby
188
- SecretConfig.set("logger/level", "debug")
189
- ~~~
190
-
191
- ### Configuration
192
-
193
- Returns a Hash copy of the configuration as a tree:
194
-
195
- ~~~ruby
196
- SecretConfig.configuration
197
- ~~~
198
-
199
- ### Refresh Configuration
200
-
201
- Tell Secret Config to refresh its in-memory copy of the configuration settings.
202
-
203
- ~~~ruby
204
- SecretConfig.refresh!
205
- ~~~
206
-
207
- Example, refresh the registry any time a SIGUSR2 is raised, add the following code on startup:
208
-
209
- ~~~ruby
210
- Signal.trap('USR2') do
211
- SecretConfig.refresh!
212
- end
213
- ~~~
214
-
215
- Then to make the process refresh it registry:
216
- ~~~shell
217
- kill -SIGUSR2 1234
218
- ~~~
219
-
220
- Where `1234` above is the process PID.
221
-
222
- ## Development and Test use
223
-
224
- In the development environment create the file `config/application.yml` within which to store local development credentials.
225
- Depending on your team setup you may want to use the same file for all developers so can check it into you change control system.
226
-
227
- For example: `config/application.yml`
228
-
229
- ~~~yaml
230
- development:
231
- mysql:
232
- database: secret_config_development
233
- username: secret_config
234
- password: secret_configrules
235
- host: 127.0.0.1
236
-
237
- mongo:
238
- database: secret_config_development
239
- primary: 127.0.0.1:27017
240
- secondary: 127.0.0.1:27018
241
-
242
- secrets:
243
- secret_key_base: somereallylongstring
244
-
245
- test:
246
- mysql:
247
- database: secret_config_test
248
- username: secret_config
249
- password: secret_configrules
250
- host: 127.0.0.1
251
-
252
- mongo:
253
- database: secret_config_test
254
- primary: 127.0.0.1:27017
255
- secondary: 127.0.0.1:27018
256
-
257
- secrets:
258
- secret_key_base: somereallylongteststring
259
- ~~~
260
-
261
- Note how the hierarchical nature of configuration values is maintained. Typical environment variable approaches have
262
- to flatten everything into a single level.
263
-
264
- Note: Do not put any production credentials into this file.
265
-
266
- ### Environment Variables
267
-
268
- Any of the above values can be overridden with an environment variable, unless explicitly configured `SecretConfig.check_env_var = false`.
269
-
270
- To overwrite any of these settings with an environment variable:
271
-
272
- * Join the keys together with an '_'
273
- * Convert to uppercase
274
-
275
- For example, `mysql/host` can be overridden with the env var:
276
-
277
- export MYSQL_HOST=test.server
278
-
279
- ### Applying to existing config files
280
-
281
- Go through all the configuration files and look for sensitive data such as passwords:
282
-
283
- Example, an unchanged common `database.yml`:
284
-
285
- ~~~yaml
286
- defaults: &defaults
287
- encoding: utf8
288
- adapter: mysql2
289
-
290
- development:
291
- <<: *defaults
292
- database: secure_config_development
293
- username: jack
294
- password: jackrules
295
- host: localhost
296
-
297
- test:
298
- <<: *defaults
299
- database: secure_config_test
300
- username: tester
301
- password: khjsdjhdsjhdsr32
302
- host: test.server
303
-
304
- production:
305
- <<: *defaults
306
- database: secure_config_production
307
- username: product
308
- password: donotexpose45
309
- host: production.server
310
- ~~~
311
-
312
- Replace the sensitive data with a `SecureConfig.fetch`:
313
-
314
- Updated `database.yml`:
315
-
316
- ~~~yaml
317
- configuration: &configuration
318
- database: <%= SecretConfig.fetch("mysql/database") %>
319
- username: <%= SecretConfig.fetch("mysql/username") %>
320
- password: <%= SecretConfig.fetch("mysql/password") %>
321
- host: <%= SecretConfig.fetch("mysql/host") %>
322
- encoding: utf8
323
- adapter: mysql2
324
-
325
- development:
326
- <<: *configuration
327
-
328
- test:
329
- <<: *configuration
330
-
331
- production:
332
- <<: *configuration
333
- ~~~
334
-
335
- Since the secrets are externalized the configuration between environments is simpler.
336
-
337
- ### Replacing custom config files
338
-
339
- When writing new components or gems, instead of requiring a proprietary config file, refer
340
- to the settings programmatically:
341
-
342
- For example, somewhere in your codebase you need a persistent http connection:
343
-
344
- ~~~ruby
345
- def http_client
346
- @http_client ||=
347
- PersistentHTTP.new(
348
- name: 'HTTPClient',
349
- url: SecretConfig.fetch('http_client/url'),
350
- logger: logger,
351
- pool_size: SecretConfig.fetch('http_client/pool_size', type: :integer, default: 10),
352
- warn_timeout: SecretConfig.fetch('http_client/warn_timeout', type: :float, default: 0.25),
353
- open_timeout: SecretConfig.fetch('http_client/open_timeout', type: :float, default: 30),
354
- read_timeout: SecretConfig.fetch('http_client/read_timeout', type: :float, default: 30),
355
- force_retry: true
356
- )
357
- end
358
- ~~~
359
-
360
- Then the application that uses the above library / gem just needs to add the relevant entries to their
361
- `application.yml` file:
362
-
363
- ~~~yaml
364
- http_client:
365
- url: https://test.example.com
366
- pool_size: 20
367
- read_timeout: 300
368
- ~~~
369
-
370
- This avoids a custom config file just for the above library.
371
-
372
- Additionally the values can be overridden with environment variables at any time:
373
-
374
- export HTTP_CLIENT_URL=https://production.example.com
375
-
376
- ## Configuration
377
-
378
- Add the following line to Gemfile
379
-
380
- gem "secret_config"
381
-
382
- Out of the box Secret Config will look in the local file system for the file `config/application.yml`
383
- as covered above. By default it will use env var `RAILS_ENV` to define the path to look under for settings.
384
-
385
- The default settings are great for getting started in development and test, but should not be used in production.
8
+ Checkout https://config.rocketjob.io/
386
9
 
387
- To ensure Secret Config is configured and available for use within any of the config files, add
388
- the following lines to the very top of `application.rb` under the line `class Application < Rails::Application`:
10
+ ## Documentation
389
11
 
390
- ~~~ruby
391
- module MyApp
392
- class Application < Rails::Application
12
+ * [Guide](https://config.rocketjob.io/)
393
13
 
394
- # Add the following lines to configure Secret Config:
395
- if Rails.env.development? || Rails.env.test?
396
- # Use 'config/application.yml'
397
- config.secret_config.use :file
398
- else
399
- # Read configuration from AWS SSM Parameter Store
400
- config.secret_config.use :ssm, path: "/#{Rails.env}/my_app"
401
- end
14
+ ## Support
402
15
 
403
- # ....
404
- end
405
- end
406
- ~~~
16
+ * Questions? Join the chat room on Gitter for [rocketjob support](https://gitter.im/rocketjob/support)
17
+ * [Report bugs](https://github.com/rocketjob/secret_config/issues)
407
18
 
408
- `path` is the path from which the configuration data will be read. This path uniquely identifies the
409
- configuration for this instance of the application. In the example above it uses the rails env and application name
410
- by default. This can be overridden using the `SECRET_CONFIG_PATH` environment variable when needed.
19
+ ## v0.10 Upgrade Notes
411
20
 
412
- By placing the secret config configuration as the very first configuration item, it allows any subsequent
413
- configuration item to access the centralized configuration in AWS System Manager Parameter Store.
21
+ String interpolation has been changed to use `$` instead of `%`. Please change
22
+ all interpolated strings to use `$` before upgrading.
414
23
 
415
- The environment variable `SECRET_CONFIG_PROVIDER` can be used to override the provider when needed.
416
- For example:
417
- `export SECRET_CONFIG_PROVIDER=ssm`
418
- Or,
419
- `export SECRET_CONFIG_PROVIDER=file`
24
+ Example: `%{date}` needs to be changed to `${date}`
420
25
 
421
- If we need 2 completely separate instances of the application running in a single AWS account then we could use
422
- multiple paths. For example:
423
-
424
- /production1/my_application
425
- /production2/my_application
426
-
427
- /production/instance1/my_application
428
- /production/instance2/my_application
429
-
430
- The `path` is completely flexible, but must be unique for every AWS account under which the application will run.
431
- The same `path` can be used in different AWS accounts though. It is also not replicated across regions.
432
-
433
- When writing settings to the parameter store, it is recommended to use a custom KMS key to encrypt the values, if you don't specify a key ID, the system uses the default key associated with your AWS account `alias/aws/ssm`.
434
- To supply the key to encrypt the values with, add the `key_id` parameter:
435
-
436
- ~~~ruby
437
- module MyApp
438
- class Application < Rails::Application
439
-
440
- # Add the following lines to configure Secret Config:
441
- if Rails.env.development? || Rails.env.test?
442
- # Use 'config/application.yml'
443
- config.secret_config.use :file
444
- else
445
- # Read configuration from AWS SSM Parameter Store
446
- config.secret_config.use :ssm,
447
- path: "/#{Rails.env}/my_app",
448
- key_id: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
449
- end
450
-
451
- # ....
452
- end
453
- end
454
- ~~~
455
-
456
- Note: The relevant KMS key must be created first prior to using it here.
457
-
458
- `ssm` provider supports various configuration parameters that can be provided as keyword arguments for `config.secret_config.use :ssm, path, **args`
459
-
460
- Args hash:
461
- * **:key_id** (String) - The `key_id` is only used when writing settings to the AWS Parameter store and can be left off when that instance will only read from the parameter store. Can be configred with environment variable `SECRET_CONFIG_KEY_ID`.
462
- * **:retry_count** (Integer, default=10) - Max number of retries in case of execution failure.
463
- * **:retry_max_ms** (Integer, default=3_000) - Interval in ms between retries, `sleep` is used to facilitate throttling.
464
- * any options suported by [Aws::SSM::Client](https://docs.aws.amazon.com/sdkforruby/api/Aws/SSM/Client.html#initialize-instance_method) e.g. **:credentials**:
465
- ~~~ruby
466
- config.secret_config.use :ssm,
467
- path: "/#{Rails.env}/my_app",
468
- key_id: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
469
- credentials: Aws::AssumeRoleCredentials.new(
470
- role_arn: "arn:aws:iam::111111122222222:role/assume_role_name",
471
- role_session_name: "session-name-to-identify-#{SecureRandom.uuid}"
472
- ))
473
- ~~~
474
-
475
- ### Secret Config Environment variables
476
-
477
- Priority describes when environment variable is used as a default value, preceds configuration value or overrides.
478
-
479
- Name | Desctiption | Priority
480
- ------------------------- | --------------------------------------------------------------- | --------
481
- `SECRET_CONFIG_PATH` | path from which the configuration data will be read | precede
482
- `SECRET_CONFIG_PROVIDER` | override the provider configured for `config.secret_config.use` | override
483
- `SECRET_CONFIG_KEY_ID` | encryption `key_id` | default
484
- `SECRET_CONFIG_ACCOUNT_ID`| used in `rspec` to configure AWS Account Id for role assuming | required
485
-
486
- ### Shared configuration for development and test
487
-
488
- When running multiple engines or private "gems" inside the same code repository, the development and test
489
- configuration file `application.yml` can be shared. Update the lines above to:
490
-
491
- ~~~ruby
492
- module MyApp
493
- class Application < Rails::Application
494
-
495
- # Add the following lines:
496
- if Rails.env.development? || Rails.env.test?
497
- # Use 'config/application.yml'
498
- config.secret_config.use :file
499
- else
500
- # Read configuration from AWS SSM Parameter Store
501
- config.secret_config.use :ssm, path: "/#{Rails.env}/my_app"
502
- end
503
-
504
- # ....
505
- end
506
- end
507
- ~~~
508
-
509
- Where `file_name` is the full path and filename for where `application.yml` is located.
510
-
511
- ### Authorization
512
-
513
- The following policy needs to be added to the IAM Group under which the application will be running:
514
-
515
- ~~~json
516
- {
517
- "Version": "2012-10-17",
518
- "Statement": [
519
- {
520
- "Sid": "VisualEditor0",
521
- "Effect": "Allow",
522
- "Action": [
523
- "ssm:GetParametersByPath",
524
- "ssm:PutParameter",
525
- "ssm:DeleteParameter",
526
- ],
527
- "Resource": "*"
528
- }
529
- ]
530
- }
531
- ~~~
532
-
533
- The above policy restricts read and write access to just the Parameter Store capabilities of AWS System Manager.
534
-
535
- These additional Actions are not used by Secret Config, but may be useful for anyone using the AWS Console directly
536
- to view and modify parameters:
537
- - `ssm:DescribeParameters`
538
- - `ssm:GetParameterHistory`
539
- - `ssm:GetParameters`
540
- - `ssm:GetParameter`
541
-
542
- ## String Interpolation
543
-
544
- Values supplied for config settings can be replaced inline with date, time, hostname, pid and random values.
545
-
546
- For example to include the `hostname` in the log file name setting:
547
-
548
- ~~~yaml
549
- development:
550
- logger:
551
- level: info
552
- file_name: /var/log/my_application_%{hostname}.log
553
- ~~~
554
-
555
- Available interpolations:
556
-
557
- * %{date}
558
- * Current date in the format of "%Y%m%d" (CCYYMMDD)
559
- * %{date:format}
560
- * Current date in the supplied format. See strftime
561
- * %{time}
562
- * Current date and time down to ms in the format of "%Y%m%d%Y%H%M%S%L" (CCYYMMDDHHMMSSmmm)
563
- * %{time:format}
564
- * Current date and time in the supplied format. See strftime
565
- * %{env:name}
566
- * Extract value from the named environment variable.
567
- * %{hostname}
568
- * Full name of this host.
569
- * %{hostname:short}
570
- * Short name of this host. Everything up to the first period.
571
- * %{pid}
572
- * Process Id for this process.
573
- * %{random}
574
- * URL safe Random 32 byte value.
575
- * %{random:size}
576
- * URL safe Random value of `size` bytes.
577
-
578
- #### Notes:
579
-
580
- * To prevent interpolation use %%{...}
581
- * %% is not touched, only %{...} is searched for.
582
- * Since these interpolations are only evaluated at load time and
583
- every time the registry is refreshed there is no runtime overhead when keys are fetched.
584
-
585
- ## Command Line Interface
586
-
587
- Secret Config has a command line interface for exporting, importing and copying between paths in the registry.
588
-
589
- ~~~
590
- secret-config [options]
591
- -e, --export SOURCE_PATH Export configuration. Use --file to specify the file name, otherwise stdout is used.
592
- -i, --import TARGET_PATH Import configuration. Use --file to specify the file name, --path for the SOURCE_PATH, otherwise stdin is used.
593
- --file FILE_NAME Import/Export/Diff to/from this file.
594
- -p, --path PATH Import/Export/Diff to/from this path.
595
- --diff TARGET_PATH Compare configuration to this path. Use --file to specify the source file name, --path for the SOURCE_PATH, otherwise stdin is used.
596
- -s, --set KEY=VALUE Set one key to value. Example: --set mysql/database=localhost
597
- -f, --fetch KEY Fetch the value for one setting. Example: --fetch mysql/database.
598
- -d, --delete KEY Delete one specific key.
599
- -r, --delete-tree PATH Recursively delete all keys under the specified path.
600
- -c, --console Start interactive console.
601
- --provider PROVIDER Provider to use. [ssm | file]. Default: ssm
602
- --no-filter For --export only. Do not filter passwords and keys.
603
- --interpolate For --export only. Evaluate string interpolation and __import__.
604
- --prune For --import only. During import delete all existing keys for which there is no key in the import file. Only works with --import.
605
- --force For --import only. Overwrite all values, not just the changed ones. Useful for changing the KMS key.
606
- --key_id KEY_ID For --import only. Encrypt config settings with this AWS KMS key id. Default: AWS Default key.
607
- --key_alias KEY_ALIAS For --import only. Encrypt config settings with this AWS KMS alias.
608
- --random_size INTEGER For --import only. Size to use when generating random values when $(random) is encountered in the source. Default: 32
609
- -v, --version Display Secret Config version.
610
- -h, --help Prints this help.
611
- ~~~
612
-
613
- ### CLI Examples
614
-
615
- #### Import from a file into SSM parameters
616
-
617
- To get started it is useful to create a YAML file with all the relevant settings and then import
618
- it into AWS SSM Parameter store. This file is the same as `applcation.yml` except that each file
619
- is just for one environment. I.e. It does not contain the `test` or `development` root level entries.
620
-
621
- For example: `production.yml`
622
-
623
- ~~~yaml
624
- mysql:
625
- database: secret_config_production
626
- username: secret_config
627
- password: secret_configrules
628
- host: mysql_server.example.net
629
-
630
- mongo:
631
- database: secret_config_production
632
- primary: mongo_primary.example.net:27017
633
- secondary: mongo_secondary.example.net:27017
634
-
635
- secrets:
636
- secret_key_base: somereallylongproductionstring
637
- ~~~
638
-
639
- Import a yaml file, into a path in AWS SSM Parameter Store:
640
-
641
- secret-config --import /production/my_application --file production.yml
642
-
643
- Import a yaml file, into a path in AWS SSM Parameter Store, using a custom KMS key to encrypt the values:
644
-
645
- secret-config --import /production/my_application --file production.yml --key_id "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
646
-
647
- Import a yaml file, into a path in AWS SSM Parameter Store, using a custom KMS key alias to encrypt the values:
648
-
649
- secret-config --import /production/my_application --file production.yml --key_alias my_key_alias
650
-
651
- #### Diff
652
-
653
- Before importing a new config file into the AWS SSM Parameter store, a diff can be performed to determine
654
- what the differences are that will be applied when the import is run with the `--prune` option.
655
-
656
- secret-config --diff /production/my_application --file production.yml
657
-
658
- Key:
659
-
660
- + Adding a new key to the registry.
661
- - The key will be removed from the registry during the import if --prune is specified.
662
- * The value for that key will change during an import.
663
-
664
- #### Export SSM parameters
665
-
666
- In AWS SSM Parameter store it can be difficult to
667
- Export the values from a specific path into a yaml or json file so that they are easier to read.
668
-
669
- Export from a path in AWS SSM Parameter Store to a yaml file, where passwords are filtered:
670
-
671
- secret-config --export /production/my_application --file production.yml
672
-
673
- Export from a path in AWS SSM Parameter Store to a yaml file, _without_ filtering out passwords:
674
-
675
- secret-config --export /production/my_application --file production.yml --no-filter
676
-
677
- Export from a path in AWS SSM Parameter Store to a json file, where passwords are filtered:
678
-
679
- secret-config --export /production/my_application --file production.json
680
-
681
- #### Copy values between paths in AWS SSM parameter store
682
-
683
- It can be useful to keep a "master" copy of the values for an environment or stack in a custom path
684
- in AWS Parameter Store. Then for each stack or environment that is spun up, copy the "master" / "common" values
685
- into the new path. Once copied the values specific to that path can be updated accordingly.
686
-
687
- Import configuration from an existing path in AWS SSM Parameter Store into another:
688
-
689
- secret-config --import /tenant73/my_application --path /production/my_application
690
-
691
- #### Generating random passwords
692
-
693
- In the multi-tenant example above, we may want to generate a secure random password for each tenant.
694
- In the source file or registry, set the value to `$random`, this will ensure that during the `import`
695
- that the destination will receive a secure random value.
696
-
697
- By default the length of the randomized value is 32 bytes, use `--random_size` to adjust the length of
698
- the randomized string.
699
-
700
- ## Docker
701
-
702
- Secret Config is at its best when the application is containerized. By externalizing the configuration the same
703
- docker container can be tested in one or more environments and then deployed directly to production without
704
- any changes. The only difference being the path that container uses to read its configuration from.
705
-
706
- Another important benefit is that the docker image does not contain any production or test credentials since
707
- these are all stored in AWS SSM Parameter Store.
708
-
709
- When a Ruby / Rails application is using Secret Config for its configuration settings, it only requires the
710
- following environment variables when starting up the container in for example AWS ECS or AWS Fargate:
711
-
712
- ~~~shell
713
- export SECRET_CONFIG_PATH=/production/my_application
714
- ~~~
715
-
716
- For rails applications, typically the `RAILS_ENV` is also needed, but not required for Secret Config.
717
-
718
- ~~~shell
719
- export RAILS_ENV=production
720
- ~~~
721
-
722
- ### Logging
723
-
724
- When using Semantic Logger, the following code could be added to `application.rb` to facilitate configuration
725
- of the logging output via Secret Config:
726
-
727
- ~~~ruby
728
- # Logging
729
- config.log_level = config.secret_config.fetch("logger/level", default: :info, type: :symbol)
730
- config.semantic_logger.backtrace_level = config.secret_config.fetch("logger/backtrace_level", default: :error, type: :symbol)
731
- config.semantic_logger.application = config.secret_config.fetch("logger/application", default: "my_app")
732
- config.semantic_logger.environment = config.secret_config.fetch("logger/environment", default: Rails.env)
733
- ~~~
734
-
735
- In any environment the log level can be changed, for example set `logger/level` to `debug`. And it can be changed
736
- in the AWS SSM Parameter Store, or directly with the environment variable `export LOGGER_LEVEL=debug`
737
-
738
- `logger/environment` can be used to identify which tenant the log messages are emanating from. By default it is just
739
- the rails environment. For example set `logger/environment` to `tenant73`.
740
-
741
- Additionally the following code can be used with containers to send log output to standard out:
742
-
743
- ~~~ruby
744
- destination = config.secret_config.fetch("logger/destination", default: :file, type: :symbol)
745
- if destination == :stdout
746
- STDOUT.sync = true
747
- config.rails_semantic_logger.add_file_appender = false
748
- config.semantic_logger.add_appender(
749
- io: STDOUT,
750
- level: config.log_level,
751
- formatter: config.secret_config.fetch("logger/formatter", default: :default, type: :symbol)
752
- )
753
- end
754
- ~~~
755
-
756
- Specifically for docker containers it is necessary to turn off file logging and turn on logging to standard out
757
- so that AWS Cloud Watch can pick up the log data.
758
-
759
- To start with `logger/destination` of `stdout` will work with regular non-colorized output. When feeding the
760
- log output into something that can process JSON, set `logger/formatter` to `json`.
761
-
762
- The benefit with the above approach is that a developer can pull the exact same container image that is running
763
- in production and configure it to run locally on their laptop. For example, set `logger/destination` to `file`.
764
-
765
- The above code can be modified as necessary to add any Semantic Logger appender to write directly to external
766
- centralized logging systems, instead of writing to standard out or local files.
767
-
768
- ### Email Server and Assets
769
-
770
- An example of how to setup the email server and the assets for html emails. Add to `application.rb`:
771
-
772
- ~~~ruby
773
- # Emails
774
- application_url = config.secret_config.fetch("emails/asset_host")
775
- uri = URI.parse(application_url)
776
-
777
- config.action_mailer.default_url_options = {host: uri.host, protocol: uri.scheme}
778
- config.action_mailer.asset_host = application_url
779
- config.action_mailer.smtp_settings = {address: config.secret_config.fetch("emails/smtp/address", default: "localhost")}
780
- config.action_mailer.raise_delivery_errors = config.secret_config.fetch("emails/raise_delivery_errors", default: true, type: :boolean)
781
- ~~~
782
-
783
- ### Symmetric Encryption
784
-
785
- An example of how to setup Symmetric Encryption. Add to `application.rb`:
786
-
787
- ~~~ruby
788
- # Encryption
789
- config.symmetric_encryption.cipher =
790
- SymmetricEncryption::Cipher.new(
791
- key: config.secret_config.fetch('symmetric_encryption/key', encoding: :base64),
792
- iv: config.secret_config.fetch('symmetric_encryption/iv', encoding: :base64),
793
- version: config.secret_config.fetch('symmetric_encryption/version', type: :integer),
794
- )
795
-
796
- # Also support one prior encryption key version during key rotation
797
- if config.secret_config.key?('symmetric_encryption/old/key')
798
- SymmetricEncryption.secondary_ciphers = [
799
- SymmetricEncryption::Cipher.new(
800
- key: config.secret_config.fetch('symmetric_encryption/old/key', encoding: :base64),
801
- iv: config.secret_config.fetch('symmetric_encryption/old/iv', encoding: :base64),
802
- version: config.secret_config.fetch('symmetric_encryption/old/version', type: :integer),
803
- ),
804
- ]
805
- end
806
- ~~~
807
-
808
- Using this approach the file `config/symmetric-encryption.yml` can be removed once the keys have been moved to
809
- the registry.
810
-
811
- To extract existing keys from the config file so that they can be imported into the registry,
812
- run the code below inside a console in each of the respective environments.
813
-
814
- ~~~ruby
815
- require "yaml"
816
- require "base64"
817
-
818
- def se_config(cipher)
819
- {
820
- "key" => Base64.strict_encode64(cipher.send(:key)),
821
- "iv" => Base64.strict_encode64(cipher.iv),
822
- "version" => cipher.version
823
- }
824
- end
26
+ ## v0.9 Upgrade Notes
825
27
 
826
- config = { "symmetric_encryption" => se_config(SymmetricEncryption.cipher) }
827
- if cipher = SymmetricEncryption.secondary_ciphers.first
828
- config["symmetric_encryption"]["old"] = se_config(cipher)
829
- end
830
- puts config.to_yaml
831
- ~~~
28
+ Note that the command line program name has changed from `secret_config` to `secret-config`.
29
+ Be careful that the arguments have also changed. The arguments are now consistent across operations.
30
+ The command line examples below have also been updated to reflect the changes.
31
+
32
+ Please run `secret-config --help` to see the new arguments and updated operations.
832
33
 
833
34
  ## Versioning
834
35
 
835
- This project adheres to [Semantic Versioning](http://semver.org/).
36
+ This project adheres to [Semantic Versioning](https://semver.org/).
836
37
 
837
38
  ## Author
838
39
 
@@ -840,7 +41,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
840
41
 
841
42
  ## License
842
43
 
843
- Copyright 2019 Reid Morrison
44
+ Copyright 2020 Reid Morrison
844
45
 
845
46
  Licensed under the Apache License, Version 2.0 (the "License");
846
47
  you may not use this file except in compliance with the License.
@@ -97,5 +97,5 @@ module SecretConfig
97
97
  end
98
98
 
99
99
  @check_env_var = true
100
- @filters = [/password/i, /key\Z/i, /passphrase/i]
100
+ @filters = [/password/i, /key\Z/i, /passphrase/i, /secret/i, /pwd\Z/i]
101
101
  end
@@ -210,7 +210,13 @@ module SecretConfig
210
210
  begin
211
211
  case provider
212
212
  when :ssm
213
- Providers::Ssm.new(key_id: key_id, key_alias: key_alias)
213
+ if key_alias
214
+ Providers::Ssm.new(key_alias: key_alias)
215
+ elsif key_id
216
+ Providers::Ssm.new(key_id: key_id)
217
+ else
218
+ Providers::Ssm.new
219
+ end
214
220
  else
215
221
  raise ArgumentError, "Invalid provider: #{provider}"
216
222
  end
@@ -15,7 +15,7 @@ module SecretConfig
15
15
  # Keys are returned with path names relative to the supplied path.
16
16
  def parse(key, value)
17
17
  relative_key = relative_key?(key) ? key : key.sub("#{path}/", "")
18
- value = interpolator.parse(value) if interpolator && value.is_a?(String) && value.include?("%{")
18
+ value = interpolator.parse(value) if interpolator && value.is_a?(String) && value.include?("${")
19
19
  tree[relative_key] = value
20
20
  end
21
21
 
@@ -4,16 +4,16 @@ require "securerandom"
4
4
  # * SecretConfig Interpolations
5
5
  #
6
6
  # Expanding values inline for date, time, hostname, pid and random values.
7
- # %{date} # Current date in the format of "%Y%m%d" (CCYYMMDD)
8
- # %{date:format} # Current date in the supplied format. See strftime
9
- # %{time} # Current date and time down to ms in the format of "%Y%m%d%Y%H%M%S%L" (CCYYMMDDHHMMSSmmm)
10
- # %{time:format} # Current date and time in the supplied format. See strftime
11
- # %{env:name} # Extract value from the named environment value.
12
- # %{hostname} # Full name of this host.
13
- # %{hostname:short} # Short name of this host. Everything up to the first period.
14
- # %{pid} # Process Id for this process.
15
- # %{random} # URL safe Random 32 byte value.
16
- # %{random:size} # URL safe Random value of `size` bytes.
7
+ # ${date} # Current date in the format of "%Y%m%d" (CCYYMMDD)
8
+ # ${date:format} # Current date in the supplied format. See strftime
9
+ # ${time} # Current date and time down to ms in the format of "%Y%m%d%Y%H%M%S%L" (CCYYMMDDHHMMSSmmm)
10
+ # ${time:format} # Current date and time in the supplied format. See strftime
11
+ # ${env:name} # Extract value from the named environment value.
12
+ # ${hostname} # Full name of this host.
13
+ # ${hostname:short} # Short name of this host. Everything up to the first period.
14
+ # ${pid} # Process Id for this process.
15
+ # ${random} # URL safe Random 32 byte value.
16
+ # ${random:size} # URL safe Random value of `size` bytes.
17
17
  module SecretConfig
18
18
  class SettingInterpolator < StringInterpolator
19
19
  def date(format = "%Y%m%d")
@@ -1,4 +1,4 @@
1
- # Parse strings containing %{key:value1,value2,value3}
1
+ # Parse strings containing ${key:value1,value2,value3}
2
2
  # Where `key` is a method implemented by a class inheriting from this class
3
3
  #
4
4
  # The following `key`s are reserved:
@@ -6,20 +6,20 @@
6
6
  # * initialize
7
7
  #
8
8
  # Notes:
9
- # * To prevent interpolation use %%{...}
10
- # * %% is not touched, only %{...} is identified.
9
+ # * To prevent interpolation use $${...}
10
+ # * $$ is not touched, only ${...} is identified.
11
11
  module SecretConfig
12
12
  class StringInterpolator
13
13
  def initialize(pattern = nil)
14
- @pattern = pattern || /%{1,2}\{([^}]+)\}/
14
+ @pattern = pattern || /\${1,2}\{([^}]+)\}/
15
15
  end
16
16
 
17
17
  def parse(string)
18
- string.gsub(/%{1,2}\{([^}]+)\}/) do |match|
19
- if match.start_with?("%%")
18
+ string.gsub(/\${1,2}\{([^}]+)\}/) do |match|
19
+ if match.start_with?("$$")
20
20
  match[1..-1]
21
21
  else
22
- expr = Regexp.last_match(1) || Regexp.last_match(2) || match.tr("%{}", "")
22
+ expr = Regexp.last_match(1) || Regexp.last_match(2) || match.tr("${}", "")
23
23
  key, args_str = expr.split(":")
24
24
  key = key.strip.to_sym
25
25
  arguments = args_str&.split(",")&.map { |v| v.strip == "" ? nil : v.strip } || []
@@ -1,3 +1,3 @@
1
1
  module SecretConfig
2
- VERSION = "0.9.1".freeze
2
+ VERSION = "0.10.1".freeze
3
3
  end
@@ -45,7 +45,7 @@ test:
45
45
  mongo:
46
46
  database: secret_config_test
47
47
  primary: 127.0.0.1:27017
48
- secondary: "%{hostname}:27018"
48
+ secondary: "${hostname}:27018"
49
49
 
50
50
  secrets:
51
51
  secret_key_base: somereallylongteststring
@@ -59,15 +59,15 @@ test:
59
59
  key: key0
60
60
 
61
61
  mysql:
62
- # database: "%{fetch: /test/my_application/mysql/database }"
62
+ # database: "${fetch: /test/my_application/mysql/database }"
63
63
  username: other
64
64
  password: otherrules
65
- host: "%{hostname}"
65
+ host: "${hostname}"
66
66
 
67
67
  mongo:
68
68
  database: secret_config_test
69
69
  primary: localhost:27017
70
- secondary: "%{hostname}:27018"
70
+ secondary: "${hostname}:27018"
71
71
 
72
72
  mongo2:
73
73
  __import__: mongo
@@ -26,7 +26,7 @@ class ParserTest < Minitest::Test
26
26
  #
27
27
  # Retrieve values elsewhere in the registry.
28
28
  # Paths can be relative to the current root, or absolute paths outside the current root.
29
- # %{fetch:key} # Fetches a single value from a relative or absolute path
29
+ # ${fetch:key} # Fetches a single value from a relative or absolute path
30
30
  # Return the value of the supplied key.
31
31
  #
32
32
  # With a relative key, look for the value in the current registry.
@@ -47,7 +47,7 @@ class ParserTest < Minitest::Test
47
47
  # end
48
48
  # end
49
49
 
50
- # %{import:path} # Imports a path of keys and values into the current path
50
+ # ${import:path} # Imports a path of keys and values into the current path
51
51
  # Replace the current value with a tree of values with the supplied path.
52
52
  #
53
53
  describe "#import" do
@@ -15,7 +15,7 @@ module Providers
15
15
  {
16
16
  "/test/my_application/mongo/database" => "secret_config_test",
17
17
  "/test/my_application/mongo/primary" => "127.0.0.1:27017",
18
- "/test/my_application/mongo/secondary" => "%{hostname}:27018",
18
+ "/test/my_application/mongo/secondary" => "${hostname}:27018",
19
19
  "/test/my_application/mysql/database" => "secret_config_test",
20
20
  "/test/my_application/mysql/password" => "secret_configrules",
21
21
  "/test/my_application/mysql/username" => "secret_config",
@@ -15,7 +15,7 @@ module Providers
15
15
  {
16
16
  "/test/my_application/mongo/database" => "secret_config_test",
17
17
  "/test/my_application/mongo/primary" => "127.0.0.1:27017",
18
- "/test/my_application/mongo/secondary" => "%{hostname}:27018",
18
+ "/test/my_application/mongo/secondary" => "${hostname}:27018",
19
19
  "/test/my_application/mysql/database" => "secret_config_test",
20
20
  "/test/my_application/mysql/password" => "secret_configrules",
21
21
  "/test/my_application/mysql/username" => "secret_config",
@@ -6,23 +6,23 @@ module SecretConfig
6
6
 
7
7
  describe "#parse" do
8
8
  it "handles good key" do
9
- string = "Set a date of %{date} here."
10
- expected = string.gsub("%{date}", Date.today.strftime("%Y%m%d"))
9
+ string = "Set a date of ${date} here."
10
+ expected = string.gsub("${date}", Date.today.strftime("%Y%m%d"))
11
11
  actual = interpolator.parse(string)
12
12
  assert_equal expected, actual, string
13
13
  end
14
14
 
15
15
  it "handles multiple keys" do
16
- string = "%{pid}: Set a date of %{date} here and a %{time:%H%M} here and for luck %{pid}"
17
- expected = string.gsub("%{date}", Date.today.strftime("%Y%m%d"))
18
- expected = expected.gsub("%{time:%H%M}", Time.now.strftime("%H%M"))
19
- expected = expected.gsub("%{pid}", $$.to_s)
16
+ string = "${pid}: Set a date of ${date} here and a ${time:%H%M} here and for luck ${pid}"
17
+ expected = string.gsub("${date}", Date.today.strftime("%Y%m%d"))
18
+ expected = expected.gsub("${time:%H%M}", Time.now.strftime("%H%M"))
19
+ expected = expected.gsub("${pid}", $$.to_s)
20
20
  actual = interpolator.parse(string)
21
21
  assert_equal expected, actual, string
22
22
  end
23
23
 
24
24
  it "handles bad key" do
25
- string = "Set a date of %{blah} here."
25
+ string = "Set a date of ${blah} here."
26
26
  assert_raises InvalidInterpolation do
27
27
  interpolator.parse(string)
28
28
  end
@@ -31,22 +31,22 @@ module SecretConfig
31
31
 
32
32
  describe "#date" do
33
33
  it "interpolates date only" do
34
- string = "%{date}"
34
+ string = "${date}"
35
35
  expected = Date.today.strftime("%Y%m%d")
36
36
  actual = interpolator.parse(string)
37
37
  assert_equal expected, actual, string
38
38
  end
39
39
 
40
40
  it "interpolates date" do
41
- string = "Set a date of %{date} here."
42
- expected = string.gsub("%{date}", Date.today.strftime("%Y%m%d"))
41
+ string = "Set a date of ${date} here."
42
+ expected = string.gsub("${date}", Date.today.strftime("%Y%m%d"))
43
43
  actual = interpolator.parse(string)
44
44
  assert_equal expected, actual, string
45
45
  end
46
46
 
47
47
  it "interpolates date with custom format" do
48
- string = "Set a custom %{date:%m%d%Y} here."
49
- expected = string.gsub("%{date:%m%d%Y}", Date.today.strftime("%m%d%Y"))
48
+ string = "Set a custom ${date:%m%d%Y} here."
49
+ expected = string.gsub("${date:%m%d%Y}", Date.today.strftime("%m%d%Y"))
50
50
  actual = interpolator.parse(string)
51
51
  assert_equal expected, actual, string
52
52
  end
@@ -54,7 +54,7 @@ module SecretConfig
54
54
 
55
55
  describe "#time" do
56
56
  it "interpolates time only" do
57
- string = "%{time}"
57
+ string = "${time}"
58
58
  time = Time.now
59
59
  Time.stub(:now, time) do
60
60
  expected = Time.now.strftime("%Y%m%d%H%M%S%L")
@@ -64,18 +64,18 @@ module SecretConfig
64
64
  end
65
65
 
66
66
  it "interpolates time" do
67
- string = "Set a time of %{time} here."
67
+ string = "Set a time of ${time} here."
68
68
  time = Time.now
69
69
  Time.stub(:now, time) do
70
- expected = string.gsub("%{time}", Time.now.strftime("%Y%m%d%H%M%S%L"))
70
+ expected = string.gsub("${time}", Time.now.strftime("%Y%m%d%H%M%S%L"))
71
71
  actual = interpolator.parse(string)
72
72
  assert_equal expected, actual, string
73
73
  end
74
74
  end
75
75
 
76
76
  it "interpolates time with custom format" do
77
- string = "Set a custom time of %{time:%H%M} here."
78
- expected = string.gsub("%{time:%H%M}", Time.now.strftime("%H%M"))
77
+ string = "Set a custom time of ${time:%H%M} here."
78
+ expected = string.gsub("${time:%H%M}", Time.now.strftime("%H%M"))
79
79
  actual = interpolator.parse(string)
80
80
  assert_equal expected, actual, string
81
81
  end
@@ -87,20 +87,20 @@ module SecretConfig
87
87
  end
88
88
 
89
89
  it "fetches existing ENV var" do
90
- string = "%{env:TEST_SETTING}"
90
+ string = "${env:TEST_SETTING}"
91
91
  actual = interpolator.parse(string)
92
92
  assert_equal "Secret", actual, string
93
93
  end
94
94
 
95
95
  it "fetches existing ENV var into a larger string" do
96
- string = "Hello %{env:TEST_SETTING}. How are you?"
96
+ string = "Hello ${env:TEST_SETTING}. How are you?"
97
97
  actual = interpolator.parse(string)
98
- expected = string.gsub("%{env:TEST_SETTING}", "Secret")
98
+ expected = string.gsub("${env:TEST_SETTING}", "Secret")
99
99
  assert_equal expected, actual, string
100
100
  end
101
101
 
102
102
  it "handles missing ENV var" do
103
- string = "%{env:OTHER_TEST_SETTING}"
103
+ string = "${env:OTHER_TEST_SETTING}"
104
104
  actual = interpolator.parse(string)
105
105
  assert_equal "", actual, string
106
106
  end
@@ -108,13 +108,13 @@ module SecretConfig
108
108
 
109
109
  describe "#hostname" do
110
110
  it "returns hostname" do
111
- string = "%{hostname}"
111
+ string = "${hostname}"
112
112
  actual = interpolator.parse(string)
113
113
  assert_equal Socket.gethostname, actual, string
114
114
  end
115
115
 
116
116
  it "returns short hostname" do
117
- string = "%{hostname:short}"
117
+ string = "${hostname:short}"
118
118
  actual = interpolator.parse(string)
119
119
  assert_equal Socket.gethostname.split(".")[0], actual, string
120
120
  end
@@ -122,7 +122,7 @@ module SecretConfig
122
122
 
123
123
  describe "#pid" do
124
124
  it "returns process id" do
125
- string = "%{pid}"
125
+ string = "${pid}"
126
126
  actual = interpolator.parse(string)
127
127
  assert_equal $$.to_s, actual, string
128
128
  end
@@ -130,7 +130,7 @@ module SecretConfig
130
130
 
131
131
  describe "#random" do
132
132
  it "interpolates random 32 byte string" do
133
- string = "%{random}"
133
+ string = "${random}"
134
134
  random = SecureRandom.urlsafe_base64(32)
135
135
  SecureRandom.stub(:urlsafe_base64, random) do
136
136
  actual = interpolator.parse(string)
@@ -139,7 +139,7 @@ module SecretConfig
139
139
  end
140
140
 
141
141
  it "interpolates custom length random string" do
142
- string = "%{random:64}"
142
+ string = "${random:64}"
143
143
  random = SecureRandom.urlsafe_base64(64)
144
144
  SecureRandom.stub(:urlsafe_base64, random) do
145
145
  actual = interpolator.parse(string)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: secret_config
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.1
4
+ version: 0.10.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Reid Morrison
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-01 00:00:00.000000000 Z
11
+ date: 2020-06-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby