Remove incidentals without coverage (#71788)

* Remove incidental_lookup_hashi_vault
* Remove incidental_connection_chroot
* Remove incidental_selinux
* Remove incidental_win_hosts
This commit is contained in:
Matt Martz 2020-09-17 16:57:28 -05:00 committed by GitHub
parent 2d2c5d5ed7
commit e6e9840717
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 0 additions and 2283 deletions

View file

@ -1,3 +0,0 @@
needs/root
shippable/posix/incidental
needs/target/connection

View file

@ -1,18 +0,0 @@
#!/usr/bin/env bash
set -eux
# Connection tests for POSIX platforms use this script by linking to it from the appropriate 'connection_' target dir.
# The name of the inventory group to test is extracted from the directory name following the 'connection_' prefix.
group=$(python -c \
"from os import path; print(path.basename(path.abspath(path.dirname('$0'))).replace('incidental_connection_', ''))")
cd ../connection
INVENTORY="../incidental_connection_${group}/test_connection.inventory" ./test.sh \
-e target_hosts="${group}" \
-e action_prefix= \
-e local_tmp=/tmp/ansible-local \
-e remote_tmp=/tmp/ansible-remote \
"$@"

View file

@ -1,7 +0,0 @@
[chroot]
chroot-pipelining ansible_ssh_pipelining=true
chroot-no-pipelining ansible_ssh_pipelining=false
[chroot:vars]
ansible_host=/
ansible_connection=chroot
ansible_python_interpreter="{{ ansible_playbook_python }}"

View file

@ -1,7 +0,0 @@
shippable/posix/incidental
destructive
needs/target/incidental_setup_openssl
needs/file/test/lib/ansible_test/_data/requirements/constraints.txt
skip/aix
skip/power/centos
skip/python2.6

View file

@ -1,4 +0,0 @@
---
vault_gen_path: 'gen/testproject'
vault_kv1_path: 'kv1/testproject'
vault_kv2_path: 'kv2/data/testproject'

View file

@ -1,21 +0,0 @@
- name: 'Create an approle policy'
shell: "echo '{{ policy }}' | {{ vault_cmd }} policy write approle-policy -"
vars:
policy: |
path "auth/approle/login" {
capabilities = [ "create", "read" ]
}
- name: 'Enable the AppRole auth method'
command: '{{ vault_cmd }} auth enable approle'
- name: 'Create a named role'
command: '{{ vault_cmd }} write auth/approle/role/test-role policies="test-policy,approle-policy"'
- name: 'Fetch the RoleID of the AppRole'
command: '{{ vault_cmd }} read -field=role_id auth/approle/role/test-role/role-id'
register: role_id_cmd
- name: 'Get a SecretID issued against the AppRole'
command: '{{ vault_cmd }} write -field=secret_id -f auth/approle/role/test-role/secret-id'
register: secret_id_cmd

View file

@ -1,45 +0,0 @@
- vars:
role_id: '{{ role_id_cmd.stdout }}'
secret_id: '{{ secret_id_cmd.stdout }}'
block:
- name: 'Fetch secrets using "hashi_vault" lookup'
set_fact:
secret1: "{{ lookup('hashi_vault', conn_params ~ 'secret=' ~ vault_kv2_path ~ '/secret1 auth_method=approle secret_id=' ~ secret_id ~ ' role_id=' ~ role_id) }}"
secret2: "{{ lookup('hashi_vault', conn_params ~ 'secret=' ~ vault_kv2_path ~ '/secret2 auth_method=approle secret_id=' ~ secret_id ~ ' role_id=' ~ role_id) }}"
- name: 'Check secret values'
fail:
msg: 'unexpected secret values'
when: secret1['value'] != 'foo1' or secret2['value'] != 'foo2'
- name: 'Failure expected when erroneous credentials are used'
vars:
secret_wrong_cred: "{{ lookup('hashi_vault', conn_params ~ 'secret=' ~ vault_kv2_path ~ '/secret2 auth_method=approle secret_id=toto role_id=' ~ role_id) }}"
debug:
msg: 'Failure is expected ({{ secret_wrong_cred }})'
register: test_wrong_cred
ignore_errors: true
- name: 'Failure expected when unauthorized secret is read'
vars:
secret_unauthorized: "{{ lookup('hashi_vault', conn_params ~ 'secret=' ~ vault_kv2_path ~ '/secret3 auth_method=approle secret_id=' ~ secret_id ~ ' role_id=' ~ role_id) }}"
debug:
msg: 'Failure is expected ({{ secret_unauthorized }})'
register: test_unauthorized
ignore_errors: true
- name: 'Failure expected when inexistent secret is read'
vars:
secret_inexistent: "{{ lookup('hashi_vault', conn_params ~ 'secret=' ~ vault_kv2_path ~ '/secret4 auth_method=approle secret_id=' ~ secret_id ~ ' role_id=' ~ role_id) }}"
debug:
msg: 'Failure is expected ({{ secret_inexistent }})'
register: test_inexistent
ignore_errors: true
- name: 'Check expected failures'
assert:
msg: "an expected failure didn't occur"
that:
- test_wrong_cred is failed
- test_unauthorized is failed
- test_inexistent is failed

View file

@ -1,155 +0,0 @@
---
- name: Install Hashi Vault on controlled node and test
vars:
vault_version: '0.11.0'
vault_uri: 'https://ansible-ci-files.s3.amazonaws.com/test/integration/targets/lookup_hashi_vault/vault_{{ vault_version }}_{{ ansible_system | lower }}_{{ vault_arch }}.zip'
vault_cmd: '{{ local_temp_dir }}/vault'
block:
- name: Create a local temporary directory
tempfile:
state: directory
register: tempfile_result
- set_fact:
local_temp_dir: '{{ tempfile_result.path }}'
- when: pyopenssl_version.stdout is version('0.15', '>=')
block:
- name: Generate privatekey
openssl_privatekey:
path: '{{ local_temp_dir }}/privatekey.pem'
- name: Generate CSR
openssl_csr:
path: '{{ local_temp_dir }}/csr.csr'
privatekey_path: '{{ local_temp_dir }}/privatekey.pem'
subject:
commonName: localhost
- name: Generate selfsigned certificate
openssl_certificate:
path: '{{ local_temp_dir }}/cert.pem'
csr_path: '{{ local_temp_dir }}/csr.csr'
privatekey_path: '{{ local_temp_dir }}/privatekey.pem'
provider: selfsigned
selfsigned_digest: sha256
register: selfsigned_certificate
- name: 'Install unzip'
package:
name: unzip
when: ansible_distribution != "MacOSX" # unzip already installed
- assert:
# Linux: x86_64, FreeBSD: amd64
that: ansible_architecture in ['i386', 'x86_64', 'amd64']
- set_fact:
vault_arch: '386'
when: ansible_architecture == 'i386'
- set_fact:
vault_arch: amd64
when: ansible_architecture in ['x86_64', 'amd64']
- name: 'Download vault binary'
unarchive:
src: '{{ vault_uri }}'
dest: '{{ local_temp_dir }}'
remote_src: true
- environment:
# used by vault command
VAULT_DEV_ROOT_TOKEN_ID: '47542cbc-6bf8-4fba-8eda-02e0a0d29a0a'
block:
- name: 'Create configuration file'
template:
src: vault_config.hcl.j2
dest: '{{ local_temp_dir }}/vault_config.hcl'
- name: 'Start vault service'
environment:
VAULT_ADDR: 'http://localhost:8200'
block:
- name: 'Start vault server (dev mode enabled)'
shell: 'nohup {{ vault_cmd }} server -dev -config {{ local_temp_dir }}/vault_config.hcl </dev/null >/dev/null 2>&1 &'
- name: 'Create generic secrets engine'
command: '{{ vault_cmd }} secrets enable -path=gen generic'
- name: 'Create KV v1 secrets engine'
command: '{{ vault_cmd }} secrets enable -path=kv1 -version=1 kv'
- name: 'Create KV v2 secrets engine'
command: '{{ vault_cmd }} secrets enable -path=kv2 -version=2 kv'
- name: 'Create a test policy'
shell: "echo '{{ policy }}' | {{ vault_cmd }} policy write test-policy -"
vars:
policy: |
path "{{ vault_gen_path }}/secret1" {
capabilities = ["read"]
}
path "{{ vault_gen_path }}/secret2" {
capabilities = ["read", "update"]
}
path "{{ vault_gen_path }}/secret3" {
capabilities = ["deny"]
}
path "{{ vault_kv1_path }}/secret1" {
capabilities = ["read"]
}
path "{{ vault_kv1_path }}/secret2" {
capabilities = ["read", "update"]
}
path "{{ vault_kv1_path }}/secret3" {
capabilities = ["deny"]
}
path "{{ vault_kv2_path }}/secret1" {
capabilities = ["read"]
}
path "{{ vault_kv2_path }}/secret2" {
capabilities = ["read", "update"]
}
path "{{ vault_kv2_path }}/secret3" {
capabilities = ["deny"]
}
- name: 'Create generic secrets'
command: '{{ vault_cmd }} write {{ vault_gen_path }}/secret{{ item }} value=foo{{ item }}'
loop: [1, 2, 3]
- name: 'Create KV v1 secrets'
command: '{{ vault_cmd }} kv put {{ vault_kv1_path }}/secret{{ item }} value=foo{{ item }}'
loop: [1, 2, 3]
- name: 'Create KV v2 secrets'
command: '{{ vault_cmd }} kv put {{ vault_kv2_path | regex_replace("/data") }}/secret{{ item }} value=foo{{ item }}'
loop: [1, 2, 3]
- name: setup approle auth
import_tasks: approle_setup.yml
when: ansible_distribution != 'RedHat' or ansible_distribution_major_version is version('7', '>')
- name: setup token auth
import_tasks: token_setup.yml
- import_tasks: tests.yml
vars:
auth_type: approle
when: ansible_distribution != 'RedHat' or ansible_distribution_major_version is version('7', '>')
- import_tasks: tests.yml
vars:
auth_type: token
always:
- name: 'Kill vault process'
shell: "kill $(cat {{ local_temp_dir }}/vault.pid)"
ignore_errors: true
always:
- name: 'Delete temp dir'
file:
path: '{{ local_temp_dir }}'
state: absent

View file

@ -1,35 +0,0 @@
- name: 'test {{ auth_type }} auth without SSL (lookup parameters)'
include_tasks: '{{ auth_type }}_test.yml'
vars:
conn_params: 'url=http://localhost:8200 '
- name: 'test {{ auth_type }} auth without SSL (environment variable)'
include_tasks: '{{ auth_type }}_test.yml'
args:
apply:
vars:
conn_params: ''
environment:
VAULT_ADDR: 'http://localhost:8200'
- when: pyopenssl_version.stdout is version('0.15', '>=')
block:
- name: 'test {{ auth_type }} auth with certs (validation enabled, lookup parameters)'
include_tasks: '{{ auth_type }}_test.yml'
vars:
conn_params: 'url=https://localhost:8201 ca_cert={{ local_temp_dir }}/cert.pem validate_certs=True '
- name: 'test {{ auth_type }} auth with certs (validation enabled, environment variables)'
include_tasks: '{{ auth_type }}_test.yml'
args:
apply:
vars:
conn_params: ''
environment:
VAULT_ADDR: 'https://localhost:8201'
VAULT_CACERT: '{{ local_temp_dir }}/cert.pem'
- name: 'test {{ auth_type }} auth with certs (validation disabled, lookup parameters)'
include_tasks: '{{ auth_type }}_test.yml'
vars:
conn_params: 'url=https://localhost:8201 validate_certs=False '

View file

@ -1,3 +0,0 @@
- name: 'Create a test credentials (token)'
command: '{{ vault_cmd }} token create -policy test-policy -field token'
register: user_token_cmd

View file

@ -1,58 +0,0 @@
- vars:
user_token: '{{ user_token_cmd.stdout }}'
block:
- name: 'Fetch secrets using "hashi_vault" lookup'
set_fact:
gen_secret1: "{{ lookup('hashi_vault', conn_params ~ 'secret=' ~ vault_gen_path ~ '/secret1 auth_method=token token=' ~ user_token) }}"
gen_secret2: "{{ lookup('hashi_vault', conn_params ~ 'secret=' ~ vault_gen_path ~ '/secret2 token=' ~ user_token) }}"
kv1_secret1: "{{ lookup('hashi_vault', conn_params ~ 'secret=' ~ vault_kv1_path ~ '/secret1 auth_method=token token=' ~ user_token) }}"
kv1_secret2: "{{ lookup('hashi_vault', conn_params ~ 'secret=' ~ vault_kv1_path ~ '/secret2 token=' ~ user_token) }}"
kv2_secret1: "{{ lookup('hashi_vault', conn_params ~ 'secret=' ~ vault_kv2_path ~ '/secret1 auth_method=token token=' ~ user_token) }}"
kv2_secret2: "{{ lookup('hashi_vault', conn_params ~ 'secret=' ~ vault_kv2_path ~ '/secret2 token=' ~ user_token) }}"
- name: 'Check secret generic values'
fail:
msg: 'unexpected secret values'
when: gen_secret1['value'] != 'foo1' or gen_secret2['value'] != 'foo2'
- name: 'Check secret kv1 values'
fail:
msg: 'unexpected secret values'
when: kv1_secret1['value'] != 'foo1' or kv1_secret2['value'] != 'foo2'
- name: 'Check secret kv2 values'
fail:
msg: 'unexpected secret values'
when: kv2_secret1['value'] != 'foo1' or kv2_secret2['value'] != 'foo2'
- name: 'Failure expected when erroneous credentials are used'
vars:
secret_wrong_cred: "{{ lookup('hashi_vault', conn_params ~ 'secret=' ~ vault_kv2_path ~ '/secret2 auth_method=token token=wrong_token') }}"
debug:
msg: 'Failure is expected ({{ secret_wrong_cred }})'
register: test_wrong_cred
ignore_errors: true
- name: 'Failure expected when unauthorized secret is read'
vars:
secret_unauthorized: "{{ lookup('hashi_vault', conn_params ~ 'secret=' ~ vault_kv2_path ~ '/secret3 token=' ~ user_token) }}"
debug:
msg: 'Failure is expected ({{ secret_unauthorized }})'
register: test_unauthorized
ignore_errors: true
- name: 'Failure expected when inexistent secret is read'
vars:
secret_inexistent: "{{ lookup('hashi_vault', conn_params ~ 'secret=' ~ vault_kv2_path ~ '/secret4 token=' ~ user_token) }}"
debug:
msg: 'Failure is expected ({{ secret_inexistent }})'
register: test_inexistent
ignore_errors: true
- name: 'Check expected failures'
assert:
msg: "an expected failure didn't occur"
that:
- test_wrong_cred is failed
- test_unauthorized is failed
- test_inexistent is failed

View file

@ -1,10 +0,0 @@
# {{ ansible_managed }}
pid_file = "{{ local_temp_dir }}/vault.pid"
{% if pyopenssl_version.stdout is version('0.15', '>=') %}
listener "tcp" {
tls_key_file = "{{ local_temp_dir }}/privatekey.pem"
tls_cert_file = "{{ local_temp_dir }}/cert.pem"
tls_disable = false
address = "localhost:8201"
}
{% endif %}

View file

@ -1,19 +0,0 @@
- hosts: localhost
tasks:
- name: Install openssl
import_role:
name: incidental_setup_openssl
- name: "RedHat <= 7, select last version compatible with request 2.6.0 (this version doesn't support approle auth)"
set_fact:
hvac_package: 'hvac==0.2.5'
when: ansible_distribution == 'RedHat' and ansible_distribution_major_version is version('7', '<=')
- name: 'CentOS < 7, select last version compatible with Python 2.6'
set_fact:
hvac_package: 'hvac==0.5.0'
when: ansible_distribution == 'CentOS' and ansible_distribution_major_version is version('7', '<')
- name: 'Install hvac Python package'
pip:
name: "{{ hvac_package|default('hvac') }}"

View file

@ -1,9 +0,0 @@
- hosts: localhost
tasks:
- name: register pyOpenSSL version
command: "{{ ansible_python.executable }} -c 'import OpenSSL; print(OpenSSL.__version__)'"
register: pyopenssl_version
- name: Test lookup hashi_vault
import_role:
name: incidental_lookup_hashi_vault/lookup_hashi_vault

View file

@ -1,23 +0,0 @@
#!/usr/bin/env bash
set -eux
# First install pyOpenSSL, then test lookup in a second playbook in order to
# workaround this error which occurs on OS X 10.11 only:
#
# TASK [lookup_hashi_vault : test token auth with certs (validation enabled, lookup parameters)] ***
# included: lookup_hashi_vault/tasks/token_test.yml for testhost
#
# TASK [lookup_hashi_vault : Fetch secrets using "hashi_vault" lookup] ***
# From cffi callback <function _verify_callback at 0x106f995f0>:
# Traceback (most recent call last):
# File "/usr/local/lib/python2.7/site-packages/OpenSSL/SSL.py", line 309, in wrapper
# _lib.X509_up_ref(x509)
# AttributeError: 'module' object has no attribute 'X509_up_ref'
# fatal: [testhost]: FAILED! => { "msg": "An unhandled exception occurred while running the lookup plugin 'hashi_vault'. Error was a <class 'requests.exceptions.SSLError'>, original message: HTTPSConnectionPool(host='localhost', port=8201): Max retries exceeded with url: /v1/auth/token/lookup-self (Caused by SSLError(SSLError(\"bad handshake: Error([('SSL routines', 'ssl3_get_server_certificate', 'certificate verify failed')],)\",),))"}
ANSIBLE_ROLES_PATH=../ \
ansible-playbook playbooks/install_dependencies.yml -v "$@"
ANSIBLE_ROLES_PATH=../ \
ansible-playbook playbooks/test_lookup_hashi_vault.yml -v "$@"

View file

@ -1,3 +0,0 @@
needs/root
shippable/posix/incidental
skip/aix

View file

@ -1,36 +0,0 @@
# (c) 2017, Sam Doran <sdoran@redhat.com>
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
- debug:
msg: SELinux is disabled
when: ansible_selinux is defined and ansible_selinux == False
- debug:
msg: SELinux is {{ ansible_selinux.status }}
when: ansible_selinux is defined and ansible_selinux != False
- include: selinux.yml
when:
- ansible_selinux is defined
- ansible_selinux != False
- ansible_selinux.status == 'enabled'
- include: selogin.yml
when:
- ansible_selinux is defined
- ansible_selinux != False
- ansible_selinux.status == 'enabled'

View file

@ -1,364 +0,0 @@
# (c) 2017, Sam Doran <sdoran@redhat.com>
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
# First Test
# ##############################################################################
# Test changing the state, which requires a reboot
- name: TEST 1 | Get current SELinux config file contents
set_fact:
selinux_config_original: "{{ lookup('file', '/etc/sysconfig/selinux').split('\n') }}"
before_test_sestatus: "{{ ansible_selinux }}"
- debug:
var: "{{ item }}"
verbosity: 1
with_items:
- selinux_config_original
- before_test_sestatus
- ansible_selinux
- name: TEST 1 | Setup SELinux configuration for tests
selinux:
state: enforcing
policy: targeted
- name: TEST 1 | Disable SELinux
selinux:
state: disabled
policy: targeted
register: _disable_test1
- debug:
var: _disable_test1
verbosity: 1
- name: TEST 1 | Re-gather facts
setup:
- name: TEST 1 | Assert that status was changed, reboot_required is True, a warning was displayed, and SELinux is configured properly
assert:
that:
- _disable_test1 is changed
- _disable_test1.reboot_required
- (_disable_test1.warnings | length ) >= 1
- ansible_selinux.config_mode == 'disabled'
- ansible_selinux.type == 'targeted'
- debug:
var: ansible_selinux
verbosity: 1
- name: TEST 1 | Disable SELinux again
selinux:
state: disabled
policy: targeted
register: _disable_test2
- debug:
var: _disable_test2
verbosity: 1
- name: TEST 1 | Assert that no change is reported, a warnking was dispalyed, and reboot_required is True
assert:
that:
- _disable_test2 is not changed
- (_disable_test1.warnings | length ) >= 1
- _disable_test2.reboot_required
- name: TEST 1 | Get modified config file
set_fact:
selinux_config_after: "{{ lookup('file', '/etc/sysconfig/selinux').split('\n') }}"
- debug:
var: selinux_config_after
verbosity: 1
- name: TEST 1 | Ensure SELinux config file is properly formatted
assert:
that:
- selinux_config_original | length == selinux_config_after | length
- selinux_config_after[selinux_config_after.index('SELINUX=disabled')] is search("^SELINUX=\w+$")
- selinux_config_after[selinux_config_after.index('SELINUXTYPE=targeted')] is search("^SELINUXTYPE=\w+$")
- name: TEST 1 | Reset SELinux configuration for next test
selinux:
state: enforcing
policy: targeted
# Second Test
# ##############################################################################
# Test changing only the policy, which does not require a reboot
- name: TEST 2 | Make sure the policy is present
package:
name: selinux-policy-mls
state: present
- name: TEST 2 | Set SELinux policy
selinux:
state: enforcing
policy: mls
register: _state_test1
- debug:
var: _state_test1
verbosity: 1
- name: TEST 2 | Re-gather facts
setup:
- debug:
var: ansible_selinux
tags: debug
- name: TEST 2 | Assert that status was changed, reboot_required is False, no warnings were displayed, and SELinux is configured properly
assert:
that:
- _state_test1 is changed
- not _state_test1.reboot_required
- _state_test1.warnings is not defined
- ansible_selinux.config_mode == 'enforcing'
- ansible_selinux.type == 'mls'
- name: TEST 2 | Set SELinux policy again
selinux:
state: enforcing
policy: mls
register: _state_test2
- debug:
var: _state_test2
verbosity: 1
- name: TEST 2 | Assert that no change was reported, no warnings were dispalyed, and reboot_required is False
assert:
that:
- _state_test2 is not changed
- _state_test2.warnings is not defined
- not _state_test2.reboot_required
- name: TEST 2 | Get modified config file
set_fact:
selinux_config_after: "{{ lookup('file', '/etc/sysconfig/selinux').split('\n') }}"
- debug:
var: selinux_config_after
verbosity: 1
- name: TEST 2 | Ensure SELinux config file is properly formatted
assert:
that:
- selinux_config_original | length == selinux_config_after | length
- selinux_config_after[selinux_config_after.index('SELINUX=enforcing')] is search("^SELINUX=\w+$")
- selinux_config_after[selinux_config_after.index('SELINUXTYPE=mls')] is search("^SELINUXTYPE=\w+$")
- name: TEST 2 | Reset SELinux configuration for next test
selinux:
state: enforcing
policy: targeted
# Third Test
# ##############################################################################
# Test changing non-existing policy
- name: TEST 3 | Set SELinux policy
selinux:
state: enforcing
policy: non-existing-selinux-policy
register: _state_test1
ignore_errors: yes
- debug:
var: _state_test1
verbosity: 1
- name: TEST 3 | Re-gather facts
setup:
- debug:
var: ansible_selinux
tags: debug
- name: TEST 3 | Assert that status was not changed, the task failed, the msg contains proper information and SELinux was not changed
assert:
that:
- _state_test1 is not changed
- _state_test1 is failed
- _state_test1.msg == 'Policy non-existing-selinux-policy does not exist in /etc/selinux/'
- ansible_selinux.config_mode == 'enforcing'
- ansible_selinux.type == 'targeted'
# Fourth Test
# ##############################################################################
# Test if check mode returns correct changed values and
# doesn't make any changes
- name: TEST 4 | Set SELinux to enforcing
selinux:
state: enforcing
policy: targeted
register: _check_mode_test1
- debug:
var: _check_mode_test1
verbosity: 1
- name: TEST 4 | Set SELinux to enforcing in check mode
selinux:
state: enforcing
policy: targeted
register: _check_mode_test1
check_mode: yes
- name: TEST 4 | Re-gather facts
setup:
- debug:
var: ansible_selinux
verbosity: 1
tags: debug
- name: TEST 4 | Assert that check mode is idempotent
assert:
that:
- _check_mode_test1 is success
- not _check_mode_test1.reboot_required
- ansible_selinux.config_mode == 'enforcing'
- ansible_selinux.type == 'targeted'
- name: TEST 4 | Set SELinux to permissive in check mode
selinux:
state: permissive
policy: targeted
register: _check_mode_test2
check_mode: yes
- name: TEST 4 | Re-gather facts
setup:
- debug:
var: ansible_selinux
verbosity: 1
tags: debug
- name: TEST 4 | Assert that check mode doesn't set state permissive and returns changed
assert:
that:
- _check_mode_test2 is changed
- not _check_mode_test2.reboot_required
- ansible_selinux.config_mode == 'enforcing'
- ansible_selinux.type == 'targeted'
- name: TEST 4 | Disable SELinux in check mode
selinux:
state: disabled
register: _check_mode_test3
check_mode: yes
- name: TEST 4 | Re-gather facts
setup:
- debug:
var: ansible_selinux
verbosity: 1
tags: debug
- name: TEST 4 | Assert that check mode didn't change anything, status is changed, reboot_required is True, a warning was displayed
assert:
that:
- _check_mode_test3 is changed
- _check_mode_test3.reboot_required
- (_check_mode_test3.warnings | length ) >= 1
- ansible_selinux.config_mode == 'enforcing'
- ansible_selinux.type == 'targeted'
- name: TEST 4 | Set SELinux to permissive
selinux:
state: permissive
policy: targeted
register: _check_mode_test4
- debug:
var: _check_mode_test4
verbosity: 1
- name: TEST 4 | Disable SELinux in check mode
selinux:
state: disabled
register: _check_mode_test4
check_mode: yes
- name: TEST 4 | Re-gather facts
setup:
- debug:
var: ansible_selinux
verbosity: 1
tags: debug
- name: TEST 4 | Assert that check mode didn't change anything, status is changed, reboot_required is True, a warning was displayed
assert:
that:
- _check_mode_test4 is changed
- _check_mode_test4.reboot_required
- (_check_mode_test3.warnings | length ) >= 1
- ansible_selinux.config_mode == 'permissive'
- ansible_selinux.type == 'targeted'
- name: TEST 4 | Set SELinux to enforcing
selinux:
state: enforcing
policy: targeted
register: _check_mode_test5
- debug:
var: _check_mode_test5
verbosity: 1
- name: TEST 4 | Disable SELinux
selinux:
state: disabled
register: _check_mode_test5
- name: TEST 4 | Disable SELinux in check mode
selinux:
state: disabled
register: _check_mode_test5
check_mode: yes
- name: TEST 4 | Re-gather facts
setup:
- debug:
var: ansible_selinux
verbosity: 1
tags: debug
- name: TEST 4 | Assert that in check mode status was not changed, reboot_required is True, a warning was displayed, and SELinux is configured properly
assert:
that:
- _check_mode_test5 is success
- _check_mode_test5.reboot_required
- (_check_mode_test5.warnings | length ) >= 1
- ansible_selinux.config_mode == 'disabled'
- ansible_selinux.type == 'targeted'

View file

@ -1,81 +0,0 @@
---
- name: create user for testing
user:
name: seuser
- name: attempt to add mapping without 'seuser'
selogin:
login: seuser
register: selogin_error
ignore_errors: yes
- name: verify failure
assert:
that:
- selogin_error is failed
- name: map login to SELinux user
selogin:
login: seuser
seuser: staff_u
register: selogin_new_mapping
check_mode: "{{ item }}"
with_items:
- yes
- no
- yes
- no
- name: new mapping- verify functionality and check_mode
assert:
that:
- selogin_new_mapping.results[0] is changed
- selogin_new_mapping.results[1] is changed
- selogin_new_mapping.results[2] is not changed
- selogin_new_mapping.results[3] is not changed
- name: change SELinux user login mapping
selogin:
login: seuser
seuser: user_u
register: selogin_mod_mapping
check_mode: "{{ item }}"
with_items:
- yes
- no
- yes
- no
- name: changed mapping- verify functionality and check_mode
assert:
that:
- selogin_mod_mapping.results[0] is changed
- selogin_mod_mapping.results[1] is changed
- selogin_mod_mapping.results[2] is not changed
- selogin_mod_mapping.results[3] is not changed
- name: remove SELinux user mapping
selogin:
login: seuser
state: absent
register: selogin_del_mapping
check_mode: "{{ item }}"
with_items:
- yes
- no
- yes
- no
- name: delete mapping- verify functionality and check_mode
assert:
that:
- selogin_del_mapping.results[0] is changed
- selogin_del_mapping.results[1] is changed
- selogin_del_mapping.results[2] is not changed
- selogin_del_mapping.results[3] is not changed
- name: remove test user
user:
name: seuser
state: absent

View file

@ -1,2 +0,0 @@
shippable/windows/incidental
windows

View file

@ -1,13 +0,0 @@
---
test_win_hosts_cname: testhost
test_win_hosts_ip: 192.168.168.1
test_win_hosts_aliases_set:
- alias1
- alias2
- alias3
- alias4
test_win_hosts_aliases_remove:
- alias3
- alias4

View file

@ -1,2 +0,0 @@
dependencies:
- setup_remote_tmp_dir

View file

@ -1,17 +0,0 @@
---
- name: take a copy of the original hosts file
win_copy:
src: C:\Windows\System32\drivers\etc\hosts
dest: '{{ remote_tmp_dir }}\hosts'
remote_src: yes
- block:
- name: run tests
include_tasks: tests.yml
always:
- name: restore hosts file
win_copy:
src: '{{ remote_tmp_dir }}\hosts'
dest: C:\Windows\System32\drivers\etc\hosts
remote_src: yes

View file

@ -1,189 +0,0 @@
---
- name: add a simple host with address
win_hosts:
state: present
ip_address: "{{ test_win_hosts_ip }}"
canonical_name: "{{ test_win_hosts_cname }}"
register: add_ip
- assert:
that:
- "add_ip.changed == true"
- name: get actual dns result
win_shell: "try{ [array]$t = [Net.DNS]::GetHostEntry('{{ test_win_hosts_cname }}') } catch { return 'false' } if ($t[0].HostName -eq '{{ test_win_hosts_cname }}' -and $t[0].AddressList[0].toString() -eq '{{ test_win_hosts_ip }}'){ return 'true' } else { return 'false' }"
register: add_ip_actual
- assert:
that:
- "add_ip_actual.stdout_lines[0]|lower == 'true'"
- name: add a simple host with ipv4 address (idempotent)
win_hosts:
state: present
ip_address: "{{ test_win_hosts_ip }}"
canonical_name: "{{ test_win_hosts_cname }}"
register: add_ip
- assert:
that:
- "add_ip.changed == false"
- name: remove simple host
win_hosts:
state: absent
ip_address: "{{ test_win_hosts_ip }}"
canonical_name: "{{ test_win_hosts_cname }}"
register: remove_ip
- assert:
that:
- "remove_ip.changed == true"
- name: get actual dns result
win_shell: "try{ [array]$t = [Net.DNS]::GetHostEntry('{{ test_win_hosts_cname}}') } catch { return 'false' } if ($t[0].HostName -eq '{{ test_win_hosts_cname }}' -and $t[0].AddressList[0].toString() -eq '{{ test_win_hosts_ip }}'){ return 'true' } else { return 'false' }"
register: remove_ip_actual
failed_when: "remove_ip_actual.rc == 0"
- assert:
that:
- "remove_ip_actual.stdout_lines[0]|lower == 'false'"
- name: remove simple host (idempotent)
win_hosts:
state: absent
ip_address: "{{ test_win_hosts_ip }}"
canonical_name: "{{ test_win_hosts_cname }}"
register: remove_ip
- assert:
that:
- "remove_ip.changed == false"
- name: add host and set aliases
win_hosts:
state: present
ip_address: "{{ test_win_hosts_ip }}"
canonical_name: "{{ test_win_hosts_cname }}"
aliases: "{{ test_win_hosts_aliases_set | union(test_win_hosts_aliases_remove) }}"
action: set
register: set_aliases
- assert:
that:
- "set_aliases.changed == true"
- name: get actual dns result for host
win_shell: "try{ [array]$t = [Net.DNS]::GetHostEntry('{{ test_win_hosts_cname }}') } catch { return 'false' } if ($t[0].HostName -eq '{{ test_win_hosts_cname }}' -and $t[0].AddressList[0].toString() -eq '{{ test_win_hosts_ip }}'){ return 'true' } else { return 'false' }"
register: set_aliases_actual_host
- assert:
that:
- "set_aliases_actual_host.stdout_lines[0]|lower == 'true'"
- name: get actual dns results for aliases
win_shell: "try{ [array]$t = [Net.DNS]::GetHostEntry('{{ item }}') } catch { return 'false' } if ($t[0].HostName -eq '{{ test_win_hosts_cname }}' -and $t[0].AddressList[0].toString() -eq '{{ test_win_hosts_ip }}'){ return 'true' } else { return 'false' }"
register: set_aliases_actual
with_items: "{{ test_win_hosts_aliases_set | union(test_win_hosts_aliases_remove) }}"
- assert:
that:
- "item.stdout_lines[0]|lower == 'true'"
with_items: "{{ set_aliases_actual.results }}"
- name: add host and set aliases (idempotent)
win_hosts:
state: present
ip_address: "{{ test_win_hosts_ip }}"
canonical_name: "{{ test_win_hosts_cname }}"
aliases: "{{ test_win_hosts_aliases_set | union(test_win_hosts_aliases_remove) }}"
action: set
register: set_aliases
- assert:
that:
- "set_aliases.changed == false"
- name: remove aliases from the list
win_hosts:
state: present
ip_address: "{{ test_win_hosts_ip }}"
canonical_name: "{{ test_win_hosts_cname }}"
aliases: "{{ test_win_hosts_aliases_remove }}"
action: remove
register: remove_aliases
- assert:
that:
- "remove_aliases.changed == true"
- name: get actual dns result for removed aliases
win_shell: "try{ [array]$t = [Net.DNS]::GetHostEntry('{{ item }}') } catch { return 'false' } if ($t[0].HostName -eq '{{ test_win_hosts_cname }}' -and $t[0].AddressList[0].toString() -eq '{{ test_win_hosts_ip }}'){ return 'true' } else { return 'false' }"
register: remove_aliases_removed_actual
failed_when: "remove_aliases_removed_actual.rc == 0"
with_items: "{{ test_win_hosts_aliases_remove }}"
- assert:
that:
- "item.stdout_lines[0]|lower == 'false'"
with_items: "{{ remove_aliases_removed_actual.results }}"
- name: get actual dns result for remaining aliases
win_shell: "try{ [array]$t = [Net.DNS]::GetHostEntry('{{ item }}') } catch { return 'false' } if ($t[0].HostName -eq '{{ test_win_hosts_cname }}' -and $t[0].AddressList[0].toString() -eq '{{ test_win_hosts_ip }}'){ return 'true' } else { return 'false' }"
register: remove_aliases_remain_actual
with_items: "{{ test_win_hosts_aliases_set | difference(test_win_hosts_aliases_remove) }}"
- assert:
that:
- "item.stdout_lines[0]|lower == 'true'"
with_items: "{{ remove_aliases_remain_actual.results }}"
- name: remove aliases from the list (idempotent)
win_hosts:
state: present
ip_address: "{{ test_win_hosts_ip }}"
canonical_name: "{{ test_win_hosts_cname }}"
aliases: "{{ test_win_hosts_aliases_remove }}"
action: remove
register: remove_aliases
- assert:
that:
- "remove_aliases.changed == false"
- name: add aliases back
win_hosts:
state: present
ip_address: "{{ test_win_hosts_ip }}"
canonical_name: "{{ test_win_hosts_cname }}"
aliases: "{{ test_win_hosts_aliases_remove }}"
action: add
register: add_aliases
- assert:
that:
- "add_aliases.changed == true"
- name: get actual dns results for aliases
win_shell: "try{ [array]$t = [Net.DNS]::GetHostEntry('{{ item }}') } catch { return 'false' } if ($t[0].HostName -eq '{{ test_win_hosts_cname }}' -and $t[0].AddressList[0].toString() -eq '{{ test_win_hosts_ip }}'){ return 'true' } else { return 'false' }"
register: add_aliases_actual
with_items: "{{ test_win_hosts_aliases_set | union(test_win_hosts_aliases_remove) }}"
- assert:
that:
- "item.stdout_lines[0]|lower == 'true'"
with_items: "{{ add_aliases_actual.results }}"
- name: add aliases back (idempotent)
win_hosts:
state: present
ip_address: "{{ test_win_hosts_ip }}"
canonical_name: "{{ test_win_hosts_cname }}"
aliases: "{{ test_win_hosts_aliases_remove }}"
action: add
register: add_aliases
- assert:
that:
- "add_aliases.changed == false"

View file

@ -1,208 +0,0 @@
# Based on local.py (c) 2012, Michael DeHaan <michael.dehaan@gmail.com>
#
# (c) 2013, Maykel Moya <mmoya@speedyrails.com>
# (c) 2015, Toshio Kuratomi <tkuratomi@ansible.com>
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
DOCUMENTATION = """
author: Maykel Moya <mmoya@speedyrails.com>
connection: chroot
short_description: Interact with local chroot
description:
- Run commands or put/fetch files to an existing chroot on the Ansible controller.
version_added: "1.1"
options:
remote_addr:
description:
- The path of the chroot you want to access.
default: inventory_hostname
vars:
- name: ansible_host
executable:
description:
- User specified executable shell
ini:
- section: defaults
key: executable
env:
- name: ANSIBLE_EXECUTABLE
vars:
- name: ansible_executable
default: /bin/sh
chroot_exe:
version_added: '2.8'
description:
- User specified chroot binary
ini:
- section: chroot_connection
key: exe
env:
- name: ANSIBLE_CHROOT_EXE
vars:
- name: ansible_chroot_exe
default: chroot
"""
import os
import os.path
import subprocess
import traceback
from ansible.errors import AnsibleError
from ansible.module_utils.basic import is_executable
from ansible.module_utils.common.process import get_bin_path
from ansible.module_utils.six.moves import shlex_quote
from ansible.module_utils._text import to_bytes, to_native
from ansible.plugins.connection import ConnectionBase, BUFSIZE
from ansible.utils.display import Display
display = Display()
class Connection(ConnectionBase):
''' Local chroot based connections '''
transport = 'chroot'
has_pipelining = True
# su currently has an undiagnosed issue with calculating the file
# checksums (so copy, for instance, doesn't work right)
# Have to look into that before re-enabling this
has_tty = False
default_user = 'root'
def __init__(self, play_context, new_stdin, *args, **kwargs):
super(Connection, self).__init__(play_context, new_stdin, *args, **kwargs)
self.chroot = self._play_context.remote_addr
if os.geteuid() != 0:
raise AnsibleError("chroot connection requires running as root")
# we're running as root on the local system so do some
# trivial checks for ensuring 'host' is actually a chroot'able dir
if not os.path.isdir(self.chroot):
raise AnsibleError("%s is not a directory" % self.chroot)
chrootsh = os.path.join(self.chroot, 'bin/sh')
# Want to check for a usable bourne shell inside the chroot.
# is_executable() == True is sufficient. For symlinks it
# gets really complicated really fast. So we punt on finding that
# out. As long as it's a symlink we assume that it will work
if not (is_executable(chrootsh) or (os.path.lexists(chrootsh) and os.path.islink(chrootsh))):
raise AnsibleError("%s does not look like a chrootable dir (/bin/sh missing)" % self.chroot)
def _connect(self):
''' connect to the chroot '''
if os.path.isabs(self.get_option('chroot_exe')):
self.chroot_cmd = self.get_option('chroot_exe')
else:
try:
self.chroot_cmd = get_bin_path(self.get_option('chroot_exe'))
except ValueError as e:
raise AnsibleError(to_native(e))
super(Connection, self)._connect()
if not self._connected:
display.vvv("THIS IS A LOCAL CHROOT DIR", host=self.chroot)
self._connected = True
def _buffered_exec_command(self, cmd, stdin=subprocess.PIPE):
''' run a command on the chroot. This is only needed for implementing
put_file() get_file() so that we don't have to read the whole file
into memory.
compared to exec_command() it looses some niceties like being able to
return the process's exit code immediately.
'''
executable = self.get_option('executable')
local_cmd = [self.chroot_cmd, self.chroot, executable, '-c', cmd]
display.vvv("EXEC %s" % (local_cmd), host=self.chroot)
local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd]
p = subprocess.Popen(local_cmd, shell=False, stdin=stdin,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
return p
def exec_command(self, cmd, in_data=None, sudoable=False):
''' run a command on the chroot '''
super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable)
p = self._buffered_exec_command(cmd)
stdout, stderr = p.communicate(in_data)
return (p.returncode, stdout, stderr)
def _prefix_login_path(self, remote_path):
''' Make sure that we put files into a standard path
If a path is relative, then we need to choose where to put it.
ssh chooses $HOME but we aren't guaranteed that a home dir will
exist in any given chroot. So for now we're choosing "/" instead.
This also happens to be the former default.
Can revisit using $HOME instead if it's a problem
'''
if not remote_path.startswith(os.path.sep):
remote_path = os.path.join(os.path.sep, remote_path)
return os.path.normpath(remote_path)
def put_file(self, in_path, out_path):
''' transfer a file from local to chroot '''
super(Connection, self).put_file(in_path, out_path)
display.vvv("PUT %s TO %s" % (in_path, out_path), host=self.chroot)
out_path = shlex_quote(self._prefix_login_path(out_path))
try:
with open(to_bytes(in_path, errors='surrogate_or_strict'), 'rb') as in_file:
if not os.fstat(in_file.fileno()).st_size:
count = ' count=0'
else:
count = ''
try:
p = self._buffered_exec_command('dd of=%s bs=%s%s' % (out_path, BUFSIZE, count), stdin=in_file)
except OSError:
raise AnsibleError("chroot connection requires dd command in the chroot")
try:
stdout, stderr = p.communicate()
except Exception:
traceback.print_exc()
raise AnsibleError("failed to transfer file %s to %s" % (in_path, out_path))
if p.returncode != 0:
raise AnsibleError("failed to transfer file %s to %s:\n%s\n%s" % (in_path, out_path, stdout, stderr))
except IOError:
raise AnsibleError("file or module does not exist at: %s" % in_path)
def fetch_file(self, in_path, out_path):
''' fetch a file from chroot to local '''
super(Connection, self).fetch_file(in_path, out_path)
display.vvv("FETCH %s TO %s" % (in_path, out_path), host=self.chroot)
in_path = shlex_quote(self._prefix_login_path(in_path))
try:
p = self._buffered_exec_command('dd if=%s bs=%s' % (in_path, BUFSIZE))
except OSError:
raise AnsibleError("chroot connection requires dd command in the chroot")
with open(to_bytes(out_path, errors='surrogate_or_strict'), 'wb+') as out_file:
try:
chunk = p.stdout.read(BUFSIZE)
while chunk:
out_file.write(chunk)
chunk = p.stdout.read(BUFSIZE)
except Exception:
traceback.print_exc()
raise AnsibleError("failed to transfer file %s to %s" % (in_path, out_path))
stdout, stderr = p.communicate()
if p.returncode != 0:
raise AnsibleError("failed to transfer file %s to %s:\n%s\n%s" % (in_path, out_path, stdout, stderr))
def close(self):
''' terminate the connection; nothing to do here '''
super(Connection, self).close()
self._connected = False

