new windows module, win_audit_rule (#30473)

* added win_audit_rule with integration test

* Updated integration testing to target files as well as directories
and registry keys. Split testing files apart to be more organized.

Updated powershell for better handling when targetting file objects
and optimized a bit. Removed duplicated sections that got there from a
previous merge I think.

* Decided to make all the fact names the same in integration testing.
Seemed like there would be less change of accidentally using the wrong
variable when copy/pasting that way, and not much upside to having
unique names.

Did final cleanup and fixed a few errors in the integration testing.

* Fixed a bug where results was displaying a wrong value

Fixed a bug where removal was failing if multiple rules existed due to
inheritance from higher level objects.

* Resolved issue with unhandled error when used didn't have permissions
for get-acl.

Changed from setauditrule to addauditrule, see comment in script for reasoning.

Fixed state absent to be able to remove multiple entries if they exist.

* fixed docs issue

* updated to fail if invalid inheritance_rule when defining a file rather than warn
This commit is contained in:
nwsparks 2017-10-19 21:20:33 -04:00 committed by Jordan Borean
commit 5cccad8ed4
9 changed files with 962 additions and 0 deletions

View file

@ -0,0 +1 @@
windows/ci/group3

View file

@ -0,0 +1,7 @@
test_audit_rule_folder: c:\windows\temp\{{ 'ansible test win_audit_policy' | to_uuid }}
test_audit_rule_file: c:\windows\temp\{{ 'ansible test win_audit_policy' | to_uuid }}.txt
test_audit_rule_registry: HKCU:\{{ 'ansible test win_audit_policy' | to_uuid }}
test_audit_rule_rights: 'delete'
test_audit_rule_new_rights: 'delete,changepermissions'
test_audit_rule_user: 'everyone'
test_audit_rule_audit_flags: success

View file

@ -0,0 +1,98 @@
#!powershell
# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#Requires -Module Ansible.ModuleUtils.Legacy.psm1
#Requires -Module Ansible.ModuleUtils.SID.psm1
$params = Parse-Args -arguments $args -supports_check_mode $true
# these are your module parameters
$path = Get-AnsibleParam -obj $params -name "path" -type "path" -failifempty $true -aliases "destination","dest"
$user = Get-AnsibleParam -obj $params -name "user" -type "str" -failifempty $true
$rights = Get-AnsibleParam -obj $params -name "rights" -type "list"
$inheritance_flags = Get-AnsibleParam -obj $params -name "inheritance_flags" -type "list" -default 'ContainerInherit','ObjectInherit' # -validateset 'None','ContainerInherit','ObjectInherit'
$propagation_flags = Get-AnsibleParam -obj $params -name "propagation_flags" -type "str" -default "none" -ValidateSet 'InheritOnly','None','NoPropagateInherit'
$audit_flags = Get-AnsibleParam -obj $params -name "audit_flags" -type "list" -default "success" #-ValidateSet 'Success','Failure'
#$state = Get-AnsibleParam -obj $params -name "state" -type "str" -default "present" -validateset 'present','absent'
If (! (Test-Path $path) )
{
Fail-Json $result "Path not found ($path)"
}
Function Get-CurrentAuditRules ($path) {
$ACL = Get-Acl -Path $path -Audit
$HT = Foreach ($Obj in $ACL.Audit)
{
@{
user = $Obj.IdentityReference.ToString()
rights = ($Obj | Select-Object -expand "*rights").ToString()
audit_flags = $Obj.AuditFlags.ToString()
is_inherited = $Obj.InheritanceFlags.ToString()
inheritance_flags = $Obj.IsInherited.ToString()
propagation_flags = $Obj.PropagationFlags.ToString()
}
}
If (-Not $HT)
{
"No audit rules defined on $path"
}
Else {$HT}
}
$result = @{
changed = $false
matching_rule_found = $false
current_audit_rules = Get-CurrentAuditRules $path
}
$ACL = Get-ACL $Path -Audit
$SID = Convert-ToSid $user
$ItemType = (Get-Item $path).GetType()
switch ($ItemType)
{
([Microsoft.Win32.RegistryKey]) {
$rights = [System.Security.AccessControl.RegistryRights]$rights
$result.path_type = 'registry'
}
([System.IO.FileInfo]) {
$rights = [System.Security.AccessControl.FileSystemRights]$rights
$result.path_type = 'file'
}
([System.IO.DirectoryInfo]) {
$rights = [System.Security.AccessControl.FileSystemRights]$rights
$result.path_type = 'directory'
}
}
$flags = [System.Security.AccessControl.AuditFlags]$audit_flags
$inherit = [System.Security.AccessControl.InheritanceFlags]$inheritance_flags
$prop = [System.Security.AccessControl.PropagationFlags]$propagation_flags
Foreach ($group in $ACL.Audit)
{
#exit here if any existing rule matches defined rule, otherwise exit below
#with no matches
If (
($group | select -expand "*Rights") -eq $rights -and
$group.AuditFlags -eq $flags -and
$group.IdentityReference.Translate([System.Security.Principal.SecurityIdentifier]) -eq $SID -and
$group.InheritanceFlags -eq $inherit -and
$group.PropagationFlags -eq $prop
)
{
$result.matching_rule_found = $true
$result.current_audit_rules = Get-CurrentAuditRules $path
Exit-Json $result
}
}
$result.current_audit_rules = Get-CurrentAuditRules $path
Exit-Json $result

View file

@ -0,0 +1,172 @@
######################
### check mode add ###
######################
- name: check mode ADD audit policy directory
win_audit_rule:
path: "{{ test_audit_rule_folder }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_rights }}"
state: present
audit_flags: "{{ test_audit_rule_audit_flags }}"
register: directory
check_mode: yes
- name: check mode ADD audit policy file
win_audit_rule:
path: "{{ test_audit_rule_file }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_rights }}"
state: present
audit_flags: "{{ test_audit_rule_audit_flags }}"
inheritance_flags: none
register: file
check_mode: yes
- name: check mode ADD audit policy registry
win_audit_rule:
path: "{{ test_audit_rule_registry }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_rights }}"
state: present
audit_flags: "{{ test_audit_rule_audit_flags }}"
register: registry
check_mode: yes
- name: check mode ADD get directory results
test_get_audit_rule:
path: "{{ test_audit_rule_folder }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_rights }}"
audit_flags: "{{ test_audit_rule_audit_flags }}"
register: directory_results
- name: check mode ADD get file results
test_get_audit_rule:
path: "{{ test_audit_rule_file }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_rights }}"
audit_flags: "{{ test_audit_rule_audit_flags }}"
inheritance_flags: none
register: file_results
- name: check mode ADD get REGISTRY results
test_get_audit_rule:
path: "{{ test_audit_rule_registry }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_rights }}"
audit_flags: "{{ test_audit_rule_audit_flags }}"
register: registry_results
- name: check mode ADD assert that a change is needed, but no change occurred to the audit rules
assert:
that:
- directory | changed
- file | changed
- registry | changed
- not directory_results.matching_rule_found and directory_results.path_type == 'directory'
- not file_results.matching_rule_found and file_results.path_type == 'file'
- not registry_results.matching_rule_found and registry_results.path_type == 'registry'
##################
### add a rule ###
##################
- name: ADD audit policy directory
win_audit_rule:
path: "{{ test_audit_rule_folder }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_rights }}"
state: present
audit_flags: "{{ test_audit_rule_audit_flags }}"
register: directory
- name: ADD audit policy file
win_audit_rule:
path: "{{ test_audit_rule_file }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_rights }}"
state: present
audit_flags: "{{ test_audit_rule_audit_flags }}"
inheritance_flags: none
register: file
- name: ADD audit policy registry
win_audit_rule:
path: "{{ test_audit_rule_registry }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_rights }}"
state: present
audit_flags: "{{ test_audit_rule_audit_flags }}"
register: registry
- name: ADD get directory results
test_get_audit_rule:
path: "{{ test_audit_rule_folder }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_rights }}"
audit_flags: "{{ test_audit_rule_audit_flags }}"
register: directory_results
- name: ADD get file results
test_get_audit_rule:
path: "{{ test_audit_rule_file }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_rights }}"
audit_flags: "{{ test_audit_rule_audit_flags }}"
inheritance_flags: none
register: file_results
- name: ADD get REGISTRY results
test_get_audit_rule:
path: "{{ test_audit_rule_registry }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_rights }}"
audit_flags: "{{ test_audit_rule_audit_flags }}"
register: registry_results
- name: ADD assert that the rules were added and a change is detected
assert:
that:
- directory | changed
- file | changed
- registry | changed
- directory_results.matching_rule_found and directory_results.path_type == 'directory'
- file_results.matching_rule_found and file_results.path_type == 'file'
- registry_results.matching_rule_found and registry_results.path_type == 'registry'
#############################
### idempotent add a rule ###
#############################
- name: idempotent ADD audit policy directory
win_audit_rule:
path: "{{ test_audit_rule_folder }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_rights }}"
state: present
audit_flags: "{{ test_audit_rule_audit_flags }}"
register: directory
- name: idempotent ADD audit policy file
win_audit_rule:
path: "{{ test_audit_rule_file }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_rights }}"
state: present
audit_flags: "{{ test_audit_rule_audit_flags }}"
inheritance_flags: none
register: file
- name: idempotent ADD audit policy registry idempotent
win_audit_rule:
path: "{{ test_audit_rule_registry }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_rights }}"
state: present
audit_flags: "{{ test_audit_rule_audit_flags }}"
register: registry
- name: idempotent ADD assert that a change did not occur
assert:
that:
- not directory | changed and directory.path_type == 'directory'
- not file | changed and file.path_type == 'file'
- not registry | changed and registry.path_type == 'registry'

View file

@ -0,0 +1,33 @@
- name: create temporary folder to test with
win_file:
path: "{{ test_audit_rule_folder }}"
state: directory
- name: create temporary file to test with
win_file:
path: "{{ test_audit_rule_file }}"
state: touch
- name: create temporary registry key to test with
win_regedit:
path: "{{ test_audit_rule_registry }}"
- block:
- include_tasks: add.yml
- include_tasks: modify.yml
- include_tasks: remove.yml
always:
- name: remove testing folder
win_file:
path: "{{ test_audit_rule_folder }}"
state: absent
- name: remove testing file
win_file:
path: "{{ test_audit_rule_file }}"
state: absent
- name: remove registry key
win_regedit:
path: "{{ test_audit_rule_registry }}"
state: absent

View file

@ -0,0 +1,172 @@
#########################
### modify check mode ###
#########################
- name: check mode modify audit policy directory
win_audit_rule:
path: "{{ test_audit_rule_folder }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_new_rights }}"
state: present
audit_flags: "{{ test_audit_rule_audit_flags }}"
register: directory
check_mode: yes
- name: check mode modify audit policy file
win_audit_rule:
path: "{{ test_audit_rule_file }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_new_rights }}"
state: present
audit_flags: "{{ test_audit_rule_audit_flags }}"
inheritance_flags: none
register: file
check_mode: yes
- name: check mode modify audit policy registry
win_audit_rule:
path: "{{ test_audit_rule_registry }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_new_rights }}"
state: present
audit_flags: "{{ test_audit_rule_audit_flags }}"
register: registry
check_mode: yes
- name: check mode modify get directory rule results
test_get_audit_rule:
path: "{{ test_audit_rule_folder }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_new_rights }}"
audit_flags: "{{ test_audit_rule_audit_flags }}"
register: directory_results
- name: check mode modify get file rule results
test_get_audit_rule:
path: "{{ test_audit_rule_file }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_new_rights }}"
audit_flags: "{{ test_audit_rule_audit_flags }}"
inheritance_flags: none
register: file_results
- name: check mode modify get REGISTRY rule results
test_get_audit_rule:
path: "{{ test_audit_rule_registry }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_new_rights }}"
audit_flags: "{{ test_audit_rule_audit_flags }}"
register: registry_results
- name: check mode modify assert that change is needed but rights still equal the original rights and not test_audit_rule_new_rights
assert:
that:
- directory | changed
- file | changed
- registry | changed
- not directory_results.matching_rule_found and directory_results.path_type == 'directory'
- not file_results.matching_rule_found and file_results.path_type == 'file'
- not registry_results.matching_rule_found and registry_results.path_type == 'registry'
##############
### modify ###
##############
- name: modify audit policy directory
win_audit_rule:
path: "{{ test_audit_rule_folder }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_new_rights }}"
state: present
audit_flags: "{{ test_audit_rule_audit_flags }}"
register: directory
- name: modify audit policy file
win_audit_rule:
path: "{{ test_audit_rule_file }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_new_rights }}"
state: present
audit_flags: "{{ test_audit_rule_audit_flags }}"
inheritance_flags: none
register: file
- name: modify audit policy registry
win_audit_rule:
path: "{{ test_audit_rule_registry }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_new_rights }}"
state: present
audit_flags: "{{ test_audit_rule_audit_flags }}"
register: registry
- name: modify get directory rule results
test_get_audit_rule:
path: "{{ test_audit_rule_folder }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_new_rights }}"
audit_flags: "{{ test_audit_rule_audit_flags }}"
register: directory_results
- name: modify get file rule results
test_get_audit_rule:
path: "{{ test_audit_rule_file }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_new_rights }}"
audit_flags: "{{ test_audit_rule_audit_flags }}"
inheritance_flags: none
register: file_results
- name: modify get REGISTRY rule results
test_get_audit_rule:
path: "{{ test_audit_rule_registry }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_new_rights }}"
audit_flags: "{{ test_audit_rule_audit_flags }}"
register: registry_results
- name: modify assert that the rules were modified and a change is detected
assert:
that:
- directory | changed
- file | changed
- registry | changed
- directory_results.matching_rule_found and directory_results.path_type == 'directory'
- file_results.matching_rule_found and file_results.path_type == 'file'
- registry_results.matching_rule_found and registry_results.path_type == 'registry'
#####################################
### idempotent test modify a rule ###
#####################################
- name: idempotent modify audit policy directory
win_audit_rule:
path: "{{ test_audit_rule_folder }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_new_rights }}"
state: present
audit_flags: "{{ test_audit_rule_audit_flags }}"
register: directory
- name: idempotent modify audit policy file
win_audit_rule:
path: "{{ test_audit_rule_file }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_new_rights }}"
state: present
audit_flags: "{{ test_audit_rule_audit_flags }}"
inheritance_flags: none
register: file
- name: idempotent modify audit policy registry
win_audit_rule:
path: "{{ test_audit_rule_registry }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_new_rights }}"
state: present
audit_flags: "{{ test_audit_rule_audit_flags }}"
register: registry
- name: idempotent modify assert that and a change is not detected
assert:
that:
- not directory | changed and directory.path_type == 'directory'
- not file | changed and file.path_type == 'file'
- not registry | changed and registry.path_type == 'registry'

View file

@ -0,0 +1,151 @@
################################
### check mode remove a rule ###
################################
- name: check mode remove directory rule
win_audit_rule:
path: "{{ test_audit_rule_folder }}"
user: "{{ test_audit_rule_user }}"
state: absent
register: directory
check_mode: yes
- name: check mode remove file rule
win_audit_rule:
path: "{{ test_audit_rule_file }}"
user: "{{ test_audit_rule_user }}"
state: absent
register: file
check_mode: yes
- name: check mode remove registry rule
win_audit_rule:
path: "{{ test_audit_rule_registry }}"
user: "{{ test_audit_rule_user }}"
state: absent
register: registry
check_mode: yes
- name: check mode remove get directory rule results
test_get_audit_rule:
path: "{{ test_audit_rule_folder }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_new_rights }}"
audit_flags: "{{ test_audit_rule_audit_flags }}"
register: directory_results
- name: check mode remove get file rule results
test_get_audit_rule:
path: "{{ test_audit_rule_file }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_new_rights }}"
audit_flags: "{{ test_audit_rule_audit_flags }}"
inheritance_flags: none
register: file_results
- name: check mode remove get REGISTRY rule results
test_get_audit_rule:
path: "{{ test_audit_rule_registry }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_new_rights }}"
audit_flags: "{{ test_audit_rule_audit_flags }}"
register: registry_results
- name: check mode remove assert that change detected, but rule is still present
assert:
that:
- directory | changed
- file | changed
- registry | changed
- directory_results.matching_rule_found and directory_results.path_type == 'directory'
- file_results.matching_rule_found and file_results.path_type == 'file'
- registry_results.matching_rule_found and registry_results.path_type == 'registry'
#####################
### remove a rule ###
#####################
- name: remove directory rule
win_audit_rule:
path: "{{ test_audit_rule_folder }}"
user: "{{ test_audit_rule_user }}"
state: absent
register: directory
- name: remove file rule
win_audit_rule:
path: "{{ test_audit_rule_file }}"
user: "{{ test_audit_rule_user }}"
state: absent
register: file
- name: remove registry rule
win_audit_rule:
path: "{{ test_audit_rule_registry }}"
user: "{{ test_audit_rule_user }}"
state: absent
register: registry
- name: remove get directory rule results
test_get_audit_rule:
path: "{{ test_audit_rule_folder }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_new_rights }}"
audit_flags: "{{ test_audit_rule_audit_flags }}"
register: directory_results
- name: remove get file rule results
test_get_audit_rule:
path: "{{ test_audit_rule_file }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_new_rights }}"
audit_flags: "{{ test_audit_rule_audit_flags }}"
inheritance_flags: none
register: file_results
- name: remove get REGISTRY rule results
test_get_audit_rule:
path: "{{ test_audit_rule_registry }}"
user: "{{ test_audit_rule_user }}"
rights: "{{ test_audit_rule_new_rights }}"
audit_flags: "{{ test_audit_rule_audit_flags }}"
register: registry_results
- name: remove assert that change detected and rule is gone
assert:
that:
- directory | changed
- file | changed
- registry | changed
- not directory_results.matching_rule_found and directory_results.path_type == 'directory'
- not file_results.matching_rule_found and file_results.path_type == 'file'
- not registry_results.matching_rule_found and registry_results.path_type == 'registry'
################################
### idempotent remove a rule ###
################################
- name: idempotent remove directory rule
win_audit_rule:
path: "{{ test_audit_rule_folder }}"
user: "{{ test_audit_rule_user }}"
state: absent
register: directory
- name: idempotent remove file rule
win_audit_rule:
path: "{{ test_audit_rule_file }}"
user: "{{ test_audit_rule_user }}"
state: absent
register: file
- name: idempotent remove registry rule
win_audit_rule:
path: "{{ test_audit_rule_registry }}"
user: "{{ test_audit_rule_user }}"
state: absent
register: registry
- name: idempotent remove assert that no change detected
assert:
that:
- not directory | changed and directory.path_type == 'directory'
- not file | changed and file.path_type == 'file'
- not registry | changed and registry.path_type == 'registry'