Add ability to alias secrets for tags

Aliasing for secrets was introduced in #1439, but only supported
"top-level" secrets. This adds support for aliasing/mapping secrets
for tags.
This commit is contained in:
Camillo Visini
2025-03-22 12:07:22 +01:00
parent 58e23f9167
commit c1d8ce7f70
3 changed files with 42 additions and 7 deletions

View File

@@ -65,6 +65,13 @@ env:
# MAIN_DB_PASSWORD=$(kamal secrets extract MAIN_DB_PASSWORD $SECRETS) # MAIN_DB_PASSWORD=$(kamal secrets extract MAIN_DB_PASSWORD $SECRETS)
# SECONDARY_DB_PASSWORD=$(kamal secrets extract SECONDARY_DB_PASSWORD $SECRETS) # SECONDARY_DB_PASSWORD=$(kamal secrets extract SECONDARY_DB_PASSWORD $SECRETS)
# ``` # ```
env:
secret:
- DB_PASSWORD:MAIN_DB_PASSWORD
tags:
secondary_db:
secret:
- DB_PASSWORD:SECONDARY_DB_PASSWORD
accessories: accessories:
main_db_accessory: main_db_accessory:
env: env:

View File

@@ -1,7 +1,7 @@
class Kamal::Configuration::Env class Kamal::Configuration::Env
include Kamal::Configuration::Validation include Kamal::Configuration::Validation
attr_reader :context, :secrets attr_reader :context
attr_reader :clear, :secret_keys attr_reader :clear, :secret_keys
delegate :argumentize, to: Kamal::Utils delegate :argumentize, to: Kamal::Utils
@@ -11,27 +11,37 @@ class Kamal::Configuration::Env
@secret_keys = config.fetch("secret", []) @secret_keys = config.fetch("secret", [])
@context = context @context = context
validate! config, context: context, with: Kamal::Configuration::Validator::Env validate! config, context: context, with: Kamal::Configuration::Validator::Env
@secret_map = build_secret_map(@secret_keys)
end end
def clear_args def clear_args
argumentize("--env", clear) argumentize("--env", clear)
end end
def secrets
@resolved_secrets ||= resolve_secrets
end
def secrets_io def secrets_io
Kamal::EnvFile.new(secrets_hash).to_io Kamal::EnvFile.new(secrets).to_io
end end
def merge(other) def merge(other)
self.class.new \ self.class.new \
config: { "clear" => clear.merge(other.clear), "secret" => secret_keys | other.secret_keys }, config: { "clear" => clear.merge(other.clear), "secret" => secret_keys | other.secret_keys },
secrets: secrets secrets: @secrets
end end
private private
def secrets_hash def build_secret_map(secret_keys)
secret_keys.to_h do |key| Array(secret_keys).to_h do |key|
key_name, key_aliased_to = key.split(":") key_name, key_aliased_to = key.split(":", 2)
[ key_name, secrets[key_aliased_to || key_name] ] key_aliased_to ||= key_name
[ key_name, key_aliased_to ]
end end
end end
def resolve_secrets
@secret_map.transform_values { |secret_key| @secrets[secret_key] }
end
end end

View File

@@ -96,6 +96,24 @@ class ConfigurationEnvTagsTest < ActiveSupport::TestCase
end end
end end
test "aliased tag secret env" do
with_test_secrets("secrets" => "PASSWORD=hello\nALIASED_PASSWORD=aliased_hello") do
deploy = {
service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" },
servers: [ { "1.1.1.1" => "secrets" } ],
builder: { "arch" => "amd64" },
env: {
"tags" => {
"secrets" => { "secret" => [ "PASSWORD:ALIASED_PASSWORD" ] }
}
}
}
config = Kamal::Configuration.new(deploy)
assert_equal "aliased_hello", config.role("web").env("1.1.1.1").secrets["PASSWORD"]
end
end
test "tag clear env" do test "tag clear env" do
deploy = { deploy = {
service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" }, service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" },