View file

@ -1,302 +0,0 @@
# (c) 2015, Jonathan Davila <jonathan(at)davila.io>
# (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
DOCUMENTATION = """
lookup: hashi_vault
author: Jonathan Davila <jdavila(at)ansible.com>
version_added: "2.0"
short_description: retrieve secrets from HashiCorp's vault
requirements:
- hvac (python library)
description:
- retrieve secrets from HashiCorp's vault
notes:
- Due to a current limitation in the HVAC library there won't necessarily be an error if a bad endpoint is specified.
- As of Ansible 2.10, only the latest secret is returned when specifying a KV v2 path.
options:
secret:
description: query you are making.
required: True
token:
description: vault token.
env:
- name: VAULT_TOKEN
url:
description: URL to vault service.
env:
- name: VAULT_ADDR
default: 'http://127.0.0.1:8200'
username:
description: Authentication user name.
password:
description: Authentication password.
role_id:
description: Role id for a vault AppRole auth.
env:
- name: VAULT_ROLE_ID
secret_id:
description: Secret id for a vault AppRole auth.
env:
- name: VAULT_SECRET_ID
auth_method:
description:
- Authentication method to be used.
- C(userpass) is added in version 2.8.
env:
- name: VAULT_AUTH_METHOD
choices:
- userpass
- ldap
- approle
mount_point:
description: vault mount point, only required if you have a custom mount point.
default: ldap
ca_cert:
description: path to certificate to use for authentication.
aliases: [ cacert ]
validate_certs:
description: controls verification and validation of SSL certificates, mostly you only want to turn off with self signed ones.
type: boolean
default: True
namespace:
version_added: "2.8"
description: namespace where secrets reside. requires HVAC 0.7.0+ and Vault 0.11+.
"""
EXAMPLES = """
- debug:
msg: "{{ lookup('hashi_vault', 'secret=secret/hello:value token=c975b780-d1be-8016-866b-01d0f9b688a5 url=http://myvault:8200')}}"
- name: Return all secrets from a path
debug:
msg: "{{ lookup('hashi_vault', 'secret=secret/hello token=c975b780-d1be-8016-866b-01d0f9b688a5 url=http://myvault:8200')}}"
- name: Vault that requires authentication via LDAP
debug:
msg: "{{ lookup('hashi_vault', 'secret=secret/hello:value auth_method=ldap mount_point=ldap username=myuser password=mypas url=http://myvault:8200')}}"
- name: Vault that requires authentication via username and password
debug:
msg: "{{ lookup('hashi_vault', 'secret=secret/hello:value auth_method=userpass username=myuser password=mypas url=http://myvault:8200')}}"
- name: Using an ssl vault
debug:
msg: "{{ lookup('hashi_vault', 'secret=secret/hola:value token=c975b780-d1be-8016-866b-01d0f9b688a5 url=https://myvault:8200 validate_certs=False')}}"
- name: using certificate auth
debug:
msg: "{{ lookup('hashi_vault', 'secret=secret/hi:value token=xxxx-xxx-xxx url=https://myvault:8200 validate_certs=True cacert=/cacert/path/ca.pem')}}"
- name: authenticate with a Vault app role
debug:
msg: "{{ lookup('hashi_vault', 'secret=secret/hello:value auth_method=approle role_id=myroleid secret_id=mysecretid url=http://myvault:8200')}}"
- name: Return all secrets from a path in a namespace
debug:
msg: "{{ lookup('hashi_vault', 'secret=secret/hello token=c975b780-d1be-8016-866b-01d0f9b688a5 url=http://myvault:8200 namespace=teama/admins')}}"
# When using KV v2 the PATH should include "data" between the secret engine mount and path (e.g. "secret/data/:path")
# see: https://www.vaultproject.io/api/secret/kv/kv-v2.html#read-secret-version
- name: Return latest KV v2 secret from path
debug:
msg: "{{ lookup('hashi_vault', 'secret=secret/data/hello token=my_vault_token url=http://myvault_url:8200') }}"
"""
RETURN = """
_raw:
description:
- secrets(s) requested
"""
import os
from ansible.errors import AnsibleError
from ansible.module_utils.parsing.convert_bool import boolean
from ansible.plugins.lookup import LookupBase
HAS_HVAC = False
try:
import hvac
HAS_HVAC = True
except ImportError:
HAS_HVAC = False
ANSIBLE_HASHI_VAULT_ADDR = 'http://127.0.0.1:8200'
if os.getenv('VAULT_ADDR') is not None:
ANSIBLE_HASHI_VAULT_ADDR = os.environ['VAULT_ADDR']
class HashiVault:
def __init__(self, **kwargs):
self.url = kwargs.get('url', ANSIBLE_HASHI_VAULT_ADDR)
self.namespace = kwargs.get('namespace', None)
self.avail_auth_method = ['approle', 'userpass', 'ldap']
# split secret arg, which has format 'secret/hello:value' into secret='secret/hello' and secret_field='value'
s = kwargs.get('secret')
if s is None:
raise AnsibleError("No secret specified for hashi_vault lookup")
s_f = s.rsplit(':', 1)
self.secret = s_f[0]
if len(s_f) >= 2:
self.secret_field = s_f[1]
else:
self.secret_field = ''
self.verify = self.boolean_or_cacert(kwargs.get('validate_certs', True), kwargs.get('cacert', ''))
# If a particular backend is asked for (and its method exists) we call it, otherwise drop through to using
# token auth. This means if a particular auth backend is requested and a token is also given, then we
# ignore the token and attempt authentication against the specified backend.
#
# to enable a new auth backend, simply add a new 'def auth_<type>' method below.
#
self.auth_method = kwargs.get('auth_method', os.environ.get('VAULT_AUTH_METHOD'))
self.verify = self.boolean_or_cacert(kwargs.get('validate_certs', True), kwargs.get('cacert', ''))
if self.auth_method and self.auth_method != 'token':
try:
if self.namespace is not None:
self.client = hvac.Client(url=self.url, verify=self.verify, namespace=self.namespace)
else:
self.client = hvac.Client(url=self.url, verify=self.verify)
# prefixing with auth_ to limit which methods can be accessed
getattr(self, 'auth_' + self.auth_method)(**kwargs)
except AttributeError:
raise AnsibleError("Authentication method '%s' not supported."
" Available options are %r" % (self.auth_method, self.avail_auth_method))
else:
self.token = kwargs.get('token', os.environ.get('VAULT_TOKEN', None))
if self.token is None and os.environ.get('HOME'):
token_filename = os.path.join(
os.environ.get('HOME'),
'.vault-token'
)
if os.path.exists(token_filename):
with open(token_filename) as token_file:
self.token = token_file.read().strip()
if self.token is None:
raise AnsibleError("No Vault Token specified")
if self.namespace is not None:
self.client = hvac.Client(url=self.url, token=self.token, verify=self.verify, namespace=self.namespace)
else:
self.client = hvac.Client(url=self.url, token=self.token, verify=self.verify)
if not self.client.is_authenticated():
raise AnsibleError("Invalid Hashicorp Vault Token Specified for hashi_vault lookup")
def get(self):
data = self.client.read(self.secret)
# Check response for KV v2 fields and flatten nested secret data.
#
# https://vaultproject.io/api/secret/kv/kv-v2.html#sample-response-1
try:
# sentinel field checks
check_dd = data['data']['data']
check_md = data['data']['metadata']
# unwrap nested data
data = data['data']
except KeyError:
pass
if data is None:
raise AnsibleError("The secret %s doesn't seem to exist for hashi_vault lookup" % self.secret)
if self.secret_field == '':
return data['data']
if self.secret_field not in data['data']:
raise AnsibleError("The secret %s does not contain the field '%s'. for hashi_vault lookup" % (self.secret, self.secret_field))
return data['data'][self.secret_field]
def check_params(self, **kwargs):
username = kwargs.get('username')
if username is None:
raise AnsibleError("Authentication method %s requires a username" % self.auth_method)
password = kwargs.get('password')
if password is None:
raise AnsibleError("Authentication method %s requires a password" % self.auth_method)
mount_point = kwargs.get('mount_point')
return username, password, mount_point
def auth_userpass(self, **kwargs):
username, password, mount_point = self.check_params(**kwargs)
if mount_point is None:
mount_point = 'userpass'
self.client.auth_userpass(username, password, mount_point=mount_point)
def auth_ldap(self, **kwargs):
username, password, mount_point = self.check_params(**kwargs)
if mount_point is None:
mount_point = 'ldap'
self.client.auth.ldap.login(username, password, mount_point=mount_point)
def boolean_or_cacert(self, validate_certs, cacert):
validate_certs = boolean(validate_certs, strict=False)
'''' return a bool or cacert '''
if validate_certs is True:
if cacert != '':
return cacert
else:
return True
else:
return False
def auth_approle(self, **kwargs):
role_id = kwargs.get('role_id', os.environ.get('VAULT_ROLE_ID', None))
if role_id is None:
raise AnsibleError("Authentication method app role requires a role_id")
secret_id = kwargs.get('secret_id', os.environ.get('VAULT_SECRET_ID', None))
if secret_id is None:
raise AnsibleError("Authentication method app role requires a secret_id")
self.client.auth_approle(role_id, secret_id)
class LookupModule(LookupBase):
def run(self, terms, variables=None, **kwargs):
if not HAS_HVAC:
raise AnsibleError("Please pip install hvac to use the hashi_vault lookup module.")
vault_args = terms[0].split()
vault_dict = {}
ret = []
for param in vault_args:
try:
key, value = param.split('=')
except ValueError:
raise AnsibleError("hashi_vault lookup plugin needs key=value pairs, but received %s" % terms)
vault_dict[key] = value
if 'ca_cert' in vault_dict.keys():
vault_dict['cacert'] = vault_dict['ca_cert']
vault_dict.pop('ca_cert', None)
vault_conn = HashiVault(**vault_dict)
for term in terms:
key = term.split()[0]
value = vault_conn.get()
ret.append(value)
return ret

