Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Enpass - a password manager for secrets #1189

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

egze
Copy link

@egze egze commented Nov 3, 2024

I hope the maintainers would like to add support for one more password manager - Enpass. It is a well known app, and I would be thrilled to use it together with Kamal. I also promise to fix any future issues with it.

Given a saved secret like this:
382569507-ed83f416-ecae-4c40-bf2e-d720dea5b712

Usage with Kamal would be:

# Fetch from item `FooBar ` in the vault `PATH_TO_VAULT `
kamal secrets fetch --adapter enpass --from <PATH_TO_VAULT> FooBar

kamal secrets extract DB_PASSWORD <SECRETS-FETCH-OUTPUT>
kamal secrets extract FooBar/DB_PASSWORD <SECRETS-FETCH-OUTPUT>

@egze egze marked this pull request as draft November 3, 2024 18:13
@egze egze marked this pull request as ready for review November 3, 2024 22:34
Copy link
Collaborator

@djmb djmb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR @egze!

I've added a few suggestions, let me know if they make sense!

end

def fetch_secret_titles(secrets)
secrets.reduce(Set.new) do |acc, secret|
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does acc mean here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accumulator. Common naming in Elixir. What would you recommend?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed it to secrets_with_passwords

unparsed_result.split("\n").reduce({}) do |acc, line|
title = line[/title:\s{1}(\w+)/, 1]
label = line[/label:\s{1}(.*?)\s{2}/, 1]
password = line[/password:\s{1}([^"]+)/, 1]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This parsing seems very fragile - what about titles with spaces, or labels with two spaces?

I think this is really just a function of Enpass's output format though - it would be nice if it offered JSON.

Maybe we should just ask for each password one by one to avoid ambiguity or misparsing of results? How fast is a single enpasscli pass call?

Copy link
Author

@egze egze Nov 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now they don't offer JSON, but I have brought it up. If it gets added - then I will change the current implementation.

As to getting the password one by one - it won't be a good experience, because there is no concept of a session. So you would have to enter the master password for each item.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created a PR for JSON support hazcod/enpass-cli#142

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@djmb The PR is merged and I implemented the logic with JSON in mind.

secrets_titles = fetch_secret_titles(secrets)

# Enpass outputs result as stderr, I did not find a way to stub backticks and output to stderr. Open3 did the job.
_stdout, stderr, status = Open3.capture3("enpass-cli -vault #{account.shellescape} show #{secrets_titles.map(&:shellescape).join(" ")}")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There no account here, so we probably:

  1. Avoid passing an account at all
  2. Use the from field to specify the vault

The base adapter just appends the from field and secrets together and passes them into fetch_secrets.

That's not going to work here since the separator it uses is a /, so I think it should be ok to replace the fetch method for this adapter and have it pass the from field separately.

We can refactor that to be neater later once all the other new adapter PRs have landed to avoid messing with them.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, if I could override the fetch, that would be cleaner.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@djmb The -account option is marked as required in Kamal::Cli::Secrets (option :account, type: :string, required: true). If I want to not pass it at all, I need to make it optional. Is this a good idea to do it, just because of the way Enpass works? For other password managers it does make sense to have it required.

I think it's more practical to treat the Vault path as account for Enpass. What do you think?

Another option is to pass some dummy value as account and just not use it, but I'm also not sure about it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went ahead and make --account optional and passed vault in --from 327d716

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants