Prefix secrets in fetch_secrets

This allows us to remove the custom fetch method for enpass.
This commit is contained in:
Donal McBreen
2025-01-17 12:24:46 +00:00
parent db7556ed99
commit a1708f687f
10 changed files with 40 additions and 30 deletions

View File

@@ -4,9 +4,9 @@ class Kamal::Secrets::Adapters::AwsSecretsManager < Kamal::Secrets::Adapters::Ba
nil
end
def fetch_secrets(secrets, account:, session:)
def fetch_secrets(secrets, from:, account:, session:)
{}.tap do |results|
get_from_secrets_manager(secrets, account: account).each do |secret|
get_from_secrets_manager(prefixed_secrets(secrets, from: from), account: account).each do |secret|
secret_name = secret["Name"]
secret_string = JSON.parse(secret["SecretString"])

View File

@@ -7,8 +7,7 @@ class Kamal::Secrets::Adapters::Base
check_dependencies!
session = login(account)
full_secrets = secrets.map { |secret| [ from, secret ].compact.join("/") }
fetch_secrets(full_secrets, account: account, session: session)
fetch_secrets(secrets, from: from, account: account, session: session)
end
def requires_account?
@@ -27,4 +26,8 @@ class Kamal::Secrets::Adapters::Base
def check_dependencies!
raise NotImplementedError
end
def prefixed_secrets(secrets, from:)
secrets.map { |secret| [ from, secret ].compact.join("/") }
end
end

View File

@@ -21,9 +21,9 @@ class Kamal::Secrets::Adapters::Bitwarden < Kamal::Secrets::Adapters::Base
session
end
def fetch_secrets(secrets, account:, session:)
def fetch_secrets(secrets, from:, account:, session:)
{}.tap do |results|
items_fields(secrets).each do |item, fields|
items_fields(prefixed_secrets(secrets, from: from)).each do |item, fields|
item_json = run_command("get item #{item.shellescape}", session: session, raw: true)
raise RuntimeError, "Could not read #{item} from Bitwarden" unless $?.success?
item_json = JSON.parse(item_json)

View File

@@ -9,17 +9,11 @@ class Kamal::Secrets::Adapters::BitwardenSecretsManager < Kamal::Secrets::Adapte
LIST_COMMAND = "secret list -o env"
GET_COMMAND = "secret get -o env"
def fetch_secrets(secrets, account:, session:)
def fetch_secrets(secrets, from:, account:, session:)
raise RuntimeError, "You must specify what to retrieve from Bitwarden Secrets Manager" if secrets.length == 0
if secrets.length == 1
if secrets[0] == LIST_ALL_SELECTOR
command = LIST_COMMAND
elsif secrets[0].end_with?(LIST_ALL_FROM_PROJECT_SUFFIX)
project = secrets[0].split(LIST_ALL_FROM_PROJECT_SUFFIX).first
command = "#{LIST_COMMAND} #{project}"
end
end
secrets = prefixed_secrets(secrets, from: from)
command, project = extract_command_and_project(secrets)
{}.tap do |results|
if command.nil?
@@ -40,6 +34,17 @@ class Kamal::Secrets::Adapters::BitwardenSecretsManager < Kamal::Secrets::Adapte
end
end
def extract_command_and_project(secrets)
if secrets.length == 1
if secrets[0] == LIST_ALL_SELECTOR
[ LIST_COMMAND, nil ]
elsif secrets[0].end_with?(LIST_ALL_FROM_PROJECT_SUFFIX)
project = secrets[0].split(LIST_ALL_FROM_PROJECT_SUFFIX).first
[ "#{LIST_COMMAND} #{project}", project ]
end
end
end
def parse_secret(secret)
key, value = secret.split("=", 2)
value = value.gsub(/^"|"$/, "")

View File

@@ -16,8 +16,10 @@ class Kamal::Secrets::Adapters::Doppler < Kamal::Secrets::Adapters::Base
$?.success?
end
def fetch_secrets(secrets, **)
def fetch_secrets(secrets, from:, **)
secrets = prefixed_secrets(secrets, from: from)
project_and_config_flags = ""
unless service_token_set?
project, config, _ = secrets.first.split("/")