View file

@ -1,266 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2012, Derek Carter<goozbach@friocorte.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['stableinterface'],
'supported_by': 'core'
}
DOCUMENTATION = r'''
---
module: selinux
short_description: Change policy and state of SELinux
description:
- Configures the SELinux mode and policy.
- A reboot may be required after usage.
- Ansible will not issue this reboot but will let you know when it is required.
version_added: "0.7"
options:
policy:
description:
- The name of the SELinux policy to use (e.g. C(targeted)) will be required if state is not C(disabled).
state:
description:
- The SELinux mode.
required: true
choices: [ disabled, enforcing, permissive ]
configfile:
description:
- The path to the SELinux configuration file, if non-standard.
default: /etc/selinux/config
aliases: [ conf, file ]
requirements: [ libselinux-python ]
author:
- Derek Carter (@goozbach) <goozbach@friocorte.com>
'''
EXAMPLES = r'''
- name: Enable SELinux
selinux:
policy: targeted
state: enforcing
- name: Put SELinux in permissive mode, logging actions that would be blocked.
selinux:
policy: targeted
state: permissive
- name: Disable SELinux
selinux:
state: disabled
'''
RETURN = r'''
msg:
description: Messages that describe changes that were made.
returned: always
type: str
sample: Config SELinux state changed from 'disabled' to 'permissive'
configfile:
description: Path to SELinux configuration file.
returned: always
type: str
sample: /etc/selinux/config
policy:
description: Name of the SELinux policy.
returned: always
type: str
sample: targeted
state:
description: SELinux mode.
returned: always
type: str
sample: enforcing
reboot_required:
description: Whether or not an reboot is required for the changes to take effect.
returned: always
type: bool
sample: true
'''
import os
import re
import tempfile
import traceback
SELINUX_IMP_ERR = None
try:
import selinux
HAS_SELINUX = True
except ImportError:
SELINUX_IMP_ERR = traceback.format_exc()
HAS_SELINUX = False
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils.facts.utils import get_file_lines
# getter subroutines
def get_config_state(configfile):
lines = get_file_lines(configfile, strip=False)
for line in lines:
stateline = re.match(r'^SELINUX=.*$', line)
if stateline:
return line.split('=')[1].strip()
def get_config_policy(configfile):
lines = get_file_lines(configfile, strip=False)
for line in lines:
stateline = re.match(r'^SELINUXTYPE=.*$', line)
if stateline:
return line.split('=')[1].strip()
# setter subroutines
def set_config_state(module, state, configfile):
# SELINUX=permissive
# edit config file with state value
stateline = 'SELINUX=%s' % state
lines = get_file_lines(configfile, strip=False)
tmpfd, tmpfile = tempfile.mkstemp()
with open(tmpfile, "w") as write_file:
for line in lines:
write_file.write(re.sub(r'^SELINUX=.*', stateline, line) + '\n')
module.atomic_move(tmpfile, configfile)
def set_state(module, state):
if state == 'enforcing':
selinux.security_setenforce(1)
elif state == 'permissive':
selinux.security_setenforce(0)
elif state == 'disabled':
pass
else:
msg = 'trying to set invalid runtime state %s' % state
module.fail_json(msg=msg)
def set_config_policy(module, policy, configfile):
if not os.path.exists('/etc/selinux/%s/policy' % policy):
module.fail_json(msg='Policy %s does not exist in /etc/selinux/' % policy)
# edit config file with state value
# SELINUXTYPE=targeted
policyline = 'SELINUXTYPE=%s' % policy
lines = get_file_lines(configfile, strip=False)
tmpfd, tmpfile = tempfile.mkstemp()
with open(tmpfile, "w") as write_file:
for line in lines:
write_file.write(re.sub(r'^SELINUXTYPE=.*', policyline, line) + '\n')
module.atomic_move(tmpfile, configfile)
def main():
module = AnsibleModule(
argument_spec=dict(
policy=dict(type='str'),
state=dict(type='str', required='True', choices=['enforcing', 'permissive', 'disabled']),
configfile=dict(type='str', default='/etc/selinux/config', aliases=['conf', 'file']),
),
supports_check_mode=True,
)
if not HAS_SELINUX:
module.fail_json(msg=missing_required_lib('libselinux-python'), exception=SELINUX_IMP_ERR)
# global vars
changed = False
msgs = []
configfile = module.params['configfile']
policy = module.params['policy']
state = module.params['state']
runtime_enabled = selinux.is_selinux_enabled()
runtime_policy = selinux.selinux_getpolicytype()[1]
runtime_state = 'disabled'
reboot_required = False
if runtime_enabled:
# enabled means 'enforcing' or 'permissive'
if selinux.security_getenforce():
runtime_state = 'enforcing'
else:
runtime_state = 'permissive'
if not os.path.isfile(configfile):
module.fail_json(msg="Unable to find file {0}".format(configfile),
details="Please install SELinux-policy package, "
"if this package is not installed previously.")
config_policy = get_config_policy(configfile)
config_state = get_config_state(configfile)
# check to see if policy is set if state is not 'disabled'
if state != 'disabled':
if not policy:
module.fail_json(msg="Policy is required if state is not 'disabled'")
else:
if not policy:
policy = config_policy
# check changed values and run changes
if policy != runtime_policy:
if module.check_mode:
module.exit_json(changed=True)
# cannot change runtime policy
msgs.append("Running SELinux policy changed from '%s' to '%s'" % (runtime_policy, policy))
changed = True
if policy != config_policy:
if module.check_mode:
module.exit_json(changed=True)
set_config_policy(module, policy, configfile)
msgs.append("SELinux policy configuration in '%s' changed from '%s' to '%s'" % (configfile, config_policy, policy))
changed = True
if state != runtime_state:
if runtime_enabled:
if state == 'disabled':
if runtime_state != 'permissive':
# Temporarily set state to permissive
if not module.check_mode:
set_state(module, 'permissive')
module.warn("SELinux state temporarily changed from '%s' to 'permissive'. State change will take effect next reboot." % (runtime_state))
changed = True
else:
module.warn('SELinux state change will take effect next reboot')
reboot_required = True
else:
if not module.check_mode:
set_state(module, state)
msgs.append("SELinux state changed from '%s' to '%s'" % (runtime_state, state))
# Only report changes if the file is changed.
# This prevents the task from reporting changes every time the task is run.
changed = True
else:
module.warn("Reboot is required to set SELinux state to '%s'" % state)
reboot_required = True
if state != config_state:
if not module.check_mode:
set_config_state(module, state, configfile)
msgs.append("Config SELinux state changed from '%s' to '%s'" % (config_state, state))
changed = True
module.exit_json(changed=changed, msg=', '.join(msgs), configfile=configfile, policy=policy, state=state, reboot_required=reboot_required)
if __name__ == '__main__':
main()

