├── ansible ├── __init__.py ├── modules │ ├── __init__.py │ └── hashivault │ │ ├── __init__.py │ │ ├── hashivault_write_from_file.py │ │ ├── hashivault_rekey_status.py │ │ ├── hashivault_generate_root_status.py │ │ ├── hashivault_status.py │ │ ├── hashivault_leader.py │ │ ├── hashivault_audit_list.py │ │ ├── hashivault_read_to_file.py │ │ ├── hashivault_seal.py │ │ ├── hashivault_auth_list.py │ │ ├── hashivault_rekey_cancel.py │ │ ├── hashivault_secret_list.py │ │ ├── hashivault_generate_root_cancel.py │ │ ├── hashivault_unseal.py │ │ ├── hashivault_policy_list.py │ │ ├── hashivault_generate_root.py │ │ ├── hashivault_approle_role_list.py │ │ ├── hashivault_rekey.py │ │ ├── hashivault_policy_get.py │ │ ├── hashivault_approle_role_id.py │ │ ├── _hashivault_userpass_delete.py │ │ ├── hashivault_read.py │ │ ├── hashivault_approle_role_get.py │ │ ├── _hashivault_approle_role_secret_delete.py │ │ ├── _hashivault_secret_disable.py │ │ ├── hashivault_pki_cert_list.py │ │ ├── hashivault_pki_role_list.py │ │ ├── hashivault_generate_root_init.py │ │ ├── _hashivault_policy_delete.py │ │ ├── hashivault_approle_role_secret_list.py │ │ ├── hashivault_pki_url_get.py │ │ ├── _hashivault_audit_enable.py │ │ ├── hashivault_pki_crl_rotate.py │ │ ├── hashivault_pki_crl_get.py │ │ ├── hashivault_approle_role_secret_accessor_get.py │ │ ├── hashivault_token_revoke.py │ │ ├── _hashivault_policy_set.py │ │ ├── hashivault_pki_cert_get.py │ │ ├── _hashivault_auth_enable.py │ │ ├── hashivault_cluster_status.py │ │ ├── _hashivault_userpass_create.py │ │ ├── hashivault_token_lookup.py │ │ ├── hashivault_pki_role_get.py │ │ ├── hashivault_token_renew.py │ │ ├── _hashivault_policy_set_from_file.py │ │ ├── hashivault_rekey_init.py │ │ ├── hashivault_approle_role_secret_get.py │ │ ├── hashivault_pki_cert_revoke.py │ │ ├── _hashivault_secret_enable.py │ │ ├── hashivault_namespace.py │ │ ├── _hashivault_mount_tune.py │ │ ├── hashivault_consul_secret_engine_config.py │ │ ├── hashivault_pki_ca_set.py │ │ ├── hashivault_pki_crl.py │ │ └── hashivault_delete.py ├── module_utils │ └── __init__.py └── plugins │ ├── action │ └── hashivault_write_from_file.py │ └── doc_fragments │ └── hashivault.py ├── functional ├── hosts.ini ├── ansible.cfg ├── jwt.jws ├── stop.sh ├── templates │ ├── policy_rules.hcl │ ├── userpassenv.sh.j2 │ ├── vaultenv.sh.j2 │ └── approlenv.sh.j2 ├── test_enable_kv.yml ├── test_secret_list.yml ├── test_audit_old.yml ├── test_aws_auth_config.yml ├── test_environment_lookup.yml ├── test_aws_auth_role.yml ├── test_delete.yml ├── test_check.yml ├── test_init.yml ├── cacert.pem ├── test_policy_old.yml ├── test_consul_config.yml ├── test_full_path.yml ├── start.sh ├── test_userpass_idempotent.yml ├── test_azure_auth_role.yml ├── test_lookup.yml ├── test_unseal.yml ├── test_oidc_auth_role.yml ├── test_azure_auth_config.yml ├── test_status.yml ├── test_userpass_no_policy.yml ├── test_oidc_auth_method_config.yml ├── test_auth.yml ├── test_azure_config.yml ├── test_read.yml ├── test_userpass.yml ├── test_not_there.yml ├── test_namespace.yml ├── test_mounts.yml ├── test_azure_role.yml ├── test_ldap_group.yml ├── test_consul_role.yml ├── test_audit.yml ├── test_db_role.yml ├── test_approle_old.yml ├── test_db_config.yml ├── test_rekey.yml ├── test_approle_check_mode.yml ├── test_generate_root.yml ├── test_k8_auth.yml ├── test_auth_method.yml └── test_identity_entity.yml ├── library ├── module_utils ├── action_plugins ├── lookup_plugins ├── AUTHORS ├── example ├── hosts ├── ansible.cfg ├── run.sh ├── test_remote_host.yml ├── Dockerfile └── README.rst ├── ansible.cfg ├── test-requirements.txt ├── setup.cfg ├── MANIFEST.in ├── meta └── main.yml ├── .editorconfig ├── .gitchangelog.rc ├── .gitignore ├── tox.ini ├── link.sh ├── makedocs.sh ├── setup.py ├── LICENSE ├── upload.sh └── .travis.yml /ansible/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ansible/modules/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ansible/module_utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /functional/hosts.ini: -------------------------------------------------------------------------------- 1 | local 2 | -------------------------------------------------------------------------------- /library: -------------------------------------------------------------------------------- 1 | ansible/modules/hashivault -------------------------------------------------------------------------------- /module_utils: -------------------------------------------------------------------------------- 1 | ansible/module_utils -------------------------------------------------------------------------------- /action_plugins: -------------------------------------------------------------------------------- 1 | ansible/plugins/action -------------------------------------------------------------------------------- /ansible/modules/hashivault/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lookup_plugins: -------------------------------------------------------------------------------- 1 | ansible/plugins/lookup -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Terry Howe 2 | -------------------------------------------------------------------------------- /example/hosts: -------------------------------------------------------------------------------- 1 | sandbox ansible_port=3022 ansible_host=127.0.0.1 2 | -------------------------------------------------------------------------------- /ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | retry_files_enabled = False 3 | nocows = 1 4 | -------------------------------------------------------------------------------- /test-requirements.txt: -------------------------------------------------------------------------------- 1 | pycodestyle==2.5.0 2 | tox==3.7.0 3 | sphinx 4 | sphinx_rtd_theme 5 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | description-file = README.rst 3 | 4 | [tool:pytest] 5 | pep8maxlinelength = 120 -------------------------------------------------------------------------------- /functional/ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | retry_files_enabled = False 3 | inventory = ./hosts.ini 4 | 5 | [inventory] 6 | enable_plugins = ini 7 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include AUTHORS 2 | include CHANGELOG.rst 3 | include LICENSE 4 | include README.rst 5 | exclude .gitignore 6 | 7 | global-exclude *.pyc 8 | -------------------------------------------------------------------------------- /example/ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | retry_files_enabled = False 3 | inventory = ./hosts 4 | private_key_file = .ssh/id_rsa 5 | remote_port = 3022 6 | remote_user = root 7 | -------------------------------------------------------------------------------- /functional/jwt.jws: -------------------------------------------------------------------------------- 1 | eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c 2 | -------------------------------------------------------------------------------- /functional/stop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -ex 2 | # 3 | # Stop the test vault container 4 | # 5 | export NAME=${NAME:-test_vault} 6 | docker stop $NAME 2>/dev/null || true 7 | rm -f ./vaultenv.sh approlenv.sh 8 | -------------------------------------------------------------------------------- /functional/templates/policy_rules.hcl: -------------------------------------------------------------------------------- 1 | path "secret/bob/*" { 2 | capabilities = ["create", "read", "update", "delete", "list"] 3 | } 4 | path "secret/bob" { 5 | capabilities = ["list"] 6 | } 7 | -------------------------------------------------------------------------------- /meta/main.yml: -------------------------------------------------------------------------------- 1 | galaxy_info: 2 | author: Terry Howe 3 | description: Ansible modules for Hashicorp Vault 4 | license: MIT 5 | 6 | min_ansible_version: 2.0 7 | 8 | galaxy_tags: 9 | - hashicorp 10 | - vault 11 | - secrets 12 | - security 13 | 14 | dependencies: [] 15 | -------------------------------------------------------------------------------- /example/run.sh: -------------------------------------------------------------------------------- 1 | docker stop sandbox 2>/dev/null 2 | docker rm -f sandbox 2>/dev/null 3 | docker rmi -f sandbox 2>/dev/null 4 | mkdir -p .ssh 5 | chmod 700 .ssh 6 | ssh-keygen -t rsa -f .ssh/id_rsa -N '' -q [0-9]+\.[0-9]+(\.[0-9]+))\s+\([0-9]+-[0-9]{2}-[0-9]{2}\)\n--+\n" 4 | revs = [ 5 | Caret(FileFirstRegexMatch(OUTPUT_FILE, INSERT_POINT)), 6 | "HEAD" 7 | ] 8 | 9 | publish = FileInsertAtFirstRegexMatch( 10 | OUTPUT_FILE, 11 | INSERT_POINT, 12 | idx=lambda m: m.start(1) 13 | ) 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | .venv 3 | .cache 4 | .testenv 5 | 6 | # Packages 7 | .eggs 8 | *.egg 9 | *.egg-info 10 | dist 11 | build 12 | eggs 13 | sdist 14 | MANIFEST 15 | 16 | # Test 17 | .tox 18 | .testrepository 19 | 20 | # Editors 21 | *~ 22 | .*.swp 23 | .idea 24 | .vscode 25 | 26 | functional/approlenv.sh 27 | functional/userpassenv.sh 28 | functional/vaultenv.sh 29 | example/.ssh 30 | 31 | # Git 32 | *.orig 33 | -------------------------------------------------------------------------------- /functional/test_enable_kv.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | gather_facts: no 4 | tasks: 5 | - name: Make surea backend is enabled 6 | hashivault_secret_list: 7 | register: vault_secret_list 8 | - block: 9 | - name: Enable secret backend 10 | hashivault_secret_engine: 11 | name: "secret" 12 | backend: "kv" 13 | when: "'secret/' not in vault_secret_list.backends" 14 | -------------------------------------------------------------------------------- /functional/test_secret_list.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | gather_facts: no 4 | tasks: 5 | - name: List secret stores 6 | hashivault_secret_list: 7 | register: 'vault_secret_list' 8 | - assert: { that: "{{vault_secret_list.changed}} == False" } 9 | - assert: { that: "{{vault_secret_list.failed}} == False" } 10 | - assert: { that: "'backends' in vault_secret_list" } 11 | - assert: { that: "{{vault_secret_list.rc}} == 0" } 12 | 13 | -------------------------------------------------------------------------------- /example/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:xenial 2 | 3 | RUN apt-get update 4 | RUN apt-get install -y openssh-server python 5 | RUN mkdir /var/run/sshd 6 | RUN mkdir /root/.ssh 7 | RUN chmod 0700 /root/.ssh 8 | COPY .ssh/id_rsa.pub /root/.ssh/authorized_keys 9 | RUN chmod 0600 /root/.ssh/authorized_keys 10 | RUN echo 'root:root' |chpasswd 11 | RUN echo 'PermitRootLogin yes' >>/etc/ssh/sshd_config 12 | RUN sed -ri 's/UsePAM yes/#UsePAM yes/g' /etc/ssh/sshd_config 13 | RUN sed -ri 's/^#PubkeyAuthentication/PubkeyAuthentication/g' /etc/ssh/sshd_config 14 | RUN sed -ri 's/^#AuthorizedKeysFile/AuthorizedKeysFile/g' /etc/ssh/sshd_config 15 | 16 | EXPOSE 22 17 | 18 | CMD ["/usr/sbin/sshd", "-D"] 19 | -------------------------------------------------------------------------------- /functional/test_audit_old.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | gather_facts: no 4 | tasks: 5 | - hashivault_audit_list: 6 | register: 'vault_audit_list' 7 | 8 | - hashivault_audit_enable: 9 | name: "file" 10 | options: 11 | file_path: "/tmp/vault.log" 12 | register: 'vault_audit_enable' 13 | - assert: { that: "{{vault_audit_enable.changed}} == True" } 14 | - assert: { that: "{{vault_audit_enable.rc}} == 0" } 15 | 16 | - hashivault_audit_enable: 17 | name: "file" 18 | options: 19 | file_path: "/tmp/vault.log" 20 | register: 'vault_audit_enable_twice' 21 | - assert: { that: "{{vault_audit_enable_twice.changed}} == False" } 22 | - assert: { that: "{{vault_audit_enable_twice.rc}} == 0" } 23 | -------------------------------------------------------------------------------- /functional/test_aws_auth_config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | gather_facts: false 4 | tasks: 5 | - hashivault_auth_list: 6 | register: auth_list 7 | 8 | - hashivault_auth_method: 9 | method_type: aws 10 | when: "'strokes/' not in auth_list.backends" 11 | 12 | - hashivault_aws_auth_config: 13 | mount_point: aws 14 | access_key: bob 15 | secret_key: topsecret 16 | register: aws_result 17 | - assert: { that: "{{aws_result.changed}} == True" } 18 | - assert: { that: "{{aws_result.rc}} == 0" } 19 | 20 | - hashivault_aws_auth_config: 21 | mount_point: aws 22 | state: absent 23 | register: aws_result 24 | - assert: { that: "{{aws_result.changed}} == True" } 25 | - assert: { that: "{{aws_result.rc}} == 0" } 26 | -------------------------------------------------------------------------------- /functional/test_environment_lookup.yml: -------------------------------------------------------------------------------- 1 | # 2 | # This test depends on successful test_write run 3 | # 4 | --- 5 | - hosts: localhost 6 | gather_facts: no 7 | environment: 8 | VAULT_ADDR: 'http://127.0.0.1:8201' 9 | BOGUS: 'asdf' 10 | vars: 11 | namespace: '' 12 | name_root: '{{namespace}}basic' 13 | name_folder: '{{namespace}}stalks/bean' 14 | name_dict: '{{namespace}}_dict' 15 | name_array: '{{namespace}}_array' 16 | vars_foo: "{{lookup('hashivault', '{{name_root}}', 'foo')}}" 17 | dict_value: 18 | foo: 'bar' 19 | baz: 'stuff' 20 | array_value: 21 | - 'one' 22 | - 'two' 23 | - 'three' 24 | tasks: 25 | - set_fact: 26 | a_set_fie: "{{lookup('hashivault', '{{name_root}}', 'fie')}}" 27 | - assert: { that: "'{{a_set_fie}}' == 'fum'" } 28 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = pep8,py27,py36 3 | 4 | [testenv] 5 | install_command = pip install {opts} {packages} 6 | setenv = 7 | VIRTUAL_ENV={envdir} 8 | LANG=en_US.UTF-8 9 | LANGUAGE=en_US:en 10 | LC_ALL=C 11 | whitelist_externals = bash 12 | commands = bash -ex {toxinidir}/functional/run.sh 13 | 14 | [testenv:venv] 15 | commands = {posargs} 16 | 17 | [testenv:pep8] 18 | install_command = pip install {opts} {packages} 19 | setenv = 20 | VIRTUAL_ENV={envdir} 21 | LANG=en_US.UTF-8 22 | LANGUAGE=en_US:en 23 | LC_ALL=C 24 | deps = pycodestyle==2.5.0 25 | commands = 26 | pycodestyle --max-line-length=120 --statistics ansible 27 | 28 | [testenv:docs] 29 | setenv = 30 | VIRTUAL_ENV={envdir} 31 | LANG=en_US.UTF-8 32 | LANGUAGE=en_US:en 33 | LC_ALL=C 34 | commands = 35 | ./makedocs.sh 36 | -------------------------------------------------------------------------------- /functional/test_aws_auth_role.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | gather_facts: false 4 | tasks: 5 | - hashivault_auth_list: 6 | register: auth_list 7 | 8 | - hashivault_auth_method: 9 | method_type: aws 10 | when: "'aws/' not in auth_list.backends" 11 | 12 | - hashivault_aws_auth_role: 13 | name: ec2-role 14 | auth_type: iam 15 | inferred_entity_type: ec2_instance 16 | inferred_aws_region: eu-west-1 17 | bound_iam_role_arn: arn:aws:iam::12345678:role/ec2-role 18 | register: aws_result 19 | - assert: { that: "{{aws_result.changed}} == True" } 20 | - assert: { that: "{{aws_result.rc}} == 0" } 21 | 22 | - hashivault_aws_auth_role: 23 | name: ec2-role 24 | state: absent 25 | register: aws_result 26 | - assert: { that: "{{aws_result.changed}} == True" } 27 | - assert: { that: "{{aws_result.rc}} == 0" } 28 | -------------------------------------------------------------------------------- /link.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | DEST=$(echo "${VIRTUAL_ENV}"/lib/python*/site-packages/ansible/) 3 | 4 | rm -rf "$DEST"/modules/hashivault 5 | rm -f "$DEST"/module_utils/hashivault.py 6 | rm -f "$DEST"/plugins/lookup/hashivault.py 7 | rm -f "$DEST"/plugins/doc_fragments/hashivault.py 8 | rm -f "$DEST"/plugins/action/hashivault_read_to_file.py 9 | rm -f "$DEST"/plugins/action/hashivault_write_from_file.py 10 | 11 | ln -s "$PWD"/ansible/modules/hashivault "$DEST"/modules/hashivault 12 | ln "$PWD"/ansible/module_utils/hashivault.py "$DEST"/module_utils/hashivault.py 13 | ln "$PWD"/ansible/plugins/lookup/hashivault.py "$DEST"/plugins/lookup/hashivault.py 14 | ln "$PWD"/ansible/plugins/doc_fragments/hashivault.py "$DEST"/plugins/doc_fragments/hashivault.py 15 | ln "$PWD"/ansible/plugins/action/hashivault_read_to_file.py "$DEST"/plugins/action/hashivault_read_to_file.py 16 | ln "$PWD"/ansible/plugins/action/hashivault_write_from_file.py "$DEST"/plugins/action/hashivault_write_from_file.py 17 | -------------------------------------------------------------------------------- /functional/test_delete.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | gather_facts: no 4 | tasks: 5 | - hashivault_write: 6 | secret: test_delete 7 | data: 8 | uno: 'beck' 9 | duo: 'clash' 10 | 11 | - name: Make sure we can read it 12 | hashivault_read: 13 | secret: test_delete 14 | 15 | - name: Delete secret 16 | hashivault_delete: 17 | secret: test_delete 18 | register: vault_delete 19 | - assert: { that: "{{vault_delete.changed}} == True" } 20 | - assert: { that: "{{vault_delete.rc}} == 0" } 21 | - assert: { that: "'{{vault_delete.msg}}' == 'Secret secret/test_delete deleted'" } 22 | 23 | - name: Make sure secret value is gone 24 | hashivault_read: 25 | secret: test_delete 26 | register: vault_read 27 | failed_when: False 28 | - assert: { that: "{{vault_read.changed}} == False" } 29 | - assert: { that: "'{{vault_read.msg}}' == 'Secret secret/test_delete is not in vault'" } 30 | -------------------------------------------------------------------------------- /makedocs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | CHANGES=$(git diff-index --name-only HEAD --) 3 | export PLUGINS='' 4 | rm -rf ansible-repo 5 | mkdir -p ansible-repo 6 | cd ansible-repo 7 | git clone --branch 'v2.9.6' https://github.com/ansible/ansible.git 8 | pip install -r ansible/requirements.txt 9 | pip install sphinx sphinx_rtd_theme 10 | pip install straight.plugin 11 | pip install sphinx-notfound-page==0.4 12 | rm -rf ansible/lib/ansible/modules/ && mkdir -p ansible/lib/ansible/modules/hashivault 13 | cp -r ../ansible/modules/hashivault/hashivault*.py ansible/lib/ansible/modules/hashivault/ 14 | rm -f ansible/lib/ansible/plugins/doc_fragments/hashivault.py 15 | cp {..,ansible/lib}/ansible/plugins/doc_fragments/hashivault.py 16 | ls ansible/lib/ansible/modules/hashivault 17 | export MODULES=$(ls -m ansible/lib/ansible/modules/hashivault/ | grep -v '^_' | tr -d '[:space:]' | sed 's/.py//g') 18 | cd ansible/docs/docsite/ 19 | rm -f $(find . -name developing_modules_general_windows.rst) 20 | make webdocs || true 21 | touch _build/html/.nojekyll 22 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from setuptools import setup 3 | 4 | py_files = [ 5 | "ansible/module_utils/hashivault", 6 | "ansible/plugins/lookup/hashivault", 7 | "ansible/plugins/action/hashivault_read_to_file", 8 | "ansible/plugins/action/hashivault_write_from_file", 9 | "ansible/plugins/doc_fragments/hashivault", 10 | ] 11 | files = [ 12 | "ansible/modules/hashivault", 13 | ] 14 | 15 | long_description = open('README.rst', 'r').read() 16 | 17 | setup( 18 | name='ansible-modules-hashivault', 19 | version='4.5.6', 20 | description='Ansible Modules for Hashicorp Vault', 21 | long_description=long_description, 22 | long_description_content_type='text/x-rst', 23 | author='Terry Howe', 24 | author_email='terrylhowe@example.com', 25 | url='https://github.com/TerryHowe/ansible-modules-hashivault', 26 | py_modules=py_files, 27 | packages=files, 28 | install_requires=[ 29 | 'ansible>=2.0.0', 30 | 'hvac>=0.9.5', 31 | 'requests', 32 | ], 33 | ) 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Terry L Howe 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /functional/test_check.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | gather_facts: no 4 | vars: 5 | noo_value: 'noe' 6 | nie_value: 'num' 7 | dict_value: 8 | noo: 'bar' 9 | baz: 'stuff' 10 | tasks: 11 | - name: Write basic secret and verify it is changed 12 | hashivault_write: 13 | secret: 'check_one' 14 | data: 15 | noo: '{{noo_value}}' 16 | nie: '{{nie_value}}' 17 | register: 'vault_write' 18 | - assert: { that: vault_write.changed == True } 19 | - assert: { that: vault_write.rc == 0 } 20 | 21 | - name: Write single secret in folder 22 | hashivault_write: 23 | secret: check/two 24 | data: 25 | height: tall 26 | register: vault_write 27 | - assert: { that: vault_write.changed == True } 28 | - assert: { that: vault_write.rc == 0 } 29 | 30 | - name: Write secret dictionary 31 | hashivault_write: 32 | secret: 'check_three' 33 | data: "{{ dict_value }}" 34 | register: vault_write 35 | - assert: { that: vault_write.changed == True } 36 | - assert: { that: vault_write.rc == 0 } 37 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_write_from_file.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'community', 'version': '1.1'} 3 | DOCUMENTATION = ''' 4 | --- 5 | module: hashivault_write_from_file 6 | version_added: "3.8.3" 7 | short_description: Hashicorp Vault write file module 8 | description: 9 | - "Writes a file encoded in base64 to Hashicorp Vault. Implementation in 10 | `/plugins/action/hashivault_write_from_file.py`." 11 | options: 12 | secret: 13 | description: 14 | - vault secret to write. 15 | key: 16 | description: 17 | - secret key/name of file to write to vault. 18 | dest: 19 | description: 20 | - fully qualified path name of file to read from remote host. 21 | update: 22 | description: 23 | - Update secret rather than overwrite. 24 | default: True 25 | extends_documentation_fragment: hashivault 26 | ''' 27 | EXAMPLES = ''' 28 | --- 29 | - hosts: localhost 30 | tasks: 31 | - hashivault_write_from_file: 32 | secret: giant 33 | key: foo.dat 34 | path: /tmp/foo.dat 35 | ''' 36 | -------------------------------------------------------------------------------- /functional/test_init.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | gather_facts: no 4 | tasks: 5 | - name: Initialize vault 6 | hashivault_init: 7 | secret_shares: 1 8 | secret_threshold: 1 9 | register: 'vault_init' 10 | - block: 11 | - assert: { that: "{{vault_init.rc}} == 0" } 12 | when: "vault_init.changed == False" 13 | - block: 14 | - assert: { that: "'keys' in vault_init" } 15 | - assert: { that: "'root_token' in vault_init" } 16 | - assert: { that: "{{vault_init.rc}} == 0" } 17 | - set_fact: 18 | vault_keys: "{{vault_init['keys'] | join(' ')}}" 19 | - name: Unseal the vault 20 | hashivault_unseal: 21 | keys: '{{vault_keys}}' 22 | register: 'vault_unseal' 23 | - assert: { that: "{{vault_unseal.changed}} == True" } 24 | - assert: { that: "{{vault_unseal.status.progress}} == 0" } 25 | - assert: { that: "{{vault_unseal.status.sealed}} == False" } 26 | - assert: { that: "{{vault_unseal.rc}} == 0" } 27 | - template: 28 | src: "{{playbook_dir}}/templates/vaultenv.sh.j2" 29 | dest: "{{playbook_dir}}/vaultenv.sh" 30 | mode: 0700 31 | when: "vault_init.changed == True" 32 | -------------------------------------------------------------------------------- /upload.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Make sure you have a ~/.pypirc file first 4 | # 5 | CHANGES=$(git diff-index --name-only HEAD --) 6 | if [ -n "${CHANGES}" ] 7 | then 8 | echo "Changes have not been committed" 9 | exit 1 10 | fi 11 | BRANCH=$(git rev-parse --abbrev-ref HEAD) 12 | if [ "${BRANCH}" != "master" ] 13 | then 14 | echo "You must be on master" 15 | exit 1 16 | fi 17 | git pull 18 | pip install gitchangelog 19 | pip install twine 20 | OLDVERSION=$(grep version setup.py | sed -e "s/.*='//" -e "s/',//") 21 | vi setup.py 22 | VERSION=$(grep version setup.py | sed -e "s/.*='//" -e "s/',//") 23 | if [ "$OLDVERSION" == "$VERSION" ] 24 | then 25 | echo "Old version $OLDVERSION same as $VERSION" 26 | read ANS 27 | fi 28 | git tag -a $VERSION -m v$VERSION 29 | gitchangelog 30 | vi CHANGELOG.rst 31 | echo "Ready to push $VERSION (cntrl-c to quit)?" 32 | read ANS 33 | git commit -m "Version $VERSION" CHANGELOG.rst setup.py 34 | git push origin master 35 | git tag --force -a $VERSION -m v$VERSION 36 | git push origin --tags 37 | #python setup.py register -r pypi 38 | 39 | # old school 40 | # python setup.py sdist upload -r pypi 41 | 42 | # twine 43 | rm -rf dist 44 | python setup.py sdist # bdist_wheel 45 | twine upload dist/* 46 | -------------------------------------------------------------------------------- /functional/cacert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDWzCCAkOgAwIBAgIUMHq/CSkqKJyXvHQMLTHPZhSCTJ4wDQYJKoZIhvcNAQEL 3 | BQAwPTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNPMSEwHwYDVQQKDBhJbnRlcm5l 4 | dCBXaWRnaXRzIFB0eSBMdGQwHhcNMjAwNDEzMTg1MzE4WhcNMzAwNDExMTg1MzE4 5 | WjA9MQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ08xITAfBgNVBAoMGEludGVybmV0 6 | IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB 7 | ANEaqjseROsu3jTD0cy8rvy1e6++IJDwoHmVjf6PJAwiN+mzma2zEE9ZmP3x7Uzr 8 | POcWMjkvg5b2JtnmhB9KtvQsT0LBXHB5vPpTLRuA4GzSk1hdkvSw/a8Q4OIt22P+ 9 | FBHuKyeFiDwLOvn63lMWoKhhcB2Jj1r5s4FJmgJXWX+VVkESlbdg/1eALP4h+3L0 10 | rcSqyJvk8OZZfKVivZP+UcVSFeawxKBdvG9a42jIfKiu5Id2L5pWsl/eUk6qc8iO 11 | 7iEBOoox29mn/HNvXbp0n0WGbqV8M3h4oQ+YK4c6cVWMAk2fS7zc35oDepvT5+EG 12 | rPOAuYhWPTp+cPJTzk3aTu0CAwEAAaNTMFEwHQYDVR0OBBYEFOIZsbDQJN6YWNEA 13 | VWF7kTi1ehobMB8GA1UdIwQYMBaAFOIZsbDQJN6YWNEAVWF7kTi1ehobMA8GA1Ud 14 | EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAGmfODnrzcix5+vFspsUcFGD 15 | Hf0PnH6cEVXRkrEjprwAwbdjk2uSfdx4abOD2v/tBDq2r5jUKJMJUD1dp3OzuB7y 16 | K3v8YoKASQnOTpBZny+EN0/txG17yI7RbNRu0QISF/l9G09SapiHZCs+mqjTImVb 17 | yvZqJhPDxnCiUVbasqut7rX99NF6amQz+ONzV0YjLGJsxaOBBUFtGuqQpSTv4LgE 18 | TQlXHJTonUVhlnZF4j+ZeivVj/r526tynInD7kEhkE0ORfoXqZ6gUxosIKhccw80 19 | B9e322y39ilxKobRrR/rQkqgbdGFrqXny5lsyZUCPLBJgg67lYoLDE8/b3QEoek= 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /functional/test_policy_old.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | gather_facts: no 4 | vars: 5 | bobs_rules: > 6 | path "secret/oldbob/*" { 7 | capabilities = ["create", "read", "update", "delete", "list"] 8 | } 9 | path "secret/oldbob" { 10 | capabilities = ["list"] 11 | } 12 | tasks: 13 | - hashivault_policy: 14 | name: oldbob 15 | state: absent 16 | 17 | - name: Set new policy 18 | hashivault_policy_set: 19 | name: oldbob 20 | rules: "{{bobs_rules}}" 21 | register: 'vault_policy_set' 22 | - assert: { that: "{{vault_policy_set.changed}} == True" } 23 | - assert: { that: "{{vault_policy_set.rc}} == 0" } 24 | 25 | - name: Set new policy from file 26 | hashivault_policy_set_from_file: 27 | name: oldbob 28 | rules_file: "templates/policy_rules.hcl" 29 | register: 'vault_policy_set' 30 | - assert: { that: "{{vault_policy_set.changed}} == True" } 31 | - assert: { that: "{{vault_policy_set.rc}} == 0" } 32 | 33 | - name: Delete new policy 34 | hashivault_policy_delete: 35 | name: oldbob 36 | register: 'vault_policy_delete' 37 | - assert: { that: "{{vault_policy_delete.changed}} == True" } 38 | - assert: { that: "{{vault_policy_delete.rc}} == 0" } 39 | -------------------------------------------------------------------------------- /functional/test_consul_config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | gather_facts: no 4 | vars: 5 | consul_address: consul.local:8500 6 | scheme: https 7 | consul_token: myAwesomeConsulManagementToken 8 | tasks: 9 | - name: start with engine disabled 10 | hashivault_secret_engine: 11 | name: consul 12 | backend: consul 13 | state: absent 14 | 15 | - name: make sure test fails when no mount exists 16 | hashivault_consul_secret_engine_config: 17 | consul_address: "{{ consul_address }}" 18 | scheme: "{{ scheme }}" 19 | consul_token: "{{ consul_token }}" 20 | register: fail_config 21 | failed_when: false 22 | - assert: { that: "{{ fail_config.changed }} == False" } 23 | - assert: { that: "{{ fail_config.rc }} == 1" } 24 | 25 | - name: enable database secret engine 26 | hashivault_secret_enable: 27 | name: consul 28 | backend: consul 29 | 30 | - name: successfully configure 31 | hashivault_consul_secret_engine_config: 32 | consul_address: "{{ consul_address }}" 33 | scheme: "{{ scheme }}" 34 | consul_token: "{{ consul_token }}" 35 | register: success_config 36 | - assert: { that: "{{ success_config.changed }} == True" } 37 | - assert: { that: "{{ success_config.rc }} == 0" } 38 | -------------------------------------------------------------------------------- /functional/test_full_path.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | gather_facts: no 4 | tasks: 5 | - name: Delete full path before we start 6 | hashivault_delete: 7 | secret: /secret/full/path 8 | failed_when: False 9 | 10 | - name: Write full path 11 | hashivault_write: 12 | secret: /secret/full/path 13 | data: 14 | basket: ball 15 | register: vault_write 16 | - assert: { that: "{{vault_write.changed}} == True" } 17 | - assert: { that: "'{{vault_write.msg}}' == 'Secret secret/full/path written'" } 18 | - assert: { that: "{{vault_write.rc}} == 0" } 19 | 20 | - name: Read full path 21 | hashivault_read: 22 | secret: /secret/full/path 23 | key: basket 24 | register: vault_read 25 | - assert: { that: "'{{vault_read.value}}' == 'ball'" } 26 | 27 | - set_fact: 28 | basket: "{{lookup('hashivault', '/secret/full/path', 'basket')}}" 29 | - assert: { that: "'{{basket}}' == 'ball'" } 30 | 31 | - name: Delete full path 32 | hashivault_delete: 33 | secret: /secret/full/path 34 | register: vault_delete 35 | - assert: { that: "{{vault_delete.changed}} == True" } 36 | - assert: { that: "{{vault_delete.rc}} == 0" } 37 | - assert: { that: "'{{vault_delete.msg}}' == 'Secret secret/full/path deleted'" } -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_rekey_status.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_client 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = ''' 9 | --- 10 | module: hashivault_rekey_status 11 | version_added: "3.3.0" 12 | short_description: Hashicorp Vault rekey status module 13 | description: 14 | - Module to get rekey status of Hashicorp Vault. 15 | extends_documentation_fragment: hashivault 16 | ''' 17 | EXAMPLES = ''' 18 | --- 19 | - hosts: localhost 20 | tasks: 21 | - hashivault_rekey_status: 22 | register: "vault_rekey_status" 23 | ''' 24 | 25 | 26 | def main(): 27 | argspec = hashivault_argspec() 28 | module = hashivault_init(argspec) 29 | result = hashivault_rekey_status(module.params) 30 | if result.get('failed'): 31 | module.fail_json(**result) 32 | else: 33 | module.exit_json(**result) 34 | 35 | 36 | @hashiwrapper 37 | def hashivault_rekey_status(params): 38 | client = hashivault_client(params) 39 | return {'status': client.rekey_status} 40 | 41 | 42 | if __name__ == '__main__': 43 | main() 44 | -------------------------------------------------------------------------------- /functional/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -ex 2 | # 3 | # Start the test vault container 4 | # 5 | set -e 6 | DOCKER_NAME=testvault 7 | PORT=8201 8 | export VAULT_ADDR="http://127.0.0.1:${PORT}" 9 | 10 | TMP_CONFIG=$(mktemp -q /tmp/$0.XXXXXX) 11 | trap "rm $TMP_CONFIG" EXIT 12 | 13 | cat < $TMP_CONFIG 14 | { 15 | "backend": { 16 | "file": { 17 | "path": "/vault/file" 18 | } 19 | }, 20 | "listener": { 21 | "tcp": { 22 | "address": "0.0.0.0:${PORT}", 23 | "tls_disable": 1 24 | } 25 | }, 26 | "default_lease_ttl": "168h", 27 | "max_lease_ttl": "720h", 28 | "disable_mlock": true 29 | } 30 | EOF 31 | chmod a+r $TMP_CONFIG 32 | 33 | docker stop $DOCKER_NAME 2>/dev/null || true 34 | docker rm $DOCKER_NAME 2>/dev/null || true 35 | docker run --name $DOCKER_NAME -h $DOCKER_NAME -d \ 36 | --cap-add IPC_LOCK \ 37 | -p 127.0.0.1:${PORT}:${PORT} \ 38 | -v $TMP_CONFIG:/etc/vault/config.json:ro \ 39 | vault server -config /etc/vault/config.json 40 | 41 | # 42 | # Wait for vault to come up 43 | # 44 | CNT=0 45 | while ! curl -sI "$VAULT_ADDR/v1/sys/health" > /dev/null; do 46 | sleep 0.1 47 | CNT=$(expr $CNT + 1) 48 | if [ $CNT -gt 20 ] 49 | then 50 | docker logs $DOCKER_NAME 51 | exit 1 52 | fi 53 | done 54 | 55 | # 56 | # Initialize the vault 57 | # 58 | ansible-playbook -v test_init.yml 59 | source ./vaultenv.sh 60 | ansible-playbook -v test_enable_kv.yml 61 | exit $? 62 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_generate_root_status.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_client 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = ''' 9 | --- 10 | module: hashivault_generate_root_status 11 | version_added: "3.14.0" 12 | short_description: Hashicorp Vault generate_root status module 13 | description: 14 | - Module to get generate_root status of Hashicorp Vault. 15 | extends_documentation_fragment: hashivault 16 | ''' 17 | EXAMPLES = ''' 18 | --- 19 | - hosts: localhost 20 | tasks: 21 | - hashivault_generate_root_status: 22 | ''' 23 | 24 | 25 | def main(): 26 | argspec = hashivault_argspec() 27 | module = hashivault_init(argspec) 28 | result = hashivault_generate_root_status(module.params) 29 | if result.get('failed'): 30 | module.fail_json(**result) 31 | else: 32 | module.exit_json(**result) 33 | 34 | 35 | @hashiwrapper 36 | def hashivault_generate_root_status(params): 37 | client = hashivault_client(params) 38 | return {'status': client.generate_root_status} 39 | 40 | 41 | if __name__ == '__main__': 42 | main() 43 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_status.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_client 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = ''' 9 | --- 10 | module: hashivault_status 11 | version_added: "1.2.0" 12 | short_description: Hashicorp Vault status module 13 | description: 14 | - Module to get status of Hashicorp Vault. 15 | extends_documentation_fragment: hashivault 16 | ''' 17 | EXAMPLES = ''' 18 | --- 19 | - hosts: localhost 20 | tasks: 21 | - hashivault_status: 22 | register: 'vault_status' 23 | - debug: msg="Seal progress is {{vault_status.status.progress}}" 24 | ''' 25 | 26 | 27 | def main(): 28 | argspec = hashivault_argspec() 29 | module = hashivault_init(argspec) 30 | result = hashivault_status(module.params) 31 | if result.get('failed'): 32 | module.fail_json(**result) 33 | else: 34 | module.exit_json(**result) 35 | 36 | 37 | @hashiwrapper 38 | def hashivault_status(params): 39 | client = hashivault_client(params) 40 | return {'status': client.sys.read_seal_status()} 41 | 42 | 43 | if __name__ == '__main__': 44 | main() 45 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_leader.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_client 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = ''' 9 | --- 10 | module: hashivault_leader 11 | version_added: "3.16.4" 12 | short_description: Hashicorp Vault leader module 13 | description: 14 | - Module to get leader information of Hashicorp Vault. 15 | extends_documentation_fragment: hashivault 16 | ''' 17 | EXAMPLES = ''' 18 | --- 19 | - hosts: localhost 20 | tasks: 21 | - hashivault_leader: 22 | register: 'vault_leader' 23 | - debug: msg="Leader is {{vault_leader.status.leader_address}}" 24 | ''' 25 | 26 | 27 | def main(): 28 | argspec = hashivault_argspec() 29 | module = hashivault_init(argspec) 30 | result = hashivault_leader(module.params) 31 | if result.get('failed'): 32 | module.fail_json(**result) 33 | else: 34 | module.exit_json(**result) 35 | 36 | 37 | @hashiwrapper 38 | def hashivault_leader(params): 39 | client = hashivault_client(params) 40 | return {'status': client.sys.read_leader_status()} 41 | 42 | 43 | if __name__ == '__main__': 44 | main() 45 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_audit_list.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_auth_client 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = ''' 9 | --- 10 | module: hashivault_audit_list 11 | version_added: "2.2.0" 12 | short_description: Hashicorp Vault audit list module 13 | description: 14 | - Module to list audit backends in Hashicorp Vault. 15 | extends_documentation_fragment: hashivault 16 | ''' 17 | EXAMPLES = ''' 18 | --- 19 | - hosts: localhost 20 | tasks: 21 | - hashivault_audit_list: 22 | ''' 23 | 24 | 25 | def main(): 26 | argspec = hashivault_argspec() 27 | module = hashivault_init(argspec) 28 | result = hashivault_audit_list(module.params) 29 | if result.get('failed'): 30 | module.fail_json(**result) 31 | else: 32 | module.exit_json(**result) 33 | 34 | 35 | @hashiwrapper 36 | def hashivault_audit_list(params): 37 | client = hashivault_auth_client(params) 38 | backends = client.sys.list_enabled_audit_devices() 39 | backends = backends.get('data', backends) 40 | return {'changed': True, 'backends': backends} 41 | 42 | 43 | if __name__ == '__main__': 44 | main() 45 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_read_to_file.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'community', 'version': '1.1'} 3 | DOCUMENTATION = ''' 4 | --- 5 | module: hashivault_read_to_file 6 | version_added: "3.8.3" 7 | short_description: Hashicorp Vault read module 8 | description: 9 | - "Reads and deocdes a base64 encoded file from Hashicorp Vault and saves it to disk. Implementation in\ 10 | `/plugins/action/hashivault_read_to_file.py`." 11 | options: 12 | secret: 13 | description: 14 | - vault secret to read. 15 | key: 16 | description: 17 | - secret key/name of file to read from vault. 18 | dest: 19 | description: 20 | - fully qualified path name of file to write to remote host. 21 | force: 22 | description: 23 | - force overwrite of file. 24 | default: false 25 | mode: 26 | description: 27 | - file permissions of file to write on remote host. 28 | - in octal, don't forget leading zero! 29 | default: 0664 30 | base64: 31 | description: 32 | - Secret is base64 encoded 33 | default: True 34 | extends_documentation_fragment: hashivault 35 | ''' 36 | EXAMPLES = ''' 37 | --- 38 | - hosts: localhost 39 | tasks: 40 | - hashivault_read_to_file: 41 | secret: 'giant' 42 | key: 'foo.dat' 43 | dest: '/tmp/foo.dat' 44 | ''' 45 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_seal.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_auth_client 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = ''' 9 | --- 10 | module: hashivault_seal 11 | version_added: "1.2.0" 12 | short_description: Hashicorp Vault seal module 13 | description: 14 | - Module to seal Hashicorp Vault. 15 | extends_documentation_fragment: hashivault 16 | ''' 17 | EXAMPLES = ''' 18 | --- 19 | - hosts: localhost 20 | tasks: 21 | - hashivault_seal: 22 | register: 'vault_seal' 23 | - debug: msg="Seal return is {{vault_seal.rc}}" 24 | ''' 25 | 26 | 27 | def main(): 28 | argspec = hashivault_argspec() 29 | module = hashivault_init(argspec) 30 | result = hashivault_seal(module.params) 31 | if result.get('failed'): 32 | module.fail_json(**result) 33 | else: 34 | module.exit_json(**result) 35 | 36 | 37 | @hashiwrapper 38 | def hashivault_seal(params): 39 | client = hashivault_auth_client(params) 40 | if not client.sys.is_sealed(): 41 | status = client.sys.seal().ok 42 | return {'status': status, 'changed': True} 43 | else: 44 | return {'changed': False} 45 | 46 | 47 | if __name__ == '__main__': 48 | main() 49 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_auth_list.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_auth_client 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = ''' 9 | --- 10 | module: hashivault_auth_list 11 | version_added: "2.2.0" 12 | short_description: Hashicorp Vault auth list module 13 | description: 14 | - Module to list authentication backends in Hashicorp Vault. 15 | extends_documentation_fragment: hashivault 16 | ''' 17 | EXAMPLES = ''' 18 | --- 19 | - hosts: localhost 20 | tasks: 21 | - hashivault_auth_list: 22 | register: 'hashivault_auth_list' 23 | ''' 24 | 25 | 26 | def main(): 27 | argspec = hashivault_argspec() 28 | module = hashivault_init(argspec) 29 | result = hashivault_auth_list(module.params) 30 | if result.get('failed'): 31 | module.fail_json(**result) 32 | else: 33 | module.exit_json(**result) 34 | 35 | 36 | @hashiwrapper 37 | def hashivault_auth_list(params): 38 | client = hashivault_auth_client(params) 39 | result = client.sys.list_auth_methods() 40 | if isinstance(result, dict): 41 | result = result.get('data', result) 42 | return {'changed': False, 'backends': result} 43 | 44 | 45 | if __name__ == '__main__': 46 | main() 47 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_rekey_cancel.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_client 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = ''' 9 | --- 10 | module: hashivault_rekey_cancel 11 | version_added: "3.3.0" 12 | short_description: Hashicorp Vault rekey cancel module 13 | description: 14 | - Module to cancel rekey Hashicorp Vault. 15 | extends_documentation_fragment: hashivault 16 | ''' 17 | EXAMPLES = ''' 18 | --- 19 | - hosts: localhost 20 | tasks: 21 | - hashivault_rekey_cancel: 22 | register: "vault_rekey_cancel" 23 | ''' 24 | 25 | 26 | def main(): 27 | argspec = hashivault_argspec() 28 | module = hashivault_init(argspec) 29 | result = hashivault_rekey_cancel(module.params) 30 | if result.get('failed'): 31 | module.fail_json(**result) 32 | else: 33 | module.exit_json(**result) 34 | 35 | 36 | @hashiwrapper 37 | def hashivault_rekey_cancel(params): 38 | client = hashivault_client(params) 39 | # Check if rekey is on-going & return when rekey not in progress 40 | status = client.rekey_status 41 | if not status['started']: 42 | return {'changed': False} 43 | return {'status': client.sys.cancel_rekey().ok, 'changed': True} 44 | 45 | 46 | if __name__ == '__main__': 47 | main() 48 | -------------------------------------------------------------------------------- /functional/test_userpass_idempotent.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | gather_facts: no 4 | vars: 5 | username: 'portugal_idempotent' 6 | userpass: 'Th3m@n!!' 7 | tasks: 8 | - name: Enable kv2 secret store 9 | hashivault_userpass: 10 | name: bob 11 | state: absent 12 | no_log: True 13 | 14 | - name: Enable kv2 secret store 15 | hashivault_userpass: 16 | name: bob 17 | pass: S3cre7s 18 | policies: bob 19 | register: hashivault_userpass 20 | no_log: True 21 | - assert: { that: "{{hashivault_userpass.changed}} == True" } 22 | - assert: { that: "{{hashivault_userpass.rc}} == 0" } 23 | 24 | - name: Set token_bound_cidr for userpass 25 | hashivault_userpass: 26 | name: "{{username}}" 27 | pass: "{{userpass}}" 28 | policies: "default" 29 | token_bound_cidrs: "127.0.0.1" 30 | register: 'hashivault_userpass_token_bound_cidr' 31 | - assert: { that: "{{hashivault_userpass_token_bound_cidr.changed}} == True" } 32 | - assert: { that: "{{hashivault_userpass_token_bound_cidr.rc}} == 0" } 33 | 34 | - name: Set token_bound_cidr for userpass (idempotent) 35 | hashivault_userpass: 36 | name: "{{username}}" 37 | pass: "{{userpass}}" 38 | policies: "default" 39 | token_bound_cidrs: "127.0.0.1" 40 | register: 'hashivault_userpass_token_bound_cidr' 41 | - assert: { that: "{{hashivault_userpass_token_bound_cidr.changed}} == False" } 42 | - assert: { that: "{{hashivault_userpass_token_bound_cidr.rc}} == 0" } -------------------------------------------------------------------------------- /functional/test_azure_auth_role.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: localhost 4 | gather_facts: no 5 | vars: 6 | client_id: values 7 | client_secret: dont 8 | tenant_id: matter 9 | tasks: 10 | - hashivault_auth_method: 11 | method_type: azure 12 | state: disabled 13 | failed_when: false 14 | 15 | - name: enable azure secret engine 16 | hashivault_auth_method: 17 | method_type: azure 18 | 19 | - name: successfully configure mount 20 | hashivault_azure_auth_config: 21 | client_id: "{{ client_id }}" 22 | client_secret: "{{ client_secret }}" 23 | tenant_id: "{{ tenant_id }}" 24 | 25 | - name: create 1st role 26 | hashivault_azure_auth_role: 27 | name: "test" 28 | policies: ["test"] 29 | bound_subscription_ids: ["6a1d5988-5917-4221-b224-904cd7e24a25"] 30 | num_uses: 3 31 | register: success_config 32 | 33 | - assert: { that: "{{ success_config.changed }} == True" } 34 | 35 | - name: idempotently create role 36 | hashivault_azure_auth_role: 37 | name: "test" 38 | policies: ["test"] 39 | bound_subscription_ids: ["6a1d5988-5917-4221-b224-904cd7e24a25"] 40 | num_uses: 3 41 | register: idem_config 42 | 43 | - assert: { that: "{{ idem_config.changed }} == False" } 44 | 45 | - name: delete role 46 | hashivault_azure_auth_role: 47 | name: test 48 | state: absent 49 | register: del_config 50 | 51 | - assert: { that: "{{ del_config.changed }} == True" } 52 | -------------------------------------------------------------------------------- /functional/test_lookup.yml: -------------------------------------------------------------------------------- 1 | # 2 | # This test depends on successful test_write run 3 | # 4 | --- 5 | - hosts: localhost 6 | gather_facts: no 7 | vars: 8 | namespace: '' 9 | name_root: '{{namespace}}basic' 10 | name_folder: '{{namespace}}stalks/bean' 11 | name_dict: '{{namespace}}_dict' 12 | name_array: '{{namespace}}_array' 13 | vars_foo: "{{lookup('hashivault', '{{name_root}}', 'foo')}}" 14 | dict_value: 15 | foo: 'bar' 16 | baz: 'stuff' 17 | array_value: 18 | - 'one' 19 | - 'two' 20 | - 'three' 21 | tasks: 22 | - assert: { that: "'{{vars_foo}}' == 'new'" } 23 | 24 | - set_fact: 25 | a_set_fie: "{{lookup('hashivault', '{{name_root}}', 'fie')}}" 26 | - assert: { that: "'{{a_set_fie}}' == 'fum'" } 27 | 28 | - set_fact: 29 | a_set_fie: "{{lookup('hashivault', '{{name_folder}}', 'height')}}" 30 | - assert: { that: "'{{a_set_fie}}' == 'tall'" } 31 | 32 | - set_fact: 33 | a_set_dict: "{{lookup('hashivault', '{{name_dict}}', 'foo')}}" 34 | - assert: { that: "'{{a_set_dict}}' == 'bar'" } 35 | 36 | - set_fact: 37 | a_set_array: "{{lookup('hashivault', '{{name_array}}', 'value') | first}}" 38 | - assert: { that: "'{{a_set_array}}' == 'one'" } 39 | 40 | - set_fact: 41 | a_set_dict_all: "{{lookup('hashivault', '{{name_dict}}')}}" 42 | - assert: { that: "a_set_dict_all == dict_value" } 43 | 44 | - set_fact: 45 | a_set_array_all: "{{lookup('hashivault', '{{name_array}}')['value']}}" 46 | - assert: { that: "a_set_array_all == array_value" } 47 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_secret_list.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_auth_client 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = ''' 9 | --- 10 | module: hashivault_secret_list 11 | version_added: "2.2.0" 12 | short_description: Hashicorp Vault secret list module 13 | description: 14 | - Module to list secret backends in Hashicorp Vault. 15 | extends_documentation_fragment: hashivault 16 | ''' 17 | EXAMPLES = ''' 18 | --- 19 | - hosts: localhost 20 | tasks: 21 | - hashivault_secret_list: 22 | register: 'hashivault_secret_list' 23 | ''' 24 | 25 | 26 | def main(): 27 | argspec = hashivault_argspec() 28 | module = hashivault_init(argspec) 29 | result = hashivault_secret_list(module.params) 30 | if result.get('failed'): 31 | module.fail_json(**result) 32 | else: 33 | module.exit_json(**result) 34 | 35 | 36 | @hashiwrapper 37 | def hashivault_secret_list(params): 38 | client = hashivault_auth_client(params) 39 | current_backends = client.sys.list_mounted_secrets_engines() 40 | if isinstance(current_backends, dict): 41 | current_backends = current_backends.get('data', current_backends) 42 | return {'changed': False, 'backends': current_backends} 43 | 44 | 45 | if __name__ == '__main__': 46 | main() 47 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_generate_root_cancel.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_client 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = ''' 9 | --- 10 | module: hashivault_generate_root_cancel 11 | version_added: "3.14.0" 12 | short_description: Hashicorp Vault generate_root cancel module 13 | description: 14 | - Module to cancel generation of root token of Hashicorp Vault. 15 | extends_documentation_fragment: hashivault 16 | ''' 17 | EXAMPLES = ''' 18 | --- 19 | - hosts: localhost 20 | tasks: 21 | - hashivault_generate_root_cancel: 22 | ''' 23 | 24 | 25 | def main(): 26 | argspec = hashivault_argspec() 27 | module = hashivault_init(argspec) 28 | result = hashivault_generate_root_cancel(module.params) 29 | if result.get('failed'): 30 | module.fail_json(**result) 31 | else: 32 | module.exit_json(**result) 33 | 34 | 35 | @hashiwrapper 36 | def hashivault_generate_root_cancel(params): 37 | client = hashivault_client(params) 38 | # Check if generate_root is on-going & return when generate_root not in progress 39 | status = client.generate_root_status 40 | if not status['started']: 41 | return {'changed': False} 42 | return {'status': client.cancel_generate_root(), 'changed': True} 43 | 44 | 45 | if __name__ == '__main__': 46 | main() 47 | -------------------------------------------------------------------------------- /functional/test_unseal.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | gather_facts: no 4 | vars: 5 | vault_keys: "{{ lookup('env','VAULT_KEYS') }}" 6 | tasks: 7 | - assert: 8 | that: "'{{vault_keys}}' != ''" 9 | msg: "VAULT_KEYS must be set to run this test" 10 | - name: Get status of vault before unseal 11 | hashivault_status: 12 | register: 'vault_status' 13 | 14 | - block: 15 | - name: Vault is not sealed so seal it 16 | hashivault_seal: 17 | register: 'vault_seal' 18 | - assert: { that: "{{vault_seal.changed}} == True" } 19 | - assert: { that: "{{vault_seal.rc}} == 0" } 20 | when: "vault_status.status.sealed == False" 21 | 22 | - name: Seal the vault but it is already sealed 23 | hashivault_seal: 24 | register: 'vault_seal_st' 25 | - assert: { that: "{{vault_seal_st.changed}} == False" } 26 | - assert: { that: "{{vault_seal_st.rc}} == 0" } 27 | 28 | - name: Unseal the vault 29 | hashivault_unseal: 30 | keys: '{{vault_keys}}' 31 | register: 'vault_unseal' 32 | - assert: { that: "{{vault_unseal.changed}} == True" } 33 | - assert: { that: "{{vault_unseal.status.progress}} == 0" } 34 | - assert: { that: "{{vault_unseal.status.sealed}} == False" } 35 | - assert: { that: "{{vault_unseal.rc}} == 0" } 36 | 37 | - name: Unseal the vault but it is not sealed 38 | hashivault_unseal: 39 | keys: '{{vault_keys}}' 40 | register: 'vault_unseal_st' 41 | - assert: { that: "{{vault_unseal_st.changed}} == False" } 42 | - assert: { that: "{{vault_unseal_st.rc}} == 0" } 43 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_unseal.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_client 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = ''' 9 | --- 10 | module: hashivault_unseal 11 | version_added: "1.2.0" 12 | short_description: Hashicorp Vault unseal module 13 | description: 14 | - Module to unseal Hashicorp Vault. 15 | options: 16 | keys: 17 | description: 18 | - vault key shard(s). 19 | extends_documentation_fragment: hashivault 20 | ''' 21 | EXAMPLES = ''' 22 | --- 23 | - hosts: localhost 24 | tasks: 25 | - hashivault_unseal: 26 | keys: '{{vault_keys}}' 27 | ''' 28 | 29 | 30 | def main(): 31 | argspec = hashivault_argspec() 32 | argspec['keys'] = dict(required=True, type='str', no_log=True) 33 | module = hashivault_init(argspec) 34 | result = hashivault_unseal(module.params) 35 | if result.get('failed'): 36 | module.fail_json(**result) 37 | else: 38 | module.exit_json(**result) 39 | 40 | 41 | @hashiwrapper 42 | def hashivault_unseal(params): 43 | keys = params.get('keys') 44 | client = hashivault_client(params) 45 | if client.sys.is_sealed(): 46 | return {'status': client.sys.submit_unseal_keys(keys.split()), 'changed': True} 47 | else: 48 | return {'changed': False} 49 | 50 | 51 | if __name__ == '__main__': 52 | main() 53 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_policy_list.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_auth_client 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = ''' 9 | --- 10 | module: hashivault_policy_list 11 | version_added: "2.1.0" 12 | short_description: Hashicorp Vault policy list module 13 | description: 14 | - Module to list policies in Hashicorp Vault. 15 | extends_documentation_fragment: hashivault 16 | ''' 17 | EXAMPLES = ''' 18 | --- 19 | - hosts: localhost 20 | tasks: 21 | - hashivault_policy_list: 22 | register: 'vault_policy_list' 23 | - debug: msg="Policies are {{vault_policy_list.policy}}" 24 | ''' 25 | 26 | 27 | def main(): 28 | argspec = hashivault_argspec() 29 | module = hashivault_init(argspec) 30 | result = hashivault_policy_list(module.params) 31 | if result.get('failed'): 32 | module.fail_json(**result) 33 | else: 34 | module.exit_json(**result) 35 | 36 | 37 | @hashiwrapper 38 | def hashivault_policy_list(params): 39 | client = hashivault_auth_client(params) 40 | current_policies = client.sys.list_policies() 41 | if isinstance(current_policies, dict): 42 | current_policies = current_policies.get('data', current_policies) 43 | current_policies = current_policies.get('policies', current_policies) 44 | return {'policies': current_policies} 45 | 46 | 47 | if __name__ == '__main__': 48 | main() 49 | -------------------------------------------------------------------------------- /functional/test_oidc_auth_role.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: localhost 4 | gather_facts: no 5 | vars: 6 | oidc_discovery_url: https://samples.auth0.com/ 7 | oidc_client_id: dont 8 | oidc_client_secret: matter 9 | tasks: 10 | - hashivault_auth_method: 11 | method_type: oidc 12 | state: disabled 13 | failed_when: false 14 | 15 | - name: enable oidc secret engine 16 | hashivault_auth_method: 17 | method_type: oidc 18 | 19 | - name: successfully configure mount 20 | hashivault_oidc_auth_method_config: 21 | oidc_discovery_url: "{{ oidc_discovery_url }}" 22 | oidc_client_id: "{{ oidc_client_id }}" 23 | oidc_client_secret: "{{ oidc_client_secret }}" 24 | 25 | - name: create 1st role 26 | hashivault_oidc_auth_role: 27 | name: "test" 28 | bound_audiences: ["123456"] 29 | allowed_redirect_uris: ["https://123456.com/callback"] 30 | token_policies: ["test"] 31 | register: success_config 32 | 33 | - assert: { that: "{{ success_config.changed }} == True" } 34 | 35 | - name: idempotently create role 36 | hashivault_oidc_auth_role: 37 | name: "test" 38 | bound_audiences: ["123456"] 39 | allowed_redirect_uris: ["https://123456.com/callback"] 40 | token_policies: ["test"] 41 | register: idem_config 42 | 43 | - assert: { that: "{{ idem_config.changed }} == False" } 44 | 45 | - name: delete role 46 | hashivault_oidc_auth_role: 47 | name: "test" 48 | state: absent 49 | allowed_redirect_uris: ["https://123456.com/callback"] 50 | register: del_config 51 | 52 | - assert: { that: "{{ del_config.changed }} == True" } 53 | -------------------------------------------------------------------------------- /functional/test_azure_auth_config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: localhost 4 | gather_facts: no 5 | vars: 6 | client_id: values 7 | client_secret: dont 8 | tenant_id: matter 9 | tasks: 10 | - hashivault_auth_method: 11 | method_type: azure 12 | state: disabled 13 | failed_when: false 14 | 15 | - name: make sure test fails when no mount exists 16 | hashivault_azure_auth_config: 17 | client_id: "{{ client_id }}" 18 | client_secret: "{{ client_secret }}" 19 | tenant_id: "{{ tenant_id }}" 20 | register: fail_config 21 | failed_when: false 22 | 23 | - assert: { that: "{{ fail_config.changed }} == False" } 24 | 25 | - name: enable azure auth method 26 | hashivault_auth_method: 27 | method_type: azure 28 | 29 | - name: successfully configure method 30 | hashivault_azure_auth_config: 31 | client_id: "{{ client_id }}" 32 | client_secret: "{{ client_secret }}" 33 | tenant_id: "{{ tenant_id }}" 34 | register: success_config 35 | 36 | - assert: { that: "{{ success_config.changed }} == True" } 37 | 38 | - name: attempt 2nd config with same values 39 | hashivault_azure_auth_config: 40 | client_id: "{{ client_id }}" 41 | client_secret: "{{ client_secret }}" 42 | tenant_id: "{{ tenant_id }}" 43 | register: idem_config 44 | 45 | - assert: { that: "{{ idem_config.changed }} == False" } 46 | 47 | - name: attempt 3rd config with different values 48 | hashivault_azure_auth_config: 49 | client_id: flergh 50 | client_secret: mlergh 51 | tenant_id: splurgh 52 | register: overwrite_config 53 | 54 | - assert: { that: "{{ overwrite_config.changed }} == True" } 55 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_generate_root.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_init 4 | from ansible.module_utils.hashivault import hashiwrapper 5 | from ansible.module_utils.hashivault import hashivault_client 6 | 7 | ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = ''' 9 | --- 10 | module: hashivault_generate_root 11 | version_added: "3.14.0" 12 | short_description: Hashicorp Vault generate_root module 13 | description: 14 | - Module to (update) generate_root Hashicorp Vault. 15 | options: 16 | key: 17 | description: 18 | - vault key shard. 19 | nonce: 20 | description: 21 | - generate_root nonce. 22 | extends_documentation_fragment: hashivault 23 | ''' 24 | EXAMPLES = ''' 25 | --- 26 | - hosts: localhost 27 | tasks: 28 | - hashivault_generate_root: 29 | key: '{{vault_unseal_key}}' 30 | nonce: '{{nonce}}' 31 | ''' 32 | 33 | 34 | def main(): 35 | argspec = hashivault_argspec() 36 | argspec['key'] = dict(required=False, type='str', no_log=True) 37 | argspec['nonce'] = dict(required=True, type='str') 38 | module = hashivault_init(argspec) 39 | result = hashivault_generate_root(module.params) 40 | if result.get('failed'): 41 | module.fail_json(**result) 42 | else: 43 | module.exit_json(**result) 44 | 45 | 46 | @hashiwrapper 47 | def hashivault_generate_root(params): 48 | key = params.get('key') 49 | nonce = params.get('nonce') 50 | client = hashivault_client(params) 51 | return {'status': client.generate_root(key, nonce), 'changed': True} 52 | 53 | 54 | if __name__ == '__main__': 55 | main() 56 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_approle_role_list.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_auth_client 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = ''' 9 | --- 10 | module: hashivault_approle_role_list 11 | version_added: "3.8.0" 12 | short_description: Hashicorp Vault approle list roles module 13 | description: 14 | - Module to list approle roles from Hashicorp Vault. 15 | options: 16 | mount_point: 17 | description: 18 | - mount point for role 19 | default: approle 20 | extends_documentation_fragment: hashivault 21 | ''' 22 | EXAMPLES = ''' 23 | --- 24 | - hosts: localhost 25 | tasks: 26 | - hashivault_approle_role_list: 27 | register: 'vault_approle_role_list' 28 | - debug: msg="Roles are {{vault_approle_role_list.roles}}" 29 | ''' 30 | 31 | 32 | def main(): 33 | argspec = hashivault_argspec() 34 | argspec['mount_point'] = dict(required=False, type='str', default='approle') 35 | module = hashivault_init(argspec) 36 | result = hashivault_approle_role_list(module.params) 37 | if result.get('failed'): 38 | module.fail_json(**result) 39 | else: 40 | module.exit_json(**result) 41 | 42 | 43 | @hashiwrapper 44 | def hashivault_approle_role_list(params): 45 | client = hashivault_auth_client(params) 46 | roles = client.list_roles(mount_point=params.get('mount_point')) 47 | roles = roles.get('data', {}).get('keys', []) 48 | return {'roles': roles} 49 | 50 | 51 | if __name__ == '__main__': 52 | main() 53 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_rekey.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_client 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = ''' 9 | --- 10 | module: hashivault_rekey 11 | version_added: "3.3.0" 12 | short_description: Hashicorp Vault rekey module 13 | description: 14 | - Module to (update) rekey Hashicorp Vault. Requires that a rekey 15 | be started with hashivault_rekey_init. 16 | options: 17 | key: 18 | description: 19 | - vault key shard (aka unseal key). 20 | nonce: 21 | description: 22 | - rekey nonce. 23 | extends_documentation_fragment: hashivault 24 | ''' 25 | EXAMPLES = ''' 26 | --- 27 | - hosts: localhost 28 | tasks: 29 | - hashivault_rekey: 30 | key: '{{vault_key}}' 31 | nonce: '{{nonce}}' 32 | ''' 33 | 34 | 35 | def main(): 36 | argspec = hashivault_argspec() 37 | argspec['key'] = dict(required=True, type='str', no_log=True) 38 | argspec['nonce'] = dict(required=True, type='str') 39 | module = hashivault_init(argspec) 40 | result = hashivault_rekey(module.params) 41 | if result.get('failed'): 42 | module.fail_json(**result) 43 | else: 44 | module.exit_json(**result) 45 | 46 | 47 | @hashiwrapper 48 | def hashivault_rekey(params): 49 | key = params.get('key') 50 | nonce = params.get('nonce') 51 | client = hashivault_client(params) 52 | return {'status': client.sys.rekey(key, nonce), 'changed': True} 53 | 54 | 55 | if __name__ == '__main__': 56 | main() 57 | -------------------------------------------------------------------------------- /functional/test_status.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | gather_facts: no 4 | tasks: 5 | - name: Get vault status and make sure it is unsealed 6 | hashivault_status: 7 | register: 'vault_status' 8 | - assert: { that: "{{vault_status.changed}} == False" } 9 | - assert: { that: "{{vault_status.status.progress}} == 0" } 10 | - assert: { that: "{{vault_status.status.sealed}} == False" } 11 | - assert: { that: "{{vault_status.rc}} == 0" } 12 | 13 | - name: Get hashivault_leader 14 | hashivault_leader: 15 | register: 'vault_status' 16 | - assert: { that: "{{vault_status.changed}} == False" } 17 | - assert: { that: "{{vault_status.status.ha_enabled}} == False" } 18 | - assert: { that: "{{vault_status.rc}} == 0" } 19 | 20 | - name: Get hashivault_cluster_status 21 | hashivault_cluster_status: 22 | register: 'vault_status' 23 | - assert: { that: "{{vault_status.changed}} == False" } 24 | - assert: { that: "{{vault_status.rc}} == 0" } 25 | 26 | - name: Get hashivault_cluster_status 27 | hashivault_cluster_status: 28 | standby_ok: false 29 | register: 'vault_status' 30 | - assert: { that: "{{vault_status.changed}} == False" } 31 | - assert: { that: "{{vault_status.rc}} == 0" } 32 | 33 | - name: Get hashivault_cluster_status 34 | hashivault_cluster_status: 35 | method: GET 36 | register: 'vault_status' 37 | - assert: { that: "{{vault_status.changed}} == False" } 38 | - assert: { that: "{{vault_status.rc}} == 0" } 39 | 40 | - name: Get hashivault_cluster_status 41 | hashivault_cluster_status: 42 | standby_ok: false 43 | method: GET 44 | register: 'vault_status' 45 | - assert: { that: "{{vault_status.changed}} == False" } 46 | - assert: { that: "{{vault_status.rc}} == 0" } 47 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_policy_get.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_auth_client 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = ''' 9 | --- 10 | module: hashivault_policy_get 11 | version_added: "2.1.0" 12 | short_description: Hashicorp Vault policy get module 13 | description: 14 | - Module to get a policy from Hashicorp Vault. 15 | options: 16 | name: 17 | description: 18 | - policy name. 19 | extends_documentation_fragment: hashivault 20 | ''' 21 | EXAMPLES = ''' 22 | --- 23 | - hosts: localhost 24 | tasks: 25 | - hashivault_policy_get: 26 | name: 'annie' 27 | register: 'vault_policy_get' 28 | - debug: msg="User policy is {{vault_policy_get.policy}}" 29 | ''' 30 | 31 | 32 | def main(): 33 | argspec = hashivault_argspec() 34 | argspec['name'] = dict(required=True, type='str') 35 | module = hashivault_init(argspec) 36 | result = hashivault_policy_get(module.params) 37 | if result.get('failed'): 38 | module.fail_json(**result) 39 | else: 40 | module.exit_json(**result) 41 | 42 | 43 | @hashiwrapper 44 | def hashivault_policy_get(params): 45 | name = params.get('name') 46 | client = hashivault_auth_client(params) 47 | policy = client.get_policy(name) 48 | if policy is None: 49 | result = {"changed": False, "rc": 1, "failed": True} 50 | result['msg'] = u"Policy \"%s\" does not exist." % name 51 | return result 52 | else: 53 | return {'rules': policy} 54 | 55 | 56 | if __name__ == '__main__': 57 | main() 58 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_approle_role_id.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_auth_client 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = ''' 9 | --- 10 | module: hashivault_approle_role_id 11 | version_added: "3.8.0" 12 | short_description: Hashicorp Vault approle get role id module 13 | description: 14 | - Module to get a approle role id from Hashicorp Vault. 15 | options: 16 | name: 17 | description: 18 | - role name. 19 | mount_point: 20 | description: 21 | - mount point for role 22 | default: approle 23 | extends_documentation_fragment: hashivault 24 | ''' 25 | EXAMPLES = ''' 26 | --- 27 | - hosts: localhost 28 | tasks: 29 | - hashivault_approle_role_id: 30 | name: 'ashley' 31 | register: 'vault_approle_role_id' 32 | - debug: msg="Role id is {{vault_approle_role_id.id}}" 33 | ''' 34 | 35 | 36 | def main(): 37 | argspec = hashivault_argspec() 38 | argspec['name'] = dict(required=True, type='str') 39 | argspec['mount_point'] = dict(required=False, type='str', default='approle') 40 | module = hashivault_init(argspec) 41 | result = hashivault_approle_role_id(module.params) 42 | if result.get('failed'): 43 | module.fail_json(**result) 44 | else: 45 | module.exit_json(**result) 46 | 47 | 48 | @hashiwrapper 49 | def hashivault_approle_role_id(params): 50 | name = params.get('name') 51 | client = hashivault_auth_client(params) 52 | return {'id': client.get_role_id(name, mount_point=params.get('mount_point'))} 53 | 54 | 55 | if __name__ == '__main__': 56 | main() 57 | -------------------------------------------------------------------------------- /functional/test_userpass_no_policy.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | gather_facts: no 4 | vars: 5 | username: 'bob' 6 | userpass: 'Th3m@n!!' 7 | bobs_rules: > 8 | path "secret/*" { 9 | capabilities = ["create", "read", "update", "delete", "list"] 10 | } 11 | path "auth/token/create*" { 12 | capabilities = ["create", "read", "update", "delete", "list", "sudo"] 13 | } 14 | path "auth/token/lookup*" { 15 | capabilities = ["read", "list"] 16 | } 17 | path "auth/token/lookup/*" { 18 | capabilities = ["read", "list"] 19 | } 20 | path "sys/policy" { 21 | capabilities = ["read"] 22 | } 23 | path "sys/policy/*" { 24 | capabilities = ["create", "read", "update", "delete", "list"] 25 | } 26 | 27 | tasks: 28 | - name: Enable kv2 secret store 29 | hashivault_userpass: 30 | name: "{{username}}" 31 | state: absent 32 | no_log: True 33 | 34 | #- pause: 35 | # prompt: "Make sure org.foo.FooOverload exception is not present" 36 | 37 | - name: Create userpass for bob via POST to omit the policies field 38 | uri: 39 | url: "{{ lookup('env','VAULT_ADDR') }}/v1/auth/userpass/users/{{username}}" 40 | method: POST 41 | return_content: yes 42 | body_format: json 43 | body: 44 | password: "{{userpass}}" 45 | headers: 46 | X-Vault-Token: "{{ lookup('env','VAULT_TOKEN') }}" 47 | status_code: 204 48 | 49 | - name: Update policies 50 | hashivault_userpass: 51 | name: "{{username}}" 52 | password: "" 53 | policies: ["policy-bob", "default"] 54 | register: 'hashivault_userpass_update_policies' 55 | - assert: { that: "{{hashivault_userpass_update_policies.changed}} == True" } 56 | - assert: { that: "{{hashivault_userpass_update_policies.rc}} == 0" } 57 | -------------------------------------------------------------------------------- /example/README.rst: -------------------------------------------------------------------------------- 1 | Ansible Modules Hashivault 2 | ========================== 3 | 4 | Example sandbox for Ansible modules for Hashicorp Vault. These example 5 | directions assume you have Docker installed. You need to install the 6 | Ansible module first to use it:: 7 | 8 | pip install ansible-modules-hashivault 9 | 10 | Optionally Run Vault in Docker 11 | ------------------------------ 12 | 13 | You can use the automated functional test to create a Vault instance running 14 | in Docker. The `./start.sh` script in the `functional` directory will start 15 | an initialized vault instance. The script will create a `vaultenv.sh` which 16 | contains the environment variables needed to communicate with Vault.:: 17 | 18 | cd ../functional 19 | ./start.sh 20 | source ./vaultenv.sh 21 | 22 | Run a Ansible Ready Container 23 | ----------------------------- 24 | 25 | Use the `./run.sh` script to build and run a Ansible ready Docker container. 26 | The container will be called `sandbox`.:: 27 | 28 | ./run.sh 29 | 30 | You can see it running with `docker ps` for example:: 31 | 32 | $ docker ps 33 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS 34 | 3b214f80daf0 sandbox:latest "/usr/sbin/sshd -D" 6 minutes ago Up 6 minutes 127.0.0.1:3022->22/tcp 35 | 36 | 37 | There is a sample playbook here that writes a scret to Vault and writes it to 38 | the sandbox:: 39 | 40 | ansible-playbook test_remote_host.yml 41 | 42 | You can ssh into your sandbox and check your secret:: 43 | 44 | $ ssh -i .ssh/id_rsa -p 3022 root@127.0.0.1 45 | Last login: Wed Jan 3 16:55:09 2018 from 172.17.0.1 46 | root@sandbox:~# cat /giant.txt 47 | I smell the blood 48 | root@sandbox:~# 49 | 50 | If you run the sandbox more than once, you'll need to clear the entry in the 51 | `~/.ssh/known_hosts` file 52 | -------------------------------------------------------------------------------- /functional/test_oidc_auth_method_config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: localhost 4 | gather_facts: no 5 | vars: 6 | oidc_discovery_url: https://samples.auth0.com/ 7 | oidc_client_id: dont 8 | oidc_client_secret: matter 9 | tasks: 10 | - hashivault_auth_method: 11 | method_type: oidc 12 | state: disabled 13 | failed_when: false 14 | 15 | - name: make sure test fails when no mount exists 16 | hashivault_oidc_auth_method_config: 17 | oidc_discovery_url: "{{ oidc_discovery_url }}" 18 | oidc_client_id: "{{ oidc_client_id }}" 19 | oidc_client_secret: "{{ oidc_client_secret }}" 20 | register: fail_config 21 | failed_when: false 22 | 23 | - assert: { that: "{{ fail_config.changed }} == False" } 24 | 25 | - name: enable oidc auth method 26 | hashivault_auth_method: 27 | method_type: oidc 28 | 29 | - name: successfully configure method 30 | hashivault_oidc_auth_method_config: 31 | oidc_discovery_url: "{{ oidc_discovery_url }}" 32 | oidc_client_id: "{{ oidc_client_id }}" 33 | oidc_client_secret: "{{ oidc_client_secret }}" 34 | register: success_config 35 | 36 | - assert: { that: "{{ success_config.changed }} == True" } 37 | 38 | - name: attempt 2nd config with same values 39 | hashivault_oidc_auth_method_config: 40 | oidc_discovery_url: "{{ oidc_discovery_url }}" 41 | oidc_client_id: "{{ oidc_client_id }}" 42 | register: idem_config 43 | 44 | - assert: { that: "{{ idem_config.changed }} == False" } 45 | 46 | - name: attempt 3rd config with different values 47 | hashivault_oidc_auth_method_config: 48 | oidc_discovery_url: "{{ oidc_discovery_url }}" 49 | oidc_client_id: mango 50 | oidc_client_secret: pineapple 51 | register: overwrite_config 52 | 53 | - assert: { that: "{{ overwrite_config.changed }} == True" } 54 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/_hashivault_userpass_delete.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_auth_client 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['deprecated'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = ''' 9 | --- 10 | module: hashivault_userpass_delete 11 | version_added: "2.2.0" 12 | short_description: Hashicorp Vault userpass delete module 13 | description: 14 | - Module to delete userpass users in Hashicorp Vault. Use hashicorp_userpass instead. 15 | options: 16 | name: 17 | description: 18 | - user name. 19 | mount_point: 20 | description: 21 | - default The "path" (app-id) the auth backend is mounted on. 22 | default: userpass 23 | extends_documentation_fragment: hashivault 24 | ''' 25 | EXAMPLES = ''' 26 | --- 27 | - hosts: localhost 28 | tasks: 29 | - hashivault_userpass_delete: 30 | name: 'bob' 31 | ''' 32 | 33 | 34 | def main(): 35 | argspec = hashivault_argspec() 36 | argspec['name'] = dict(required=True, type='str') 37 | argspec['mount_point'] = dict(required=False, type='str', default='userpass') 38 | module = hashivault_init(argspec) 39 | result = hashivault_userpass_delete(module.params) 40 | if result.get('failed'): 41 | module.fail_json(**result) 42 | else: 43 | module.exit_json(**result) 44 | 45 | 46 | @hashiwrapper 47 | def hashivault_userpass_delete(params): 48 | client = hashivault_auth_client(params) 49 | username = params.get('name') 50 | mount_point = params.get('mount_point') 51 | client.delete_userpass(username, mount_point=mount_point) 52 | return {'changed': True} 53 | 54 | 55 | if __name__ == '__main__': 56 | main() 57 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_read.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from ansible.module_utils.hashivault import hashivault_argspec 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashivault_read 6 | 7 | ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = ''' 9 | --- 10 | module: hashivault_read 11 | version_added: "0.1" 12 | short_description: Hashicorp Vault read module 13 | description: 14 | - Module to read to Hashicorp Vault. 15 | options: 16 | version: 17 | description: 18 | - version of the kv engine (int) 19 | default: 1 20 | mount_point: 21 | description: 22 | - secret mount point 23 | default: secret 24 | secret: 25 | description: 26 | - secret to read. 27 | key: 28 | description: 29 | - secret key to read. 30 | extends_documentation_fragment: hashivault 31 | ''' 32 | EXAMPLES = ''' 33 | --- 34 | - hosts: localhost 35 | tasks: 36 | - hashivault_read: 37 | secret: 'giant' 38 | key: 'fie' 39 | register: 'fie' 40 | - debug: msg="Value is {{fie.value}}" 41 | ''' 42 | 43 | 44 | def main(): 45 | argspec = hashivault_argspec() 46 | argspec['version'] = dict(required=False, type='int', default=1) 47 | argspec['mount_point'] = dict(required=False, type='str', default='secret') 48 | argspec['secret'] = dict(required=True, type='str') 49 | argspec['key'] = dict(required=False, type='str') 50 | argspec['default'] = dict(required=False, default=None, type='str') 51 | module = hashivault_init(argspec) 52 | result = hashivault_read(module.params) 53 | if result.get('failed'): 54 | module.fail_json(**result) 55 | else: 56 | module.exit_json(**result) 57 | 58 | 59 | if __name__ == '__main__': 60 | main() 61 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_approle_role_get.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_auth_client 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = ''' 9 | --- 10 | module: hashivault_approle_role_get 11 | version_added: "3.8.0" 12 | short_description: Hashicorp Vault approle role get module 13 | description: 14 | - Module to get a approle role from Hashicorp Vault. 15 | options: 16 | name: 17 | description: 18 | - role name. 19 | mount_point: 20 | description: 21 | - mount point for role 22 | default: approle 23 | extends_documentation_fragment: hashivault 24 | ''' 25 | EXAMPLES = ''' 26 | --- 27 | - hosts: localhost 28 | tasks: 29 | - hashivault_approle_role_get: 30 | name: 'ashley' 31 | register: 'vault_approle_role_get' 32 | - debug: msg="Role is {{vault_approle_role_get.role}}" 33 | ''' 34 | 35 | 36 | def main(): 37 | argspec = hashivault_argspec() 38 | argspec['name'] = dict(required=True, type='str') 39 | argspec['mount_point'] = dict(required=False, type='str', default='approle') 40 | module = hashivault_init(argspec) 41 | result = hashivault_approle_role_get(module.params) 42 | if result.get('failed'): 43 | module.fail_json(**result) 44 | else: 45 | module.exit_json(**result) 46 | 47 | 48 | @hashiwrapper 49 | def hashivault_approle_role_get(params): 50 | name = params.get('name') 51 | client = hashivault_auth_client(params) 52 | result = client.get_role(name, mount_point=params.get('mount_point')) 53 | return {'role': result} 54 | 55 | 56 | if __name__ == '__main__': 57 | main() 58 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/_hashivault_approle_role_secret_delete.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from ansible.module_utils.hashivault import hashivault_argspec 4 | from ansible.module_utils.hashivault import hashivault_auth_client 5 | from ansible.module_utils.hashivault import hashivault_init 6 | from ansible.module_utils.hashivault import hashiwrapper 7 | 8 | ANSIBLE_METADATA = {'status': ['deprecated'], 'supported_by': 'community', 'version': '1.1'} 9 | DOCUMENTATION = ''' 10 | --- 11 | module: hashivault_approle_role_secret_delete 12 | version_added: "3.8.0" 13 | short_description: Hashicorp Vault approle role secret id delete module 14 | description: 15 | - Module to delete a approle role secret id from Hashicorp Vault. Use hashivault_approle_role_secret instead. 16 | options: 17 | name: 18 | description: 19 | - role name. 20 | secret: 21 | description: 22 | - secret id. 23 | extends_documentation_fragment: hashivault 24 | ''' 25 | EXAMPLES = ''' 26 | --- 27 | - hosts: localhost 28 | tasks: 29 | - hashivault_approle_role_secret_delete: 30 | name: 'ashley' 31 | secret: 'ec4bedee-e44b-c096-9ac8-1600e52ed8f8' 32 | ''' 33 | 34 | 35 | def main(): 36 | argspec = hashivault_argspec() 37 | argspec['name'] = dict(required=True, type='str') 38 | argspec['secret'] = dict(required=True, type='str') 39 | module = hashivault_init(argspec) 40 | result = hashivault_approle_role_secret_delete(module.params) 41 | if result.get('failed'): 42 | module.fail_json(**result) 43 | else: 44 | module.exit_json(**result) 45 | 46 | 47 | @hashiwrapper 48 | def hashivault_approle_role_secret_delete(params): 49 | name = params.get('name') 50 | secret = params.get('secret') 51 | client = hashivault_auth_client(params) 52 | client.delete_role_secret_id(name, secret) 53 | return {'changed': True} 54 | 55 | 56 | if __name__ == '__main__': 57 | main() 58 | -------------------------------------------------------------------------------- /functional/test_auth.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | gather_facts: no 4 | tasks: 5 | - name: List the authentications backends 6 | hashivault_auth_list: 7 | register: 'vault_auth_list' 8 | - block: 9 | - name: Enable userpass when it is already enabled 10 | hashivault_auth_method: 11 | method_type: "userpass" 12 | failed_when: False 13 | register: 'vault_auth' 14 | - assert: { that: "{{vault_auth.changed}} == False" } 15 | - assert: { that: "{{vault_auth.failed}} == False" } 16 | - assert: { that: "'{{vault_auth.msg}}' == 'Exception: path is already in use'" } 17 | - assert: { that: "{{vault_auth.rc}} == 1" } 18 | when: "'userpass/' in vault_auth_list.backends" 19 | - block: 20 | - name: Enable userpass auth for the first time 21 | hashivault_auth_method: 22 | method_type: "userpass" 23 | register: 'vault_auth' 24 | - assert: { that: "{{vault_auth.changed}} == True" } 25 | - assert: { that: "{{vault_auth.rc}} == 0" } 26 | when: "'userpass/' not in vault_auth_list.backends" 27 | - block: 28 | - name: Enable userpass auth for the second time 29 | hashivault_auth_method: 30 | method_type: "userpass" 31 | failed_when: False 32 | register: 'vault_auth' 33 | - assert: { that: "{{vault_auth.changed}} == False" } 34 | # Results from hvac/vault vary here 35 | # - assert: { that: "{{vault_auth.rc}} == 0" } 36 | # - assert: { that: "'{{vault_auth.msg}}' == 'Exception: path is already in use'" } 37 | - block: 38 | - name: Enable userpass at a different mount point 39 | hashivault_auth_method: 40 | method_type: "userpass" 41 | mount_point: "another-userpass" 42 | register: 'vault_auth_mount_point' 43 | - assert: { that: "{{vault_auth_mount_point.changed}} == True" } 44 | - assert: { that: "{{vault_auth_mount_point.rc}} == 0" } 45 | 46 | -------------------------------------------------------------------------------- /functional/test_azure_config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: localhost 4 | gather_facts: no 5 | vars: 6 | subscription_id: test 7 | client_id: values 8 | client_secret: dont 9 | tenant_id: matter 10 | tasks: 11 | - hashivault_secret_disable: 12 | name: azure 13 | failed_when: false 14 | 15 | - name: make sure test fails when no mount exists 16 | hashivault_azure_secret_engine_config: 17 | subscription_id: "{{ subscription_id }}" 18 | client_id: "{{ client_id }}" 19 | client_secret: "{{ client_secret }}" 20 | tenant_id: "{{ tenant_id }}" 21 | register: fail_config 22 | failed_when: false 23 | 24 | - assert: { that: "{{ fail_config.changed }} == False" } 25 | 26 | - hashivault_secret_enable: 27 | name: azure 28 | backend: azure 29 | 30 | - name: successfully enable mount 31 | hashivault_azure_secret_engine_config: 32 | subscription_id: "{{ subscription_id }}" 33 | client_id: "{{ client_id }}" 34 | client_secret: "{{ client_secret }}" 35 | tenant_id: "{{ tenant_id }}" 36 | register: success_config 37 | 38 | - assert: { that: "{{ success_config.changed }} == True" } 39 | 40 | - name: attempt 2nd config with same values 41 | hashivault_azure_secret_engine_config: 42 | subscription_id: "{{ subscription_id }}" 43 | client_id: "{{ client_id }}" 44 | client_secret: "{{ client_secret }}" 45 | tenant_id: "{{ tenant_id }}" 46 | register: idem_config 47 | 48 | - assert: { that: "{{ idem_config.changed }} == False" } 49 | 50 | - name: attempt 3rd config with different values 51 | hashivault_azure_secret_engine_config: 52 | subscription_id: blergh 53 | client_id: flergh 54 | client_secret: mlergh 55 | tenant_id: splurgh 56 | register: overwrite_config 57 | 58 | - assert: { that: "{{ overwrite_config.changed }} == True" } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | stages: 2 | - test 3 | language: python 4 | jobs: 5 | include: 6 | - stage: linting 7 | install: pip install pycodestyle==2.5.0 8 | name: "Linting with pycodestyle" 9 | python: "3.6" 10 | script: pycodestyle --max-line-length=120 ansible 11 | - stage: test 12 | name: Tests Python 2.7 13 | sudo: required 14 | python: 15 | - '2.7' 16 | services: 17 | - docker 18 | before_install: 19 | - docker pull vault:latest 20 | - docker ps -a 21 | install: pip install tox-travis 22 | script: tox 23 | - stage: test 24 | name: Tests Python 3.6 25 | sudo: required 26 | python: 27 | - '3.6' 28 | services: 29 | - docker 30 | before_install: 31 | - docker pull vault:latest 32 | - docker ps -a 33 | install: pip install tox-travis 34 | script: tox 35 | - stage: test 36 | name: Generating docs 37 | python: '3.6' 38 | deploy: 39 | local-dir: ansible-repo/ansible/docs/docsite/_build/html 40 | provider: pages 41 | skip-cleanup: true 42 | github-token: "$GITHUB_TOKEN" 43 | keep-history: true 44 | on: 45 | tags: true 46 | env: 47 | - PLUGINS='' 48 | install: 49 | - pip install sphinx sphinx_rtd_theme 50 | script: 51 | - ./makedocs.sh 52 | on: 53 | tags: true 54 | env: 55 | global: 56 | secure: oCC/bugXphWhcjNNFEGp5Cq7VrSrKiP7Nfw8BL8rNUia1RXD1DxE5jdddLdfWapFO9BRViOInyST9clN4Q67PmJAiTkeOcF0GbkyWzrwA7Tu9g0D7YjlgHo/euqL33hqf0iRst9gW4If0Gq9sa20+US6yNOX9OGa4LHGBjB55S0ayckCzRrOJg+eZNTe1M6YibQuvZXqBPJN3Juj3q37S4QGrIz275RrmdKdezZFs+JHt8W+HRm88lFTOMINSuc3tuoJjnAC0c+jJLiAC2HQ6AKgFS8DNqr8G8gMwhqtvAiSegQrgxot8bFdKmE0sQ61aKKzMF/GOGDPFPPeUlk33rXFyIsFEmEzhqtoGPobyZX/KRlJu55Aqgr/fHgoEAGOkb2wTsLPX9tI2GIuZ/oaV2rxgYsZhIMXG6i4+yXM4U6OBgHfdJPHwZoCpZRX6kixc3/aFny3E9jrVtDVZGwoJHq1e3O0pL0sYB5CHO7icLJrf4mOjI0hoPV9byd9JrJi5ROFwRfXeuMFYYHe/yhcclnYI/Cg91wrzLq+2877+vYWvBFoPEeKvCsLMSz3ko7QLv7s8dAhgV4TXrYNuayLtFcvij4H1s0DQcCTmFIf/LHp3Jnv2YsoNtcSYDLxGrg8w/jq4pgObyw0VXlznj2X6pMvYhufW6ObTUH4aoEQ3OA= 57 | -------------------------------------------------------------------------------- /functional/test_read.yml: -------------------------------------------------------------------------------- 1 | # 2 | # This test depends on successful test_write run 3 | # 4 | --- 5 | - hosts: localhost 6 | gather_facts: no 7 | vars: 8 | namespace: '' 9 | name_root: '{{namespace}}basic' 10 | name_folder: '{{namespace}}stalks/bean' 11 | name_dict: '{{namespace}}_dict' 12 | name_array: '{{namespace}}_array' 13 | dict_value: 14 | foo: 'bar' 15 | baz: 'stuff' 16 | array_value: 17 | - 'one' 18 | - 'two' 19 | - 'three' 20 | tasks: 21 | - name: Read the secret value 22 | hashivault_read: 23 | secret: '{{name_root}}' 24 | key: foo 25 | register: vault_read 26 | - assert: { that: "'{{vault_read.value}}' == 'new'" } 27 | 28 | - name: Read other secret value 29 | hashivault_read: 30 | secret: '{{name_root}}' 31 | key: fie 32 | register: vault_read 33 | - assert: { that: "'{{vault_read.value}}' == 'fum'" } 34 | 35 | - name: Read other secret folder 36 | hashivault_read: 37 | secret: '{{name_folder}}' 38 | key: height 39 | register: vault_read 40 | - assert: { that: "'{{vault_read.value}}' == 'tall'" } 41 | 42 | - name: Read secret dictionary 43 | hashivault_read: 44 | secret: '{{name_dict}}' 45 | register: vault_read 46 | - assert: { that: "vault_read.value == dict_value" } 47 | - assert: { that: "{{vault_read.rc}} == 0" } 48 | 49 | - name: Read array type secret and make sure it matches 50 | hashivault_read: 51 | secret: '{{name_array}}' 52 | key: value 53 | register: vault_read 54 | - assert: { that: "vault_read.value == array_value" } 55 | - assert: { that: "'{{vault_read.value[0]}}' == '{{array_value[0]}}'" } 56 | - assert: { that: "'{{vault_read.value[1]}}' == '{{array_value[1]}}'" } 57 | - assert: { that: "'{{vault_read.value[2]}}' == '{{array_value[2]}}'" } 58 | 59 | - set_fact: 60 | looky_secret: "{{lookup('hashivault', '{{name_array}}', 'value') | first}}" 61 | - assert: { that: "'{{looky_secret}}' == 'one'" } 62 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/_hashivault_secret_disable.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_auth_client 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['deprecated'], 'alternative': 'Use M(hashivault_secret_engine) instead.', 8 | 'why': 'This module does not fit the standard pattern', 9 | 'supported_by': 'community', 'version': '1.1'} 10 | DOCUMENTATION = ''' 11 | --- 12 | module: hashivault_secret_disable 13 | version_added: "2.2.0" 14 | short_description: Hashicorp Vault secret disable module 15 | description: 16 | - Module to disable secret backends in Hashicorp Vault. Use hashivault_secret_engine instead. 17 | options: 18 | name: 19 | description: 20 | - name of secret backend 21 | backend: 22 | description: 23 | - type of secret backend 24 | description: 25 | description: 26 | - description of secret backend 27 | config: 28 | description: 29 | - config of secret backend 30 | extends_documentation_fragment: hashivault 31 | ''' 32 | EXAMPLES = ''' 33 | --- 34 | - hosts: localhost 35 | tasks: 36 | - hashivault_secret_disable: 37 | name: "ephemeral" 38 | backend: "generic" 39 | ''' 40 | 41 | 42 | def main(): 43 | argspec = hashivault_argspec() 44 | argspec['name'] = dict(required=True, type='str') 45 | module = hashivault_init(argspec) 46 | result = hashivault_secret_disable(module.params) 47 | if result.get('failed'): 48 | module.fail_json(**result) 49 | else: 50 | module.exit_json(**result) 51 | 52 | 53 | @hashiwrapper 54 | def hashivault_secret_disable(params): 55 | client = hashivault_auth_client(params) 56 | name = params.get('name') 57 | client.sys.disable_secrets_engine(name) 58 | return {'changed': True} 59 | 60 | 61 | if __name__ == '__main__': 62 | main() 63 | -------------------------------------------------------------------------------- /functional/test_userpass.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | gather_facts: no 4 | vars: 5 | username: 'portugal' 6 | userpass: 'Th3m@n!!' 7 | rules: > 8 | path "secret/userpass/*" { 9 | capabilities = ["create", "read", "update", "delete", "list"] 10 | } 11 | path "secret/userpass" { 12 | capabilities = ["list"] 13 | } 14 | tasks: 15 | - hashivault_auth_method: 16 | name: "userpass" 17 | failed_when: False 18 | - hashivault_userpass_delete: 19 | name: "{{username}}" 20 | - hashivault_policy_delete: 21 | name: "{{username}}" 22 | 23 | - name: Set policy for userpass 24 | hashivault_policy: 25 | name: "{{username}}" 26 | rules: "{{rules}}" 27 | register: vault_policy 28 | - assert: { that: "{{vault_policy.changed}} == True" } 29 | - assert: { that: "{{vault_policy.rc}} == 0" } 30 | 31 | - name: Create user pass with policy 32 | hashivault_userpass_create: 33 | name: "{{username}}" 34 | pass: "{{userpass}}" 35 | policies: "{{username}}" 36 | register: 'vault_userpass_create' 37 | no_log: True 38 | - assert: { that: "{{vault_userpass_create.changed}} == True" } 39 | - assert: { that: "{{vault_userpass_create.rc}} == 0" } 40 | 41 | - name: Create user to delete with policy 42 | hashivault_userpass_create: 43 | name: "delete_{{username}}" 44 | pass: "{{userpass}}" 45 | policies: "{{username}}" 46 | register: 'vault_userpass_create' 47 | no_log: True 48 | - assert: { that: "{{vault_userpass_create.changed}} == True" } 49 | - assert: { that: "{{vault_userpass_create.rc}} == 0" } 50 | 51 | - hashivault_userpass_delete: 52 | name: "delete_{{username}}" 53 | register: 'vault_userpass_delete' 54 | - assert: { that: "{{vault_userpass_delete.changed}} == True" } 55 | - assert: { that: "{{vault_userpass_delete.rc}} == 0" } 56 | 57 | - template: 58 | src: "{{playbook_dir}}/templates/userpassenv.sh.j2" 59 | dest: "{{playbook_dir}}/userpassenv.sh" 60 | mode: 0700 61 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_pki_cert_list.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_auth_client 3 | from ansible.module_utils.hashivault import hashivault_argspec 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['preview'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = r''' 9 | --- 10 | module: hashivault_pki_cert_list 11 | version_added: "4.5.0" 12 | short_description: Hashicorp Vault PKI List Certificates 13 | description: 14 | - This module returns a list of the current certificates by serial number only. 15 | options: 16 | mount_point: 17 | default: pki 18 | description: 19 | - location where secrets engine is mounted. also known as path 20 | extends_documentation_fragment: 21 | - hashivault 22 | ''' 23 | EXAMPLES = r''' 24 | --- 25 | - hosts: localhost 26 | tasks: 27 | - hashivault_pki_cert_list: 28 | mount_point: pki 29 | register: roles_list 30 | - debug: msg="{{ roles_list.data }}" 31 | ''' 32 | RETURN = r''' 33 | --- 34 | data: 35 | description: list of roles, if pki engine has no roles will return empty list 36 | returned: success 37 | type: list 38 | ''' 39 | 40 | 41 | def main(): 42 | argspec = hashivault_argspec() 43 | argspec['mount_point'] = dict(required=False, type='str', default='pki') 44 | 45 | module = hashivault_init(argspec) 46 | result = hashivault_pki_cert_list(module) 47 | 48 | if result.get('failed'): 49 | module.fail_json(**result) 50 | else: 51 | module.exit_json(**result) 52 | 53 | 54 | @hashiwrapper 55 | def hashivault_pki_cert_list(module): 56 | params = module.params 57 | client = hashivault_auth_client(params) 58 | 59 | mount_point = params.get('mount_point').strip('/') 60 | 61 | try: 62 | return {'data': client.secrets.pki.list_certificates(mount_point=mount_point).get('data').get('keys')} 63 | except Exception: 64 | return {'data': []} 65 | 66 | 67 | if __name__ == '__main__': 68 | main() 69 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_pki_role_list.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_auth_client 3 | from ansible.module_utils.hashivault import hashivault_argspec 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['preview'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = r''' 9 | --- 10 | module: hashivault_pki_role_list 11 | version_added: "4.5.0" 12 | short_description: Hashicorp Vault PKI List Roles 13 | description: 14 | - This module returns a list of available roles. 15 | - Only the role names are returned, not any values. 16 | options: 17 | mount_point: 18 | default: pki 19 | description: 20 | - location where secrets engine is mounted. also known as path 21 | extends_documentation_fragment: 22 | - hashivault 23 | ''' 24 | EXAMPLES = r''' 25 | --- 26 | - hosts: localhost 27 | tasks: 28 | - hashivault_pki_role_list: 29 | mount_point: pki 30 | register: roles_list 31 | - debug: msg="{{ roles_list.data }}" 32 | ''' 33 | RETURN = r''' 34 | --- 35 | data: 36 | description: list of roles, if pki engine has no roles will return empty list 37 | returned: success 38 | type: list 39 | ''' 40 | 41 | 42 | def main(): 43 | argspec = hashivault_argspec() 44 | argspec['mount_point'] = dict(required=False, type='str', default='pki') 45 | 46 | module = hashivault_init(argspec) 47 | result = hashivault_pki_role_list(module) 48 | 49 | if result.get('failed'): 50 | module.fail_json(**result) 51 | else: 52 | module.exit_json(**result) 53 | 54 | 55 | @hashiwrapper 56 | def hashivault_pki_role_list(module): 57 | params = module.params 58 | client = hashivault_auth_client(params) 59 | 60 | mount_point = params.get('mount_point').strip('/') 61 | 62 | try: 63 | return {'data': client.secrets.pki.list_roles(mount_point=mount_point).get('data').get('keys')} 64 | except Exception: 65 | return {'data': []} 66 | 67 | 68 | if __name__ == '__main__': 69 | main() 70 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_generate_root_init.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_client 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = ''' 9 | --- 10 | module: hashivault_generate_root_init 11 | version_added: "3.14.0" 12 | short_description: Hashicorp Vault generate root token init module 13 | description: 14 | - Module to start root token generation of Hashicorp Vault. 15 | options: 16 | secret_shares: 17 | description: 18 | - specifies the number of shares to split the master key into. 19 | default: 5 20 | secret_threshold: 21 | description: 22 | - specifies the number of shares required to reconstruct the master key. 23 | default: 3 24 | pgp_key: 25 | description: 26 | - specifies PGP public keys used to encrypt the output root token. 27 | default: '' 28 | extends_documentation_fragment: hashivault 29 | ''' 30 | EXAMPLES = ''' 31 | --- 32 | - hosts: localhost 33 | tasks: 34 | - hashivault_generate_root_init: 35 | pgp_key: key 36 | ''' 37 | 38 | 39 | def main(): 40 | argspec = hashivault_argspec() 41 | argspec['pgp_key'] = dict(required=False, type='str', default='') 42 | module = hashivault_init(argspec) 43 | result = hashivault_generate_root_init(module.params) 44 | if result.get('failed'): 45 | module.fail_json(**result) 46 | else: 47 | module.exit_json(**result) 48 | 49 | 50 | @hashiwrapper 51 | def hashivault_generate_root_init(params): 52 | client = hashivault_client(params) 53 | # Check if rekey is on-going 54 | status = client.generate_root_status 55 | if status['started']: 56 | return {'changed': False} 57 | pgp = params.get('pgp_key') 58 | return {'status': client.start_generate_root(pgp, otp=False), 'changed': True} 59 | 60 | 61 | if __name__ == '__main__': 62 | main() 63 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/_hashivault_policy_delete.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_auth_client 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['deprecated'], 'alternative': 'Use M(hashivault_policy) instead.', 8 | 'why': 'This module does not fit the standard pattern', 9 | 'supported_by': 'community', 'version': '1.1'} 10 | DOCUMENTATION = ''' 11 | --- 12 | module: hashivault_policy_delete 13 | version_added: "2.1.0" 14 | short_description: Hashicorp Vault policy delete module 15 | description: 16 | - Module to delete a policy from Hashicorp Vault. Use hashivault_policy instead. 17 | options: 18 | name: 19 | description: 20 | - policy name. 21 | extends_documentation_fragment: hashivault 22 | ''' 23 | EXAMPLES = ''' 24 | --- 25 | - hosts: localhost 26 | tasks: 27 | - hashivault_policy_delete: 28 | name: 'annie' 29 | register: 'vault_policy_delete' 30 | - debug: msg="User policy is {{vault_policy_delete.policy}}" 31 | ''' 32 | 33 | 34 | def main(): 35 | argspec = hashivault_argspec() 36 | argspec['name'] = dict(required=True, type='str') 37 | module = hashivault_init(argspec) 38 | result = hashivault_policy_delete(module.params) 39 | if result.get('failed'): 40 | module.fail_json(**result) 41 | else: 42 | module.exit_json(**result) 43 | 44 | 45 | @hashiwrapper 46 | def hashivault_policy_delete(params): 47 | name = params.get('name') 48 | client = hashivault_auth_client(params) 49 | current_policies = client.sys.list_policies() 50 | if isinstance(current_policies, dict): 51 | current_policies = current_policies.get('data', current_policies) 52 | current_policies = current_policies.get('policies', current_policies) 53 | if name not in current_policies: 54 | return {'changed': False} 55 | client.sys.delete_policy(name) 56 | return {'changed': True} 57 | 58 | 59 | if __name__ == '__main__': 60 | main() 61 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_approle_role_secret_list.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from hvac.exceptions import InvalidPath 3 | from ansible.module_utils.hashivault import hashivault_argspec 4 | from ansible.module_utils.hashivault import hashivault_auth_client 5 | from ansible.module_utils.hashivault import hashivault_init 6 | from ansible.module_utils.hashivault import hashiwrapper 7 | 8 | ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'community', 'version': '1.1'} 9 | DOCUMENTATION = ''' 10 | --- 11 | module: hashivault_approle_role_secret_list 12 | version_added: "3.8.0" 13 | short_description: Hashicorp Vault approle role secret id get module 14 | description: 15 | - Module to get a approle role secret id from Hashicorp Vault. 16 | options: 17 | name: 18 | description: 19 | - role name. 20 | mount_point: 21 | description: 22 | - mount point for role 23 | default: approle 24 | extends_documentation_fragment: hashivault 25 | ''' 26 | EXAMPLES = ''' 27 | --- 28 | - hosts: localhost 29 | tasks: 30 | - hashivault_approle_role_secret_list: 31 | name: 'ashley' 32 | register: 'vault_approle_role_secret_list' 33 | - debug: msg="Role secrets are {{vault_approle_role_secret_list.secrets}}" 34 | ''' 35 | 36 | 37 | def main(): 38 | argspec = hashivault_argspec() 39 | argspec['name'] = dict(required=True, type='str') 40 | argspec['mount_point'] = dict(required=False, type='str', default='approle') 41 | module = hashivault_init(argspec) 42 | result = hashivault_approle_role_secret_list(module.params) 43 | if result.get('failed'): 44 | module.fail_json(**result) 45 | else: 46 | module.exit_json(**result) 47 | 48 | 49 | @hashiwrapper 50 | def hashivault_approle_role_secret_list(params): 51 | name = params.get('name') 52 | mount_point = params.get('mount_point') 53 | client = hashivault_auth_client(params) 54 | try: 55 | secrets = client.list_role_secrets(name, mount_point=mount_point) 56 | except InvalidPath: 57 | return {'secrets': []} 58 | secrets = secrets.get('data', {}).get('keys', []) 59 | return {'secrets': str(secrets)} 60 | 61 | 62 | if __name__ == '__main__': 63 | main() 64 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_pki_url_get.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_auth_client 3 | from ansible.module_utils.hashivault import hashivault_argspec 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['preview'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = r''' 9 | --- 10 | module: hashivault_pki_url_get 11 | version_added: "4.5.0" 12 | short_description: Hashicorp Vault PKI Read URLs 13 | description: 14 | - This module fetches the URLs to be encoded in generated certificates. 15 | options: 16 | mount_point: 17 | default: pki 18 | description: 19 | - location where secrets engine is mounted. also known as path 20 | extends_documentation_fragment: 21 | - hashivault 22 | ''' 23 | EXAMPLES = r''' 24 | --- 25 | - hosts: localhost 26 | tasks: 27 | - hashivault_pki_url_get: 28 | register: url_config 29 | - debug: msg="{{ url_config }}" 30 | ''' 31 | 32 | 33 | def main(): 34 | argspec = hashivault_argspec() 35 | argspec['mount_point'] = dict(required=False, type='str', default='pki') 36 | 37 | module = hashivault_init(argspec) 38 | result = hashivault_pki_url_get(module) 39 | 40 | if result.get('failed'): 41 | module.fail_json(**result) 42 | else: 43 | module.exit_json(**result) 44 | 45 | 46 | @hashiwrapper 47 | def hashivault_pki_url_get(module): 48 | params = module.params 49 | client = hashivault_auth_client(params) 50 | 51 | mount_point = params.get('mount_point').strip('/') 52 | 53 | result = {"changed": False, "rc": 0} 54 | from hvac.exceptions import InvalidPath 55 | try: 56 | result['data'] = client.secrets.pki.read_urls(mount_point=mount_point).get('data') 57 | except InvalidPath: 58 | result['rc'] = 1 59 | result['failed'] = True 60 | result['msg'] = u"URLs must be configured before beeng read" 61 | except Exception as e: 62 | result['rc'] = 1 63 | result['failed'] = True 64 | result['msg'] = u"Exception: " + str(e) 65 | return result 66 | 67 | 68 | if __name__ == '__main__': 69 | main() 70 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/_hashivault_audit_enable.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_auth_client 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['deprecated'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = ''' 9 | --- 10 | module: hashivault_audit_enable 11 | version_added: "2.2.0" 12 | short_description: Hashicorp Vault audit enable module 13 | description: 14 | - Module to enable audit backends in Hashicorp Vault. Use hashivault_audit instead. 15 | options: 16 | name: 17 | description: 18 | - name of auditor 19 | description: 20 | description: 21 | - description of auditor 22 | options: 23 | description: 24 | - options for auditor 25 | extends_documentation_fragment: hashivault 26 | ''' 27 | EXAMPLES = ''' 28 | --- 29 | - hosts: localhost 30 | tasks: 31 | - hashivault_audit_enable: 32 | name: "syslog" 33 | ''' 34 | 35 | 36 | def main(): 37 | argspec = hashivault_argspec() 38 | argspec['name'] = dict(required=True, type='str') 39 | argspec['description'] = dict(required=False, type='str') 40 | argspec['options'] = dict(required=False, type='dict') 41 | module = hashivault_init(argspec) 42 | result = hashivault_audit_enable(module.params) 43 | if result.get('failed'): 44 | module.fail_json(**result) 45 | else: 46 | module.exit_json(**result) 47 | 48 | 49 | @hashiwrapper 50 | def hashivault_audit_enable(params): 51 | client = hashivault_auth_client(params) 52 | name = params.get('name') 53 | description = params.get('description') 54 | options = params.get('options') 55 | backends = client.sys.list_enabled_audit_devices() 56 | backends = backends.get('data', backends) 57 | path = name + "/" 58 | if path in backends and backends[path]["options"] == options: 59 | return {'changed': False} 60 | client.sys.enable_audit_device(name, description=description, options=options) 61 | return {'changed': True} 62 | 63 | 64 | if __name__ == '__main__': 65 | main() 66 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_pki_crl_rotate.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_auth_client 3 | from ansible.module_utils.hashivault import hashivault_argspec 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['preview'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = r''' 9 | --- 10 | module: hashivault_pki_crl_rotate 11 | version_added: "4.5.0" 12 | short_description: Hashicorp Vault PKI Rotate CRLs 13 | description: 14 | - This module forces a rotation of the CRL. 15 | - This can be used by administrators to cut the size of the CRL if it contains a number of certificates that have 16 | now expired, but has not been rotated due to no further certificates being revoked. 17 | options: 18 | mount_point: 19 | default: pki 20 | description: 21 | - location where secrets engine is mounted. also known as path 22 | extends_documentation_fragment: 23 | - hashivault 24 | ''' 25 | EXAMPLES = r''' 26 | --- 27 | - hosts: localhost 28 | tasks: 29 | - hashivault_pki_crl_rotate: 30 | ''' 31 | 32 | 33 | def main(): 34 | argspec = hashivault_argspec() 35 | argspec['mount_point'] = dict(required=False, type='str', default='pki') 36 | 37 | supports_check_mode = True 38 | 39 | module = hashivault_init(argspec, supports_check_mode) 40 | result = hashivault_pki_crl_rotate(module) 41 | 42 | if result.get('failed'): 43 | module.fail_json(**result) 44 | else: 45 | module.exit_json(**result) 46 | 47 | 48 | @hashiwrapper 49 | def hashivault_pki_crl_rotate(module): 50 | params = module.params 51 | client = hashivault_auth_client(params) 52 | 53 | mount_point = params.get('mount_point').strip('/') 54 | 55 | failed = False 56 | 57 | # make the changes! 58 | if not module.check_mode: 59 | failed = not client.secrets.pki.rotate_crl(mount_point=mount_point).get('data').get('success') 60 | return {'failed': failed, 'changed': not failed, 61 | 'msg': 'oops, something went wrong.' if failed else '', 'rc': 1 if failed else 0} 62 | 63 | 64 | if __name__ == '__main__': 65 | main() 66 | -------------------------------------------------------------------------------- /functional/test_not_there.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | gather_facts: no 4 | vars: 5 | secret_name: 'fourofour/nothome' 6 | tasks: 7 | - hashivault_delete: 8 | secret: '{{secret_name}}' 9 | 10 | - name: Read nonexistent secret value ignoring error 11 | hashivault_read: 12 | secret: '{{secret_name}}' 13 | key: 'value' 14 | register: 'vault_read' 15 | failed_when: False 16 | - assert: { that: "{{vault_read.failed}} == False" } 17 | - assert: { that: "{{vault_read.rc}} == 1" } 18 | - assert: { that: "'{{vault_read.msg}}' == 'Secret secret/fourofour/nothome is not in vault'" } 19 | 20 | - name: Nonexistent secret path with empty default 21 | hashivault_read: 22 | secret: '{{secret_name}}' 23 | key: 'value' 24 | default: '' 25 | register: 'vault_read' 26 | - assert: { that: "'{{vault_read.value}}' == ''" } 27 | - assert: { that: "{{vault_read.failed}} == False" } 28 | - assert: { that: "{{vault_read.rc}} == 0" } 29 | 30 | - name: Nonexistent secret path with default 31 | hashivault_read: 32 | secret: '{{secret_name}}' 33 | key: 'value' 34 | default: 'carseat' 35 | register: 'vault_read' 36 | - assert: { that: "'{{vault_read.value}}' == 'carseat'" } 37 | 38 | - set_fact: 39 | looky_secret: "{{lookup('hashivault', '{{secret_name}}', 'value', default='headrest')}}" 40 | - assert: { that: "'{{looky_secret}}' == 'headrest'" } 41 | 42 | - name: Write new different value to secret store 43 | hashivault_write: 44 | secret: '{{secret_name}}' 45 | data: 46 | othervalue: 'one' 47 | 48 | - name: Nonexistent key with default 49 | hashivault_read: 50 | secret: '{{secret_name}}' 51 | key: 'value' 52 | default: 'better' 53 | register: 'vault_read' 54 | - assert: { that: "'{{vault_read.value}}' == 'better'" } 55 | 56 | - set_fact: 57 | looky_secret: "{{lookup('hashivault', '{{secret_name}}', 'othervalue', default='noob')}}" 58 | - assert: { that: "'{{looky_secret}}' == 'one'" } 59 | 60 | - set_fact: 61 | looky_secret: "{{lookup('hashivault', '{{secret_name}}', 'value', default='noob')}}" 62 | - assert: { that: "'{{looky_secret}}' == 'noob'" } 63 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_pki_crl_get.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_auth_client 3 | from ansible.module_utils.hashivault import hashivault_argspec 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['preview'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = r''' 9 | --- 10 | module: hashivault_pki_crl_get 11 | version_added: "4.5.0" 12 | short_description: Hashicorp Vault PKI Read CRL Configuration 13 | description: 14 | - This module allows getting the duration for which the generated CRL should be marked valid. 15 | options: 16 | mount_point: 17 | default: pki 18 | description: 19 | - location where secrets engine is mounted. also known as path 20 | extends_documentation_fragment: 21 | - hashivault 22 | ''' 23 | EXAMPLES = r''' 24 | --- 25 | - hosts: localhost 26 | tasks: 27 | - hashivault_pki_crl_get: 28 | register: clr_config 29 | - debug: msg="{{ clr_config }}" 30 | ''' 31 | 32 | 33 | def main(): 34 | argspec = hashivault_argspec() 35 | argspec['mount_point'] = dict(required=False, type='str', default='pki') 36 | 37 | module = hashivault_init(argspec) 38 | result = hashivault_pki_crl_get(module) 39 | 40 | if result.get('failed'): 41 | module.fail_json(**result) 42 | else: 43 | module.exit_json(**result) 44 | 45 | 46 | @hashiwrapper 47 | def hashivault_pki_crl_get(module): 48 | params = module.params 49 | client = hashivault_auth_client(params) 50 | 51 | mount_point = params.get('mount_point').strip('/') 52 | 53 | result = {"changed": False, "rc": 0} 54 | from hvac.exceptions import InvalidPath 55 | try: 56 | result['data'] = client.secrets.pki.read_crl_configuration(mount_point=mount_point).get('data') 57 | except InvalidPath: 58 | result['rc'] = 1 59 | result['failed'] = True 60 | result['msg'] = u"CRLs must be configured before reading" 61 | except Exception as e: 62 | result['rc'] = 1 63 | result['failed'] = True 64 | result['msg'] = u"Exception: " + str(e) 65 | return result 66 | 67 | 68 | if __name__ == '__main__': 69 | main() 70 | -------------------------------------------------------------------------------- /functional/test_namespace.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | connection: localhost 4 | tasks: 5 | 6 | - hashivault_namespace: 7 | name: hvtest 8 | state: absent 9 | 10 | - hashivault_namespace: 11 | name: hvtest 12 | register: first_create 13 | 14 | - assert: { that: "{{first_create.changed}} == True" } 15 | 16 | - hashivault_namespace: 17 | name: hvtest 18 | register: idem_create 19 | 20 | - assert: { that: "{{idem_create.changed}} == False" } 21 | 22 | - hashivault_namespace: 23 | name: child 24 | namespace: hvtest 25 | register: second_create 26 | 27 | - assert: { that: "{{second_create.changed}} == True" } 28 | 29 | - hashivault_namespace: 30 | name: child 31 | namespace: hvtest 32 | register: second_idem_create 33 | 34 | - assert: { that: "{{second_idem_create.changed}} == False" } 35 | 36 | - hashivault_namespace: 37 | name: child2 38 | namespace: hvtest/child 39 | register: third_create 40 | 41 | - assert: { that: "{{third_create.changed}} == True" } 42 | 43 | - hashivault_namespace: 44 | name: child2 45 | namespace: hvtest/child 46 | register: third_idem_create 47 | 48 | - assert: { that: "{{third_idem_create.changed}} == False" } 49 | 50 | - hashivault_namespace: 51 | name: hvtest 52 | state: absent 53 | register: delete_fail 54 | failed_when: False 55 | - assert: { that: "{{delete_fail.rc}} != 0" } 56 | 57 | 58 | - hashivault_namespace: 59 | name: child2 60 | namespace: hvtest/child 61 | state: absent 62 | register: delete_one 63 | 64 | - assert: { that: "{{delete_one.changed}} == True" } 65 | 66 | - hashivault_namespace: 67 | name: child 68 | namespace: hvtest 69 | state: absent 70 | register: delete_two 71 | 72 | - assert: { that: "{{delete_two.changed}} == True" } 73 | 74 | - hashivault_namespace: 75 | name: hvtest 76 | state: absent 77 | register: delete_three 78 | 79 | - assert: { that: "{{delete_three.changed}} == True" } 80 | 81 | - hashivault_namespace: 82 | name: hvtest 83 | state: absent 84 | register: delete_idem 85 | 86 | - assert: { that: "{{delete_idem.changed}} == False" } -------------------------------------------------------------------------------- /functional/test_mounts.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: localhost 4 | gather_facts: no 5 | tasks: 6 | - hashivault_secret_engine: 7 | name: kv 8 | state: absent 9 | 10 | - hashivault_secret_engine: 11 | name: blergh 12 | state: absent 13 | 14 | - name: enable with config defaults 15 | hashivault_secret_engine: 16 | name: kv 17 | state: present 18 | register: success_config 19 | 20 | - assert: { that: "{{ success_config.changed }} == True" } 21 | 22 | - name: skip with config defaults 23 | hashivault_secret_engine: 24 | name: kv 25 | state: present 26 | register: skip_config 27 | 28 | - assert: { that: "{{ skip_config.changed }} == False" } 29 | 30 | - name: changed with config vars 31 | hashivault_secret_engine: 32 | name: kv 33 | state: present 34 | config: {'default_lease_ttl': 1234567} 35 | register: chg_config 36 | 37 | - assert: { that: "{{ chg_config.changed }} == True" } 38 | 39 | - name: changed to version 2 40 | hashivault_secret_engine: 41 | name: kv 42 | state: present 43 | config: {'default_lease_ttl': 1234567} 44 | options: {'version': '2'} 45 | register: chg_version 46 | 47 | - assert: { that: "{{ chg_version.changed }} == True" } 48 | 49 | - name: dont fail when options passed to non kv 50 | hashivault_secret_engine: 51 | name: blergh 52 | backend: gcp 53 | state: present 54 | config: {'default_lease_ttl': 1234567} 55 | options: {'version': '2'} 56 | register: dont_pass_options 57 | 58 | - assert: { that: "{{ dont_pass_options.changed }} == True" } 59 | 60 | - name: cleanup 1 61 | hashivault_secret_engine: 62 | name: blergh 63 | backend: gcp 64 | state: absent 65 | config: {'default_lease_ttl': 1234567} 66 | options: {'version': '2'} 67 | register: disable 68 | 69 | - assert: { that: "{{ disable.changed }} == True" } 70 | 71 | - name: cleanup 2 72 | hashivault_secret_engine: 73 | name: kv 74 | backend: kv 75 | state: absent 76 | config: {'default_lease_ttl': 1234567} 77 | options: {'version': '2'} 78 | register: disable2 79 | 80 | - assert: { that: "{{ disable2.changed }} == True" } -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_approle_role_secret_accessor_get.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_auth_client 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = ''' 9 | --- 10 | module: hashivault_approle_role_secret_accessor_get 11 | version_added: "3.8.0" 12 | short_description: Hashicorp Vault approle role secret accessor get module 13 | description: 14 | - Module to get a approle role secret accessor from Hashicorp Vault. 15 | options: 16 | name: 17 | description: 18 | - role name. 19 | mount_point: 20 | description: 21 | - mount point for role 22 | default: approle 23 | accessor: 24 | description: 25 | - accessor id. 26 | extends_documentation_fragment: hashivault 27 | ''' 28 | EXAMPLES = ''' 29 | --- 30 | - hosts: localhost 31 | tasks: 32 | - hashivault_approle_role_secret_accessor_get: 33 | name: 'ashley' 34 | accessor: 'ec4bedee-e44b-c096-9ac8-1600e52ed8f8' 35 | register: 'vault_approle_role_secret_accessor_get' 36 | - debug: msg="Role secret is {{vault_approle_role_secret_accessor_get.secret}}" 37 | ''' 38 | 39 | 40 | def main(): 41 | argspec = hashivault_argspec() 42 | argspec['name'] = dict(required=True, type='str') 43 | argspec['mount_point'] = dict(required=False, type='str', default='approle') 44 | argspec['accessor'] = dict(required=True, type='str') 45 | module = hashivault_init(argspec) 46 | result = hashivault_approle_role_secret_accessor_get(module.params) 47 | if result.get('failed'): 48 | module.fail_json(**result) 49 | else: 50 | module.exit_json(**result) 51 | 52 | 53 | @hashiwrapper 54 | def hashivault_approle_role_secret_accessor_get(params): 55 | name = params.get('name') 56 | mount_point = params.get('mount_point') 57 | accessor = params.get('accessor') 58 | client = hashivault_auth_client(params) 59 | return {'secret': client.get_role_secret_id_accessor(name, accessor, mount_point=mount_point)['data']} 60 | 61 | 62 | if __name__ == '__main__': 63 | main() 64 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_token_revoke.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_auth_client 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = ''' 9 | --- 10 | module: hashivault_token_revoke 11 | version_added: "3.11.0" 12 | short_description: Hashicorp Vault token revoke module 13 | description: 14 | - Module to revoke tokens in Hashicorp Vault. 15 | options: 16 | revoke_token: 17 | description: 18 | - token to revoke if different from auth token 19 | default: to authentication token 20 | accessor: 21 | description: 22 | - If set, lookups will use the this accessor token 23 | orphan: 24 | description: 25 | - If set, Vault will revoke only the token, leaving the children as orphans. 26 | extends_documentation_fragment: hashivault 27 | ''' 28 | EXAMPLES = ''' 29 | --- 30 | - hosts: localhost 31 | tasks: 32 | - name: "revoke token" 33 | hashivault_token_revoke: 34 | revoke_token: "{{client_token}}" 35 | register: "vault_token_revoke" 36 | ''' 37 | 38 | 39 | def main(): 40 | argspec = hashivault_argspec() 41 | argspec['revoke_token'] = dict(required=False, type='str') 42 | argspec['accessor'] = dict(required=False, type='bool', default=False) 43 | argspec['orphan'] = dict(required=False, type='bool', default=False) 44 | module = hashivault_init(argspec) 45 | result = hashivault_token_revoke(module.params) 46 | if result.get('failed'): 47 | module.fail_json(**result) 48 | else: 49 | module.exit_json(**result) 50 | 51 | 52 | @hashiwrapper 53 | def hashivault_token_revoke(params): 54 | client = hashivault_auth_client(params) 55 | accessor = params.get('accessor') 56 | orphan = params.get('orphan') 57 | revoke_token = params.get('revoke_token') 58 | if revoke_token is None: 59 | revoke_token = params.get('token') 60 | revoke = client.revoke_token(token=revoke_token, orphan=orphan, accessor=accessor) 61 | return {'changed': True, 'revoke': revoke} 62 | 63 | 64 | if __name__ == '__main__': 65 | main() 66 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/_hashivault_policy_set.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_auth_client 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['deprecated'], 'alternative': 'Use M(hashivault_policy) instead.', 8 | 'why': 'This module does not fit the standard pattern', 9 | 'supported_by': 'community', 'version': '1.1'} 10 | DOCUMENTATION = ''' 11 | --- 12 | module: hashivault_policy_set 13 | version_added: "2.1.0" 14 | short_description: Hashicorp Vault policy set module 15 | description: 16 | - Module to set a policy in Hashicorp Vault. Use hashivault_policy instead. 17 | options: 18 | name: 19 | description: 20 | - policy name. 21 | rules: 22 | description: 23 | - policy rules. 24 | extends_documentation_fragment: hashivault 25 | ''' 26 | EXAMPLES = ''' 27 | --- 28 | - hosts: localhost 29 | tasks: 30 | - hashivault_policy_set: 31 | rules: '{{rules}}' 32 | ''' 33 | 34 | 35 | def main(): 36 | argspec = hashivault_argspec() 37 | argspec['name'] = dict(required=True, type='str') 38 | argspec['rules'] = dict(required=True, type='str') 39 | argspec['rules_file'] = dict(required=False, type='bool', default=False) 40 | module = hashivault_init(argspec) 41 | result = hashivault_policy_set(module.params) 42 | if result.get('failed'): 43 | module.fail_json(**result) 44 | else: 45 | module.exit_json(**result) 46 | 47 | 48 | @hashiwrapper 49 | def hashivault_policy_set(params): 50 | client = hashivault_auth_client(params) 51 | name = params.get('name') 52 | rules = params.get('rules') 53 | rules_file = params.get('rules_file') 54 | if rules_file: 55 | try: 56 | rules = open(rules, 'r').read() 57 | except Exception as e: 58 | return {'changed': False, 'failed': True, 'msg': 'Error opening rules file <%s>: %s' % (rules, str(e))} 59 | current = client.get_policy(name) 60 | if current == rules: 61 | return {'changed': False} 62 | client.sys.create_or_update_policy(name, rules) 63 | return {'changed': True} 64 | 65 | 66 | if __name__ == '__main__': 67 | main() 68 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_pki_cert_get.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_auth_client 3 | from ansible.module_utils.hashivault import hashivault_argspec 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['preview'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = r''' 9 | --- 10 | module: hashivault_pki_cert_get 11 | version_added: "4.5.0" 12 | short_description: Hashicorp Vault PKI Read Certificate 13 | description: 14 | - This module retrieves one of a selection of certificates. 15 | options: 16 | serial: 17 | recuired: true 18 | defaul: ca 19 | choices: ["ca", "ca_chain", "crl", ""] 20 | description: 21 | - Specifies the serial of the key to read. 22 | mount_point: 23 | default: pki 24 | description: 25 | - location where secrets engine is mounted. also known as path 26 | extends_documentation_fragment: 27 | - hashivault 28 | ''' 29 | EXAMPLES = r''' 30 | --- 31 | - hosts: localhost 32 | tasks: 33 | - hashivault_pki_cert_get: 34 | register: cert 35 | - debug: msg="{{ cert }}" 36 | 37 | - hashivault_pki_cert_get: 38 | serial: 0f-d0-bf-cc-7a-d2-b5-b8-ec-6d-8f-cb-9d-0a-c7-d1-e2-3b-82-7d 39 | register: cert 40 | - debug: msg="{{ cert }}" 41 | ''' 42 | 43 | 44 | def main(): 45 | argspec = hashivault_argspec() 46 | argspec['serial'] = dict(required=False, type='str', default='ca') 47 | argspec['mount_point'] = dict(required=False, type='str', default='pki') 48 | 49 | module = hashivault_init(argspec) 50 | result = hashivault_pki_cert_get(module) 51 | 52 | if result.get('failed'): 53 | module.fail_json(**result) 54 | else: 55 | module.exit_json(**result) 56 | 57 | 58 | @hashiwrapper 59 | def hashivault_pki_cert_get(module): 60 | params = module.params 61 | client = hashivault_auth_client(params) 62 | 63 | serial = params.get('serial') 64 | mount_point = params.get('mount_point').strip('/') 65 | 66 | try: 67 | return {'data': client.secrets.pki.read_certificate(serial=serial, mount_point=mount_point).get('data')} 68 | except Exception: 69 | return {'data': {}} 70 | 71 | 72 | if __name__ == '__main__': 73 | main() 74 | -------------------------------------------------------------------------------- /ansible/plugins/action/hashivault_write_from_file.py: -------------------------------------------------------------------------------- 1 | ######################################################################## 2 | # 3 | # Developed for AT&T by Nicholas Gibson, August 2017 4 | # 5 | # Action plugin for hashivault_write_from_file module. 6 | # 7 | # Reads file from remote host using slurp module. (base64 encoded) 8 | # Stores file/secret to Vault using hashivault_read module on localhost. 9 | # 10 | ######################################################################## 11 | 12 | from ansible.plugins.action import ActionBase 13 | from ansible.utils.vars import merge_hash 14 | 15 | 16 | class ActionModule(ActionBase): 17 | 18 | def run(self, tmp=None, task_vars=None): 19 | 20 | if task_vars is None: 21 | task_vars = dict() 22 | 23 | results = super(ActionModule, self).run(tmp, task_vars) 24 | 25 | args = self._task.args.copy() 26 | 27 | key = args.pop('key', None) 28 | path = args.pop('path', None) 29 | 30 | new_module_args = { 31 | 'src': path 32 | } 33 | self._update_module_args('slurp', new_module_args, task_vars) 34 | 35 | results = merge_hash( 36 | results, 37 | # executes slurp module on remote host 38 | self._execute_module(module_name='slurp', tmp=tmp, task_vars=task_vars, module_args=new_module_args) 39 | ) 40 | 41 | if 'failed' in results and results['failed'] is True: 42 | return results 43 | 44 | # already base64 encoded from slurp 45 | content = results.pop('content', None) 46 | 47 | self._play_context.become = False 48 | self._play_context.become_method = None 49 | 50 | self._connection = self._shared_loader_obj.connection_loader.get('local', self._play_context, 51 | self._connection._new_stdin) 52 | 53 | args['data'] = {key: content} 54 | if 'update' not in args: 55 | args['update'] = True 56 | 57 | results = merge_hash( 58 | results, 59 | # executes hashivault_write module on localhost 60 | self._execute_module(module_name='hashivault_write', tmp=tmp, task_vars=task_vars, module_args=args) 61 | ) 62 | 63 | results['invocation']['module_args']['data'] = 'VALUE_SPECIFIED_IN_NO_LOG_PARAMETER' 64 | 65 | return results 66 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/_hashivault_auth_enable.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_auth_client 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['deprecated'], 'alternative': 'Use M(hashivault_auth_method) instead.', 8 | 'why': 'This module does not fit the standard pattern', 9 | 'supported_by': 'community', 'version': '1.1'} 10 | DOCUMENTATION = ''' 11 | --- 12 | module: hashivault_auth_enable 13 | version_added: "2.2.0" 14 | short_description: Hashicorp Vault auth enable module 15 | description: 16 | - Use hashivault_auth_method instead. 17 | options: 18 | name: 19 | description: 20 | - name of authenticator 21 | description: 22 | description: 23 | - description of authenticator 24 | mount_point: 25 | description: 26 | - location where this auth backend will be mounted 27 | extends_documentation_fragment: hashivault 28 | ''' 29 | EXAMPLES = ''' 30 | --- 31 | - hosts: localhost 32 | tasks: 33 | - hashivault_auth_enable: 34 | name: "userpass" 35 | ''' 36 | 37 | 38 | def main(): 39 | argspec = hashivault_argspec() 40 | argspec['name'] = dict(required=True, type='str') 41 | argspec['description'] = dict(required=False, type='str') 42 | argspec['mount_point'] = dict(required=False, type='str', default=None) 43 | module = hashivault_init(argspec) 44 | result = hashivault_auth_enable(module.params) 45 | if result.get('failed'): 46 | module.fail_json(**result) 47 | else: 48 | module.exit_json(**result) 49 | 50 | 51 | @hashiwrapper 52 | def hashivault_auth_enable(params): 53 | client = hashivault_auth_client(params) 54 | name = params.get('name') 55 | description = params.get('description') 56 | mount_point = params.get('mount_point') 57 | result = client.sys.list_auth_methods() 58 | backends = result.get('data', result) 59 | path = (mount_point or name) + u"/" 60 | if path in backends: 61 | return {'changed': False} 62 | client.sys.enable_auth_method(name, description=description, path=mount_point) 63 | return {'changed': True} 64 | 65 | 66 | if __name__ == '__main__': 67 | main() 68 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_cluster_status.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_client 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = ''' 9 | --- 10 | module: hashivault_cluster_status 11 | version_added: "3.16.4" 12 | short_description: Hashicorp Vault cluster status module 13 | description: 14 | - Module to get cluster status of Hashicorp Vault. 15 | options: 16 | standby_ok: 17 | description: 18 | - Specifies if being a standby should still return the active status code instead of the standby status code 19 | default: False 20 | method: 21 | description: 22 | - Method to use to get cluster status, supported methods are HEAD (produces 000 (empty body)) and GET (produces 23 | 000 application/json) 24 | default: HEAD 25 | extends_documentation_fragment: hashivault 26 | ''' 27 | EXAMPLES = ''' 28 | --- 29 | - hosts: localhost 30 | tasks: 31 | - hashivault_cluster_status: 32 | register: 'vault_cluster_status' 33 | - debug: msg="Cluster is initialized: {{vault_cluster_status.status.initialized}}" 34 | ''' 35 | 36 | 37 | def main(): 38 | argspec = hashivault_argspec() 39 | argspec['standby_ok'] = dict(required=False, type='bool', default=True) 40 | argspec['method'] = dict(required=False, default="HEAD") 41 | module = hashivault_init(argspec) 42 | result = hashivault_cluster_status(module.params) 43 | if result.get('failed'): 44 | module.fail_json(**result) 45 | else: 46 | module.exit_json(**result) 47 | 48 | 49 | @hashiwrapper 50 | def hashivault_cluster_status(params): 51 | client = hashivault_client(params) 52 | response = client.sys.read_health_status(standby_ok=params.get("standby_ok"), method=params.get("method")) 53 | from requests.models import Response 54 | if isinstance(response, Response): 55 | try: 56 | status = response.json() 57 | except Exception: 58 | status = response.content 59 | else: 60 | status = response 61 | return {'status': status} 62 | 63 | 64 | if __name__ == '__main__': 65 | main() 66 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/_hashivault_userpass_create.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_auth_client 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['deprecated'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = ''' 9 | --- 10 | module: hashivault_userpass_create 11 | version_added: "2.2.0" 12 | short_description: Hashicorp Vault userpass create module 13 | description: 14 | - Module to create userpass users in Hashicorp Vault. Use hashicorp_userpass instead. 15 | options: 16 | name: 17 | description: 18 | - user name to create. 19 | pass: 20 | description: 21 | - user to create password. 22 | policies: 23 | description: 24 | - user policies. 25 | default: default 26 | mount_point: 27 | description: 28 | - default The "path" (app-id) the auth backend is mounted on. 29 | default: userpass 30 | extends_documentation_fragment: hashivault 31 | ''' 32 | EXAMPLES = ''' 33 | --- 34 | - hosts: localhost 35 | tasks: 36 | - hashivault_userpass_create: 37 | name: 'bob' 38 | pass: 'S3cre7s' 39 | policies: 'bob' 40 | ''' 41 | 42 | 43 | def main(): 44 | argspec = hashivault_argspec() 45 | argspec['name'] = dict(required=True, type='str') 46 | argspec['pass'] = dict(required=True, type='str') 47 | argspec['policies'] = dict(required=False, type='str', default='default') 48 | argspec['mount_point'] = dict(required=False, type='str', default='userpass', no_log=True) 49 | module = hashivault_init(argspec) 50 | result = hashivault_userpass_create(module.params) 51 | if result.get('failed'): 52 | module.fail_json(**result) 53 | else: 54 | module.exit_json(**result) 55 | 56 | 57 | @hashiwrapper 58 | def hashivault_userpass_create(params): 59 | client = hashivault_auth_client(params) 60 | name = params.get('name') 61 | password = params.get('pass') 62 | policies = params.get('policies') 63 | mount_point = params.get('mount_point') 64 | client.create_userpass(name, password, policies, mount_point=mount_point) 65 | return {'changed': True} 66 | 67 | 68 | if __name__ == '__main__': 69 | main() 70 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_token_lookup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from ansible.module_utils.hashivault import hashivault_argspec 4 | from ansible.module_utils.hashivault import hashivault_auth_client 5 | from ansible.module_utils.hashivault import hashivault_init 6 | from ansible.module_utils.hashivault import hashiwrapper 7 | 8 | ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'community', 'version': '1.1'} 9 | DOCUMENTATION = ''' 10 | --- 11 | module: hashivault_token_lookup 12 | version_added: "3.3.0" 13 | short_description: Hashicorp Vault token lookup module 14 | description: 15 | - Module to look up / check for existence of tokens in Hashicorp Vault. 16 | options: 17 | lookup_token: 18 | description: 19 | - token to lookup if different from auth token 20 | default: to authentication token 21 | accessor: 22 | description: 23 | - If set, lookups will use the this accessor token 24 | wrap_ttl: 25 | description: 26 | - Indicates that the response should be wrapped in a cubbyhole token with the requested TTL. 27 | extends_documentation_fragment: hashivault 28 | ''' 29 | EXAMPLES = ''' 30 | --- 31 | - hosts: localhost 32 | tasks: 33 | - name: "Lookup token" 34 | hashivault_token_lookup: 35 | lookup_token: "{{client_token}}" 36 | register: "vault_token_lookup" 37 | ''' 38 | 39 | 40 | def main(): 41 | argspec = hashivault_argspec() 42 | argspec['lookup_token'] = dict(required=False, type='str', no_log=True) 43 | argspec['accessor'] = dict(required=False, type='bool', default=False) 44 | argspec['wrap_ttl'] = dict(required=False, type='int') 45 | module = hashivault_init(argspec) 46 | result = hashivault_token_lookup(module.params) 47 | if result.get('failed'): 48 | module.fail_json(**result) 49 | else: 50 | module.exit_json(**result) 51 | 52 | 53 | @hashiwrapper 54 | def hashivault_token_lookup(params): 55 | client = hashivault_auth_client(params) 56 | accessor = params.get('accessor') 57 | lookup_token = params.get('lookup_token') 58 | if lookup_token is None: 59 | lookup_token = params.get('token') 60 | wrap_ttl = params.get('wrap_ttl') 61 | lookup = client.lookup_token(token=lookup_token, accessor=accessor, wrap_ttl=wrap_ttl) 62 | return {'changed': False, 'lookup': lookup} 63 | 64 | 65 | if __name__ == '__main__': 66 | main() 67 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_pki_role_get.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_auth_client 3 | from ansible.module_utils.hashivault import hashivault_argspec 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['preview'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = r''' 9 | --- 10 | module: hashivault_pki_role_get 11 | version_added: "4.5.0" 12 | short_description: Hashicorp Vault PKI Read Role 13 | description: 14 | - This module queries the role definition. 15 | options: 16 | name: 17 | recuired: true 18 | description: 19 | - Specifies the name of the role to create. 20 | mount_point: 21 | default: pki 22 | description: 23 | - location where secrets engine is mounted. also known as path 24 | extends_documentation_fragment: 25 | - hashivault 26 | ''' 27 | EXAMPLES = r''' 28 | --- 29 | - hosts: localhost 30 | tasks: 31 | - hashivault_pki_role_get: 32 | name: tester 33 | register: role 34 | - debug: msg="{{ role }}" 35 | ''' 36 | 37 | 38 | def main(): 39 | argspec = hashivault_argspec() 40 | argspec['name'] = dict(required=True, type='str') 41 | argspec['mount_point'] = dict(required=False, type='str', default='pki') 42 | 43 | module = hashivault_init(argspec) 44 | result = hashivault_pki_role_get(module) 45 | 46 | if result.get('failed'): 47 | module.fail_json(**result) 48 | else: 49 | module.exit_json(**result) 50 | 51 | 52 | @hashiwrapper 53 | def hashivault_pki_role_get(module): 54 | params = module.params 55 | client = hashivault_auth_client(params) 56 | 57 | name = params.get('name').strip('/') 58 | mount_point = params.get('mount_point').strip('/') 59 | 60 | result = {"changed": False, "rc": 0} 61 | from hvac.exceptions import InvalidPath 62 | try: 63 | result['data'] = client.secrets.pki.read_role(name=name, mount_point=mount_point).get('data') 64 | except InvalidPath: 65 | result['rc'] = 1 66 | result['failed'] = True 67 | result['msg'] = u"Role not found" 68 | except Exception as e: 69 | result['rc'] = 1 70 | result['failed'] = True 71 | result['msg'] = u"Exception: " + str(e) 72 | return result 73 | 74 | 75 | if __name__ == '__main__': 76 | main() 77 | -------------------------------------------------------------------------------- /functional/test_azure_role.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: localhost 4 | gather_facts: no 5 | vars: 6 | subscription_id: "xyz" 7 | client_id: "" 8 | client_secret: "" 9 | tenant_id: "" 10 | azure_role1: [{ "role_name": "Contributor","scope": "/subscriptions/xyz"}] 11 | azure_role2: [{ "role_name": "Contributor","scope": "/subscriptions/xyz"}, { "role_name": "Reader","scope": "/subscriptions/xyz"}] 12 | tasks: 13 | - hashivault_secret_disable: 14 | name: azure 15 | failed_when: false 16 | 17 | - name: fail before mount is configured 18 | hashivault_azure_secret_engine_role: 19 | name: test 20 | azure_role: "{{ azure_role1 }}" 21 | failed_when: false 22 | register: fail_config 23 | 24 | - assert: { that: "{{ fail_config.changed }} == False" } # fail 25 | 26 | - name: enable azure secret engine 27 | hashivault_secret_enable: 28 | name: azure 29 | backend: azure 30 | 31 | - name: configure azure mount 32 | hashivault_azure_secret_engine_config: 33 | subscription_id: "{{ subscription_id }}" 34 | client_id: "{{ client_id }}" 35 | client_secret: "{{ client_secret }}" 36 | tenant_id: "{{ tenant_id }}" 37 | 38 | - name: write 1 azure_role 39 | hashivault_azure_secret_engine_role: 40 | name: test 41 | azure_role: "{{ azure_role1 }}" 42 | register: success_write 43 | 44 | - assert: { that: "{{ success_write.changed }} == True" } # changed 45 | 46 | - name: idem same azure_role 47 | hashivault_azure_secret_engine_role: 48 | name: test 49 | azure_role: "{{ azure_role1 }}" 50 | register: idem_write 51 | 52 | - assert: { that: "{{ idem_write.changed }} == False" } # not changed 53 | 54 | - name: overwrite existing 55 | hashivault_azure_secret_engine_role: 56 | name: test 57 | azure_role: "{{ azure_role2 }}" 58 | register: overwrite 59 | 60 | - assert: { that: "{{ overwrite.changed }} == True" } # changed 61 | 62 | # since we're doing dict compare, ensure that a dict with less obj 63 | # correctly is overwritten 64 | - name: ensure smaller azure_role successfully overwrites 65 | hashivault_azure_secret_engine_role: 66 | name: test 67 | azure_role: "{{ azure_role1 }}" 68 | register: overwrite_smaller 69 | 70 | - assert: { that: "{{ overwrite_smaller.changed }} == True" } # changed 71 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_token_renew.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_auth_client 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = ''' 9 | --- 10 | module: hashivault_token_renew 11 | version_added: "3.11.0" 12 | short_description: Hashicorp Vault token renew module 13 | description: 14 | - Module to renew tokens in Hashicorp Vault. 15 | options: 16 | renew_token: 17 | description: 18 | - token to renew if different from auth token 19 | default: to authentication token 20 | increment: 21 | description: 22 | - "Request a specific increment for renewal. Vault is not required to honor this request. If not supplied,\ 23 | Vault will use the default TTL." 24 | wrap_ttl: 25 | description: 26 | - Indicates that the response should be wrapped in a cubbyhole token with the requested TTL. 27 | extends_documentation_fragment: hashivault 28 | ''' 29 | EXAMPLES = ''' 30 | --- 31 | - hosts: localhost 32 | tasks: 33 | - name: "Renew token" 34 | hashivault_token_renew: 35 | renew_token: "{{client_token}}" 36 | increment: "5m" 37 | register: "vault_token_renew" 38 | ''' 39 | 40 | 41 | def main(): 42 | argspec = hashivault_argspec() 43 | argspec['renew_token'] = dict(required=False, type='str', no_log=True) 44 | argspec['increment'] = dict(required=False, type='str', default=None) 45 | argspec['wrap_ttl'] = dict(required=False, type='int') 46 | module = hashivault_init(argspec) 47 | result = hashivault_token_renew(module.params) 48 | if result.get('failed'): 49 | module.fail_json(**result) 50 | else: 51 | module.exit_json(**result) 52 | 53 | 54 | @hashiwrapper 55 | def hashivault_token_renew(params): 56 | client = hashivault_auth_client(params) 57 | renew_token = params.get('renew_token') 58 | increment = params.get('increment') 59 | if renew_token is None: 60 | renew_token = params.get('token') 61 | wrap_ttl = params.get('wrap_ttl') 62 | renew = client.renew_token(token=renew_token, increment=increment, wrap_ttl=wrap_ttl) 63 | return {'changed': True, 'renew': renew} 64 | 65 | 66 | if __name__ == '__main__': 67 | main() 68 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/_hashivault_policy_set_from_file.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_auth_client 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['deprecated'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = ''' 9 | --- 10 | module: hashivault_policy_set_from_file 11 | version_added: "2.1.0" 12 | short_description: Hashicorp Vault policy set from a file module 13 | description: 14 | - Module to set a policy from a file in Hashicorp Vault. Use hashivault_policy_set instead. 15 | options: 16 | name: 17 | description: 18 | - policy name. 19 | rules_file: 20 | description: 21 | - policy rules file. 22 | extends_documentation_fragment: hashivault 23 | ''' 24 | EXAMPLES = ''' 25 | --- 26 | - hosts: localhost 27 | tasks: 28 | - hashivault_policy_set_from_file: 29 | rules_file: /path/to/policy_file.hcl 30 | ''' 31 | 32 | 33 | def main(): 34 | argspec = hashivault_argspec() 35 | argspec['name'] = dict(required=True, type='str') 36 | argspec['rules_file'] = dict(required=True, type='str') 37 | module = hashivault_init(argspec, supports_check_mode=True) 38 | result = hashivault_policy_set_from_file(module) 39 | if result.get('failed'): 40 | module.fail_json(**result) 41 | else: 42 | module.exit_json(**result) 43 | 44 | 45 | @hashiwrapper 46 | def hashivault_policy_set_from_file(module): 47 | params = module.params 48 | client = hashivault_auth_client(params) 49 | name = params.get('name') 50 | rules = open(params.get('rules_file'), 'r').read() 51 | changed = False 52 | exists = False 53 | current = str() 54 | 55 | # does policy exit 56 | try: 57 | current = client.get_policy(name) 58 | exists = True 59 | except Exception: 60 | if module.check_mode: 61 | changed = True 62 | else: 63 | return {'failed': True, 'msg': 'auth mount is not enabled', 'rc': 1} 64 | 65 | # does current policy match desired 66 | if exists: 67 | if current != rules: 68 | changed = True 69 | 70 | if exists and changed and not module.check_mode: 71 | client.sys.create_or_update_policy(name, rules) 72 | 73 | return {'changed': changed} 74 | 75 | 76 | if __name__ == '__main__': 77 | main() 78 | -------------------------------------------------------------------------------- /functional/test_ldap_group.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | gather_facts: no 4 | tasks: 5 | - name: arrange - policies - functional_testing_policy_one 6 | hashivault_policy: 7 | name: functional_testing_policy_one 8 | rules: 'path "secret/*" {capabilities = ["read", "list"]}' 9 | 10 | - name: arrange - policies - functional_testing_policy_two 11 | hashivault_policy: 12 | name: functional_testing_policy_two 13 | rules: 'path "secret/*" {capabilities = ["read", "list"]}' 14 | 15 | - name: enable ldap authentication 16 | hashivault_auth_method: 17 | method_type: ldap 18 | 19 | - name: ldap configuration 20 | hashivault_auth_ldap: 21 | ldap_url: ldap://127.0.0.1 22 | register: ldap_module 23 | - assert: { that: "{{ ldap_module.changed }} == False" } 24 | - assert: { that: "{{ ldap_module.rc }} == 0" } 25 | 26 | - name: remove ldap group 27 | hashivault_ldap_group: 28 | name: test 29 | state: absent 30 | 31 | - name: add ldap group 32 | hashivault_ldap_group: 33 | name: test 34 | state: present 35 | register: success_config 36 | 37 | - assert: { that: "{{ success_config.changed }} == True" } 38 | 39 | - name: chg policies - add functional_testing_policy_one 40 | hashivault_ldap_group: 41 | name: test 42 | state: present 43 | policies: 44 | - functional_testing_policy_one 45 | register: chg_policies 46 | 47 | - assert: { that: "{{ chg_policies.changed }} == True" } 48 | 49 | - name: duplicate policies 50 | hashivault_ldap_group: 51 | name: test 52 | state: present 53 | policies: 54 | - functional_testing_policy_one 55 | register: chg_policies 56 | 57 | - assert: { that: "{{ chg_policies.changed }} == False" } 58 | 59 | - name: chg policies - add functional_testing_policy_two 60 | hashivault_ldap_group: 61 | name: test 62 | state: present 63 | policies: 64 | - functional_testing_policy_one 65 | - functional_testing_policy_two 66 | register: chg_policies 67 | 68 | - assert: { that: "{{ chg_policies.changed }} == True" } 69 | 70 | - name: chg policies - remove functional_testing_policy_one 71 | hashivault_ldap_group: 72 | name: test 73 | state: present 74 | policies: 75 | - functional_testing_policy_two 76 | register: chg_policies 77 | 78 | - assert: { that: "{{ chg_policies.changed }} == True" } 79 | -------------------------------------------------------------------------------- /functional/test_consul_role.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | gather_facts: no 4 | vars: 5 | role_name: test 6 | policy: a2V5ICIvZm9vL2JhciIgeyBwb2xpY3kgPSAicmVhZCIgfQ== 7 | tasks: 8 | - name: enable consul secret engine 9 | hashivault_secret_engine: 10 | name: consul 11 | backend: consul 12 | 13 | - name: configure secret engine 14 | hashivault_consul_secret_engine_config: 15 | consul_address: consul.local:8500 16 | scheme: https 17 | consul_token: myAwesomeConsulManagementToken 18 | 19 | - name: make sure role is gone 20 | hashivault_consul_secret_engine_role: 21 | name: "{{ role_name }}" 22 | state: absent 23 | 24 | - name: fail role create when no policy 25 | hashivault_consul_secret_engine_role: 26 | name: "{{ role_name }}" 27 | register: fail_write 28 | failed_when: false 29 | - assert: { that: "{{ fail_write.rc }} == 1" } 30 | - assert: { that: "{{ fail_write.changed }} == False" } 31 | 32 | - name: successfully write a role 33 | hashivault_consul_secret_engine_role: 34 | name: "{{ role_name }}" 35 | policy: "{{ policy }}" 36 | register: success_write 37 | - assert: { that: "{{ success_write.rc }} == 0" } 38 | - assert: { that: "{{ success_write.changed }} == True" } 39 | 40 | - name: idempotent write a role 41 | hashivault_consul_secret_engine_role: 42 | name: "{{ role_name }}" 43 | policy: "{{ policy }}" 44 | register: idem_write 45 | - assert: { that: "{{ idem_write.rc }} == 0" } 46 | - assert: { that: "{{ idem_write.changed }} == False" } 47 | 48 | - name: successfully update a role 49 | hashivault_consul_secret_engine_role: 50 | name: "{{ role_name }}" 51 | policy: "{{ policy }}" 52 | max_ttl: 12345 53 | register: success_write 54 | - assert: { that: "{{ success_write.rc }} == 0" } 55 | - assert: { that: "{{ success_write.changed }} == True" } 56 | 57 | - name: delete role 58 | hashivault_consul_secret_engine_role: 59 | name: "{{ role_name }}" 60 | state: absent 61 | register: success_del 62 | - assert: { that: "{{ success_del.rc }} == 0" } 63 | - assert: { that: "{{ success_del.changed }} == True" } 64 | 65 | - name: idempotent delete role 66 | hashivault_consul_secret_engine_role: 67 | name: "{{ role_name }}" 68 | state: absent 69 | register: success_del 70 | - assert: { that: "{{ success_del.rc }} == 0" } 71 | - assert: { that: "{{ success_del.changed }} == False" } 72 | -------------------------------------------------------------------------------- /functional/test_audit.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | gather_facts: no 4 | tasks: 5 | - hashivault_audit: 6 | device_type: file 7 | state: absent 8 | register: audit_module 9 | 10 | - hashivault_audit: 11 | device_type: file 12 | path: pathy 13 | state: absent 14 | register: audit_module 15 | 16 | - hashivault_audit_list: 17 | register: vault_audit_list 18 | 19 | - name: Create audit 20 | hashivault_audit: 21 | device_type: file 22 | options: 23 | path: "/tmp/vault.log" 24 | register: audit_module 25 | - assert: { that: "{{audit_module.changed}} == True" } 26 | - assert: { that: "{{audit_module.rc}} == 0" } 27 | 28 | - name: Create audit idempotent (Vault does not support update at the moment anyway) 29 | hashivault_audit: 30 | device_type: file 31 | options: 32 | path: "/tmp/vault.log" 33 | register: audit_module 34 | - assert: { that: "{{audit_module.changed}} == False" } 35 | - assert: { that: "{{audit_module.rc}} == 0" } 36 | 37 | - name: Create audit path 38 | hashivault_audit: 39 | device_type: file 40 | path: pathy 41 | options: 42 | path: "/tmp/path_vault.log" 43 | register: audit_module 44 | - assert: { that: "{{audit_module.changed}} == True" } 45 | - assert: { that: "{{audit_module.rc}} == 0" } 46 | 47 | - name: Create audit path again 48 | hashivault_audit: 49 | device_type: file 50 | path: pathy 51 | options: 52 | path: "/tmp/path_vault.log" 53 | register: audit_module 54 | - assert: { that: "{{audit_module.changed}} == False" } 55 | - assert: { that: "{{audit_module.rc}} == 0" } 56 | 57 | - name: Delete audit 58 | hashivault_audit: 59 | device_type: file 60 | state: absent 61 | register: audit_module 62 | - assert: { that: "{{audit_module.changed}} == True" } 63 | - assert: { that: "{{audit_module.rc}} == 0" } 64 | 65 | - name: Delete audit path 66 | hashivault_audit: 67 | device_type: file 68 | path: pathy 69 | state: absent 70 | register: audit_module 71 | - assert: { that: "{{audit_module.changed}} == True" } 72 | - assert: { that: "{{audit_module.rc}} == 0" } 73 | 74 | - name: Delete audit idempotent 75 | hashivault_audit: 76 | device_type: file 77 | state: absent 78 | register: audit_module 79 | - assert: { that: "{{audit_module.changed}} == False" } 80 | - assert: { that: "{{audit_module.rc}} == 0" } -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_rekey_init.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_client 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = ''' 9 | --- 10 | module: hashivault_rekey_init 11 | version_added: "3.3.0" 12 | short_description: Hashicorp Vault rekey init module 13 | description: 14 | - Module to start rekey Hashicorp Vault. 15 | options: 16 | secret_shares: 17 | description: 18 | - specifies the number of shares to split the master key into. 19 | default: 5 20 | secret_threshold: 21 | description: 22 | - specifies the number of shares required to reconstruct the master key. 23 | default: 3 24 | pgp_keys: 25 | description: 26 | - specifies an array of PGP public keys used to encrypt the output unseal keys. 27 | default: [] 28 | extends_documentation_fragment: hashivault 29 | ''' 30 | EXAMPLES = ''' 31 | --- 32 | - hosts: localhost 33 | tasks: 34 | - hashivault_rekey_init: 35 | secret_shares: 7 36 | secret_threshold: 4 37 | ''' 38 | 39 | 40 | def main(): 41 | argspec = hashivault_argspec() 42 | argspec['secret_shares'] = dict(required=False, type='int', default=5) 43 | argspec['secret_threshold'] = dict(required=False, type='int', default=3) 44 | argspec['pgp_keys'] = dict(required=False, type='list', default=[], no_log=True) 45 | argspec['backup'] = dict(required=False, type='bool', default=False) 46 | module = hashivault_init(argspec) 47 | result = hashivault_rekey_init(module.params) 48 | if result.get('failed'): 49 | module.fail_json(**result) 50 | else: 51 | module.exit_json(**result) 52 | 53 | 54 | @hashiwrapper 55 | def hashivault_rekey_init(params): 56 | client = hashivault_client(params) 57 | # Check if rekey is on-going, exit if there is a rekey in progress 58 | status = client.rekey_status 59 | if status['started']: 60 | return {'changed': False} 61 | secret_shares = params.get('secret_shares') 62 | secret_threshold = params.get('secret_threshold') 63 | pgp_keys = params.get('pgp_keys') 64 | backup = params.get('backup') 65 | return {'status': client.sys.start_rekey(secret_shares, secret_threshold, pgp_keys, backup), 'changed': True} 66 | 67 | 68 | if __name__ == '__main__': 69 | main() 70 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_approle_role_secret_get.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from ansible.module_utils.hashivault import hashivault_argspec 4 | from ansible.module_utils.hashivault import hashivault_auth_client 5 | from ansible.module_utils.hashivault import hashivault_init 6 | from ansible.module_utils.hashivault import hashiwrapper 7 | 8 | ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'community', 'version': '1.1'} 9 | DOCUMENTATION = ''' 10 | --- 11 | module: hashivault_approle_role_secret_get 12 | version_added: "3.8.0" 13 | short_description: Hashicorp Vault approle role secret id get module 14 | description: 15 | - Module to get a approle role secret id from Hashicorp Vault. 16 | options: 17 | name: 18 | description: 19 | - role name. 20 | mount_point: 21 | description: 22 | - mount point for role 23 | default: approle 24 | secret: 25 | description: 26 | - secret id. 27 | extends_documentation_fragment: hashivault 28 | ''' 29 | EXAMPLES = ''' 30 | --- 31 | - hosts: localhost 32 | tasks: 33 | - hashivault_approle_role_secret_get: 34 | name: 'ashley' 35 | secret: 'ec4bedee-e44b-c096-9ac8-1600e52ed8f8' 36 | register: 'vault_approle_role_secret_get' 37 | - debug: msg="Role secret is {{vault_approle_role_secret_get.secret}}" 38 | ''' 39 | 40 | 41 | def main(): 42 | argspec = hashivault_argspec() 43 | argspec['name'] = dict(required=True, type='str') 44 | argspec['mount_point'] = dict(required=False, type='str', default='approle') 45 | argspec['secret'] = dict(required=True, type='str') 46 | module = hashivault_init(argspec) 47 | result = hashivault_approle_role_secret_get(module.params) 48 | if result.get('failed'): 49 | module.fail_json(**result) 50 | else: 51 | module.exit_json(**result) 52 | 53 | 54 | @hashiwrapper 55 | def hashivault_approle_role_secret_get(params): 56 | try: 57 | name = params.get('name') 58 | mount_point = params.get('mount_point') 59 | secret = params.get('secret') 60 | client = hashivault_auth_client(params) 61 | response = client.get_role_secret_id(name, secret, mount_point=mount_point) 62 | if type(response) is not dict and response.status_code == 204: # No content 63 | return {'secret': {}, 'status': 'absent'} 64 | else: 65 | return {'secret': response['data'], 'response': response, 'status': 'present'} 66 | except Exception as e: 67 | return {'failed': True, 'msg': str(e)} 68 | 69 | 70 | if __name__ == '__main__': 71 | main() 72 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_pki_cert_revoke.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_auth_client 3 | from ansible.module_utils.hashivault import hashivault_argspec 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['preview'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = r''' 9 | --- 10 | module: hashivault_pki_cert_revoke 11 | version_added: "4.5.0" 12 | short_description: Hashicorp Vault PKI Revoke Certificate 13 | description: 14 | - This module revokes a certificate using its serial number. 15 | - This is an alternative option to the standard method of revoking using Vault lease IDs. 16 | - A successful revocation will rotate the CRL. 17 | options: 18 | serial: 19 | recuired: true 20 | description: 21 | - Specifies the serial number of the certificate to revoke, in hyphen-separated or colon-separated octal. 22 | mount_point: 23 | default: pki 24 | description: 25 | - location where secrets engine is mounted. also known as path 26 | extends_documentation_fragment: 27 | - hashivault 28 | ''' 29 | 30 | EXAMPLES = r''' 31 | --- 32 | - hosts: localhost 33 | tasks: 34 | - hashivault_pki_cert_revoke: 35 | role: 'tester' 36 | common_name: 'test.example.com' 37 | register: cert 38 | - debug: msg="{{ cert }}" 39 | 40 | ''' 41 | 42 | 43 | def main(): 44 | argspec = hashivault_argspec() 45 | argspec['serial'] = dict(required=True, type='str') 46 | argspec['mount_point'] = dict(required=False, type='str', default='pki') 47 | 48 | module = hashivault_init(argspec) 49 | result = hashivault_pki_cert_revoke(module) 50 | 51 | if result.get('failed'): 52 | module.fail_json(**result) 53 | else: 54 | module.exit_json(**result) 55 | 56 | 57 | @hashiwrapper 58 | def hashivault_pki_cert_revoke(module): 59 | params = module.params 60 | client = hashivault_auth_client(params) 61 | 62 | serial = params.get('serial') 63 | mount_point = params.get('mount_point').strip('/') 64 | 65 | result = {"changed": False, "rc": 0} 66 | try: 67 | result['data'] = client.secrets.pki.revoke_certificate(serial_number=serial, 68 | mount_point=mount_point).get('data') 69 | except Exception as e: 70 | result['rc'] = 1 71 | result['failed'] = True 72 | result['msg'] = u"Exception: " + str(e) 73 | return result 74 | 75 | 76 | if __name__ == '__main__': 77 | main() 78 | -------------------------------------------------------------------------------- /functional/test_db_role.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: localhost 4 | gather_facts: no 5 | vars: 6 | plugin_name: blergh 7 | allowed_roles: ["flergh"] 8 | allowed_roles2: ["splurgh", "doesnt-exist"] 9 | username: "user@dbnamer" 10 | password: "P@ssw0rd" 11 | connection_url: "postgresql://{{'{{username}}'}}:{{'{{password}}'}}@cool-modern-db-name" 12 | tasks: 13 | - name: start with engine disabled 14 | hashivault_secret_disable: 15 | name: database 16 | 17 | - name: make sure test fails when no mount exists 18 | hashivault_db_secret_engine_config: 19 | name: test 20 | plugin_name: "{{ plugin_name }}" 21 | allowed_roles: "{{ allowed_roles }}" 22 | username: "{{ username }}" 23 | password: "{{ password }}" 24 | connection_url: "{{ connection_url }}" 25 | register: fail_config 26 | failed_when: false 27 | 28 | - assert: { that: "{{ fail_config.changed }} == False" } 29 | 30 | - name: enable database secret engine 31 | hashivault_secret_enable: 32 | name: database 33 | backend: database 34 | 35 | - name: successfully configure 36 | hashivault_db_secret_engine_config: 37 | name: test 38 | plugin_name: "{{ plugin_name }}" 39 | allowed_roles: "{{ allowed_roles }}" 40 | username: "{{ username }}" 41 | password: "{{ password }}" 42 | connection_url: "{{ connection_url }}" 43 | register: success_config 44 | 45 | - assert: { that: "{{ success_config.changed }} == True" } 46 | 47 | - name: successfully write a role 48 | hashivault_db_secret_engine_role: 49 | name: tester 50 | db_name: test 51 | creation_statements: [] 52 | register: success_write 53 | 54 | - assert: { that: "{{ success_write.changed }} == True" } 55 | 56 | - name: skip write a role 57 | hashivault_db_secret_engine_role: 58 | name: tester 59 | db_name: test 60 | creation_statements: [] 61 | register: idem_write 62 | 63 | - assert: { that: "{{ idem_write.changed }} == False" } 64 | 65 | - name: delete role 66 | hashivault_db_secret_engine_role: 67 | name: tester 68 | db_name: test 69 | state: absent 70 | register: success_del 71 | 72 | - assert: { that: "{{ success_del.changed }} == True" } 73 | 74 | - name: skip delete role 75 | hashivault_db_secret_engine_role: 76 | name: tester 77 | db_name: test 78 | state: absent 79 | register: success_del 80 | 81 | - assert: { that: "{{ success_del.changed }} == False" } -------------------------------------------------------------------------------- /functional/test_approle_old.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | gather_facts: no 4 | tasks: 5 | - name: create role 6 | hashivault_approle_role_create: 7 | name: casserole 8 | policies: 9 | - approle_test_policy 10 | register: 'vault_role_create' 11 | - assert: { that: "{{vault_role_create.changed}} == True" } 12 | - assert: { that: "{{vault_role_create.rc}} == 0" } 13 | 14 | - name: list roles 15 | hashivault_approle_role_list: 16 | register: 'vault_role_list' 17 | - assert: { that: "{{vault_role_list.changed}} == False" } 18 | - assert: { that: "{{vault_role_list.rc}} == 0" } 19 | - fail: msg="role casserole not in list {{vault_role_list.roles}}" 20 | when: '"casserole" not in vault_role_list.roles' 21 | 22 | - name: create role secret id 23 | hashivault_approle_role_secret_create: 24 | name: casserole 25 | register: 'vault_role_secret_create' 26 | - assert: { that: "{{vault_role_secret_create.changed}} == False" } 27 | - assert: { that: "{{vault_role_secret_create.rc}} == 0" } 28 | - assert: 29 | that: 30 | - vault_role_secret_create.secret_id_accessor|default('') != '' 31 | - vault_role_secret_create.secret_id|default('') != '' 32 | - set_fact: 33 | approle_secret_id: "{{vault_role_secret_create.secret_id}}" 34 | - set_fact: 35 | approle_secret_id_accessor: "{{vault_role_secret_create.secret_id_accessor}}" 36 | 37 | - name: list secrets 38 | hashivault_approle_role_secret_list: 39 | name: casserole 40 | register: 'vault_role_secret_list' 41 | - assert: { that: "{{vault_role_secret_list.changed}} == False" } 42 | - assert: { that: "{{vault_role_secret_list.rc}} == 0" } 43 | - fail: msg="secret {{approle_secret_id_accessor}} not in list" 44 | when: approle_secret_id_accessor not in vault_role_secret_list.secrets 45 | 46 | - name: delete secret 47 | hashivault_approle_role_secret_delete: 48 | name: casserole 49 | secret: "{{approle_secret_id}}" 50 | register: 'vault_role_secret_delete' 51 | - assert: { that: "{{vault_role_secret_delete.changed}} == True" } 52 | - assert: { that: "{{vault_role_secret_delete.rc}} == 0" } 53 | 54 | - name: make sure secret is gone 55 | hashivault_approle_role_secret_list: 56 | name: casserole 57 | register: 'vault_role_secret_list' 58 | - assert: { that: "{{vault_role_secret_list.changed}} == False" } 59 | - assert: { that: "{{vault_role_secret_list.rc}} == 0" } 60 | - fail: msg="secret {{approle_secret_id_accessor}} shoud not be in list" 61 | when: approle_secret_id_accessor in vault_role_secret_list.secrets -------------------------------------------------------------------------------- /functional/test_db_config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: localhost 4 | gather_facts: no 5 | vars: 6 | plugin_name: blergh 7 | allowed_roles: ["flergh"] 8 | allowed_roles2: ["splurgh", "doesnt-exist"] 9 | connection_details: 10 | username: "user@dbnamer" 11 | password: "P@ssw0rd" 12 | connection_url: "postgresql://{{'{{username}}'}}:{{'{{password}}'}}@cool-modern-db-name" 13 | tasks: 14 | - name: start with engine disabled 15 | hashivault_secret_disable: 16 | name: database 17 | 18 | - name: make sure test fails when no mount exists 19 | hashivault_db_secret_engine_config: 20 | name: test 21 | plugin_name: "{{ plugin_name }}" 22 | allowed_roles: "{{ allowed_roles }}" 23 | connection_details: 24 | username: "{{ db_username }}" 25 | password: "{{ db_password }}" 26 | connection_url: "{{ connection_url }}" 27 | register: fail_config 28 | failed_when: false 29 | 30 | - assert: { that: "{{ fail_config.changed }} == False" } 31 | 32 | - name: enable database secret engine 33 | hashivault_secret_enable: 34 | name: database 35 | backend: database 36 | 37 | - name: successfully configure 38 | hashivault_db_secret_engine_config: 39 | name: test 40 | plugin_name: "{{ plugin_name }}" 41 | allowed_roles: "{{ allowed_roles }}" 42 | connection_details: 43 | username: "{{ db_username }}" 44 | password: "{{ db_password }}" 45 | connection_url: "{{ connection_url }}" 46 | register: success_config 47 | 48 | - assert: { that: "{{ success_config.changed }} == True" } 49 | 50 | - name: skip 2nd config attempt with same values 51 | hashivault_db_secret_engine_config: 52 | name: test 53 | plugin_name: "{{ plugin_name }}" 54 | allowed_roles: "{{ allowed_roles }}" 55 | connection_details: 56 | username: "{{ db_username }}" 57 | password: "{{ db_password }}" 58 | connection_url: "{{ connection_url }}" 59 | register: idem_config 60 | 61 | - assert: { that: "{{ idem_config.changed }} == False" } 62 | 63 | - name: attempt 3rd config with different values 64 | hashivault_db_secret_engine_config: 65 | name: test 66 | plugin_name: "{{ plugin_name }}" 67 | allowed_roles: "{{ allowed_roles2 }}" 68 | connection_details: 69 | username: "{{ db_username }}" 70 | password: "{{ db_password }}" 71 | connection_url: "{{ connection_url }}" 72 | register: overwrite_config 73 | 74 | - assert: { that: "{{ overwrite_config.changed }} == True" } 75 | -------------------------------------------------------------------------------- /functional/test_rekey.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | gather_facts: no 4 | vars: 5 | unseal_key: "{{ lookup('env','VAULT_KEYS') }}" 6 | tasks: 7 | - name: Check rekey status 8 | hashivault_rekey_status: 9 | register: 'vault_rekey_status' 10 | - assert: { that: "{{vault_rekey_status.changed}} == False" } 11 | - assert: { that: "{{vault_rekey_status.rc}} == 0" } 12 | 13 | - block: 14 | - name: Cancel the rekey if one was started 15 | hashivault_rekey_cancel: 16 | register: 'vault_rekey_cancel' 17 | - assert: { that: "{{vault_rekey_cancel.changed}} == True" } 18 | - assert: { that: "{{vault_rekey_cancel.rc}} == 0" } 19 | when: "vault_rekey_status.status.started == True" 20 | 21 | - name: Start a rekey 22 | hashivault_rekey_init: 23 | secret_shares: 1 24 | secret_threshold: 1 25 | register: 'vault_rekey_init' 26 | - assert: { that: "{{vault_rekey_init.changed}} == True" } 27 | - assert: { that: "{{vault_rekey_init.status.progress}} == 0" } 28 | - assert: { that: "{{vault_rekey_init.status.started}} == True" } 29 | - assert: { that: "{{vault_rekey_init.rc}} == 0" } 30 | 31 | - name: Make sure the rekey started 32 | hashivault_rekey_status: 33 | register: 'vault_rekey_status' 34 | - assert: { that: "{{vault_rekey_status.changed}} == False" } 35 | - assert: { that: "{{vault_rekey_status.rc}} == 0" } 36 | - assert: { that: "{{vault_rekey_init.status.progress}} == 0" } 37 | - assert: { that: "{{vault_rekey_status.status.started}} == True" } 38 | 39 | - name: Canel the rekey 40 | hashivault_rekey_cancel: 41 | register: 'vault_rekey_cancel' 42 | - assert: { that: "{{vault_rekey_cancel.changed}} == True" } 43 | - assert: { that: "{{vault_rekey_cancel.rc}} == 0" } 44 | 45 | - name: Restart that rekey again 46 | hashivault_rekey_init: 47 | secret_shares: 1 48 | secret_threshold: 1 49 | register: 'vault_rekey_init' 50 | - assert: { that: "{{vault_rekey_init.changed}} == True" } 51 | - assert: { that: "{{vault_rekey_init.status.progress}} == 0" } 52 | - assert: { that: "{{vault_rekey_init.status.started}} == True" } 53 | - assert: { that: "{{vault_rekey_init.rc}} == 0" } 54 | 55 | - name: Update the rekey 56 | hashivault_rekey: 57 | key: "{{ unseal_key }}" 58 | nonce: "{{ vault_rekey_init.status.nonce }}" 59 | register: 'vault_rekey' 60 | - assert: { that: "{{vault_rekey.changed}} == True" } 61 | - assert: { that: "{{vault_rekey.rc}} == 0" } 62 | 63 | - name: Update vaultenv.sh with new keys 64 | lineinfile: 65 | name: vaultenv.sh 66 | regexp: '^export VAULT_KEYS=' 67 | line: export VAULT_KEYS='{{ vault_rekey['status']['keys'][0] }}' 68 | -------------------------------------------------------------------------------- /functional/test_approle_check_mode.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | gather_facts: no 4 | tasks: 5 | - name: create role check_mode exists 6 | hashivault_approle_role: 7 | name: testrole 8 | token_policies: 9 | - approle_test_policy 10 | state: present 11 | check_mode: true 12 | register: 'vault_role_create' 13 | - assert: { that: "{{vault_role_create.changed}} == False" } 14 | - assert: { that: "{{vault_role_create.rc}} == 0" } 15 | 16 | - name: create role check_mode does not exist 17 | hashivault_approle_role: 18 | name: testrole_two 19 | token_policies: 20 | - approle_test_policy 21 | state: present 22 | check_mode: true 23 | register: 'vault_role_create' 24 | - assert: { that: "{{vault_role_create.changed}} == True" } 25 | - assert: { that: "{{vault_role_create.rc}} == 0" } 26 | 27 | - name: delete role check_mode exists 28 | hashivault_approle_role: 29 | name: testrole 30 | state: absent 31 | check_mode: true 32 | register: 'vault_role_create' 33 | - assert: { that: "{{vault_role_create.changed}} == True" } 34 | - assert: { that: "{{vault_role_create.rc}} == 0" } 35 | 36 | - name: delete role check_mode does not exist 37 | hashivault_approle_role: 38 | name: testrole_two 39 | state: absent 40 | check_mode: true 41 | register: 'vault_role_create' 42 | - assert: { that: "{{vault_role_create.changed}} == False" } 43 | - assert: { that: "{{vault_role_create.rc}} == 0" } 44 | 45 | - name: create secret for check_mode test 46 | hashivault_approle_role_secret: 47 | name: testrole 48 | state: present 49 | register: 'vault_role_secret_create' 50 | - set_fact: 51 | approle_secret_id: "{{vault_role_secret_create.data.secret_id}}" 52 | - set_fact: 53 | approle_secret_id_accessor: "{{vault_role_secret_create.data.secret_id_accessor}}" 54 | 55 | - name: delete secret exists check_mode 56 | hashivault_approle_role_secret: 57 | name: testrole 58 | secret: "{{approle_secret_id}}" 59 | state: absent 60 | check_mode: true 61 | register: 'vault_role_secret_delete' 62 | - assert: { that: "{{vault_role_secret_delete.changed}} == True" } 63 | - assert: { that: "{{vault_role_secret_delete.rc}} == 0" } 64 | 65 | - name: delete secret does not exist check_mode 66 | hashivault_approle_role_secret: 67 | name: testrole_two 68 | secret: "{{approle_secret_id}}" 69 | state: absent 70 | check_mode: true 71 | register: 'vault_role_secret_delete' 72 | - assert: { that: "{{vault_role_secret_delete.changed}} == False" } 73 | - assert: { that: "{{vault_role_secret_delete.rc}} == 0" } 74 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/_hashivault_secret_enable.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_auth_client 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['deprecated'], 'alternative': 'Use M(hashivault_secret_engine) instead.', 8 | 'why': 'This module does not fit the standard pattern', 9 | 'supported_by': 'community', 'version': '1.1'} 10 | DOCUMENTATION = ''' 11 | --- 12 | module: hashivault_secret_enable 13 | version_added: "2.2.0" 14 | short_description: Hashicorp Vault secret enable module 15 | description: 16 | - Module to enable secret backends in Hashicorp Vault. Use hashivault_secret_engine instead. 17 | options: 18 | name: 19 | description: 20 | - name of secret backend 21 | backend: 22 | description: 23 | - type of secret backend 24 | description: 25 | description: 26 | - description of secret backend 27 | config: 28 | description: 29 | - config of secret backend 30 | options: 31 | description: 32 | - options of secret backend 33 | extends_documentation_fragment: hashivault 34 | ''' 35 | EXAMPLES = ''' 36 | --- 37 | - hosts: localhost 38 | tasks: 39 | - hashivault_secret_enable: 40 | name: "ephemeral" 41 | backend: "generic" 42 | ''' 43 | 44 | 45 | def main(): 46 | argspec = hashivault_argspec() 47 | argspec['name'] = dict(required=True, type='str') 48 | argspec['backend'] = dict(required=True, type='str') 49 | argspec['description'] = dict(required=False, type='str') 50 | argspec['config'] = dict(required=False, type='dict') 51 | argspec['options'] = dict(required=False, type='dict') 52 | module = hashivault_init(argspec) 53 | result = hashivault_secret_enable(module.params) 54 | if result.get('failed'): 55 | module.fail_json(**result) 56 | else: 57 | module.exit_json(**result) 58 | 59 | 60 | @hashiwrapper 61 | def hashivault_secret_enable(params): 62 | client = hashivault_auth_client(params) 63 | name = params.get('name') 64 | backend = params.get('backend') 65 | description = params.get('description') 66 | config = params.get('config') 67 | options = params.get('options') 68 | secrets = client.sys.list_mounted_secrets_engines() 69 | secrets = secrets.get('data', secrets) 70 | path = name + "/" 71 | if path in secrets: 72 | return {'changed': False} 73 | client.sys.enable_secrets_engine(backend, description=description, path=name, config=config, options=options) 74 | return {'changed': True} 75 | 76 | 77 | if __name__ == '__main__': 78 | main() 79 | -------------------------------------------------------------------------------- /functional/test_generate_root.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | gather_facts: no 4 | vars: 5 | vault_keys: "{{ lookup('env','VAULT_KEYS') }}" 6 | tasks: 7 | - assert: 8 | that: "'{{vault_keys}}' != ''" 9 | msg: "VAULT_KEYS must be set to run this test" 10 | 11 | - name: Cancel anything that might be going 12 | hashivault_generate_root_cancel: 13 | register: hashivault_generate_root_cancel 14 | - assert: { that: "{{hashivault_generate_root_cancel.rc}} == 0" } 15 | 16 | - name: Generate root token initialize 17 | hashivault_generate_root_init: 18 | register: hashivault_generate_root_init 19 | - assert: { that: "{{hashivault_generate_root_init.changed}} == True" } 20 | - assert: { that: "{{hashivault_generate_root_init.rc}} == 0" } 21 | 22 | - name: Generate root status 23 | hashivault_generate_root_status: 24 | register: hashivault_generate_root_status 25 | - assert: { that: "{{hashivault_generate_root_status.changed}} == False" } 26 | - assert: { that: "{{hashivault_generate_root_status.rc}} == 0" } 27 | 28 | - name: Generate a root token 29 | hashivault_generate_root: 30 | key: "{{vault_keys}}" 31 | nonce: "{{hashivault_generate_root_init.status.nonce}}" 32 | register: hashivault_generate_root 33 | - assert: { that: "{{hashivault_generate_root.changed}} == True" } 34 | - assert: { that: "{{hashivault_generate_root.rc}} == 0" } 35 | - assert: { that: "{{hashivault_generate_root.status.complete}} == True" } 36 | 37 | - name: Generate root token initialize 38 | hashivault_generate_root_init: 39 | register: hashivault_generate_root_init 40 | - assert: { that: "{{hashivault_generate_root_init.changed}} == True" } 41 | - assert: { that: "{{hashivault_generate_root_init.rc}} == 0" } 42 | 43 | - name: Generate root status 44 | hashivault_generate_root_status: 45 | register: hashivault_generate_root_status 46 | - assert: { that: "{{hashivault_generate_root_status.changed}} == False" } 47 | - assert: { that: "{{hashivault_generate_root_status.rc}} == 0" } 48 | - assert: { that: "{{hashivault_generate_root_status.status.started}} == True" } 49 | 50 | - name: Cancel that 51 | hashivault_generate_root_cancel: 52 | register: hashivault_generate_root_cancel 53 | - assert: { that: "{{hashivault_generate_root_cancel.changed}} == True" } 54 | - assert: { that: "{{hashivault_generate_root_cancel.rc}} == 0" } 55 | 56 | - name: Generate root status 57 | hashivault_generate_root_status: 58 | register: hashivault_generate_root_status 59 | - assert: { that: "{{hashivault_generate_root_status.changed}} == False" } 60 | - assert: { that: "{{hashivault_generate_root_status.rc}} == 0" } 61 | - assert: { that: "{{hashivault_generate_root_status.status.started}} == False" } -------------------------------------------------------------------------------- /functional/test_k8_auth.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | gather_facts: no 4 | tasks: 5 | - hashivault_auth_method: 6 | method_type: kubernetes 7 | state: disabled 8 | failed_when: false 9 | 10 | - name: enable azure secret engine 11 | hashivault_auth_method: 12 | method_type: kubernetes 13 | 14 | - name: create config 15 | register: k8s_module 16 | hashivault_k8s_auth_config: 17 | kubernetes_host: http://127.0.0.1:8443 18 | kubernetes_ca_cert: "{{ lookup('file', './cacert.pem') }}" 19 | token_reviewer_jwt: "{{ lookup('file', './jwt.jws') }}" 20 | - assert: { that: "{{ k8s_module.changed }} == True" } 21 | - assert: { that: "{{ k8s_module.rc }} == 0" } 22 | 23 | - name: idempotent create config 24 | register: k8s_module 25 | hashivault_k8s_auth_config: 26 | kubernetes_host: http://127.0.0.1:8443 27 | kubernetes_ca_cert: "{{ lookup('file', './cacert.pem') }}" 28 | token_reviewer_jwt: "{{ lookup('file', './jwt.jws') }}" 29 | - assert: { that: "{{ k8s_module.changed }} == True" } 30 | - assert: { that: "{{ k8s_module.rc }} == 0" } 31 | 32 | - name: update config 33 | register: k8s_module 34 | hashivault_k8s_auth_config: 35 | kubernetes_host: http://127.0.0.2:8443 36 | kubernetes_ca_cert: "{{ lookup('file', './cacert.pem') }}" 37 | token_reviewer_jwt: "{{ lookup('file', './jwt.jws') }}" 38 | # issuer: bob hvac 0.10.2 39 | - assert: { that: "{{ k8s_module.changed }} == True" } 40 | - assert: { that: "{{ k8s_module.rc }} == 0" } 41 | 42 | - name: create role delete 43 | hashivault_k8s_auth_role: 44 | name: "testk8srole" 45 | state: absent 46 | 47 | - name: create role 48 | hashivault_k8s_auth_role: 49 | name: "testk8srole" 50 | policies: ["test", "test2"] 51 | bound_service_account_names: ["vault-auth"] 52 | bound_service_account_namespaces: ["default", "some-app"] 53 | register: k8s_module 54 | - assert: { that: "{{ k8s_module.changed }} == True" } 55 | - assert: { that: "{{ k8s_module.rc }} == 0" } 56 | 57 | - name: create role idempotent 58 | hashivault_k8s_auth_role: 59 | name: "testk8srole" 60 | policies: ["test", "test2"] 61 | bound_service_account_names: ["vault-auth"] 62 | bound_service_account_namespaces: ["default", "some-app"] 63 | register: k8s_module 64 | - assert: { that: "{{ k8s_module.changed }} == False" } 65 | - assert: { that: "{{ k8s_module.rc }} == 0" } 66 | 67 | - name: create role delete 68 | hashivault_k8s_auth_role: 69 | name: "testk8srole" 70 | state: absent 71 | register: k8s_module 72 | - assert: { that: "{{ k8s_module.changed }} == True" } 73 | - assert: { that: "{{ k8s_module.rc }} == 0" } 74 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_namespace.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_auth_client 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | DEFAULT_TTL = 2764800 8 | ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'community', 'version': '1.1'} 9 | DOCUMENTATION = ''' 10 | --- 11 | module: hashivault_namespace 12 | version_added: "4.0.1" 13 | short_description: Hashicorp Vault create / delete namespaces 14 | description: 15 | - Module to create or delete Hashicorp Vault namespaces (enterprise only) 16 | options: 17 | name: 18 | description: 19 | - name of the namespace 20 | state: 21 | description: 22 | - state of secret backend. choices: present, disabled 23 | extends_documentation_fragment: hashivault 24 | ''' 25 | EXAMPLES = ''' 26 | --- 27 | - hosts: localhost 28 | tasks: 29 | - hashivault_namespace: 30 | name: teama 31 | 32 | - name: "create a child namespace 'team1' in 'teama' ns: teama/team1" 33 | hashivault_namespace: 34 | name: team1 35 | namespace: teama 36 | ''' 37 | 38 | 39 | def main(): 40 | argspec = hashivault_argspec() 41 | argspec['name'] = dict(required=True, type='str') 42 | argspec['state'] = dict(required=False, type='str', choices=['present', 'absent'], default='present') 43 | module = hashivault_init(argspec) 44 | result = hashivault_secret_engine(module) 45 | if result.get('failed'): 46 | module.fail_json(**result) 47 | else: 48 | module.exit_json(**result) 49 | 50 | 51 | @hashiwrapper 52 | def hashivault_secret_engine(module): 53 | params = module.params 54 | client = hashivault_auth_client(params) 55 | name = params.get('name') 56 | state = params.get('state') 57 | current_state = dict() 58 | exists = False 59 | changed = False 60 | 61 | try: 62 | # does the ns exist already? 63 | current_state = client.sys.list_namespaces()['data']['keys'] 64 | if (name + '/') in current_state: 65 | exists = True 66 | except Exception: 67 | # doesnt exist 68 | pass 69 | 70 | # doesnt exist and should or does exist and shouldnt 71 | if (exists and state == 'absent') or (not exists and state == 'present'): 72 | changed = True 73 | 74 | # create 75 | if changed and not exists and state == 'present' and not module.check_mode: 76 | client.sys.create_namespace(path=name) 77 | 78 | # delete 79 | elif changed and (state == 'absent' or state == 'disabled') and not module.check_mode: 80 | client.sys.delete_namespace(path=name) 81 | 82 | return {'changed': changed} 83 | 84 | 85 | if __name__ == '__main__': 86 | main() 87 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/_hashivault_mount_tune.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_auth_client 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['deprecated'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = ''' 9 | --- 10 | module: hashivault_mount_tune 11 | version_added: "3.7.0" 12 | short_description: Hashicorp Vault tune backend 13 | description: 14 | - Module to enable tuning of backends in HashiCorp Vault. use hashivault_secret_engine instead 15 | options: 16 | mount_point: 17 | description: 18 | - location where this auth backend will be mounted 19 | default_lease_ttl: 20 | description: 21 | - Configures the default lease duration for tokens and secrets. This is an integer value in seconds. 22 | max_lease_ttl: 23 | description: 24 | - Configures the maximum lease duration for tokens and secrets. This is an integer value in seconds. 25 | extends_documentation_fragment: hashivault 26 | ''' 27 | EXAMPLES = ''' 28 | --- 29 | - hosts: localhost 30 | tasks: 31 | - hashivault_mount_tune: 32 | mount_point: ephemeral 33 | default_lease_ttl: 3600 34 | ''' 35 | 36 | 37 | def main(): 38 | argspec = hashivault_argspec() 39 | argspec['mount_point'] = dict(required=True, type='str') 40 | argspec['default_lease_ttl'] = dict(required=False, type='int', default=None) 41 | argspec['max_lease_ttl'] = dict(required=False, type='int', default=None) 42 | module = hashivault_init(argspec) 43 | result = hashivault_mount_tune(module) 44 | if result.get('failed'): 45 | module.fail_json(**result) 46 | else: 47 | module.exit_json(**result) 48 | 49 | 50 | @hashiwrapper 51 | def hashivault_mount_tune(module): 52 | client = hashivault_auth_client(module.params) 53 | mount_point = module.params.get('mount_point') 54 | default_lease_ttl = module.params.get('default_lease_ttl') 55 | max_lease_ttl = module.params.get('max_lease_ttl') 56 | 57 | changed = False 58 | current_tuning = client.sys.read_mount_configuration(mount_point) 59 | current_tuning = current_tuning.get('data', current_tuning) 60 | current_default_lease_ttl = current_tuning.get('default_lease_ttl') 61 | current_max_lease_ttl = current_tuning.get('max_lease_ttl') 62 | 63 | if (current_default_lease_ttl != default_lease_ttl) or (current_max_lease_ttl != max_lease_ttl): 64 | changed = True 65 | 66 | if not module.check_mode: 67 | client.sys.tune_mount_configuration(mount_point, default_lease_ttl=default_lease_ttl, 68 | max_lease_ttl=max_lease_ttl) 69 | 70 | return {'changed': changed} 71 | 72 | 73 | if __name__ == '__main__': 74 | main() 75 | -------------------------------------------------------------------------------- /ansible/plugins/doc_fragments/hashivault.py: -------------------------------------------------------------------------------- 1 | class ModuleDocFragment(object): 2 | # Standard documentation 3 | DOCUMENTATION = r''' 4 | requirements: 5 | - hvac>=0.10.1 6 | - ansible>=2.0.0 7 | - requests 8 | options: 9 | url: 10 | description: 11 | - url for vault 12 | default: to environment variable `VAULT_ADDR` 13 | ca_cert: 14 | description: 15 | - Path to a PEM-encoded CA cert file to use to verify the Vault server TLS certificate 16 | default: to environment variable `VAULT_CACERT` 17 | ca_path: 18 | description: 19 | - Path to a directory of PEM-encoded CA cert files to verify the Vault server TLS certificate. If 20 | ca_cert is specified, its value will take precedence 21 | default: to environment variable `VAULT_CAPATH` 22 | client_cert: 23 | description: 24 | - Path to a PEM-encoded client certificate for TLS authentication to the Vault server 25 | default: to environment variable `VAULT_CLIENT_CERT` 26 | client_key: 27 | description: 28 | - Path to an unencrypted PEM-encoded private key matching the client certificate 29 | default: to environment variable `VAULT_CLIENT_KEY` 30 | verify: 31 | description: 32 | - If set, do not verify presented TLS certificate before communicating with Vault server. Setting this 33 | variable is not recommended except during testing 34 | default: to environment variable `VAULT_SKIP_VERIFY` 35 | authtype: 36 | description: 37 | - authentication type 38 | default: token or environment variable `VAULT_AUTHTYPE` 39 | choices: ["token", "userpass", "github", "ldap", "approle"] 40 | login_mount_point: 41 | description: 42 | - authentication mount point 43 | default: value of authtype or environment varialbe `VAULT_LOGIN_MOUNT_POINT` 44 | token: 45 | description: 46 | - token for vault 47 | default: to environment variable `VAULT_TOKEN` 48 | username: 49 | description: 50 | - username to login to vault. 51 | default: to environment variable `VAULT_USER` 52 | password: 53 | description: 54 | - password to login to vault. 55 | default: to environment variable `VAULT_PASSWORD` 56 | aws_header: 57 | description: 58 | - X-Vault-AWS-IAM-Server-ID Header value to prevent replay attacks. 59 | default: to environment variable `VAULT_AWS_HEADER` 60 | namespace: 61 | description: 62 | - namespace for vault 63 | default: to environment variable VAULT_NAMESPACE 64 | ''' 65 | -------------------------------------------------------------------------------- /functional/test_auth_method.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - hosts: localhost 4 | gather_facts: no 5 | tasks: 6 | - hashivault_auth_method: 7 | method_type: oidc 8 | state: disabled 9 | - hashivault_auth_method: 10 | method_type: azure 11 | state: disabled 12 | 13 | - name: disable auth idempotent 14 | hashivault_auth_method: 15 | method_type: azure 16 | state: disabled 17 | register: disable_idem 18 | - assert: { that: "{{ disable_idem.changed }} == False" } 19 | 20 | - name: enable azure secret engine 21 | hashivault_auth_method: 22 | method_type: azure 23 | register: enable_chg 24 | - assert: { that: "{{ enable_chg.changed }} == True" } 25 | 26 | - name: disable azure 27 | hashivault_auth_method: 28 | method_type: azure 29 | state: disabled 30 | register: disable_chg 31 | - assert: { that: "{{ disable_chg.changed }} == True" } 32 | 33 | - name: "Enable OIDC auth method" 34 | hashivault_auth_method: 35 | method_type: oidc 36 | state: enabled 37 | register: oidc_idempotent 38 | - assert: { that: "{{ oidc_idempotent.rc }} == 0" } 39 | - assert: { that: "{{ oidc_idempotent.changed }} == True" } 40 | 41 | - name: "Enable OIDC auth method idempotent" 42 | hashivault_auth_method: 43 | method_type: oidc 44 | state: enabled 45 | register: oidc_idempotent 46 | - assert: { that: "{{ oidc_idempotent.rc }} == 0" } 47 | - assert: { that: "{{ oidc_idempotent.changed }} == False" } 48 | 49 | - name: "Enable OIDC auth method update" 50 | hashivault_auth_method: 51 | method_type: oidc 52 | state: enabled 53 | description: 'my oidc' 54 | register: oidc_idempotent 55 | - assert: { that: "{{ oidc_idempotent.rc }} == 0" } 56 | - assert: { that: "{{ oidc_idempotent.changed }} == True" } 57 | 58 | - name: "Enable OIDC auth method update description idempotent" 59 | hashivault_auth_method: 60 | method_type: oidc 61 | state: enabled 62 | description: 'my oidc' 63 | register: oidc_idempotent 64 | - assert: { that: "{{ oidc_idempotent.rc }} == 0" } 65 | - assert: { that: "{{ oidc_idempotent.changed }} == False" } 66 | 67 | - name: "Enable OIDC auth method update" 68 | hashivault_auth_method: 69 | method_type: oidc 70 | state: enabled 71 | config: 72 | default_lease_ttl: 2764799 73 | register: oidc_idempotent 74 | - assert: { that: "{{ oidc_idempotent.rc }} == 0" } 75 | - assert: { that: "{{ oidc_idempotent.changed }} == True" } 76 | 77 | - name: "Enable OIDC auth method update idempotent" 78 | hashivault_auth_method: 79 | method_type: oidc 80 | state: enabled 81 | config: 82 | default_lease_ttl: 2764799 83 | register: oidc_idempotent 84 | - assert: { that: "{{ oidc_idempotent.rc }} == 0" } 85 | - assert: { that: "{{ oidc_idempotent.changed }} == False" } 86 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_consul_secret_engine_config.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_argspec 3 | from ansible.module_utils.hashivault import hashivault_auth_client 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = ''' 9 | --- 10 | module: hashivault_consul_secret_engine_config 11 | version_added: "4.4.7" 12 | short_description: Hashicorp Vault consul secrets engine config 13 | description: 14 | - Module to configure the consul secrets engine 15 | options: 16 | mount_point: 17 | description: 18 | - name of the secret engine mount name. 19 | default: consul 20 | consul_address: 21 | description: 22 | - Specifies the address of the Consul instance, provided as "host:port" like "127.0.0.1:8500" 23 | scheme: 24 | description: 25 | - Specifies the URL scheme to use 26 | consul_token: 27 | description: 28 | - Specifies the Consul ACL token to use. This must be a management type token. 29 | extends_documentation_fragment: hashivault 30 | ''' 31 | EXAMPLES = ''' 32 | --- 33 | - hosts: localhost 34 | tasks: 35 | - hashivault_consul_secret_engine_config: 36 | consul_address: consul.local:8500 37 | scheme: https 38 | consul_token: myAwesomeConsulManagementToken 39 | ''' 40 | 41 | 42 | def main(): 43 | argspec = hashivault_argspec() 44 | argspec['mount_point'] = dict(required=False, type='str', default='consul') 45 | argspec['consul_address'] = dict(required=True, type='str') 46 | argspec['scheme'] = dict(required=True, type='str') 47 | argspec['consul_token'] = dict(required=True, type='str') 48 | 49 | module = hashivault_init(argspec, supports_check_mode=True) 50 | result = hashivault_consul_secret_engine_config(module) 51 | if result.get('failed'): 52 | module.fail_json(**result) 53 | else: 54 | module.exit_json(**result) 55 | 56 | 57 | @hashiwrapper 58 | def hashivault_consul_secret_engine_config(module): 59 | params = module.params 60 | client = hashivault_auth_client(params) 61 | mount_point = params.get('mount_point').strip('/') 62 | consul_address = params.get('consul_address') 63 | scheme = params.get('scheme') 64 | token = params.get('consul_token') 65 | 66 | if (mount_point + "/") not in client.sys.list_mounted_secrets_engines()['data']: 67 | return {'failed': True, 'msg': 'Consul secret engine is not enabled', 'rc': 1} 68 | 69 | if module.check_mode: 70 | return {'changed': True} 71 | 72 | response = client.secrets.consul.configure_access(consul_address, token, scheme=scheme, mount_point=mount_point) 73 | if response.ok: 74 | return {'changed': True} 75 | return {'failed': True, 'msg': response.text} 76 | 77 | 78 | if __name__ == '__main__': 79 | main() 80 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_pki_ca_set.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_auth_client 3 | from ansible.module_utils.hashivault import hashivault_argspec 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import hashiwrapper 6 | 7 | ANSIBLE_METADATA = {'status': ['preview'], 'supported_by': 'community', 'version': '1.1'} 8 | DOCUMENTATION = r''' 9 | --- 10 | module: hashivault_pki_ca_set 11 | version_added: "4.5.0" 12 | short_description: Hashicorp Vault PKI Submit CA Information 13 | description: 14 | - This module allows submitting the CA information for the backend via a PEM file containing the CA certificate and 15 | its private key, concatenated. 16 | - May optionally append additional CA certificates. Useful when creating an intermediate CA to ensure a full chain 17 | is returned when signing or generating certificates. 18 | - Not needed if you are generating a self-signed root certificate, and not used if you have a signed intermediate 19 | CA certificate with a generated key, use the hashivault_pki_set_signed for that. If you have already set a 20 | certificate and key, they will be overridden. 21 | options: 22 | mount_point: 23 | default: pki 24 | description: 25 | - location where secrets engine is mounted. also known as path 26 | pem_bundle: 27 | required: true 28 | type: str 29 | description: 30 | - Specifies the key and certificate concatenated in PEM format. 31 | extends_documentation_fragment: 32 | - hashivault 33 | ''' 34 | EXAMPLES = r''' 35 | --- 36 | - hosts: localhost 37 | tasks: 38 | - hashivault_pki_ca_set: 39 | pem_bundle: '-----BEGIN RSA PRIVATE KEY-----\n...\n-----END CERTIFICATE-----' 40 | ''' 41 | 42 | 43 | def main(): 44 | argspec = hashivault_argspec() 45 | argspec['pem_bundle'] = dict(required=True, type='str') 46 | argspec['mount_point'] = dict(required=False, type='str', default='pki') 47 | 48 | supports_check_mode = True 49 | 50 | module = hashivault_init(argspec, supports_check_mode) 51 | result = hashivault_pki_ca_set(module) 52 | 53 | if result.get('failed'): 54 | module.fail_json(**result) 55 | else: 56 | module.exit_json(**result) 57 | 58 | 59 | @hashiwrapper 60 | def hashivault_pki_ca_set(module): 61 | params = module.params 62 | client = hashivault_auth_client(params) 63 | mount_point = params.get('mount_point').strip('/') 64 | pem_bundle = params.get('pem_bundle') 65 | 66 | if module.check_mode: 67 | return {'changed': True} 68 | 69 | result = {'changed': True} 70 | data = client.secrets.pki.submit_ca_information(pem_bundle=pem_bundle, mount_point=mount_point) 71 | if data: 72 | from requests.models import Response 73 | if isinstance(data, Response): 74 | result['data'] = data.text 75 | else: 76 | result['data'] = data 77 | 78 | return result 79 | 80 | 81 | if __name__ == '__main__': 82 | main() 83 | -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_pki_crl.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ansible.module_utils.hashivault import hashivault_auth_client 3 | from ansible.module_utils.hashivault import hashivault_argspec 4 | from ansible.module_utils.hashivault import hashivault_init 5 | from ansible.module_utils.hashivault import compare_state 6 | from ansible.module_utils.hashivault import hashiwrapper 7 | 8 | ANSIBLE_METADATA = {'status': ['preview'], 'supported_by': 'community', 'version': '1.1'} 9 | DOCUMENTATION = r''' 10 | --- 11 | module: hashivault_pki_crl 12 | version_added: "4.5.0" 13 | short_description: Hashicorp Vault PKI Set CRL Configuration 14 | description: 15 | - This module allows setting the duration for which the generated CRL should be marked valid. 16 | - If the CRL is disabled, it will return a signed but zero-length CRL for any request. 17 | - If enabled, it will re-build the CRL. 18 | options: 19 | mount_point: 20 | default: pki 21 | description: 22 | - location where secrets engine is mounted. also known as path 23 | expiry: 24 | required: true 25 | type: str 26 | description: 27 | - Specifies the time until expiration. 28 | disable: 29 | type: bool 30 | default: false 31 | description: 32 | - Disables or enables CRL building. 33 | extends_documentation_fragment: 34 | - hashivault 35 | ''' 36 | EXAMPLES = r''' 37 | --- 38 | - hosts: localhost 39 | tasks: 40 | - hashivault_pki_crl: 41 | expiry: 72h 42 | disable: false 43 | 44 | ''' 45 | 46 | 47 | def main(): 48 | argspec = hashivault_argspec() 49 | argspec['expiry'] = dict(required=True, type='str') 50 | argspec['disable'] = dict(required=False, type='bool', default=False) 51 | argspec['mount_point'] = dict(required=False, type='str', default='pki') 52 | 53 | supports_check_mode = True 54 | 55 | module = hashivault_init(argspec, supports_check_mode) 56 | result = hashivault_pki_crl(module) 57 | 58 | if result.get('failed'): 59 | module.fail_json(**result) 60 | else: 61 | module.exit_json(**result) 62 | 63 | 64 | @hashiwrapper 65 | def hashivault_pki_crl(module): 66 | params = module.params 67 | client = hashivault_auth_client(params) 68 | 69 | mount_point = params.get('mount_point').strip('/') 70 | 71 | desired_state = { 72 | 'disable': params.get('disable'), 73 | 'expiry': params.get('expiry') 74 | } 75 | 76 | # compare current_state to desired_state 77 | from hvac.exceptions import InvalidPath 78 | try: 79 | current_state = client.secrets.pki.read_crl_configuration(mount_point=mount_point).get('data') 80 | changed = not compare_state(desired_state, current_state) 81 | except InvalidPath: 82 | changed = True 83 | 84 | # make the changes! 85 | if changed and not module.check_mode: 86 | client.secrets.pki.set_crl_configuration(mount_point=mount_point, extra_params=desired_state) 87 | return {'changed': changed} 88 | 89 | 90 | if __name__ == '__main__': 91 | main() 92 | -------------------------------------------------------------------------------- /functional/test_identity_entity.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | gather_facts: no 4 | tasks: 5 | - hashivault_identity_entity: 6 | name: bob 7 | state: absent 8 | - hashivault_identity_entity: 9 | name: sam 10 | state: absent 11 | 12 | - name: Create for the first time 13 | hashivault_identity_entity: 14 | name: bob 15 | policies: bob 16 | register: vault_identity 17 | - assert: { that: "{{vault_identity.changed}} == True" } 18 | - assert: { that: "{{vault_identity.rc}} == 0" } 19 | 20 | - name: Update no change 21 | hashivault_identity_entity: 22 | name: bob 23 | policies: bob 24 | register: vault_identity 25 | - assert: { that: "{{vault_identity.changed}} == False" } 26 | - assert: { that: "{{vault_identity.rc}} == 0" } 27 | 28 | - name: Update remove policy 29 | hashivault_identity_entity: 30 | name: bob 31 | policies: null 32 | register: vault_identity 33 | - assert: { that: "{{vault_identity.changed}} == False" } 34 | - assert: { that: "{{vault_identity.rc}} == 0" } 35 | 36 | - name: Update readd policy 37 | hashivault_identity_entity: 38 | name: bob 39 | policies: bob 40 | register: vault_identity 41 | - assert: { that: "{{vault_identity.changed}} == False" } 42 | - assert: { that: "{{vault_identity.rc}} == 0" } 43 | 44 | - name: Update 45 | hashivault_identity_entity: 46 | name: bob 47 | policies: bob 48 | metadata: 49 | a: b 50 | c: d 51 | disabled: True 52 | register: vault_identity 53 | - assert: { that: "{{vault_identity.changed}} == True" } 54 | - assert: { that: "{{vault_identity.rc}} == 0" } 55 | 56 | - name: Delete it for the first time 57 | hashivault_identity_entity: 58 | name: bob 59 | state: absent 60 | register: vault_identity 61 | - assert: { that: "{{vault_identity.changed}} == True" } 62 | - assert: { that: "{{vault_identity.rc}} == 0" } 63 | 64 | - name: Delete it again 65 | hashivault_identity_entity: 66 | name: bob 67 | state: absent 68 | register: vault_identity 69 | - assert: { that: "{{vault_identity.changed}} == False" } 70 | - assert: { that: "{{vault_identity.rc}} == 0" } 71 | 72 | - name: Create new one 73 | hashivault_identity_entity: 74 | name: sam 75 | policies: sam 76 | register: vault_identity 77 | - assert: { that: "{{vault_identity.changed}} == True" } 78 | - assert: { that: "{{vault_identity.rc}} == 0" } 79 | 80 | - hashivault_identity_entity_alias: 81 | name: sammy 82 | entity_name: sam 83 | register: vault_identity_alias 84 | - assert: { that: "{{vault_identity_alias.changed}} == True" } 85 | - assert: { that: "{{vault_identity_alias.rc}} == 0" } 86 | - hashivault_identity_entity_alias: 87 | name: sammy 88 | entity_name: sam 89 | state: absent 90 | register: vault_identity_alias 91 | - assert: { that: "{{vault_identity_alias.changed}} == True" } 92 | - assert: { that: "{{vault_identity_alias.rc}} == 0" } -------------------------------------------------------------------------------- /ansible/modules/hashivault/hashivault_delete.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import warnings 3 | 4 | from hvac.exceptions import InvalidPath 5 | 6 | from ansible.module_utils.hashivault import hashivault_argspec 7 | from ansible.module_utils.hashivault import hashivault_auth_client 8 | from ansible.module_utils.hashivault import hashivault_init 9 | from ansible.module_utils.hashivault import hashiwrapper 10 | 11 | ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'community', 'version': '1.1'} 12 | DOCUMENTATION = ''' 13 | --- 14 | module: hashivault_delete 15 | version_added: "3.4.0" 16 | short_description: Hashicorp Vault delete module 17 | description: 18 | - Module to delete from Hashicorp Vault. 19 | options: 20 | version: 21 | description: 22 | - version of the kv engine (int) 23 | default: 1 24 | mount_point: 25 | description: 26 | - secret mount point 27 | default: secret 28 | secret: 29 | description: 30 | - secret to delete. 31 | extends_documentation_fragment: hashivault 32 | ''' 33 | EXAMPLES = ''' 34 | --- 35 | - hosts: localhost 36 | tasks: 37 | - hashivault_delete: 38 | secret: giant 39 | ''' 40 | 41 | 42 | def main(): 43 | argspec = hashivault_argspec() 44 | argspec['version'] = dict(required=False, type='int', default=1) 45 | argspec['mount_point'] = dict(required=False, type='str', default='secret') 46 | argspec['secret'] = dict(required=True, type='str') 47 | module = hashivault_init(argspec) 48 | result = hashivault_delete(module.params) 49 | if result.get('failed'): 50 | module.fail_json(**result) 51 | else: 52 | module.exit_json(**result) 53 | 54 | 55 | @hashiwrapper 56 | def hashivault_delete(params): 57 | result = {"changed": False, "rc": 0} 58 | client = hashivault_auth_client(params) 59 | version = params.get('version') 60 | mount_point = params.get('mount_point') 61 | secret = params.get('secret') 62 | if secret.startswith('/'): 63 | secret = secret.lstrip('/') 64 | mount_point = '' 65 | if mount_point: 66 | secret_path = '%s/%s' % (mount_point, secret) 67 | else: 68 | secret_path = secret 69 | 70 | with warnings.catch_warnings(): 71 | warnings.simplefilter("ignore") 72 | returned_data = None 73 | try: 74 | if version == 2: 75 | returned_data = client.secrets.kv.v2.delete_latest_version_of_secret(secret, mount_point=mount_point) 76 | else: 77 | returned_data = client.delete(secret_path) 78 | except InvalidPath: 79 | pass 80 | except Exception as e: 81 | result['rc'] = 1 82 | result['failed'] = True 83 | error_string = "%s(%s)" % (e.__class__.__name__, e) 84 | result['msg'] = u"Error %s deleting %s" % (error_string, secret_path) 85 | return result 86 | if returned_data: 87 | result['data'] = returned_data.text 88 | result['msg'] = u"Secret %s deleted" % secret_path 89 | result['changed'] = True 90 | return result 91 | 92 | 93 | if __name__ == '__main__': 94 | main() 95 | --------------------------------------------------------------------------------