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

Feat(plugins): Add support for arista.avd.secure_hash to hash local_user passwords #4768

Draft
wants to merge 47 commits into
base: devel
Choose a base branch
from

Conversation

davidhayes9
Copy link

Change Summary

Add support for a arista.avd.secure_hash filter to allow a local_user to hash their password.

Related Issue(s)

Fixes #3883

Component(s) name

arista.avd.eos_cli_config_gen

Proposed changes

secure_hash does not accept any parameters other than the users password and returns a SHA512-Crypt password hash

local_users:
  - name: <str>
    sha512_password: "{{ 'clear_password' | secure_hash }}"

There is a dependancy on passlib and the filter been tested with passlib==1.7.4 (latest version)

The filter is named secure_hash as hash is the name of a Python built-in function but happy to hear other naming suggestions.

How to test

Added test coverage in pytest and molecule

Checklist

User Checklist

  • N/A

Repository Checklist

  • My code has been rebased from devel before I start
  • I have read the CONTRIBUTING document.
  • My change requires a change to the documentation and documentation have been updated accordingly.
  • I have updated molecule CI testing accordingly. (check the box if not applicable)

@davidhayes9 davidhayes9 requested review from a team as code owners November 28, 2024 08:41
Copy link

Review docs on Read the Docs

To test this pull request:

# Create virtual environment for this testing below the current directory
python -m venv test-avd-pr-4768
# Activate the virtual environment
source test-avd-pr-4768/bin/activate
# Install all requirements including PyAVD
pip install "pyavd[ansible] @ git+https://github.com/davidhayes9/avd.git@hash-filter#subdirectory=python-avd" --force
# Point Ansible collections path to the Python virtual environment
export ANSIBLE_COLLECTIONS_PATH=$VIRTUAL_ENV/ansible_collections
# Install Ansible collection
ansible-galaxy collection install git+https://github.com/davidhayes9/avd.git#/ansible_collections/arista/avd/,hash-filter --force
# Optional: Install AVD examples
cd test-avd-pr-4768
ansible-playbook arista.avd.install_examples

@github-actions github-actions bot added type: documentation Improvements or additions to documentation state: CI Updated CI scenario have been updated in the PR type: Python filters labels Nov 28, 2024
Copy link
Contributor

@gmuloc gmuloc 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 this PR and the implementation up to the tests! You have done all that was expected and thanks for this.

I have left a couple of comments of things to adjust.

The name in the referenced issue suggested by @ClausHolbechArista was arista.avd.hash not sure if we want to keep this one or use secure_hash

I have a slight concerned regarding not setting the salt as it means on every run of AVD the password will change (which is not going to make molecule happy among others) as it will be re-generated. It means what is produced won't be idempotent anymore (but yes it will work)

I am wondering if we should not add a salt option in the filter and tell people to generate one. And use it in the molecule scenario. Otherwise we need a different way to persist these (maybe one run and then people can take the output and remove the usage of the secure_hash)

Our stance until now also was that it was already supported by just using the builtin password_hash filter: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/password_hash_filter.html doing exactly this (offering the option to use salt)

python-avd/pyproject.toml Outdated Show resolved Hide resolved
python-avd/pyproject.toml Outdated Show resolved Hide resolved
python-avd/pyproject.toml Outdated Show resolved Hide resolved
python-avd/pyavd/j2filters/secure_hash.py Outdated Show resolved Hide resolved
python-avd/pyavd/j2filters/secure_hash.py Outdated Show resolved Hide resolved
python-avd/pyavd/j2filters/secure_hash.py Outdated Show resolved Hide resolved
python-avd/pyavd/j2filters/secure_hash.py Outdated Show resolved Hide resolved
python-avd/tests/pyavd/j2filters/test_secure_hash.py Outdated Show resolved Hide resolved
@davidhayes9
Copy link
Author

Thanks for this PR and the implementation up to the tests! You have done all that was expected and thanks for this.

I have left a couple of comments of things to adjust.

Thanks for reviewing and leaving the suggestions, i've pushed new changes and these should be resolve the suggestions.

The name in the referenced issue suggested by @ClausHolbechArista was arista.avd.hash not sure if we want to keep this one or use secure_hash

I did originally start by using arista.avd.hash but it looks like the code format is to use the filter name as the main caller function. When I used hash for this I was getting an error (I think from one of the linters) that a built-in function name was being used. I can try moving it back to hash though and confirming.

I have a slight concerned regarding not setting the salt as it means on every run of AVD the password will change (which is not going to make molecule happy among others) as it will be re-generated. It means what is produced won't be idempotent anymore (but yes it will work)