View file

@ -1,257 +0,0 @@
#!powershell
# Copyright: (c) 2018, Micah Hunsberger (@mhunsber)
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#AnsibleRequires -CSharpUtil Ansible.Basic
Set-StrictMode -Version 2
$ErrorActionPreference = "Stop"
$spec = @{
options = @{
state = @{ type = "str"; choices = "absent", "present"; default = "present" }
aliases = @{ type = "list"; elements = "str" }
canonical_name = @{ type = "str" }
ip_address = @{ type = "str" }
action = @{ type = "str"; choices = "add", "remove", "set"; default = "set" }
}
required_if = @(,@( "state", "present", @("canonical_name", "ip_address")))
supports_check_mode = $true
}
$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)
$state = $module.Params.state
$aliases = $module.Params.aliases
$canonical_name = $module.Params.canonical_name
$ip_address = $module.Params.ip_address
$action = $module.Params.action
$tmp = [ipaddress]::None
if($ip_address -and -not [ipaddress]::TryParse($ip_address, [ref]$tmp)){
$module.FailJson("win_hosts: Argument ip_address needs to be a valid ip address, but was $ip_address")
}
$ip_address_type = $tmp.AddressFamily
$hosts_file = Get-Item -LiteralPath "$env:SystemRoot\System32\drivers\etc\hosts"
Function Get-CommentIndex($line) {
$c_index = $line.IndexOf('#')
if($c_index -lt 0) {
$c_index = $line.Length
}
return $c_index
}
Function Get-HostEntryParts($line) {
$success = $true
$c_index = Get-CommentIndex -line $line
$pure_line = $line.Substring(0,$c_index).Trim()
$bits = $pure_line -split "\s+"
if($bits.Length -lt 2){
return @{
success = $false
ip_address = ""
ip_type = ""
canonical_name = ""
aliases = @()
}
}
$ip_obj = [ipaddress]::None
if(-not [ipaddress]::TryParse($bits[0], [ref]$ip_obj) ){
$success = $false
}
$cname = $bits[1]
$als = New-Object string[] ($bits.Length - 2)
[array]::Copy($bits, 2, $als, 0, $als.Length)
return @{
success = $success
ip_address = $ip_obj.IPAddressToString
ip_type = $ip_obj.AddressFamily
canonical_name = $cname
aliases = $als
}
}
Function Find-HostName($line, $name) {
$c_idx = Get-CommentIndex -line $line
$re = New-Object regex ("\s+$($name.Replace('.',"\."))(\s|$)", [System.Text.RegularExpressions.RegexOptions]::IgnoreCase)
$match = $re.Match($line, 0, $c_idx)
return $match
}
Function Remove-HostEntry($list, $idx) {
$module.Result.changed = $true
$list.RemoveAt($idx)
}
Function Add-HostEntry($list, $cname, $aliases, $ip) {
$module.Result.changed = $true
$line = "$ip $cname $($aliases -join ' ')"
$list.Add($line) | Out-Null
}
Function Remove-HostnamesFromEntry($list, $idx, $aliases) {
$line = $list[$idx]
$line_removed = $false
foreach($name in $aliases){
$match = Find-HostName -line $line -name $name
if($match.Success){
$line = $line.Remove($match.Index + 1, $match.Length -1)
# was this the last alias? (check for space characters after trimming)
if($line.Substring(0,(Get-CommentIndex -line $line)).Trim() -inotmatch "\s") {
$list.RemoveAt($idx)
$line_removed = $true
# we're done
return @{
line_removed = $line_removed
}
}
}
}
if($line -ne $list[$idx]){
$module.Result.changed = $true
$list[$idx] = $line
}
return @{
line_removed = $line_removed
}
}
Function Add-AliasesToEntry($list, $idx, $aliases) {
$line = $list[$idx]
foreach($name in $aliases){
$match = Find-HostName -line $line -name $name
if(-not $match.Success) {
# just add the alias before the comment
$line = $line.Insert((Get-CommentIndex -line $line), " $name ")
}
}
if($line -ne $list[$idx]){
$module.Result.changed = $true
$list[$idx] = $line
}
}
$hosts_lines = New-Object System.Collections.ArrayList
Get-Content -LiteralPath $hosts_file.FullName | ForEach-Object { $hosts_lines.Add($_) } | Out-Null
$module.Diff.before = ($hosts_lines -join "`n") + "`n"
if ($state -eq 'absent') {
# go through and remove canonical_name and ip
for($idx = 0; $idx -lt $hosts_lines.Count; $idx++) {
$entry = $hosts_lines[$idx]
# skip comment lines
if(-not $entry.Trim().StartsWith('#')) {
$entry_parts = Get-HostEntryParts -line $entry
if($entry_parts.success) {
if(-not $ip_address -or $entry_parts.ip_address -eq $ip_address) {
if(-not $canonical_name -or $entry_parts.canonical_name -eq $canonical_name) {
if(Remove-HostEntry -list $hosts_lines -idx $idx){
# keep index correct if we removed the line
$idx = $idx - 1
}
}
}
}
}
}
}
if($state -eq 'present') {
$entry_idx = -1
$aliases_to_keep = @()
# go through lines, find the entry and determine what to remove based on action
for($idx = 0; $idx -lt $hosts_lines.Count; $idx++) {
$entry = $hosts_lines[$idx]
# skip comment lines
if(-not $entry.Trim().StartsWith('#')) {
$entry_parts = Get-HostEntryParts -line $entry
if($entry_parts.success) {
$aliases_to_remove = @()
if($entry_parts.ip_address -eq $ip_address) {
if($entry_parts.canonical_name -eq $canonical_name) {
$entry_idx = $idx
if($action -eq 'set') {
$aliases_to_remove = $entry_parts.aliases | Where-Object { $aliases -notcontains $_ }
} elseif($action -eq 'remove') {
$aliases_to_remove = $aliases
}
} else {
# this is the right ip_address, but not the cname we were looking for.
# we need to make sure none of aliases or canonical_name exist for this entry
# since the given canonical_name should be an A/AAAA record,
# and aliases should be cname records for the canonical_name.
$aliases_to_remove = $aliases + $canonical_name
}
} else {
# this is not the ip_address we are looking for
if ($ip_address_type -eq $entry_parts.ip_type) {
if ($entry_parts.canonical_name -eq $canonical_name) {
Remove-HostEntry -list $hosts_lines -idx $idx
$idx = $idx - 1
if ($action -ne "set") {
# keep old aliases intact
$aliases_to_keep += $entry_parts.aliases | Where-Object { ($aliases + $aliases_to_keep + $canonical_name) -notcontains $_ }
}
} elseif ($action -eq "remove") {
$aliases_to_remove = $canonical_name
} elseif ($aliases -contains $entry_parts.canonical_name) {
Remove-HostEntry -list $hosts_lines -idx $idx
$idx = $idx - 1
if ($action -eq "add") {
# keep old aliases intact
$aliases_to_keep += $entry_parts.aliases | Where-Object { ($aliases + $aliases_to_keep + $canonical_name) -notcontains $_ }
}
} else {
$aliases_to_remove = $aliases + $canonical_name
}
} else {
# TODO: Better ipv6 support. There is odd behavior for when an alias can be used for both ipv6 and ipv4
}
}
if($aliases_to_remove) {
if((Remove-HostnamesFromEntry -list $hosts_lines -idx $idx -aliases $aliases_to_remove).line_removed) {
$idx = $idx - 1
}
}
}
}
}
if($entry_idx -ge 0) {
$aliases_to_add = @()
$entry_parts = Get-HostEntryParts -line $hosts_lines[$entry_idx]
if($action -eq 'remove') {
$aliases_to_add = $aliases_to_keep | Where-Object { $entry_parts.aliases -notcontains $_ }
} else {
$aliases_to_add = ($aliases + $aliases_to_keep) | Where-Object { $entry_parts.aliases -notcontains $_ }
}
if($aliases_to_add) {
Add-AliasesToEntry -list $hosts_lines -idx $entry_idx -aliases $aliases_to_add
}
} else {
# add the entry at the end
if($action -eq 'remove') {
if($aliases_to_keep) {
Add-HostEntry -list $hosts_lines -ip $ip_address -cname $canonical_name -aliases $aliases_to_keep
} else {
Add-HostEntry -list $hosts_lines -ip $ip_address -cname $canonical_name
}
} else {
Add-HostEntry -list $hosts_lines -ip $ip_address -cname $canonical_name -aliases ($aliases + $aliases_to_keep)
}
}
}
$module.Diff.after = ($hosts_lines -join "`n") + "`n"
if( $module.Result.changed -and -not $module.CheckMode ) {
Set-Content -LiteralPath $hosts_file.FullName -Value $hosts_lines
}
$module.ExitJson()

