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 lookup plugin option (file_mode) to store secret in a file #51

Merged

Conversation

jcosteatcyberark
Copy link
Contributor

@jcosteatcyberark jcosteatcyberark commented Nov 13, 2020

What does this PR do?

This PR offers a new option: file_mode as_file (boolean) which adds the possibility to store a secret as a file in /dev/shm a temporary file instead of returning it directly. The lookup function instead returns the path of the file.

This feature addresses an issue with ansible_ssh_private_key_file which doesn't accept inline ssh keys.
By adding this option, it is now possible to use the below lookup with ansible_ssh_private_key_file:

ansible_ssh_private_key_file: "{​​{​​ lookup('cyberark.conjur.conjur_variable', 'path/to/secret-id', as_file=True) }​​}​​"

Without the need to handle temporary file creation in playbooks, it extends the current support of the below:

ansible_password: "{​​{​​ lookup('cyberark.conjur.conjur_variable', 'path/to/secret-id') }​​}​​"

What ticket does this PR close?

This PR addresses Issue #52 .
This PR also addresses the post in https://discuss.cyberarkcommons.org/t/conjur-ansible-lookup-plugin-and-ssh-key-file/1070

Checklists

Change log

  • The CHANGELOG has been updated, or
  • This PR does not include user-facing changes and doesn't require a CHANGELOG update

Test coverage

  • This PR includes new unit and integration tests to go with the code changes, or
  • The changes in this PR do not require tests

Documentation

  • Docs (e.g. READMEs) were updated in this PR, and/or there is a follow-on issue to update docs, or
  • This PR does not require updating any documentation

@jcosteatcyberark jcosteatcyberark requested a review from a team as a code owner November 13, 2020 16:32
This commit adds the file_mode option (boolean) which makes the lookup plugin
store the secret in /dev/shm: a file with a random name (0600 permissions)
is created.

The lookup command returns the file path.
Copy link
Contributor

@sgnn7 sgnn7 left a comment

Choose a reason for hiding this comment

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

@jcosteatcyberark Left some comments on this PR. Needs a bit of work but you're on the right track I think.

@@ -31,6 +31,10 @@
description: Flag to control SSL certificate validation
type: boolean
default: True
file_mode:
description: Store lookup result in a temp file
Copy link
Contributor

Choose a reason for hiding this comment

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

This should include another sentence regarding what this is useful for.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I agree, done in next commit.

@@ -86,6 +90,9 @@
from base64 import b64encode
from netrc import netrc
from os import environ
import stat
from random import choice
import string
Copy link
Contributor

Choose a reason for hiding this comment

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

Imports need to be sorted alphabetically

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I sorted the one I added, others don't seem to be though.
I'll keep it out of this PR.

@@ -86,6 +90,9 @@
from base64 import b64encode
from netrc import netrc
from os import environ
import stat
from random import choice
import string
Copy link
Contributor

Choose a reason for hiding this comment

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

For stat and string, I think you can import just the constants/functions you are using instead of the whole package

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks, done in next commit

