Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: Manage Windows Local Security Policy Settings #21485

Closed
lorengordon opened this issue Mar 10, 2015 · 63 comments
Closed

Feature Request: Manage Windows Local Security Policy Settings #21485

lorengordon opened this issue Mar 10, 2015 · 63 comments
Labels
Feature new functionality including changes to functionality and code refactors, etc. Platform Relates to OS, containers, platform-based utilities like FS, system based apps Windows
Milestone

Comments

@lorengordon
Copy link
Contributor

I would like to see salt implement a module and a state to manage local security policy objects. I know salt can manage Windows registry settings, but that can be overridden when the local security policy refreshes (which in turn can be overridden by group policy, but that's a feature of Active Directory Domain Services; I'm only referring to the local policy feature). A wrapper around secedit.exe would probably be sufficient. (I don't think there is another mechanism to programatically interface with the local security policy.)

I haven't seen this capability in many configuration management tools, though Puppet seems to have modules for it now. It's interesting that they use the plain English description from the GUI to specify a configuration setting, rather than the name used in the INF for the configuration setting (i.e. 'Password must meet complexity requirements' vs 'PasswordComplexity'). This is a little friendlier for admins and makes it easier for them to find the right syntax. It can be a rather convoluted process to figure out the corresponding INF setting just from what's displayed in the gpedit.msc GUI, so this is rather convenient... I'm betting the Puppet module has a hard-coded lookup table that does the translation. It should be noted that Microsoft has a habit of changing the description in the GUI between versions, which may cause confusion over time with that approach. Personally, I'd like to be able to specify a setting either way.

A Microsoft programmer has also written a wrapper around secedit.exe, called Apply_LGPO_Delta.exe, and they provide the source. It might be useful to study their approach.

@ssgward ssgward added this to the Approved milestone Mar 10, 2015
@ssgward ssgward added Feature new functionality including changes to functionality and code refactors, etc. Windows labels Mar 10, 2015
@ssgward
Copy link

ssgward commented Mar 10, 2015

Great idea.

@eliasp
Copy link
Contributor

eliasp commented Apr 6, 2015

Was thinking about something like this for quite a while - thanks for providing these great resources, this should be a good start for anyone who finds time to implement this.

@UtahDave
Copy link
Contributor

UtahDave commented Apr 6, 2015

@lorengordon great idea!

Could you provide some samples of what you think a cli execution module and also a state should look like? Including some actual settings you'd like to configure?

So on the command line the execution module would look something like this:

salt 'win-minion01' secedit.set 'PasswordComplexity' 'some_valid_value'

And the state (sls file) would look something like this:

set_password_complexity:
  secedit.present:
    - name: PasswordComplexity
    - value: some_valid_value

Does that make sense? That would help make sure we build it in a way that makes sense if we had some examples.

@lorengordon
Copy link
Contributor Author

Yes, of course. I apologize in advance for the length of this comment... I've been thinking about this a little bit more, as well. I'll discuss the module first, then the state when I get a bit more time to think about it.

It probably will help to study the secedit command line usage. One approach for a secedit module would be to mirror the command line usage to whatever degree makes sense.

To configure a setting, secedit reads it from an .inf file. I'm not aware of any way to pass in a setting as a string on the command line. The .inf file has a fairly specific syntax. A yaml-to-inf parser may come in handy for templating and managing settings in bulk. A sample .inf is at the bottom of this comment. Notice the 'sections' in the .inf... The [Unicode] and [Version] sections are basically always the same. If you open gpedit.msc and navigate to [Local Computer Policy]\[Windows Settings]\[Security Settings], the other sections map like this:

  • [System Access] -> [Account Policies]\[Password Policy] and [Account Policies]\[Account Lockout Policy]
  • [Event Audit] -> [Local Policies]\[Audit Policy]
  • [Privilge Rights] -> [Local Policies]\[User Rights Assignment]
  • [Registry Values] -> [Local Policies]\[Security Options] and anything under [Administrative Templates] (both 'Computer' and 'User')

As it is important for the setting to be located within the correct 'section' of the .inf, I think that mapping of setting to section will need to be exposed in the interface to a secedit module (or the knowledge of the mapping will need to be otherwise built into the module...if you dig into the puppet module, I believe that's how they did it, but I think that is likely to be rather fragile or high maintenance).

All that said, I could see cli usage something like this (notice how the 'Registry Values' section requires a 'type' parameter):

salt 'win-minion01' secedit.configure section="System Access" setting="MinimumPasswordAge" value="0"
salt 'win-minion01' secedit.configure section="Event Audit" setting="AuditSystemEvents" value="0"
salt 'win-minion01' secedit.configure section="Registry Values" setting="MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Setup\RecoveryConsole\SecurityLevel" type="REG_DWORD" value="0"
salt 'win-minion01' secedit.configure section="Registry Values" setting="MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\CachedLogonsCount" type="REG_SZ" value="10"
salt 'win-minion01' secedit.configure section="Registry Values" setting="MACHINE\System\CurrentControlSet\Control\Lsa\FullPrivilegeAuditing" type="REG_BINARY" value=0
salt 'win-minion01' secedit.configure section="Registry Values" setting="MACHINE\System\CurrentControlSet\Control\SecurePipeServers\Winreg\AllowedExactPaths\Machine" type="REG_MULTI_SZ" value="System\CurrentControlSet\Control\ProductOptions,System\CurrentControlSet\Control\Server Applications,Software\Microsoft\Windows NT\CurrentVersion"

(Alternatively, each 'section' could be implemented as a separate function. Or that could be an internal implementation detail, with secedit.configure wrapping them for cli usage. I haven't thought about the implications that far down, so just kicking out ideas...)

Each of those cli commands would have to create a temp.inf file with the corresponding information in the correct format, including the [Unicode] and [Version] sections, then execute:

  • secedit.exe /configure /db "%temp%\temp.db" /cfg "%temp%\temp.inf" /overwrite

Notes on that command:

  • The name of the .db file is immaterial, but the parameter is required.
  • /overwrite is required for the setting to become effective. It makes sense to me for this to be the default.
  • The temp.db and temp.inf files are not necessary after secedit.exe returns. It would be nice if they were force removed by default.

That would work for configuring a single setting at a time, but performance could be much improved by aggregating all the settings into a single .inf for a single call to secedit.exe. I don't really know how to do that with a clean data model... (or would this best be handled in the state structure?) While messy, one possible implementation would be for secedit.configure to accept a dict of lists of dicts (I think I got this right, but it hurts my head to think about it):

{ 
  'Systems Access' : [ 
    { 'setting' : 'MinimumPasswordAge',
      'value' : '0', 
    },
    { 'setting' : 'MaximumPasswordAge',
      'value' : '42',
    },
  ],
  'Event Audit' : [ 
    { 'setting' : 'AuditSystemEvents',
      'value' : '0',
    },
    { 'setting' : 'AuditLogonEvents',
      'value' : '0',
    },
  ],
  'Privilege Rights' : [ 
    { 'setting' : 'SeNetworkLogonRight',
      'value' : '*S-1-1-0,*S-1-5-32-544,*S-1-5-32-545,*S-1-5-32-551',
    },
    { 'setting' : 'SeBackupPrivilege',
      'value' : '*S-1-5-32-544,*S-1-5-32-551',
    },
  ],
  'Registry Values' : [ 
    { 'setting' : 'MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Setup\RecoveryConsole\SecurityLevel',
      'type' : 'REG_DWORD',
      'value' : '0',
    },
    { 'setting' : 'MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\CachedLogonsCount',
      'type' : 'REG_SZ',
      'value' : "10",
    },
    { 'setting' : 'MACHINE\System\CurrentControlSet\Control\Lsa\FullPrivilegeAuditing',
      'type' : 'REG_BINARY',
      'value' : '0',
    },
    { 'setting' : 'MACHINE\System\CurrentControlSet\Control\SecurePipeServers\Winreg\AllowedExactPaths\Machine',
      'type' : 'REG_MULTI_SZ',
      'value' : 'System\CurrentControlSet\Control\ProductOptions,System\CurrentControlSet\Control\Server Applications,Software\Microsoft\Windows NT\CurrentVersion',
    },
  ],
}

sample .inf:

[Unicode]
Unicode=yes
[Version]
signature="$CHICAGO$"
Revision=1
[System Access]
;# ... password policy and account lockout policy settings ...
MinimumPasswordAge = 0
MaximumPasswordAge = 42
MinimumPasswordLength = 0
PasswordComplexity = 0
PasswordHistorySize = 0
LockoutBadCount = 0
RequireLogonToChangePassword = 0
ForceLogoffWhenHourExpire = 0
NewAdministratorName = "Administrator"
NewGuestName = "Guest"
ClearTextPassword = 0
LSAAnonymousNameLookup = 0
EnableAdminAccount = 0
EnableGuestAccount = 0
[Event Audit]
;# ... audit policy settings ...
AuditSystemEvents = 0
AuditLogonEvents = 0
AuditObjectAccess = 0
AuditPrivilegeUse = 0
AuditPolicyChange = 0
AuditAccountManage = 0
AuditProcessTracking = 0
AuditDSAccess = 0
AuditAccountLogon = 0
[Registry Values]
;# ... security options and administrative template settings ...
MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Setup\RecoveryConsole\SecurityLevel=4,0
MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Setup\RecoveryConsole\SetCommand=4,0
MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\CachedLogonsCount=1,"10"
MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\ForceUnlockLogon=4,0
MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\PasswordExpiryWarning=4,5
MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\ScRemoveOption=1,"0"
MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\ConsentPromptBehaviorAdmin=4,5
MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\ConsentPromptBehaviorUser=4,3
MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\DontDisplayLastUserName=4,0
MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\EnableInstallerDetection=4,1
MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\EnableLUA=4,1
MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\EnableSecureUIAPaths=4,1
MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\EnableUIADesktopToggle=4,0
MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\EnableVirtualization=4,1
MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\FilterAdministratorToken=4,0
MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\LegalNoticeCaption=1,""
MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\LegalNoticeText=7,
MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\PromptOnSecureDesktop=4,1
MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\ScForceOption=4,0
MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\ShutdownWithoutLogon=4,1
MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\UndockWithoutLogon=4,1
MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System\ValidateAdminCodeSignatures=4,0
MACHINE\Software\Policies\Microsoft\Windows\Safer\CodeIdentifiers\AuthenticodeEnabled=4,0
MACHINE\System\CurrentControlSet\Control\Lsa\AuditBaseObjects=4,0
MACHINE\System\CurrentControlSet\Control\Lsa\CrashOnAuditFail=4,0
MACHINE\System\CurrentControlSet\Control\Lsa\DisableDomainCreds=4,0
MACHINE\System\CurrentControlSet\Control\Lsa\EveryoneIncludesAnonymous=4,0
MACHINE\System\CurrentControlSet\Control\Lsa\FIPSAlgorithmPolicy\Enabled=4,0
MACHINE\System\CurrentControlSet\Control\Lsa\ForceGuest=4,0
MACHINE\System\CurrentControlSet\Control\Lsa\FullPrivilegeAuditing=3,0
MACHINE\System\CurrentControlSet\Control\Lsa\LimitBlankPasswordUse=4,1
MACHINE\System\CurrentControlSet\Control\Lsa\MSV1_0\NTLMMinClientSec=4,536870912
MACHINE\System\CurrentControlSet\Control\Lsa\MSV1_0\NTLMMinServerSec=4,536870912
MACHINE\System\CurrentControlSet\Control\Lsa\NoLMHash=4,1
MACHINE\System\CurrentControlSet\Control\Lsa\RestrictAnonymous=4,0
MACHINE\System\CurrentControlSet\Control\Lsa\RestrictAnonymousSAM=4,1
MACHINE\System\CurrentControlSet\Control\Print\Providers\LanMan Print Services\Servers\AddPrinterDrivers=4,0
MACHINE\System\CurrentControlSet\Control\SecurePipeServers\Winreg\AllowedExactPaths\Machine=7,System\CurrentControlSet\Control\ProductOptions,System\CurrentControlSet\Control\Server Applications,Software\Microsoft\Windows NT\CurrentVersion
MACHINE\System\CurrentControlSet\Control\SecurePipeServers\Winreg\AllowedPaths\Machine=7,System\CurrentControlSet\Control\Print\Printers,System\CurrentControlSet\Services\Eventlog,Software\Microsoft\OLAP Server,Software\Microsoft\Windows NT\CurrentVersion\Print,Software\Microsoft\Windows NT\CurrentVersion\Windows,System\CurrentControlSet\Control\ContentIndex,System\CurrentControlSet\Control\Terminal Server,System\CurrentControlSet\Control\Terminal Server\UserConfig,System\CurrentControlSet\Control\Terminal Server\DefaultUserConfiguration,Software\Microsoft\Windows NT\CurrentVersion\Perflib,System\CurrentControlSet\Services\SysmonLog
MACHINE\System\CurrentControlSet\Control\Session Manager\Kernel\ObCaseInsensitive=4,1
MACHINE\System\CurrentControlSet\Control\Session Manager\Memory Management\ClearPageFileAtShutdown=4,0
MACHINE\System\CurrentControlSet\Control\Session Manager\ProtectionMode=4,1
MACHINE\System\CurrentControlSet\Control\Session Manager\SubSystems\optional=7,
MACHINE\System\CurrentControlSet\Services\LanManServer\Parameters\AutoDisconnect=4,15
MACHINE\System\CurrentControlSet\Services\LanManServer\Parameters\EnableForcedLogOff=4,1
MACHINE\System\CurrentControlSet\Services\LanManServer\Parameters\EnableSecuritySignature=4,0
MACHINE\System\CurrentControlSet\Services\LanManServer\Parameters\NullSessionPipes=7,
MACHINE\System\CurrentControlSet\Services\LanManServer\Parameters\RequireSecuritySignature=4,0
MACHINE\System\CurrentControlSet\Services\LanManServer\Parameters\RestrictNullSessAccess=4,1
MACHINE\System\CurrentControlSet\Services\LanmanWorkstation\Parameters\EnablePlainTextPassword=4,0
MACHINE\System\CurrentControlSet\Services\LanmanWorkstation\Parameters\EnableSecuritySignature=4,1
MACHINE\System\CurrentControlSet\Services\LanmanWorkstation\Parameters\RequireSecuritySignature=4,0
MACHINE\System\CurrentControlSet\Services\LDAP\LDAPClientIntegrity=4,1
MACHINE\System\CurrentControlSet\Services\Netlogon\Parameters\DisablePasswordChange=4,0
MACHINE\System\CurrentControlSet\Services\Netlogon\Parameters\MaximumPasswordAge=4,30
MACHINE\System\CurrentControlSet\Services\Netlogon\Parameters\RequireSignOrSeal=4,1
MACHINE\System\CurrentControlSet\Services\Netlogon\Parameters\RequireStrongKey=4,1
MACHINE\System\CurrentControlSet\Services\Netlogon\Parameters\SealSecureChannel=4,1
MACHINE\System\CurrentControlSet\Services\Netlogon\Parameters\SignSecureChannel=4,1
[Privilege Rights]
;# ... user rights assignment settings...
SeNetworkLogonRight = *S-1-1-0,*S-1-5-32-544,*S-1-5-32-545,*S-1-5-32-551
SeBackupPrivilege = *S-1-5-32-544,*S-1-5-32-551
SeChangeNotifyPrivilege = *S-1-1-0,*S-1-5-19,*S-1-5-20,*S-1-5-32-544,*S-1-5-32-545,*S-1-5-32-551,*S-1-5-90-0
SeSystemtimePrivilege = *S-1-5-19,*S-1-5-32-544
SeCreatePagefilePrivilege = *S-1-5-32-544
SeDebugPrivilege = *S-1-5-32-544
SeRemoteShutdownPrivilege = *S-1-5-32-544
SeAuditPrivilege = *S-1-5-19,*S-1-5-20
SeIncreaseQuotaPrivilege = *S-1-5-19,*S-1-5-20,*S-1-5-32-544
SeIncreaseBasePriorityPrivilege = *S-1-5-32-544
SeLoadDriverPrivilege = *S-1-5-32-544
SeBatchLogonRight = *S-1-5-32-544,*S-1-5-32-551,*S-1-5-32-559
SeServiceLogonRight = *S-1-5-80-0
SeInteractiveLogonRight = __vmware__,Guest,*S-1-5-32-544,*S-1-5-32-545,*S-1-5-32-551
SeSecurityPrivilege = *S-1-5-32-544
SeSystemEnvironmentPrivilege = *S-1-5-32-544
SeProfileSingleProcessPrivilege = *S-1-5-32-544
SeSystemProfilePrivilege = *S-1-5-32-544,*S-1-5-80-3139157870-2983391045-3678747466-658725712-1809340420
SeAssignPrimaryTokenPrivilege = *S-1-5-19,*S-1-5-20
SeRestorePrivilege = *S-1-5-32-544,*S-1-5-32-551
SeShutdownPrivilege = *S-1-5-32-544,*S-1-5-32-545,*S-1-5-32-551
SeTakeOwnershipPrivilege = *S-1-5-32-544
SeDenyNetworkLogonRight = Guest
SeDenyBatchLogonRight = HomeGroupUser$
SeDenyInteractiveLogonRight = HomeGroupUser$,Guest
SeUndockPrivilege = *S-1-5-32-544,*S-1-5-32-545
SeManageVolumePrivilege = *S-1-5-32-544
SeRemoteInteractiveLogonRight = *S-1-5-32-544,*S-1-5-32-555
SeImpersonatePrivilege = *S-1-5-19,*S-1-5-20,*S-1-5-32-544,*S-1-5-6
SeCreateGlobalPrivilege = *S-1-5-19,*S-1-5-20,*S-1-5-32-544,*S-1-5-6
SeIncreaseWorkingSetPrivilege = *S-1-5-32-545,*S-1-5-90-0
SeTimeZonePrivilege = *S-1-5-19,*S-1-5-32-544,*S-1-5-32-545
SeCreateSymbolicLinkPrivilege = *S-1-5-32-544

@lorengordon
Copy link
Contributor Author

Oh, and for whoever starts down this path, it's probably worth warning: as valuable as secedit is, being pretty much the only tool available to do the job, it's also a horrible mess of brokenness. See this rant for many of the gotchas.

@jfindlay jfindlay added the Platform Relates to OS, containers, platform-based utilities like FS, system based apps label May 26, 2015
@lomeroe
Copy link
Contributor

lomeroe commented Sep 17, 2015

I've got a module started on this...mainly worked the "get" portion, though I've tested out the basics of the "put" function in my first test functions (set_password_policy/set_lockout_policy)

https://github.com/lomeroe/salt/blob/add-windows-pol-mgmt/salt/modules/win_secpol.py

Wanted to see what others thought while I was working on finishing it up....

example output:
salt 'server1*' win_secpol.get return_full_policy_names=True
server1:
----------
Account lockout duration:
1440
Account lockout threshold:
10
Accounts: Administrator account status:
Enabled
Accounts: Guest account status:
Disabled
Accounts: Limit local account use of blank passwords to console logon only:
Disabled
Accounts: Rename administrator account:
Administrator
Accounts: Rename guest account:
Guest
Audit account management:
No auditing
Audit directory service access:
No auditing
Audit logon events:
Success
Audit object access:
No auditing
Audit policy change:
No auditing
Audit privilege use:
No auditing
Audit process tracking:
No auditing
Audit system events:
No auditing
Enforce password history:
24
Maximum password age:
60
Minimum password age:
1
Minimum password length:
14
Network Access: Do not allow anonymous enumeration of SAM accounts and shares:
Disabled
Passwords must meet complexity requirements:
Enabled
Reset account lockout counter after:
1440
Store passwords using reversible encryption:
Disabled

@lorengordon
Copy link
Contributor Author

Awesome! Testing it now...

@lorengordon
Copy link
Contributor Author

Works like a charm. I think it would be great to get it in the develop branch. One thing I might change first is to set __virtualname__ = 'secpol' rather than 'win_secpol', here. That would keep it more inline with the style of other Windows modules.

@lomeroe
Copy link
Contributor

lomeroe commented Sep 17, 2015

Sounds good - I wasn't even sold on the "secpol" name and wondered if I could come up with something better...I will make that mod though.

Once I have the 'set' working, I'll do a PR into develop.

@lorengordon
Copy link
Contributor Author

I am a little curious about the reasoning and differences behind the 'How' mechanisms, Registry vs NetUserModal vs Secedit. I had really only envisioned secedit-based policies, specifically because they are applied to the local security policy and enforced at a lower level than normal registry edits. It seems like all the policy_info.policies are local security policies, so why have different mechanisms? Does win32net.NetUserModalsSet also modify the local security policy?

@lomeroe
Copy link
Contributor

lomeroe commented Sep 18, 2015

Sure -

Anytime there is an API to do something, I will likely use it over calling out to another application (like secedit), that's just personal preference. With this module, I started off needing to set the lockout/password policies on some non-domain members. I was able to do everything with the API (NetUserModalGet/Set) until you get the the reversible encryption and password complexity settings (the API for these is apparently in SAM lib which pywin32 doesn't have hooks into, and even documentation for C/.NET is very limited), so I couldn't find any other way than secedit. Once I had that basic code for secedit, and I came upon your feature request, I thought I could augment it to do just about everything you could do w/gpedit.msc.

As for the registry "how" - when secedit is just going to make a registry modification for me, I didn't see the purpose it calling out to it, when I can cut out the middle man and make the same modification myself (like using the API). For example, setting the "Network Access: Do not allow anonymous enumeration of SAM accounts and shares" policy in the GUI just sets the "RestrictAnonymous" registry key. Just like secedit will if it is in the [Registry Values] section of an INI file...

To directly answer your questions:

Different mechanisms because that's just how I chose to do it (right/wrong is rightfully debatable). :)

NetUserModalsSet does modify the policy (likely secedit calls the same underlying windows API). You can try the set_password_policy and set_lockout_policy functions to see NetUserModalSet change the policy...

@lorengordon
Copy link
Contributor Author

Gotcha. I'll give those functions a try.

But, I don't think that's right about registry entries and secedit. My understanding is that secedit does not modify the registry directly. Secedit modifies the local security policy, which in turn modifies the registry. I believe registry-based local security policy is actually stored in registry.pol files with a binary format, not just the registry. So I think registry entries supported by secedit need to be applied by secedit. Otherwise, the registry entries will be overridden when the policy refreshes (assuming that entry has been set in policy).

To see what I mean, use gpedit.msc to modify the security policy. Then use regedit.exe to manually modify the corresponding registry entry. Then run gpupdate /force. The registry entry will revert to what was set in the security policy.

@lomeroe
Copy link
Contributor

lomeroe commented Sep 18, 2015

Hrm....If I set the 'restirctanonymous' reg key it doesn't change after a gpupdate /force

The gpedit.msc also shows the policy change from Disabled to Enabled if I just flip the registry key only...

Same goes for the 'dontdisplaylastusername' registry key

There could be other keys that behave differently...which policy setting did you try?

@lorengordon
Copy link
Contributor Author

Ahh, yeah, Windows is so annoying about these things. They call it a 'registry policy' but they're specifically referring to settings that fall under the Administrative Templates section of the policy in gpedit.msc.

@lomeroe
Copy link
Contributor

lomeroe commented Sep 18, 2015

The link you provided does say that they 'get imported on update' from the .pol files, so it is possible that upon reboot something else could happen...

Looking at the registry.pol file on the system I'm working on, it looks like it only has "administrative template" settings in it. That makes sense to me, b/c I have salt states that set some of those values, but gpedit.msc doesn't show them as configured (though the reg changes are in effect)

If administrative template configuration is added to this module (which I'd like to do), then it appears to make the gui/registry line up, the registry.pol file would need to be updated as well as the registry itself...

@lorengordon
Copy link
Contributor Author

I really hate trying to configure Windows. It's so inconsistent and opaque.

@lomeroe
Copy link
Contributor

lomeroe commented Sep 18, 2015

That is the truth...

I committed some more changes, so the "set" function should be functional (added a couple more policies, but not many). Give it a try and see what you think...

I'll try to finish adding other policies to it next week and build a state module.

@lorengordon
Copy link
Contributor Author

Ok, I withdraw my concern about secedit vs direct registry modifications. I did some more testing and it turns out I was remembering how another tool behaves, rather than secedit: the LGPO utility I linked in the first post. I'm not really sure how it does it, but policies applied with LGPO override changes I make directly to the registry or via gpedit.msc. Any changes revert to what was set via LGPO, once policy refreshes (or forcing a refresh with gpupdate /force). Perhaps LGPO somehow reads and writes the registry.pol files directly. I thought LGPO only called secedit, but it must be doing something more since the behavior is so different.

Anyway, tested the set function and it works fine.

@lorengordon
Copy link
Contributor Author

Also, as far as the administrative template configuration, it can be applied with secedit. The [Registry] section of a secedit inf may contain entries for settings within the administrative template sections. Or perhaps it could be handled by modifying the registry directly, as well. I'll have to do a little more testing to see whether changes to the registry directly will be reflected in the administrative template section of the security policy, or if configuring the security policy will override changes made to the registry.

@lorengordon
Copy link
Contributor Author

Ok, I see now what you meant about the registry and administrative template settings. Did some testing and can confirm that modifying the registry entry corresponding to an administrative template setting does not update what's displayed in gpedit.msc.

Worse, I tried using secedit to configure the administrative template setting from an inf, and while it did change the registry entry it did not change what was displayed in gpedit.msc. When I ran gpupdate /force, the registry entry still reverted to what was set in gpedit.msc. Lame.

So, however LGPO is doing it may be the only way. I'm not really great at reading cpp, but they do provide the source. I'll try to struggle through it when I get some time (may not get to it for a couple weeks).

@lomeroe
Copy link
Contributor

lomeroe commented Sep 23, 2015

@lorengordon - got sidetracked for a few days, but was able to spend a little time on it again today...I added User Rights Assignments to the 'set' and 'get', I also renamed to 'gpedit', just seemed appropriate to me (since I kept running 'gpedit' to double-check output), not married to it though....

Give it a try and let me know what you think....

https://github.com/lomeroe/salt/blob/add-windows-pol-mgmt/salt/modules/win_gpedit.py

@lorengordon
Copy link
Contributor Author

I'm out for the next couple days, but can test it early next week. I'm relatively unconcerned about the name, as long as it works. But if I were forced to choose between gpedit, secpol, or secedit, I think I like secpol the best. Especially if it manages to implement functionality equivalent to LGPO, eventually, which seems to work at a lower level than gpedit or secedit.

@lorengordon
Copy link
Contributor Author

@lomeroe: I never did get around to test this any further. Are you still working on it?

Since we were already using Apply_LGPO_Delta.exe, I just wrote a custom execution module wrapper around it. First one I've written, turned out to be pretty easy. I'd appreciate any feedback, pointers, etc, if anyone has time to take a look: https://gist.github.com/lorengordon/a1d1c08e8587d92d3612.

@lomeroe
Copy link
Contributor

lomeroe commented Jan 5, 2016

No, I never finished up the module/state I was working on, the things I needed it for got back-burner'd and I unfortunately had to put off finishing it up. It is on my list of things to accomplish and I anticipate it to bubble back towards the top of my to-do list soon, may be moot with the module you've done.

@lorengordon
Copy link
Contributor Author

Ok, no worries. I've added support for secedit-based inf-style policies ("System Access" and "Privilege Rights"), in addition to the registry-based policies. I'd like to do something like you did with the policy_info class to define the data model and help validate values, but it works. https://gist.github.com/lorengordon/a1d1c08e8587d92d3612

@lorengordon
Copy link
Contributor Author

Well, it turned out to be fairly easy to use a class to define most of the data structure and various helper functions. That's likely about as far as I can take this myself at the moment. Is it worth trying to convert or import or otherwise utilize the .cpp source from Apply_LGPO_Delta so it can be used as a library in python, to eliminate the external dependency on the .exe? I have no idea how to go about that, and my Google searches are not proving particularly enlightening.

@lorengordon
Copy link
Contributor Author

@Trouble123, the virtual name for the module is just lgpo. So try salt 'minion' lgpo.get...

@damon-atkins
Copy link
Contributor

Their is a lot of code in this. Was it auto generated, i.e. how will it be maintain ?
e.g.

'SeDenyInteractiveLogonRight': {
                        'Policy': 'Deny log on locally',
                        'lgpo_section': ['Computer Configuration',
                                         'Windows Settings',
                                         'Security Settings',
                                         'Local Policies',
                                         'User Rights Assignment'],
                        'Settings': None,
                        'LsaRights': {
                            'Option': 'SeDenyInteractiveLogonRight'
                        },
                        'Transform': {
                            'Get': '_sidConversion',
                            'Put': '_usernamesToSidObjects',
                        },
                    },

@Trouble123
Copy link

Thanks, I guess copying the .py file was OK?
How do i find the module options? I tried salt 'minion' lgpo -d but it didnt show up anything.
Thanks

@lorengordon
Copy link
Contributor Author

@Trouble123, try salt 'minion' sys.doc lgpo. That should print the docstrings for the module, which contain the docs that will be published to salt's docs site once the module is merged.

And yes, you should be able to just copy the file like that into (site|dist)-packages (amzn linux?), though perhaps more typically for salt you would place it in a _modules directory within your file_roots, such that it would be available to the salt filesystem at salt://_modules. See https://docs.saltstack.com/en/latest/ref/file_server/dynamic-modules.html

@lomeroe
Copy link
Contributor

lomeroe commented Aug 29, 2016

@damon-atkins it is unfortunately statically defined/manually maintained, I was previously not able to find it defined elsewhere. I'm sure some windows dll has the similar data that the mmc snap-in is using, but I couldn't find it or how to get at it.

@lorengordon asked for documentation on the class to be added, which I will work up and put in while I'm working on the state module.

It did turn into quite a behemoth to make things work how I envisioned the module functioning. Luckily (maybe?), I think most of the items in that class have not changed (or changed much) since Windows 2000.

edited to add: Not all of the security settings policies have been added to the class either...
I'll be the first to say there is plenty of room for improvement in the module.

@Trouble123
Copy link

Hi

I have yet to get this to work. I tried to now run it locally on a Windows 2012R2 DC that i have synced the module to and i get this error:

`
C:\salt>salt-call sys.doc lgpo
[ERROR ] Command 'Import-Module ServerManager' failed with return code: 1
[ERROR ] output: Import-Module : The specified module 'ServerManager' was not loaded because no
valid module file was found in any module directory.
At line:1 char:1

  • Import-Module ServerManager
  • - CategoryInfo          : ResourceUnavailable: (ServerManager:String) [Import-Module], FileNotFoundException
    - FullyQualifiedErrorId : Modules_ModuleNotFound,Microsoft.PowerShell.Commands.ImportModuleCommand
      local:
      ----------
      `
    
    

Any ideas?

thanks

@lomeroe
Copy link
Contributor

lomeroe commented Sep 9, 2016

@Trouble123 not exactly sure what is happening, but when sys.doc is called or when "-d" is passed to the module (salt-call lgpo -d) to get the doc string, powershell is executed and the ServerManager module is imported (the lgpo module doesn't use any powershell):

'''
[INFO ] Executing command 'Powershell -NonInteractive "Import-Module ServerManager"' in directory 'C:\salt'
'''

That seems to be what is throwing the error you are seeing. What is the output of "c:\salt\salt-call --versions-report"? I don't believe the 32-bit version of powershell has the ServerManager module, so it is possible that somehow a 32-bit version of powershell.exe is being loaded (if you are on a 64-bit OS)...

@Trouble123
Copy link

Hi, sorry for the delay. Here is what i get when running it on the W2012R2 server:

Salt Version:
Salt: 2016.3.2

Dependency Versions:
cffi: Not Installed
cherrypy: 3.8.0
dateutil: 1.5
gitdb: 0.5.4
gitpython: 0.3.2 RC1
ioflo: Not Installed
Jinja2: 2.7.2
libgit2: Not Installed
libnacl: Not Installed
M2Crypto: 0.21.1
Mako: 0.9.1
msgpack-pure: Not Installed
msgpack-python: 0.4.6
mysql-python: 1.2.3
pycparser: Not Installed
pycrypto: 2.6.1
pygit2: Not Installed
Python: 2.7.6 (default, Jun 22 2015, 17:58:13)
python-gnupg: Not Installed
PyYAML: 3.10
PyZMQ: 14.4.0
RAET: Not Installed
smmap: 0.8.2
timelib: Not Installed
Tornado: 4.3
ZMQ: 4.0.4

System Versions:
dist: Ubuntu 14.04 trusty
machine: x86_64
release: 3.19.0-25-generic
system: Linux
version: Ubuntu 14.04 trusty

@lomeroe
Copy link
Contributor

lomeroe commented Sep 21, 2016

@Trouble123 that looks like the output from the master, not the minion itself.

However, I can duplicate your error message by running the 32-bit minion on a 64-bit 2012 R2 server. If you do have a 64-bit minion installed, then I'm not sure what is causing the error.

I'd suggest uninstalling the minion and re-download the minion installer, ensuring you are getting the 64-bit version and re-install it.

@lorengordon
Copy link
Contributor Author

lorengordon commented Sep 28, 2016

@lomeroe, it appears that the lxml import is failing. Or at least, I do not have that module in the python packaged with salt v2016.3.3. That's probably what is keeping the module from loading for @Trouble123. Any guidance on how you were getting that module? Also, may need to work with @twangboy to make sure it is packaged with salt...

@damon-atkins
Copy link
Contributor

ServerManager for PowerShell is only valuable if you install extra Microsoft software.
The import fails if the ServerManager is not available, and if not available this module is not enabled.

I recently fix some other powershell salt modules in Carbon.

It's not something Salt should install.

@lorengordon
Copy link
Contributor Author

@damon-atkins, what is it that you are responding to? Are you saying that lxml comes with Server Manager? I'm pretty sure the reported error by @Trouble123 is a red herring as far as this lgpo module is concerned...

@damon-atkins
Copy link
Contributor

My comments are about this error.

[ERROR ] Command 'Import-Module ServerManager' failed with return code: 1
[ERROR ] output: Import-Module : The specified module 'ServerManager' was not loaded because no
valid module file was found in any module directory.

@lorengordon
Copy link
Contributor Author

Yeah, still pretty sure that error is not relevant to the lgpo module failing to load.

Not sure what is trying to import the ServerManager powershell module in salt 2016.3...haven't dug into that.

@damon-atkins
Copy link
Contributor

It runs all the time, its in def virtual it how it determines if it is valid module. If the import failed it returns False. Unfortunately cmd.run_all outputs the error to the log.

@lorengordon
Copy link
Contributor Author

lorengordon commented Sep 29, 2016

What module are you talking about? I don't see any call here, https://github.com/saltstack/salt/blob/develop/salt/modules/win_lgpo.py#L2634-L2640. Is it in the is_windows() util function?

win_servermanager.py does do this Import-Module ServerManager in its own __virtual__() function, but the LazyLoader should not attempt to load this module unless something is calling win_servermanager... and I don't see any explicit call to win_servermanager in the lgpo module.

@lorengordon
Copy link
Contributor Author

@lorengordon
Copy link
Contributor Author

lorengordon commented Sep 29, 2016

Ahh, I wonder if it happens when a module cannot be found... I'm guessing in that case the LazyLoader iterates through every module attempting to find the requested module, hits win_servermanager, which spits out the spurious error message. Running with trace logging and a non-existent module appears to confirm this loader behavior.

In which case, still, this particular error message is not related directly to the lgpo module; the real issue with lgpo is that the lxml import is failing.

Non-existent module foo.bar:

C:\> C:\salt\salt-call.bat --local foo.bar
[ERROR   ] Command 'Import-Module ServerManager' failed with return code: 1
[ERROR   ] output: Import-Module : The specified module 'ServerManager' was not loaded because no valid module file was found in any module directory.
At line:1 char:1
+ Import-Module ServerManager
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ResourceUnavailable: (ServerManager:String) [Import-Module], FileNotFoundException
    + FullyQualifiedErrorId : Modules_ModuleNotFound,Microsoft.PowerShell.Commands.ImportModuleCommand
'foo.bar' is not available.

Real module reg.read_key:

C:\> C:\salt\salt-call.bat --local reg.read_key

Passed invalid arguments: read_key() takes at least 2 arguments (0 given).

Usage:

    .. important::
        The name of this function is misleading and will be changed to reflect
        proper usage in the Carbon release of Salt. The path option will be removed
        and the key will be the actual key. See the following issue:

        https://github.com/saltstack/salt/issues/25618

        In order to not break existing state files this function will call the
        read_value function if a key is passed. Key will be passed as the value
        name. If key is not passed, this function will return the default value for
        the key.

        In the Carbon release this function will be removed in favor of read_value.

    Read registry key value

    Returns the first unnamed value (Default) as a string.
    Returns none if first unnamed value is empty.
    Returns False if key not found.

    CLI Example:

    .. code-block:: bash

        salt '*' reg.read_key HKEY_LOCAL_MACHINE 'SOFTWARE\Salt' 'version'

@lomeroe
Copy link
Contributor

lomeroe commented Sep 29, 2016

@lorengordon

This should do the trick. If you are behind a proxy, add the proxy="" option

salt-call state.single pip.installed name=lxml==3.6.0 cwd="c:\salt\bin\scripts" bin_env="c:\salt\bin\scripts\pip.exe" upgrade=True

The 3.6.0 version of lxml must be specified as 3.6.4 (latest lxml in pypi today) does not have a binary windows package currently.

@twangboy thoughts on adding lxml to the windows salt package? If you don't think that should be done, then I'll add documentation to the module similar to the above note...

@lorengordon
Copy link
Contributor Author

@lomeroe, yep, that did it. Still seeing the ServerManager import error, but I think that's more related to the ordering of the modules when the loader is iterating through them all to find the lgpo module.

@lorengordon
Copy link
Contributor Author

Submitted a new issue for the issue with the ServerManager PowerShell import...

@damon-atkins
Copy link
Contributor

@lorengordon ServerManager its not in your code. It was a response to @Trouble123 It will always show in in the logs if its not installed, it can be ignored. Sorry if this was not clear.

@Trouble123
Copy link

@lorengordon
I was finally in a position to run the salt-call --versions-report directly on the window2012r2 box (which is a DC), and i got this error:
The program can't start because MSVCR100.dll is missing from your computer.
When i press OK on the prompt, i then see the command finish and shows this:

C:\salt>salt-call --versions-report
Salt Version:
Salt: 2016.3.1

Dependency Versions:
cffi: 1.6.0
cherrypy: 5.3.0
dateutil: 2.5.3
gitdb: 0.6.4
gitpython: 2.0.2
ioflo: 1.5.3
Jinja2: 2.8
libgit2: Not Installed
libnacl: Not Installed
M2Crypto: Not Installed
Mako: 1.0.4
msgpack-pure: Not Installed
msgpack-python: 0.4.7
mysql-python: Not Installed
pycparser: 2.14
pycrypto: 2.6.1
pygit2: Not Installed
Python: 2.7.11 (v2.7.11:6d1b6a68f775, Dec 5 2015, 20:32:19) [MSC v.150
0 32 bit (Intel)]
python-gnupg: 0.3.8
PyYAML: 3.11
PyZMQ: 15.2.0
RAET: Not Installed
smmap: 0.9.0
timelib: 0.2.4
Tornado: 4.3
ZMQ: 4.1.2

System Versions:
dist:
machine: AMD64
release: 8.1
system: Windows
version: 8.1 6.3.9600 Multiprocessor Free

I looked at the exe that i installed it from, and its definitely the 64bit: Salt-Minion-2016.3.1-AMD64-Setup.exe

I ran the command on another Win 2012R2 DC, and it gave me the result without the error. I then copied the win_lgpo.py & pyc file back into the _modules folder, and did a salt 'MINION' saltutil.sync_all. I can see it has sync'd:

MINION:
----------
beacons:
engines:
grains:
log_handlers:
modules:
- modules.win_lgpo
output:
proxymodules:
renderers:
returners:
sdb:
states:
utils:

But, still have not been able to run any commands against it.

salt 'MINION' sys.doc lgpo - gave me nothing

So i looked at the posts on this issue from 12 months ago and ran the following; still no joy

C:\salt>salt-call lgpo.get return_full_policy_names=True -l debug
[DEBUG ] Reading configuration from c:\salt\conf\minion
[DEBUG ] Including configuration from 'c:\salt\conf\minion.d_schedule.conf'
[DEBUG ] Reading configuration from c:\salt\conf\minion.d_schedule.conf
[DEBUG ] Using cached minion ID from c:\salt\conf\minion_id: MINION
[DEBUG ] Configuration file path: c:\salt\conf\minion
[WARNING ] Insecure logging configuration detected! Sensitive data may be logged.
[DEBUG ] Reading configuration from c:\salt\conf\minion
[DEBUG ] Including configuration from 'c:\salt\conf\minion.d_schedule.conf'
[DEBUG ] Reading configuration from c:\salt\conf\minion.d_schedule.conf
[DEBUG ] Connecting to master. Attempt 1 (infinite attempts)
[DEBUG ] Initializing new AsyncAuth for ('c:\salt\conf\pki\minion', 'MINION', 'tcp://10.253.254.73:4506')
[DEBUG ] Generated random reconnect delay between '1000ms' and '11000ms' (10305)
[DEBUG ] Setting zmq_reconnect_ivl to '10305ms'
[DEBUG ] Setting zmq_reconnect_ivl_max to '11000ms'
[DEBUG ] Initializing new AsyncZeroMQReqChannel for ('c:\salt\conf\pki\minion', 'MINION', 'tcp://10.253.254.73:4506', 'clear')
[DEBUG ] Decrypting the current master AES key
[DEBUG ] Loaded minion key: c:\salt\conf\pki\minion\minion.pem
[DEBUG ] Loaded minion key: c:\salt\conf\pki\minion\minion.pem
[DEBUG ] Determining pillar cache
[DEBUG ] Initializing new AsyncZeroMQReqChannel for ('c:\salt\conf\pki\minion', 'MINION', 'tcp://10.253.254.73:4506', 'aes')
[DEBUG ] Initializing new AsyncAuth for ('c:\salt\conf\pki\minion', 'MINION', 'tcp://10.253.254.73:4506')
[DEBUG ] Loaded minion key: c:\salt\conf\pki\minion\minion.pem
[DEBUG ] LazyLoaded jinja.render
[DEBUG ] LazyLoaded yaml.render
[DEBUG ] LazyLoaded cmd.retcode
[INFO ] Executing command 'Powershell -NonInteractive "Import-Module ServerManager"' in directory 'C:\Users\administrator.DOMAIN'
[DEBUG ] output:
[DEBUG ] LazyLoaded config.get
[DEBUG ] DSC: $PSVersionTable.PSVersion.Major | ConvertTo-Json
[INFO ] Executing command 'Powershell -NonInteractive "$PSVersionTable.PSVersion.Major | ConvertTo-Json"' in directory 'C:\Users\administrator.DOMAIN'
[DEBUG ] output: 4
[DEBUG ] Failed to import module mac_shadow:
Traceback (most recent call last):
File "C:\salt\bin\lib\site-packages\salt\loader.py", line 1297, in load_module
), fn
, fpath, desc)
File "C:\salt\bin\lib\site-packages\salt\modules\mac_shadow.py", line 15, in
import pwd
ImportError: No module named pwd
[DEBUG ] SMBIOS: neither dmidecode nor smbios found!
[DEBUG ] Could not LazyLoad lgpo.get
'lgpo.get' is not available.

@lomeroe
Copy link
Contributor

lomeroe commented Oct 3, 2016

@Trouble123 sorry I sent you down the x86/x64 path -- as @lorengordon pointed out, the server-manager module is also part of RSAT (I have that installed everywhere, so that point skipped my mind).

lxml is the likely missing module keeping it from loading (the lgpo module doesn't log an error that it cannot import it, it simply returns False if any of the imports fail)

@twangboy
Copy link
Contributor

twangboy commented Oct 3, 2016

@lorengordon Since there is now the win_lgpo module that addresses local group policy, can we close this ticket and open a new ticket to address other issues in the discussion?

@lorengordon
Copy link
Contributor Author

I'm good with that yes, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature new functionality including changes to functionality and code refactors, etc. Platform Relates to OS, containers, platform-based utilities like FS, system based apps Windows
Projects
None yet
Development

No branches or pull requests

10 participants