on_container 0.0.11 → 0.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/on_container/load_env_secrets.rb +7 -53
- data/lib/on_container/secrets/env_loader.rb +43 -0
- data/lib/on_container/secrets/google_cloud/env_loader.rb +6 -2
- data/lib/on_container/secrets/mounted_files/env_loader.rb +58 -0
- data/lib/on_container/secrets/url_variable_processor.rb +71 -0
- data/lib/on_container/version.rb +1 -1
- data/on_container.gemspec +1 -0
- metadata +18 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cc7ffb417b7d418f2415df1cd5c6cbd0325d78e576e71a701010bd44ead098f6
|
4
|
+
data.tar.gz: 260e06a5fa81789bc977cac9b02c8e092100a0896d9eccc4c4f88423592a1f9d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9e54869d4ec1c390a555731ac199ece8b804098eece937321123e48884d0b7fa0dff418147f97e811b4e05fb23517f433bf622b08fc4f4941d04801fa31f8570
|
7
|
+
data.tar.gz: 410eb4b5c14a632600ecccade83dcca9764965085dfa95177976365bc762516ac36e8d6ec70cdd51925d9204c19652afe80c50887774b67ffbe0990c9edeb18b
|
@@ -1,58 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
#
|
4
|
-
# variables:
|
5
|
-
|
6
|
-
require 'active_support'
|
7
|
-
require 'active_support/core_ext/object'
|
8
|
-
|
9
|
-
# Load secrets from Google Cloud Secret Manager to ENV, if any:
|
10
|
-
require 'on_container/secrets/google_cloud/env_loader'
|
11
|
-
OnContainer::Secrets::GoogleCloud::EnvLoader.perform!
|
12
|
-
|
13
|
-
# Process only a known list of env vars that can filled by reading a file (i.e.
|
14
|
-
# a docker secret):
|
15
|
-
Dir["#{ENV.fetch('SECRETS_PATH', '/run/secrets')}/**/*"].map do |path|
|
16
|
-
Pathname.new(path)
|
17
|
-
end.select(&:file?).each do |secret_filepath|
|
18
|
-
secret_envvarname = secret_filepath.basename('.*').to_s.upcase
|
19
|
-
|
20
|
-
# Skip if variable is already set - already-set variables have precedence over
|
21
|
-
# the secret files:
|
22
|
-
next if ENV.key?(secret_envvarname) && ENV[secret_envvarname].present?
|
23
|
-
|
24
|
-
ENV[secret_envvarname] = File.read(secret_filepath).strip
|
25
|
-
end
|
26
|
-
|
27
|
-
# For each *_URL environment variable where there's also a *_(USER|USERNAME) or
|
28
|
-
# *_(PASS|PASSWORD), update the URL environment variable with the given
|
29
|
-
# credentials. For example:
|
3
|
+
# This script achieves a list of secret loading & processing:
|
30
4
|
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
5
|
+
# 1. Loads secrets from Google Cloud Secret Manager to ENV, if configured.
|
6
|
+
# 2. Reads files in a configured Folder, and loads them into ENV variables.
|
7
|
+
# 3. Processes "*_URL" env vars, adding their respective "*_USER" and "*_PASS".
|
34
8
|
#
|
35
|
-
#
|
36
|
-
# DATABASE_URL = postgres://lalito:lepass@postgres:5432/demo_production
|
37
|
-
require 'uri' if (url_keys = ENV.keys.select { |key| key =~ /_URL/ }).any?
|
38
|
-
|
39
|
-
url_keys.each do |url_key|
|
40
|
-
credential_pattern_string = url_key.gsub('_URL', '_(USER(NAME)?|PASS(WORD)?)')
|
41
|
-
credential_pattern = Regexp.new "\\A#{credential_pattern_string}\\z"
|
42
|
-
credential_keys = ENV.keys.select { |key| key =~ credential_pattern }
|
43
|
-
next unless credential_keys.any?
|
44
|
-
|
45
|
-
uri = URI(ENV[url_key])
|
46
|
-
|
47
|
-
credential_keys.each do |credential_key|
|
48
|
-
credential_value = URI.encode_www_form_component ENV[credential_key]
|
49
|
-
case credential_key
|
50
|
-
when /USER/ then uri.user = credential_value
|
51
|
-
when /PASS/ then uri.password = credential_value
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
ENV[url_key] = uri.to_s
|
56
|
-
end
|
9
|
+
# - See https://github.com/IcaliaLabs/on-container-for-ruby#loading-secrets-into-environment-variables
|
57
10
|
|
58
|
-
|
11
|
+
require 'on_container/secrets/env_loader'
|
12
|
+
OnContainer::Secrets::EnvLoader.perform!
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'on_container/common/safe_performable'
|
4
|
+
require 'on_container/secrets/google_cloud/env_loader'
|
5
|
+
require 'on_container/secrets/mounted_files/env_loader'
|
6
|
+
require 'on_container/secrets/url_variable_processor'
|
7
|
+
|
8
|
+
module OnContainer
|
9
|
+
module Secrets
|
10
|
+
#= EnvLoader
|
11
|
+
#
|
12
|
+
# Reads the specified secret paths (i.e. Docker Secrets) into environment
|
13
|
+
# variables:
|
14
|
+
class EnvLoader
|
15
|
+
include OnContainer::Common::SafePerformable
|
16
|
+
|
17
|
+
def perform!
|
18
|
+
load_secrets_from_google_cloud if google_cloud_secrets?
|
19
|
+
load_secrets_from_mounted_files
|
20
|
+
process_url_variables
|
21
|
+
true
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def google_cloud_secrets?
|
27
|
+
OnContainer::Secrets::GoogleCloud::EnvLoader.secret_manager?
|
28
|
+
end
|
29
|
+
|
30
|
+
def load_secrets_from_google_cloud
|
31
|
+
OnContainer::Secrets::GoogleCloud::EnvLoader.perform!
|
32
|
+
end
|
33
|
+
|
34
|
+
def load_secrets_from_mounted_files
|
35
|
+
OnContainer::Secrets::MountedFiles::EnvLoader.perform!
|
36
|
+
end
|
37
|
+
|
38
|
+
def process_url_variables
|
39
|
+
OnContainer::Secrets::UrlVariableProcessor.perform!
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -17,9 +17,13 @@ module OnContainer
|
|
17
17
|
def env_keys?
|
18
18
|
env_keys.any?
|
19
19
|
end
|
20
|
+
|
21
|
+
def self.secret_manager?
|
22
|
+
defined?(Google::Cloud::SecretManager) == 'constant'
|
23
|
+
end
|
20
24
|
|
21
25
|
def secret_manager?
|
22
|
-
|
26
|
+
self.class.secret_manager?
|
23
27
|
end
|
24
28
|
|
25
29
|
def perform!
|
@@ -34,4 +38,4 @@ module OnContainer
|
|
34
38
|
end
|
35
39
|
end
|
36
40
|
end
|
37
|
-
end
|
41
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support'
|
4
|
+
require 'active_support/core_ext/object'
|
5
|
+
require 'on_container/common/safe_performable'
|
6
|
+
|
7
|
+
module OnContainer
|
8
|
+
module Secrets
|
9
|
+
module MountedFiles
|
10
|
+
class EnvLoader
|
11
|
+
include OnContainer::Common::SafePerformable
|
12
|
+
|
13
|
+
def perform!
|
14
|
+
setup_secrets_path
|
15
|
+
scan_secrets_path_for_files
|
16
|
+
load_secret_files_to_env_vars
|
17
|
+
end
|
18
|
+
|
19
|
+
def secrets_path
|
20
|
+
@secrets_path ||= ENV.fetch('SECRETS_PATH', '/run/secrets')
|
21
|
+
end
|
22
|
+
|
23
|
+
def secret_mounted_file_paths
|
24
|
+
@secret_mounted_file_paths ||= Dir["#{secrets_path}/**/*"]
|
25
|
+
.map { |path| Pathname.new(path) }
|
26
|
+
.select(&:file?)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
alias setup_secrets_path secrets_path
|
32
|
+
alias scan_secrets_path_for_files secret_mounted_file_paths
|
33
|
+
|
34
|
+
def load_secret_files_to_env_vars
|
35
|
+
return if @already_loaded
|
36
|
+
|
37
|
+
secret_mounted_file_paths
|
38
|
+
.each { |file_path| load_secret_file_to_env_var(file_path) }
|
39
|
+
|
40
|
+
@already_loaded = true
|
41
|
+
end
|
42
|
+
|
43
|
+
def load_secret_file_to_env_var(file_path)
|
44
|
+
env_var_name = file_path.basename('.*').to_s.upcase
|
45
|
+
|
46
|
+
# Skip if variable is already set - already-set variables have
|
47
|
+
# precedence over the secret files:
|
48
|
+
return if ENV.key?(env_var_name) && ENV[env_var_name].present?
|
49
|
+
|
50
|
+
contents = file_path.read.strip
|
51
|
+
|
52
|
+
# TODO: Do not load if content has null bytes
|
53
|
+
ENV[env_var_name] = file_path.read.strip
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'on_container/common/safe_performable'
|
4
|
+
|
5
|
+
module OnContainer
|
6
|
+
module Secrets
|
7
|
+
#= UrlVariableProcessor
|
8
|
+
#
|
9
|
+
# For each *_URL environment variable where there's also a *_(USER|USERNAME)
|
10
|
+
# or *_(PASS|PASSWORD), updates the URL environment variable with the given
|
11
|
+
# credentials. For example:
|
12
|
+
#
|
13
|
+
# DATABASE_URL: postgres://postgres:5432/demo_production
|
14
|
+
# DATABASE_USERNAME: lalito
|
15
|
+
# DATABASE_PASSWORD: lepass
|
16
|
+
#
|
17
|
+
# Results in the following updated DATABASE_URL:
|
18
|
+
# DATABASE_URL = postgres://lalito:lepass@postgres:5432/demo_production
|
19
|
+
class UrlVariableProcessor
|
20
|
+
include OnContainer::Common::SafePerformable
|
21
|
+
|
22
|
+
def perform!
|
23
|
+
require_uri_module if url_keys?
|
24
|
+
process_credential_keys
|
25
|
+
end
|
26
|
+
|
27
|
+
def url_keys
|
28
|
+
@url_keys ||= ENV.keys.select { |key| key =~ /_URL/ }
|
29
|
+
end
|
30
|
+
|
31
|
+
def url_keys?
|
32
|
+
url_keys.any?
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def process_credential_keys
|
38
|
+
url_keys.each { |url_key| process_credential_keys_for(url_key) }
|
39
|
+
end
|
40
|
+
|
41
|
+
def require_uri_module
|
42
|
+
require 'uri'
|
43
|
+
end
|
44
|
+
|
45
|
+
def credential_keys_for(url_key)
|
46
|
+
credential_pattern_string = url_key
|
47
|
+
.gsub('_URL', '_(USER(NAME)?|PASS(WORD)?)')
|
48
|
+
|
49
|
+
credential_pattern = Regexp.new "\\A#{credential_pattern_string}\\z"
|
50
|
+
ENV.keys.select { |key| key =~ credential_pattern }
|
51
|
+
end
|
52
|
+
|
53
|
+
def process_credential_keys_for(url_key)
|
54
|
+
return unless (credential_keys = credential_keys_for(url_key)).any?
|
55
|
+
|
56
|
+
uri = URI(ENV[url_key])
|
57
|
+
|
58
|
+
# Reverse sorting will place "*_USER" before "*_PASS":
|
59
|
+
credential_keys.sort.reverse.each do |credential_key|
|
60
|
+
credential_value = URI.encode_www_form_component ENV[credential_key]
|
61
|
+
case credential_key
|
62
|
+
when /USER/ then uri.user = credential_value
|
63
|
+
when /PASS/ then uri.password = credential_value
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
ENV[url_key] = uri.to_s
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/lib/on_container/version.rb
CHANGED
data/on_container.gemspec
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: on_container
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.12
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Roberto Quintanilla
|
@@ -10,6 +10,20 @@ bindir: exe
|
|
10
10
|
cert_chain: []
|
11
11
|
date: 2021-02-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: bundler
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -49,9 +63,12 @@ files:
|
|
49
63
|
- lib/on_container/dev/setup_ops.rb
|
50
64
|
- lib/on_container/load_env_secrets.rb
|
51
65
|
- lib/on_container/ops/service_connection_checks.rb
|
66
|
+
- lib/on_container/secrets/env_loader.rb
|
52
67
|
- lib/on_container/secrets/google_cloud/env_loader.rb
|
53
68
|
- lib/on_container/secrets/google_cloud/fetcher.rb
|
54
69
|
- lib/on_container/secrets/google_cloud/service_base.rb
|
70
|
+
- lib/on_container/secrets/mounted_files/env_loader.rb
|
71
|
+
- lib/on_container/secrets/url_variable_processor.rb
|
55
72
|
- lib/on_container/version.rb
|
56
73
|
- on_container.gemspec
|
57
74
|
homepage: https://github.com/IcaliaLabs/on-container-for-ruby
|