kamal 2.4.0 → 2.5.0
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/kamal/cli/accessory.rb +1 -1
- data/lib/kamal/cli/alias/command.rb +1 -0
- data/lib/kamal/cli/app.rb +15 -3
- data/lib/kamal/cli/base.rb +16 -1
- data/lib/kamal/cli/build.rb +36 -14
- data/lib/kamal/cli/main.rb +4 -3
- data/lib/kamal/cli/proxy.rb +2 -4
- data/lib/kamal/cli/registry.rb +2 -0
- data/lib/kamal/cli/templates/deploy.yml +2 -2
- data/lib/kamal/cli/templates/sample_hooks/post-app-boot.sample +3 -0
- data/lib/kamal/cli/templates/sample_hooks/pre-app-boot.sample +3 -0
- data/lib/kamal/cli.rb +1 -0
- data/lib/kamal/commander.rb +16 -25
- data/lib/kamal/commands/accessory.rb +1 -5
- data/lib/kamal/commands/app/assets.rb +4 -4
- data/lib/kamal/commands/base.rb +14 -0
- data/lib/kamal/commands/builder/base.rb +12 -5
- data/lib/kamal/commands/builder/cloud.rb +22 -0
- data/lib/kamal/commands/builder.rb +6 -20
- data/lib/kamal/commands/registry.rb +9 -7
- data/lib/kamal/configuration/accessory.rb +36 -19
- data/lib/kamal/configuration/builder.rb +4 -0
- data/lib/kamal/configuration/docs/accessory.yml +20 -1
- data/lib/kamal/configuration/docs/builder.yml +3 -0
- data/lib/kamal/configuration/registry.rb +6 -6
- data/lib/kamal/configuration/role.rb +6 -6
- data/lib/kamal/configuration/validator/role.rb +1 -1
- data/lib/kamal/configuration.rb +29 -12
- data/lib/kamal/docker.rb +30 -0
- data/lib/kamal/git.rb +10 -0
- data/lib/kamal/secrets/adapters/aws_secrets_manager.rb +12 -4
- data/lib/kamal/secrets/adapters/base.rb +5 -2
- data/lib/kamal/secrets/adapters/bitwarden.rb +2 -2
- data/lib/kamal/secrets/adapters/bitwarden_secrets_manager.rb +72 -0
- data/lib/kamal/secrets/adapters/doppler.rb +15 -11
- data/lib/kamal/secrets/adapters/enpass.rb +71 -0
- data/lib/kamal/secrets/adapters/gcp_secret_manager.rb +112 -0
- data/lib/kamal/secrets/adapters/last_pass.rb +3 -2
- data/lib/kamal/secrets/adapters/one_password.rb +2 -2
- data/lib/kamal/secrets/adapters/test.rb +2 -2
- data/lib/kamal/secrets/adapters.rb +2 -0
- data/lib/kamal/version.rb +1 -1
- metadata +10 -4
- data/lib/kamal/secrets/adapters/test_optional_account.rb +0 -5
@@ -0,0 +1,112 @@
|
|
1
|
+
class Kamal::Secrets::Adapters::GcpSecretManager < Kamal::Secrets::Adapters::Base
|
2
|
+
private
|
3
|
+
def login(account)
|
4
|
+
# Since only the account option is passed from the cli, we'll use it for both account and service account
|
5
|
+
# impersonation.
|
6
|
+
#
|
7
|
+
# Syntax:
|
8
|
+
# ACCOUNT: USER | USER "|" DELEGATION_CHAIN
|
9
|
+
# USER: DEFAULT_USER | EMAIL
|
10
|
+
# DELEGATION_CHAIN: EMAIL | EMAIL "," DELEGATION_CHAIN
|
11
|
+
# EMAIL: <The email address of the user or service account, like "my-user@example.com" >
|
12
|
+
# DEFAULT_USER: "default"
|
13
|
+
#
|
14
|
+
# Some valid examples:
|
15
|
+
# - "my-user@example.com" sets the user
|
16
|
+
# - "my-user@example.com|my-service-user@example.com" will use my-user and enable service account impersonation as my-service-user
|
17
|
+
# - "default" will use the default user and no impersonation
|
18
|
+
# - "default|my-service-user@example.com" will use the default user, and enable service account impersonation as my-service-user
|
19
|
+
# - "default|my-service-user@example.com,another-service-user@example.com" same as above, but with an impersonation delegation chain
|
20
|
+
|
21
|
+
unless logged_in?
|
22
|
+
`gcloud auth login`
|
23
|
+
raise RuntimeError, "could not login to gcloud" unless logged_in?
|
24
|
+
end
|
25
|
+
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def fetch_secrets(secrets, from:, account:, session:)
|
30
|
+
user, service_account = parse_account(account)
|
31
|
+
|
32
|
+
{}.tap do |results|
|
33
|
+
secrets_with_metadata(prefixed_secrets(secrets, from: from)).each do |secret, (project, secret_name, secret_version)|
|
34
|
+
item_name = "#{project}/#{secret_name}"
|
35
|
+
results[item_name] = fetch_secret(project, secret_name, secret_version, user, service_account)
|
36
|
+
raise RuntimeError, "Could not read #{item_name} from Google Secret Manager" unless $?.success?
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def fetch_secret(project, secret_name, secret_version, user, service_account)
|
42
|
+
secret = run_command(
|
43
|
+
"secrets versions access #{secret_version.shellescape} --secret=#{secret_name.shellescape}",
|
44
|
+
project: project,
|
45
|
+
user: user,
|
46
|
+
service_account: service_account
|
47
|
+
)
|
48
|
+
Base64.decode64(secret.dig("payload", "data"))
|
49
|
+
end
|
50
|
+
|
51
|
+
# The secret needs to at least contain a secret name, but project name, and secret version can also be specified.
|
52
|
+
#
|
53
|
+
# The string "default" can be used to refer to the default project configured for gcloud.
|
54
|
+
#
|
55
|
+
# The version can be either the string "latest", or a version number.
|
56
|
+
#
|
57
|
+
# The following formats are valid:
|
58
|
+
#
|
59
|
+
# - The following are all equivalent, and sets project: default, secret name: my-secret, version: latest
|
60
|
+
# - "my-secret"
|
61
|
+
# - "default/my-secret"
|
62
|
+
# - "default/my-secret/latest"
|
63
|
+
# - "my-secret/latest" in combination with --from=default
|
64
|
+
# - "my-secret/123" (only in combination with --from=some-project) -> project: some-project, secret name: my-secret, version: 123
|
65
|
+
# - "some-project/my-secret/123" -> project: some-project, secret name: my-secret, version: 123
|
66
|
+
def secrets_with_metadata(secrets)
|
67
|
+
{}.tap do |items|
|
68
|
+
secrets.each do |secret|
|
69
|
+
parts = secret.split("/")
|
70
|
+
parts.unshift("default") if parts.length == 1
|
71
|
+
project = parts.shift
|
72
|
+
secret_name = parts.shift
|
73
|
+
secret_version = parts.shift || "latest"
|
74
|
+
|
75
|
+
items[secret] = [ project, secret_name, secret_version ]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def run_command(command, project: "default", user: "default", service_account: nil)
|
81
|
+
full_command = [ "gcloud", command ]
|
82
|
+
full_command << "--project=#{project.shellescape}" unless project == "default"
|
83
|
+
full_command << "--account=#{user.shellescape}" unless user == "default"
|
84
|
+
full_command << "--impersonate-service-account=#{service_account.shellescape}" if service_account
|
85
|
+
full_command << "--format=json"
|
86
|
+
full_command = full_command.join(" ")
|
87
|
+
|
88
|
+
result = `#{full_command}`.strip
|
89
|
+
JSON.parse(result)
|
90
|
+
end
|
91
|
+
|
92
|
+
def check_dependencies!
|
93
|
+
raise RuntimeError, "gcloud CLI is not installed" unless cli_installed?
|
94
|
+
end
|
95
|
+
|
96
|
+
def cli_installed?
|
97
|
+
`gcloud --version 2> /dev/null`
|
98
|
+
$?.success?
|
99
|
+
end
|
100
|
+
|
101
|
+
def logged_in?
|
102
|
+
JSON.parse(`gcloud auth list --format=json`).any?
|
103
|
+
end
|
104
|
+
|
105
|
+
def parse_account(account)
|
106
|
+
account.split("|", 2)
|
107
|
+
end
|
108
|
+
|
109
|
+
def is_user?(candidate)
|
110
|
+
candidate.include?("@")
|
111
|
+
end
|
112
|
+
end
|
@@ -11,7 +11,8 @@ class Kamal::Secrets::Adapters::LastPass < Kamal::Secrets::Adapters::Base
|
|
11
11
|
`lpass status --color never`.strip == "Logged in as #{account}."
|
12
12
|
end
|
13
13
|
|
14
|
-
def fetch_secrets(secrets, account:, session:)
|
14
|
+
def fetch_secrets(secrets, from:, account:, session:)
|
15
|
+
secrets = prefixed_secrets(secrets, from: from)
|
15
16
|
items = `lpass show #{secrets.map(&:shellescape).join(" ")} --json`
|
16
17
|
raise RuntimeError, "Could not read #{secrets} from LastPass" unless $?.success?
|
17
18
|
|
@@ -23,7 +24,7 @@ class Kamal::Secrets::Adapters::LastPass < Kamal::Secrets::Adapters::Base
|
|
23
24
|
end
|
24
25
|
|
25
26
|
if (missing_items = secrets - results.keys).any?
|
26
|
-
raise RuntimeError, "Could not find #{missing_items.join(", ")} in
|
27
|
+
raise RuntimeError, "Could not find #{missing_items.join(", ")} in LastPass"
|
27
28
|
end
|
28
29
|
end
|
29
30
|
end
|
@@ -15,9 +15,9 @@ class Kamal::Secrets::Adapters::OnePassword < Kamal::Secrets::Adapters::Base
|
|
15
15
|
$?.success?
|
16
16
|
end
|
17
17
|
|
18
|
-
def fetch_secrets(secrets, account:, session:)
|
18
|
+
def fetch_secrets(secrets, from:, account:, session:)
|
19
19
|
{}.tap do |results|
|
20
|
-
vaults_items_fields(secrets).map do |vault, items|
|
20
|
+
vaults_items_fields(prefixed_secrets(secrets, from: from)).map do |vault, items|
|
21
21
|
items.each do |item, fields|
|
22
22
|
fields_json = JSON.parse(op_item_get(vault, item, fields, account: account, session: session))
|
23
23
|
fields_json = [ fields_json ] if fields.one?
|
@@ -4,8 +4,8 @@ class Kamal::Secrets::Adapters::Test < Kamal::Secrets::Adapters::Base
|
|
4
4
|
true
|
5
5
|
end
|
6
6
|
|
7
|
-
def fetch_secrets(secrets, account:, session:)
|
8
|
-
secrets.to_h { |secret| [ secret, secret.reverse ] }
|
7
|
+
def fetch_secrets(secrets, from:, account:, session:)
|
8
|
+
prefixed_secrets(secrets, from: from).to_h { |secret| [ secret, secret.reverse ] }
|
9
9
|
end
|
10
10
|
|
11
11
|
def check_dependencies!
|
@@ -3,6 +3,8 @@ module Kamal::Secrets::Adapters
|
|
3
3
|
def self.lookup(name)
|
4
4
|
name = "one_password" if name.downcase == "1password"
|
5
5
|
name = "last_pass" if name.downcase == "lastpass"
|
6
|
+
name = "gcp_secret_manager" if name.downcase == "gcp"
|
7
|
+
name = "bitwarden_secrets_manager" if name.downcase == "bitwarden-sm"
|
6
8
|
adapter_class(name)
|
7
9
|
end
|
8
10
|
|
data/lib/kamal/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kamal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-02-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -236,8 +236,10 @@ files:
|
|
236
236
|
- lib/kamal/cli/server.rb
|
237
237
|
- lib/kamal/cli/templates/deploy.yml
|
238
238
|
- lib/kamal/cli/templates/sample_hooks/docker-setup.sample
|
239
|
+
- lib/kamal/cli/templates/sample_hooks/post-app-boot.sample
|
239
240
|
- lib/kamal/cli/templates/sample_hooks/post-deploy.sample
|
240
241
|
- lib/kamal/cli/templates/sample_hooks/post-proxy-reboot.sample
|
242
|
+
- lib/kamal/cli/templates/sample_hooks/pre-app-boot.sample
|
241
243
|
- lib/kamal/cli/templates/sample_hooks/pre-build.sample
|
242
244
|
- lib/kamal/cli/templates/sample_hooks/pre-connect.sample
|
243
245
|
- lib/kamal/cli/templates/sample_hooks/pre-deploy.sample
|
@@ -260,6 +262,7 @@ files:
|
|
260
262
|
- lib/kamal/commands/builder.rb
|
261
263
|
- lib/kamal/commands/builder/base.rb
|
262
264
|
- lib/kamal/commands/builder/clone.rb
|
265
|
+
- lib/kamal/commands/builder/cloud.rb
|
263
266
|
- lib/kamal/commands/builder/hybrid.rb
|
264
267
|
- lib/kamal/commands/builder/local.rb
|
265
268
|
- lib/kamal/commands/builder/remote.rb
|
@@ -309,6 +312,7 @@ files:
|
|
309
312
|
- lib/kamal/configuration/validator/role.rb
|
310
313
|
- lib/kamal/configuration/validator/servers.rb
|
311
314
|
- lib/kamal/configuration/volume.rb
|
315
|
+
- lib/kamal/docker.rb
|
312
316
|
- lib/kamal/env_file.rb
|
313
317
|
- lib/kamal/git.rb
|
314
318
|
- lib/kamal/secrets.rb
|
@@ -316,11 +320,13 @@ files:
|
|
316
320
|
- lib/kamal/secrets/adapters/aws_secrets_manager.rb
|
317
321
|
- lib/kamal/secrets/adapters/base.rb
|
318
322
|
- lib/kamal/secrets/adapters/bitwarden.rb
|
323
|
+
- lib/kamal/secrets/adapters/bitwarden_secrets_manager.rb
|
319
324
|
- lib/kamal/secrets/adapters/doppler.rb
|
325
|
+
- lib/kamal/secrets/adapters/enpass.rb
|
326
|
+
- lib/kamal/secrets/adapters/gcp_secret_manager.rb
|
320
327
|
- lib/kamal/secrets/adapters/last_pass.rb
|
321
328
|
- lib/kamal/secrets/adapters/one_password.rb
|
322
329
|
- lib/kamal/secrets/adapters/test.rb
|
323
|
-
- lib/kamal/secrets/adapters/test_optional_account.rb
|
324
330
|
- lib/kamal/secrets/dotenv/inline_command_substitution.rb
|
325
331
|
- lib/kamal/sshkit_with_ext.rb
|
326
332
|
- lib/kamal/tags.rb
|
@@ -346,7 +352,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
346
352
|
- !ruby/object:Gem::Version
|
347
353
|
version: '0'
|
348
354
|
requirements: []
|
349
|
-
rubygems_version: 3.
|
355
|
+
rubygems_version: 3.5.22
|
350
356
|
signing_key:
|
351
357
|
specification_version: 4
|
352
358
|
summary: Deploy web apps in containers to servers running Docker with zero downtime.
|