View File

@@ -9,20 +9,15 @@
# Fetch only DB_PASSWORD from FooBar item
# `kamal secrets fetch --adapter enpass --from /Users/YOUR_USERNAME/Library/Containers/in.sinew.Enpass-Desktop/Data/Documents/Vaults/primary FooBar/DB_PASSWORD`
class Kamal::Secrets::Adapters::Enpass < Kamal::Secrets::Adapters::Base
def fetch(secrets, account: nil, from:)
check_dependencies!
fetch_secrets(secrets, from)
end
def requires_account?
false
end
private
def fetch_secrets(secrets, vault)
def fetch_secrets(secrets, from:, account:, session:)
secrets_titles = fetch_secret_titles(secrets)
result = `enpass-cli -json -vault #{vault.shellescape} show #{secrets_titles.map(&:shellescape).join(" ")}`.strip
result = `enpass-cli -json -vault #{from.shellescape} show #{secrets_titles.map(&:shellescape).join(" ")}`.strip
parse_result_and_take_secrets(result, secrets)
end
@@ -36,6 +31,10 @@ class Kamal::Secrets::Adapters::Enpass < Kamal::Secrets::Adapters::Base
$?.success?
end
def login(account)
nil
end
def fetch_secret_titles(secrets)
secrets.reduce(Set.new) do |secret_titles, secret|
# Sometimes secrets contain a '/', when the intent is to fetch a single password for an item. Example: FooBar/DB_PASSWORD

View File

@@ -26,11 +26,11 @@ class Kamal::Secrets::Adapters::GcpSecretManager < Kamal::Secrets::Adapters::Bas
nil
end
def fetch_secrets(secrets, account:, session:)
def fetch_secrets(secrets, from:, account:, session:)
user, service_account = parse_account(account)
{}.tap do |results|
secrets_with_metadata(secrets).each do |secret, (project, secret_name, secret_version)|
secrets_with_metadata(prefixed_secrets(secrets, from: from)).each do |secret, (project, secret_name, secret_version)|
item_name = "#{project}/#{secret_name}"
results[item_name] = fetch_secret(project, secret_name, secret_version, user, service_account)
raise RuntimeError, "Could not read #{item_name} from Google Secret Manager" unless $?.success?

View File

@@ -11,7 +11,8 @@ class Kamal::Secrets::Adapters::LastPass < Kamal::Secrets::Adapters::Base
`lpass status --color never`.strip == "Logged in as #{account}."
end
def fetch_secrets(secrets, account:, session:)
def fetch_secrets(secrets, from:, account:, session:)
secrets = prefixed_secrets(secrets, from: from)
items = `lpass show #{secrets.map(&:shellescape).join(" ")} --json`
raise RuntimeError, "Could not read #{secrets} from LastPass" unless $?.success?

View File

@@ -15,9 +15,9 @@ class Kamal::Secrets::Adapters::OnePassword < Kamal::Secrets::Adapters::Base
$?.success?
end
def fetch_secrets(secrets, account:, session:)
def fetch_secrets(secrets, from:, account:, session:)
{}.tap do |results|
vaults_items_fields(secrets).map do |vault, items|
vaults_items_fields(prefixed_secrets(secrets, from: from)).map do |vault, items|
items.each do |item, fields|
fields_json = JSON.parse(op_item_get(vault, item, fields, account: account, session: session))
fields_json = [ fields_json ] if fields.one?

View File

@@ -4,8 +4,8 @@ class Kamal::Secrets::Adapters::Test < Kamal::Secrets::Adapters::Base
true
end
def fetch_secrets(secrets, account:, session:)
secrets.to_h { |secret| [ secret, secret.reverse ] }
def fetch_secrets(secrets, from:, account:, session:)
prefixed_secrets(secrets, from: from).to_h { |secret| [ secret, secret.reverse ] }
end
def check_dependencies!