CHANGELOG.md Outdated
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- The [Conjur Ansible role](https://galaxy.ansible.com/cyberark/conjur-host-identity) has been
migrated to this collection, where it will be maintained moving forward.
[cyberark/ansible-conjur-host-identity#30](https://github.com/cyberark/ansible-conjur-host-identity/issues/30)
- Add `file_mode` boolean option to store the secret as a temporary file in /dev/shm/ and return its path.
Copy link
Contributor

Choose a reason for hiding this comment

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

This should also include a link to the issue it is trying to resolve.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think we also need to add usage of this in the README too

Copy link
Contributor

Choose a reason for hiding this comment

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

This is a UX issue but file_mode isn't quite as descriptive as it should be to explain this feature. Any suggestions for a better one maybe?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added a link to the Cyberark Commons post. Regarding the usage, I'm not sure where to put it in README.
I renamed file_mode to as_file


if file_mode:
return _store_in_file(conjur_variable)
else:
Copy link
Contributor

Choose a reason for hiding this comment

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

else isn't needed at this point since there's only a single logic path that remain after file_mode return

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks, removed.

@@ -203,12 +210,24 @@ def _fetch_conjur_variable(conjur_variable, token, conjur_url, account, validate
return {}


def _store_in_file(value):
file_name = ''.join(choice(string.ascii_uppercase + string.digits) for i in range(12))
file_path = os.path.join("/dev/shm", file_name)
Copy link
Contributor

Choose a reason for hiding this comment

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

/dev/shm is not guaranteed to exist on the target system

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I created a function to return the best possible path, inspired by Summon equivalent

@@ -203,12 +210,24 @@ def _fetch_conjur_variable(conjur_variable, token, conjur_url, account, validate
return {}


def _store_in_file(value):
file_name = ''.join(choice(string.ascii_uppercase + string.digits) for i in range(12))
Copy link
Contributor

Choose a reason for hiding this comment

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

You probably should use something like tempfile.NamedTemporaryFile and set prefix/suffix/dir instead of manually assembling the name.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks, I didn't know this lib. I made the change in next commit

def _store_in_file(value):
file_name = ''.join(choice(string.ascii_uppercase + string.digits) for i in range(12))
file_path = os.path.join("/dev/shm", file_name)
with open(file_path, 'w+') as file:
Copy link
Contributor

Choose a reason for hiding this comment

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

+ in the mode isn't needed since we won't be reading the file

Copy link
Contributor

Choose a reason for hiding this comment

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

file -> secrets_file

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I agree!

file_path = os.path.join("/dev/shm", file_name)
with open(file_path, 'w+') as file:
file.write(value[0])
os.chmod(file_path, stat.S_IRUSR | stat.S_IWUSR)
Copy link
Contributor

Choose a reason for hiding this comment

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

We should chmod the file before we write the secret into it

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in next commit

file.write(value[0])
os.chmod(file_path, stat.S_IRUSR | stat.S_IWUSR)

return [file_path]
Copy link
Contributor

Choose a reason for hiding this comment

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

This return should happen as part of the function context, not the with context so it should be indented 1 lower level

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This piece of code is removed in next commit thanks to tempfile.NamedTemporaryFile.

@sgnn7
Copy link
Contributor

sgnn7 commented Nov 18, 2020

@jcosteatcyberark Is this ready for another review cycle? I haven't seen any messages that indicate that it is.

@jcosteatcyberark
Copy link
Contributor Author

Hi @sgnn7, sorry for the delay. It's updated and ready for a review!

@doodlesbykumbi doodlesbykumbi requested a review from a team December 4, 2020 22:08
@doodlesbykumbi
Copy link
Contributor

Hi @jcosteatcyberark. Just wanted to let you know that I've tagged the team (@cyberark/community-and-integrations-team) and we should be able to get someone to look at this soon.

Copy link
Contributor

@diverdane diverdane left a comment

Choose a reason for hiding this comment

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

@jcosteatcyberark , thank you for proposing this change! This looks very good to me. The only suggestion that I have is that it might be helpful to add an example of this lookup in the README (in addition to the plain variable lookup that's already there).
Also a question on the syntax for a call to check_output(), just for my own understanding.

assert secret_file.exists
assert secret_file.mode == 0o600

secret = host.check_output("cat {0}".format(secret_path), shell=True)
Copy link
Contributor

Choose a reason for hiding this comment

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

@jcosteatcyberark, just for my own understanding... Can you explain what this line is doing? I know it's doing a level of indirection (taking secret_path and cating the file that it points to), but I'd like to understand better.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hi @diverdane, the test playbook stores the lookup output in /conjur_secret_path.txt. This file contains the path to the file that contains the secret (secret_path).
To resume this test asserts that cat (cat /conjur_secret_path) = secret

Copy link
Contributor

Choose a reason for hiding this comment

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

since it wasn't clear to Dane from the code, is it worth writing this in a more-verbose-but-more-clear way or at least adding a code comment?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hi @izgeri I cleaned up the code and commented. It should be easier to understand now.

@jcosteatcyberark
Copy link
Contributor Author

jcosteatcyberark commented Dec 15, 2020

Hi @diverdane I added an example to the README and rewrote + commented the test for better readability.
It's ready for review!

Copy link
Contributor

@diverdane diverdane left a comment

Choose a reason for hiding this comment

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

LGTM! Thanks for adding this feature!

@diverdane diverdane merged commit 5421f66 into cyberark:master Dec 16, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

None yet

5 participants