I am wondering if we should not add a salt option in the filter and tell people to generate one. And use it in the molecule scenario. Otherwise we need a different way to persist these (maybe one run and then people can take the output and remove the usage of the secure_hash)

Our stance until now also was that it was already supported by just using the builtin password_hash filter: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/password_hash_filter.html doing exactly this (offering the option to use salt)

Yes good point about the password being re-generated each time. I can add an optional salt parameter similar to the password_hash

@davidhayes9
Copy link
Author

the linter errors when I use hash

ruff....................................................................................................................Failed
- hook id: ruff
- exit code: 1

ansible_collections/arista/avd/plugins/filter/hash.py:18:5: A001 Variable `hash` is shadowing a Python builtin
   |
16 |     from pyavd.j2filters import hash
17 | except ImportError as e:
18 |     hash = RaiseOnUse(
   |     ^^^^ A001
19 |         AnsibleFilterError(
20 |             f"The '{PLUGIN_NAME}' plugin requires the 'pyavd' Python library. Got import error",
   |

python-avd/pyavd/j2filters/hash.py:46:5: A001 Variable `hash` is shadowing a Python builtin
   |
46 | def hash(user_password: str) -> str:
   |     ^^^^ A001
47 |     return _get_password_hash(user_password)
   |

Found 2 errors.

Let me know what the preference is for the filter name.

Comment on lines 46 to 47
def secure_hash(user_password: str) -> str:
return _get_password_hash(user_password)
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think we need this function as long as we don't provide any options. You can just rename the main function.

Since we asume it is a user password we can either decide to rename this to user_password_hash or maybe better keep this function with an extra argument to specify the type of password, and then call a _user_password_hash function. (only supported option is the user password for now, but maybe others will come later).

@carlbuchmann @gmuloc comments?

Copy link
Member

Choose a reason for hiding this comment

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

Sorry, I completely missed this notification. I would keep this function with an extra argument to specify the type of password, and then call a _user_password_hash function. I agree that other options will likely come later.

Copy link
Author

Choose a reason for hiding this comment

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

The extra arg has been done. There is an output_type arg that can take sha512_password for now. More values can be added in the future when there are more use cases. It will also default tosha512_password if the arg is left out. Below are some examples:

local_users:
  # Create a sha512 password hash with a user defined salt value (recommended). The output_type will default to sha512_password.
  - name: cvpadmin
    sha512_password: "{{ 'securepassword' | arista.avd.secure_hash(salt='Yar49ahkzKddRVYS')}}"

    # Create a sha512 password hash with a user defined salt value and specifying the output_type as a sha512_password.
  - name: cvpuser
    sha512_password: "{{ 'newpassword' | arista.avd.secure_hash(salt='Kte5paJ3czRQczbk', output_type='sha512_password')}}"

  # Create a sha512 password hash with a random salt. Note: this will create a new hash each time AVD is run.
  - name: admin
    sha512_password: "{{ 'password123' | arista.avd.secure_hash }}"

@github-actions github-actions bot added the state: conflict PR with conflict label Dec 10, 2024
Copy link

This pull request has conflicts, please resolve those before we can evaluate the pull request.

@github-actions github-actions bot removed role: cvp_configlet_upload issue related to cvp_configlet_upload role role: eos_cli_config_gen issue related to eos_cli_config_gen role module: inventory_to_container role: eos_config_deploy_cvp issue related to eos_config_deploy_cvp role role: eos_config_deploy_eapi issue related to eos_config_deploy_eapi role type: code quality CI and development toolset role: eos_validate_state state: Documentation role Updated role: eos_snapshot role: eos_designs issue related to eos_designs role labels Jan 3, 2025
python-avd/pyavd/j2filters/secure_hash.py Outdated Show resolved Hide resolved
python-avd/pyavd/j2filters/secure_hash.py Outdated Show resolved Hide resolved
@@ -25,6 +25,7 @@ dependencies = [
"deepmerge>=1.1.0",
"Jinja2>=3.0",
"requests>=2.27.0",
"passlib>=1.7.4",
Copy link
Contributor

Choose a reason for hiding this comment

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

@gmuloc , are you able to install this pyavd from source without adding passlib>=1.7.4 dependency under [build-system]?
I'm facing an issue as passlib is required for filters used in J2 templates that need to be compiled during the build

@gmuloc gmuloc marked this pull request as draft January 30, 2025 12:31
@gmuloc
Copy link
Contributor

gmuloc commented Jan 30, 2025

on-hold until we bring some alternative to passlib

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
state: CI Updated CI scenario have been updated in the PR type: documentation Improvements or additions to documentation type: Python filters
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Feat(plugins): Add local_users to a new hash filter
5 participants