View file

@ -1,126 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2018, Micah Hunsberger (@mhunsber)
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
# this is a windows documentation stub. actual code lives in the .ps1
# file of the same name
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = r'''
---
module: win_hosts
version_added: '2.8'
short_description: Manages hosts file entries on Windows.
description:
- Manages hosts file entries on Windows.
- Maps IPv4 or IPv6 addresses to canonical names.
- Adds, removes, or sets cname records for ip and hostname pairs.
- Modifies %windir%\\system32\\drivers\\etc\\hosts.
options:
state:
description:
- Whether the entry should be present or absent.
- If only I(canonical_name) is provided when C(state=absent), then
all hosts entries with the canonical name of I(canonical_name)
will be removed.
- If only I(ip_address) is provided when C(state=absent), then all
hosts entries with the ip address of I(ip_address) will be removed.
- If I(ip_address) and I(canonical_name) are both omitted when
C(state=absent), then all hosts entries will be removed.
choices:
- absent
- present
default: present
type: str
canonical_name:
description:
- A canonical name for the host entry.
- required for C(state=present).
type: str
ip_address:
description:
- The ip address for the host entry.
- Can be either IPv4 (A record) or IPv6 (AAAA record).
- Required for C(state=present).
type: str
aliases:
description:
- A list of additional names (cname records) for the host entry.
- Only applicable when C(state=present).
type: list
action:
choices:
- add
- remove
- set
description:
- Controls the behavior of I(aliases).
- Only applicable when C(state=present).
- If C(add), each alias in I(aliases) will be added to the host entry.
- If C(set), each alias in I(aliases) will be added to the host entry,
and other aliases will be removed from the entry.
default: set
type: str
author:
- Micah Hunsberger (@mhunsber)
notes:
- Each canonical name can only be mapped to one IPv4 and one IPv6 address.
If I(canonical_name) is provided with C(state=present) and is found
to be mapped to another IP address that is the same type as, but unique
from I(ip_address), then I(canonical_name) and all I(aliases) will
be removed from the entry and added to an entry with the provided IP address.
- Each alias can only be mapped to one canonical name. If I(aliases) is provided
with C(state=present) and an alias is found to be mapped to another canonical
name, then the alias will be removed from the entry and either added to or removed
from (depending on I(action)) an entry with the provided canonical name.
seealso:
- module: win_template
- module: win_file
- module: win_copy
'''
EXAMPLES = r'''
- name: Add 127.0.0.1 as an A record for localhost
win_hosts:
state: present
canonical_name: localhost
ip_address: 127.0.0.1
- name: Add ::1 as an AAAA record for localhost
win_hosts:
state: present
canonical_name: localhost
ip_address: '::1'
- name: Remove 'bar' and 'zed' from the list of aliases for foo (192.168.1.100)
win_hosts:
state: present
canoncial_name: foo
ip_address: 192.168.1.100
action: remove
aliases:
- bar
- zed
- name: Remove hosts entries with canonical name 'bar'
win_hosts:
state: absent
canonical_name: bar
- name: Remove 10.2.0.1 from the list of hosts
win_hosts:
state: absent
ip_address: 10.2.0.1
- name: Ensure all name resolution is handled by DNS
win_hosts:
state: absent
'''
RETURN = r'''
'''