kubes_google 0.2.0 → 0.3.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d795d19cc6f90fc23eb69f9e93a2e04993ce14d8681634961fb8ef349c95fd7c
4
- data.tar.gz: 3acb4ab90062ac61f1e1a82cbe70319ea0086d7fcd9490bd290cc92fc0141683
3
+ metadata.gz: d5ef849665496ae62a2621fe4d7732913c358a357334811413b109df5913d34c
4
+ data.tar.gz: 26fe10736966f7c027a88395206605c1bc1928b6f23b139680e21c5a325e0b26
5
5
  SHA512:
6
- metadata.gz: 8048442e2abd946050b7740f1c7f60b7d528a18464e779f9a677cc41ed67182b218f44852096ab65558616c5b1bd3b293b2ca6b164dee12808d575ca1227c607
7
- data.tar.gz: ae2add8d4baf621d40174eca105add4df3a752d0a27873f50ae1b97e830d601ad95c65b12e976f0320e2bbf60cd4866249dda677078bd17134ad639354856e49
6
+ metadata.gz: 3cd2ceaa682f677ec6d660a0fd6accceb2380e6ad5c50c9a946c78d24cafee5a563e8932d1c1bf27191a029088b35463717d9bf03dabd377faa4432601bd0b90
7
+ data.tar.gz: 697904843b0e1c5ca6185732a126a966151288896c9192725348d6a5fdd560b29d7cf08ed198f4f90c7bf9d9c1b7773e398de4d44ec02608fcb822da48cb09b1
@@ -3,6 +3,21 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  This project *loosely tries* to adhere to [Semantic Versioning](http://semver.org/), even before v1.0.
5
5
 
6
+ ## [0.3.4] - 2020-11-12
7
+ - fix KubesGoogle.config.secrets.fetcher check
8
+
9
+ ## [0.3.3] - 2020-11-12
10
+ - [#6](https://github.com/boltops-tools/kubes_google/pull/6) sdk and gcloud secrets fetcher strategy: secrets.fetcher option
11
+
12
+ ## [0.3.2] - 2020-11-11
13
+ - [#5](https://github.com/boltops-tools/kubes_google/pull/5) config.base64 option
14
+
15
+ ## [0.3.1] - 2020-11-11
16
+ - [#4](https://github.com/boltops-tools/kubes_google/pull/4) get_credentials hook
17
+
18
+ ## [0.3.0]
19
+ - #3 gke hook to whitelist ip
20
+
6
21
  ## [0.2.0]
7
22
  - #2 add google_secret helper and register plugin
8
23
  - fix GOOGLE_PROJECT check
@@ -23,7 +23,10 @@ Gem::Specification.new do |spec|
23
23
  spec.require_paths = ["lib"]
24
24
 
25
25
  spec.add_dependency "activesupport"
26
+ spec.add_dependency "google-cloud-container"
26
27
  spec.add_dependency "google-cloud-secret_manager"
27
28
  spec.add_dependency "memoist"
28
29
  spec.add_dependency "zeitwerk"
30
+
31
+ spec.add_development_dependency "kubes"
29
32
  end
@@ -0,0 +1,22 @@
1
+ gke = KubesGoogle::Gke.new(
2
+ cluster_name: KubesGoogle.config.gke.cluster_name,
3
+ google_region: KubesGoogle.config.gke.google_region,
4
+ google_project: KubesGoogle.config.gke.google_project,
5
+ enable_get_credentials: KubesGoogle.config.gke.enable_get_credentials,
6
+ whitelist_ip: KubesGoogle.config.gke.whitelist_ip,
7
+ )
8
+
9
+ before("apply",
10
+ label: "gke get-credentials hook",
11
+ execute: gke.method(:get_credentials).to_proc,
12
+ ) if gke.get_credentials_enabled?
13
+
14
+ before("apply",
15
+ label: "gke whitelist hook",
16
+ execute: gke.method(:allow).to_proc,
17
+ ) if gke.enabled?
18
+
19
+ after("apply",
20
+ label: "gke whitelist hook",
21
+ execute: gke.method(:deny).to_proc,
22
+ ) if gke.enabled?
@@ -16,6 +16,25 @@ module KubesGoogle
16
16
  @@logger = v
17
17
  end
18
18
 
19
+ # Friendlier method configure.
20
+ #
21
+ # .kubes/config/env/dev.rb
22
+ # .kubes/config/plugins/google.rb # also works
23
+ #
24
+ # Example:
25
+ #
26
+ # KubesGoogle.configure do |config|
27
+ # config.hooks.gke_whitelist = true
28
+ # end
29
+ #
30
+ def configure(&block)
31
+ Config.instance.configure(&block)
32
+ end
33
+
34
+ def config
35
+ Config.instance.config
36
+ end
37
+
19
38
  extend self
20
39
  end
21
40
 
@@ -0,0 +1,29 @@
1
+ module KubesGoogle
2
+ class Config
3
+ include Singleton
4
+
5
+ def defaults
6
+ c = ActiveSupport::OrderedOptions.new
7
+ c.gke = ActiveSupport::OrderedOptions.new
8
+ c.gke.cluster_name = nil
9
+ c.gke.enable_get_credentials = nil
10
+ c.gke.enable_hooks = nil # nil since need cluster_name also. setting to false will explicitly disable hooks
11
+ c.gke.google_project = nil
12
+ c.gke.google_region = nil
13
+ c.gke.whitelist_ip = nil # default will auto-detect IP
14
+ c.secrets = ActiveSupport::OrderedOptions.new
15
+ c.secrets.fetcher = "sdk"
16
+ c.secrets.base64 = true
17
+ c
18
+ end
19
+
20
+ @@config = nil
21
+ def config
22
+ @@config ||= defaults
23
+ end
24
+
25
+ def configure
26
+ yield(config)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,120 @@
1
+ require 'open-uri'
2
+
3
+ module KubesGoogle
4
+ class Gke
5
+ extend Memoist
6
+ include Logging
7
+ include Services
8
+ include Util::Sh
9
+
10
+ def initialize(cluster_name:,
11
+ enable_get_credentials: false,
12
+ google_project: nil,
13
+ google_region: "us-central1",
14
+ whitelist_ip: nil)
15
+ @cluster_name = cluster_name
16
+ @enable_get_credentials = enable_get_credentials
17
+ @google_project = ENV['GOOGLE_PROJECT'] || google_project
18
+ @google_region = ENV['GOOGLE_REGION'] || google_region
19
+ @whitelist_ip = whitelist_ip
20
+ end
21
+
22
+ def allow
23
+ logger.debug "Updating cluster. Adding IP: #{ip}"
24
+ update_cluster(cidr_blocks(:with_whitelist))
25
+ end
26
+
27
+ def deny
28
+ logger.debug "Updating cluster. Removing IP: #{ip}"
29
+ update_cluster(cidr_blocks(:without_whitelist))
30
+ end
31
+
32
+ def get_credentials
33
+ return unless get_credentials_enabled?
34
+ sh "gcloud container clusters get-credentials --project=#{@google_project} --region=#{@google_region} #{@cluster_name}"
35
+ end
36
+
37
+ def full_name
38
+ "projects/#{@google_project}/locations/#{@google_region}/clusters/#{@cluster_name}"
39
+ end
40
+
41
+ def enabled?
42
+ enable = KubesGoogle.config.gke.enable_hooks
43
+ enable = enable.nil? ? true : enable
44
+ # gke = KubesGoogle::Gke.new(name: KubesGoogle.config.gke.cluster_name)
45
+ # so @name = KubesGoogle.config.gke.cluster_name
46
+ !!(enable && @cluster_name)
47
+ end
48
+
49
+ def get_credentials_enabled?
50
+ enable = KubesGoogle.config.gke.enable_get_credentials
51
+ enable = enable.nil? ? false : enable
52
+ !!(enable && full_name)
53
+ end
54
+
55
+ def update_cluster(cidr_blocks)
56
+ resp = cluster_manager.update_cluster(
57
+ name: full_name,
58
+ update: {
59
+ desired_master_authorized_networks_config: {
60
+ cidr_blocks: cidr_blocks,
61
+ enabled: true,
62
+ }
63
+ }
64
+ )
65
+ operation_name = resp.self_link.sub(/.*projects/,'projects')
66
+ wait_for(operation_name)
67
+ end
68
+
69
+ def wait_for(operation_name)
70
+ resp = cluster_manager.get_operation(name: operation_name)
71
+ until resp.status != :RUNNING do
72
+ sleep 5
73
+ resp = cluster_manager.get_operation(name: operation_name)
74
+ end
75
+ end
76
+
77
+ def cidr_blocks(type)
78
+ # so we dont keep adding duplicates
79
+ old = old_cidrs.reject do |x|
80
+ x[:display_name] == new_cidr[:display_name] &&
81
+ x[:cidr_block] == new_cidr[:cidr_block]
82
+ end
83
+ if type == :with_whitelist
84
+ old + [new_cidr]
85
+ else
86
+ old
87
+ end
88
+ end
89
+
90
+ def old_cidrs
91
+ resp = cluster_manager.get_cluster(name: full_name)
92
+ config = resp.master_authorized_networks_config.to_h
93
+ config[:cidr_blocks]
94
+ end
95
+ memoize :old_cidrs
96
+
97
+ def new_cidr
98
+ {
99
+ display_name: "added-by-kubes-google",
100
+ cidr_block: ip,
101
+ }
102
+ end
103
+ memoize :new_cidr
104
+
105
+ def ip
106
+ @whitelist_ip || current_ip
107
+ end
108
+
109
+ def current_ip
110
+ resp = URI.open("http://ifconfig.me")
111
+ ip = resp.read
112
+ "#{ip}/32"
113
+ rescue SocketError => e
114
+ logger.info "WARN: #{e.message}"
115
+ logger.info "Unable to detect current ip. Will use 0.0.0.0/0"
116
+ "0.0.0.0/0"
117
+ end
118
+ memoize :current_ip
119
+ end
120
+ end
@@ -0,0 +1,7 @@
1
+ module KubesGoogle
2
+ class Hooks
3
+ def path
4
+ File.expand_path("../hooks", __dir__)
5
+ end
6
+ end
7
+ end
@@ -1,41 +1,22 @@
1
1
  class KubesGoogle::Secrets
2
2
  class Fetcher
3
- include KubesGoogle::Logging
4
- include KubesGoogle::Services
3
+ extend Memoist
5
4
 
6
5
  def initialize(options={})
7
6
  @options = options
8
- @base64 = options[:base64].nil? ? true : options[:base64]
9
- @project_id = ENV['GOOGLE_PROJECT'] || raise("GOOGLE_PROJECT env variable is not set. It's required.")
10
7
  end
11
8
 
12
9
  def fetch(short_name)
13
- value = fetch_value(short_name)
14
- value = Base64.strict_encode64(value).strip if @base64
15
- value
10
+ fetcher.fetch(short_name)
16
11
  end
17
12
 
18
- def fetch_value(short_name)
19
- name = "projects/#{project_number}/secrets/#{short_name}/versions/latest"
20
- version = secret_manager_service.access_secret_version(name: name)
21
- version.payload.data
22
- rescue Google::Cloud::NotFoundError => e
23
- logger.info "WARN: secret #{name} not found".color(:yellow)
24
- logger.info e.message
25
- "NOT FOUND #{name}" # simple string so Kubernetes YAML is valid
26
- end
27
-
28
- # TODO: Get the project from the list project api instead. Unsure where the docs are for this.
29
- # If someone knows, let me know.
30
- # Right now grabbing the first secret to then be able to get the google project number
31
- @@project_number = nil
32
- def project_number
33
- return @@project_number if @@project_number
34
-
35
- parent = "projects/#{@project_id}"
36
- resp = secret_manager_service.list_secrets(parent: parent) # note: page_size doesnt seem to get respected
37
- name = resp.first.name # IE: projects/686010496118/secrets/demo-dev-db_host
38
- @@project_number = name.split('/')[1]
13
+ def fetcher
14
+ if KubesGoogle.config.secrets.fetcher == "sdk"
15
+ Sdk.new(@options)
16
+ else
17
+ Gcloud.new(@options)
18
+ end
39
19
  end
20
+ memoize :fetcher
40
21
  end
41
22
  end
@@ -0,0 +1,15 @@
1
+ class KubesGoogle::Secrets::Fetcher
2
+ class Base
3
+ include KubesGoogle::Logging
4
+
5
+ def initialize(options={})
6
+ @options = options
7
+ @base64 = options[:base64]
8
+ @project_id = options[:google_project] || ENV['GOOGLE_PROJECT'] || raise("GOOGLE_PROJECT env variable is not set. It's required.")
9
+ end
10
+
11
+ def base64?
12
+ @base64.nil? ? KubesGoogle.config.secrets.base64 : @base64
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,21 @@
1
+ class KubesGoogle::Secrets::Fetcher
2
+ class Gcloud < Base
3
+ include KubesGoogle::Util::Sh
4
+
5
+ def fetch(short_name, version="latest")
6
+ value = gcloud("secrets versions access #{version} --secret #{short_name}")
7
+ if value.include?("ERROR") && value.include?("NOT_FOUND")
8
+ logger.info "WARN: secret #{short_name} not found".color(:yellow)
9
+ logger.info e.message
10
+ "NOT FOUND #{short_name}" # simple string so Kubernetes YAML is valid
11
+ else
12
+ value = Base64.strict_encode64(value).strip if base64?
13
+ value
14
+ end
15
+ end
16
+
17
+ def gcloud(args)
18
+ capture("gcloud --project #{@project_id} #{args}")
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,34 @@
1
+ class KubesGoogle::Secrets::Fetcher
2
+ class Sdk < Base
3
+ include KubesGoogle::Services
4
+
5
+ def fetch(short_name, version="latest")
6
+ value = fetch_value(short_name, version)
7
+ value = Base64.strict_encode64(value).strip if base64?
8
+ value
9
+ end
10
+
11
+ def fetch_value(short_name, version="latest")
12
+ name = "projects/#{project_number}/secrets/#{short_name}/versions/#{version}"
13
+ version = secret_manager_service.access_secret_version(name: name)
14
+ version.payload.data
15
+ rescue Google::Cloud::NotFoundError => e
16
+ logger.info "WARN: secret #{name} not found".color(:yellow)
17
+ logger.info e.message
18
+ "NOT FOUND #{name}" # simple string so Kubernetes YAML is valid
19
+ end
20
+
21
+ # TODO: Get the project from the list project api instead. Unsure where the docs are for this.
22
+ # If someone knows, let me know.
23
+ # Right now grabbing the first secret to then be able to get the google project number
24
+ @@project_number = nil
25
+ def project_number
26
+ return @@project_number if @@project_number
27
+
28
+ parent = "projects/#{@project_id}"
29
+ resp = secret_manager_service.list_secrets(parent: parent) # note: page_size doesnt seem to get respected
30
+ name = resp.first.name # IE: projects/686010496118/secrets/demo-dev-db_host
31
+ @@project_number = name.split('/')[1]
32
+ end
33
+ end
34
+ end
@@ -4,6 +4,7 @@ require "json"
4
4
  module KubesGoogle
5
5
  class ServiceAccount
6
6
  include Logging
7
+ include Util::Sh
7
8
 
8
9
  def initialize(app:, namespace:nil, roles: [], gsa: nil, ksa: nil)
9
10
  @app, @roles = app, roles
@@ -71,25 +72,5 @@ module KubesGoogle
71
72
  --member=serviceAccount:#{@service_account} \
72
73
  --role=#{role} > /dev/null".squish
73
74
  end
74
-
75
- private
76
- def sh(command)
77
- logger.debug "=> #{command}"
78
- success = system(command)
79
- unless success
80
- logger.info "WARN: Running #{command}"
81
- end
82
- success
83
- end
84
-
85
- def capture(command)
86
- out = `#{command}`
87
- unless $?.exitstatus == 0
88
- logger.info "ERROR: Running #{command}"
89
- logger.info out
90
- exit 1
91
- end
92
- out
93
- end
94
75
  end
95
76
  end
@@ -1,9 +1,15 @@
1
1
  require "google-cloud-secret_manager"
2
+ require "google/cloud/container"
2
3
 
3
4
  module KubesGoogle
4
5
  module Services
5
6
  extend Memoist
6
7
 
8
+ def cluster_manager
9
+ Google::Cloud::Container.cluster_manager
10
+ end
11
+ memoize :cluster_manager
12
+
7
13
  def secret_manager_service
8
14
  Google::Cloud::SecretManager.secret_manager_service
9
15
  end
@@ -0,0 +1,23 @@
1
+ module KubesGoogle::Util
2
+ module Sh
3
+ private
4
+ def sh(command)
5
+ logger.debug "=> #{command}"
6
+ success = system(command)
7
+ unless success
8
+ logger.info "WARN: Running #{command}"
9
+ end
10
+ success
11
+ end
12
+
13
+ def capture(command)
14
+ out = `#{command}`
15
+ unless $?.exitstatus == 0
16
+ logger.info "ERROR: Running #{command}"
17
+ logger.info out
18
+ exit 1
19
+ end
20
+ out
21
+ end
22
+ end
23
+ end
@@ -1,3 +1,3 @@
1
1
  module KubesGoogle
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.4"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kubes_google
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tung Nguyen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-11-09 00:00:00.000000000 Z
11
+ date: 2020-11-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: google-cloud-container
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: google-cloud-secret_manager
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -66,6 +80,20 @@ dependencies:
66
80
  - - ">="
67
81
  - !ruby/object:Gem::Version
68
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: kubes
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
69
97
  description:
70
98
  email:
71
99
  - tung@boltops.com
@@ -81,14 +109,22 @@ files:
81
109
  - README.md
82
110
  - Rakefile
83
111
  - kubes_google.gemspec
112
+ - lib/hooks/kubes.rb
84
113
  - lib/kubes_google.rb
85
114
  - lib/kubes_google/autoloader.rb
115
+ - lib/kubes_google/config.rb
116
+ - lib/kubes_google/gke.rb
86
117
  - lib/kubes_google/helpers.rb
118
+ - lib/kubes_google/hooks.rb
87
119
  - lib/kubes_google/logging.rb
88
120
  - lib/kubes_google/secrets.rb
89
121
  - lib/kubes_google/secrets/fetcher.rb
122
+ - lib/kubes_google/secrets/fetcher/base.rb
123
+ - lib/kubes_google/secrets/fetcher/gcloud.rb
124
+ - lib/kubes_google/secrets/fetcher/sdk.rb
90
125
  - lib/kubes_google/service_account.rb
91
126
  - lib/kubes_google/services.rb
127
+ - lib/kubes_google/util/sh.rb
92
128
  - lib/kubes_google/version.rb
93
129
  homepage: https://github.com/boltops-tools/kubes_google
94
130
  licenses: