Add lastpass, bitwarden adapters
This commit is contained in:
24
lib/kamal/secrets/adapters/base.rb
Normal file
24
lib/kamal/secrets/adapters/base.rb
Normal file
@@ -0,0 +1,24 @@
|
||||
class Kamal::Secrets::Adapters::Base
|
||||
delegate :optionize, to: Kamal::Utils
|
||||
|
||||
def fetch(secrets, account:, location: nil)
|
||||
session = login(account)
|
||||
full_secrets = secrets.map { |secret| [ location, secret ].compact.join("/") }
|
||||
fetch_from_vault(full_secrets, account: account, session: session)
|
||||
rescue => e
|
||||
$stderr.puts " \e[31mERROR (#{e.class}): #{e.message}\e[0m"
|
||||
$stderr.puts e.backtrace if ENV["VERBOSE"]
|
||||
|
||||
Process.kill("INT", Process.ppid) if ENV["KAMAL_SECRETS_KILL_PARENT"]
|
||||
exit 1
|
||||
end
|
||||
|
||||
private
|
||||
def login(...)
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
def fetch_from_vault(...)
|
||||
raise NotImplementedError
|
||||
end
|
||||
end
|
||||
52
lib/kamal/secrets/adapters/bitwarden.rb
Normal file
52
lib/kamal/secrets/adapters/bitwarden.rb
Normal file
@@ -0,0 +1,52 @@
|
||||
class Kamal::Secrets::Adapters::Bitwarden < Kamal::Secrets::Adapters::Base
|
||||
private
|
||||
def login(account)
|
||||
status = run_command("status")
|
||||
|
||||
if status["status"] == "unauthenticated"
|
||||
run_command("login #{account}")
|
||||
status = run_command("status")
|
||||
end
|
||||
|
||||
if status["status"] == "locked"
|
||||
session = run_command("unlock --raw", raw: true)
|
||||
status = run_command("status", session: session)
|
||||
end
|
||||
|
||||
raise RuntimeError, "Failed to login to and unlock Bitwarden" unless status["status"] == "unlocked"
|
||||
|
||||
run_command("sync", raw: true)
|
||||
raise RuntimeError, "Failed to sync Bitwarden" unless $?.success?
|
||||
|
||||
session
|
||||
end
|
||||
|
||||
def fetch_from_vault(secrets, account:, session:)
|
||||
{}.tap do |results|
|
||||
secrets.each do |secret|
|
||||
item, field = secret.split("/")
|
||||
item = run_command("get item #{item}", session: session)
|
||||
raise RuntimeError, "Could not read #{item} from Bitwarden" unless $?.success?
|
||||
if field
|
||||
item_field = item["fields"].find { |f| f["name"] == field }
|
||||
raise RuntimeError, "Could not find field #{field} in item #{item} in Bitwarden" unless item_field
|
||||
value = item_field["value"]
|
||||
results[secret] = value
|
||||
results[field] = value
|
||||
else
|
||||
results[secret] = item["login"]["password"]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def signedin?(account)
|
||||
JSON.parse(`bw status`.strip)["status"] != "unauthenticated"
|
||||
end
|
||||
|
||||
def run_command(command, session: nil, raw: false)
|
||||
full_command = [ *("BW_SESSION=#{session}" if session), "bw", command ].join(" ")
|
||||
result = `#{full_command}`.strip
|
||||
raw ? result : JSON.parse(result)
|
||||
end
|
||||
end
|
||||
29
lib/kamal/secrets/adapters/last_pass.rb
Normal file
29
lib/kamal/secrets/adapters/last_pass.rb
Normal file
@@ -0,0 +1,29 @@
|
||||
class Kamal::Secrets::Adapters::LastPass < Kamal::Secrets::Adapters::Base
|
||||
private
|
||||
def login(account)
|
||||
unless loggedin?(account)
|
||||
`lpass login #{account}`
|
||||
raise RuntimeError, "Failed to login to 1Password" unless $?.success?
|
||||
end
|
||||
end
|
||||
|
||||
def loggedin?(account)
|
||||
`lpass status --color never`.strip == "Logged in as #{account}."
|
||||
end
|
||||
|
||||
def fetch_from_vault(secrets, account:, session:)
|
||||
items = JSON.parse(`lpass show #{secrets.join(" ")} --json`
|
||||
raise RuntimeError, "Could not read #{fields} from 1Password" unless $?.success?
|
||||
|
||||
{}.tap do |results|
|
||||
items.each do |item|
|
||||
results[item["name"]] = item["password"]
|
||||
results[item["fullname"]] = item["password"]
|
||||
end
|
||||
|
||||
if (missing_items = secrets - results.keys).any?
|
||||
raise RuntimeError, "Could not find #{missing_items.join(", ")} in LassPass"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user