{"id":5971,"date":"2015-05-24T00:01:00","date_gmt":"2015-05-24T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2015\/05\/24\/weekend-scripter-use-powershell-for-jit-administration-and-pam-part-2\/"},"modified":"2019-02-18T09:47:48","modified_gmt":"2019-02-18T16:47:48","slug":"weekend-scripter-use-powershell-for-jit-administration-and-pam-part-2","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/weekend-scripter-use-powershell-for-jit-administration-and-pam-part-2\/","title":{"rendered":"Weekend Scripter: Use PowerShell for JIT Administration and PAM &#8211; Part 2"},"content":{"rendered":"<p><b style=\"font-size:12px\">Summary<\/b><span style=\"font-size:12px\">: Guest blogger, and Microsoft PFE Ian Farr, continues his series about JIT administration with Windows PowerShell.<\/span><\/p>\n<p align=\"left\">Microsoft Scripting Guy, Ed Wilson, is here. Today, welcome back Ian Farr for the conclusion of his two-part blog. Before you dig into today&#039;s post, please read <a href=\"https:\/\/devblogs.microsoft.com\/scripting\/weekend-scripter-use-powershell-for-jit-administration-and-pam-part-1\/\" target=\"_blank\">Use PowerShell for JIT Administration and PAM &ndash; Part 1<\/a>. To read more of Ian&#039;s previous guest posts, see these <a href=\"https:\/\/devblogs.microsoft.com\/scripting\/tag\/ian-farr\/\" target=\"_blank\">Hey, Scripting Guy! Blog posts<\/a>.<\/p>\n<p>Yesterday, I discussed an advanced function that was written with my teammate, Phil Lane. The function grants membership of a high-privileged group for a defined period of time. I talked about just-in-time (JIT) administration, including time-bound elevation and privileged access management or PAM (that is, special administrative considerations for high-privileged users and groups).<\/p>\n<p>Here&rsquo;s the function:<\/p>\n<p style=\"margin-left:30px\"><a href=\"https:\/\/gallery.technet.microsoft.com\/scriptcenter\/Set-ADUserJitAdmin-b8bb1f47\" target=\"_blank\">Set-ADUserJitAdmin<\/a><\/p>\n<p>Here&rsquo;s its parameters:<\/p>\n<ul>\n<li><b>UserDn<\/b>&hellip;&nbsp;&nbsp;The distinguished name of the user account to be granted high-privileged access<\/li>\n<li><b>Domain<\/b>&hellip;&nbsp;&nbsp;The domain in which the privileged group resides<\/li>\n<li><b>PrivGroup<\/b>&hellip;&nbsp;&nbsp;Either Domain Admins, Enterprise Admins, or Schema Admins<\/li>\n<li><b>TtlHours<\/b>&hellip;&nbsp;&nbsp;The number of hours high-privileged access is granted for<\/li>\n<\/ul>\n<p>And here&#039;s its switches:<\/p>\n<ul>\n<li><b>CountDown<\/b>&hellip;&nbsp;&nbsp;A countdown, in seconds, of the time remaining before the dynamic group object is removed<\/li>\n<li><b>ProtectedUser<\/b>&hellip;&nbsp;&nbsp;This makes use of some of the credential theft protections included in the later operating systems<\/li>\n<\/ul>\n<p>Last time out, I also promised to discuss the <b>&ndash;ProtectedUser<\/b> switch. Here goes&hellip;<\/p>\n<h2>The three-headed dog<\/h2>\n<p>In testing Phil&rsquo;s proof-of-concept JIT administration script, I realized that because of how the <a href=\"https:\/\/technet.microsoft.com\/en-us\/library\/cc772815(v=ws.10).aspx\" target=\"_blank\">Kerberos authentication protocol<\/a> works, we needed some additional functionality.<\/p>\n<p>The background&#8230;<\/p>\n<p>In Active Directory, Kerberos is the preferred authentication protocol. It provides you with a time-bound ticket that confirms who you are. Think of this ticket as a passport that&rsquo;s issued for only 10 hours. You can use this passport to prove who you are to the various services that you&rsquo;ll find in your Active Directory infrastructure (the file servers). In turn, you&rsquo;ll get another passport\/ticket to access that service until your original ticket expires.<\/p>\n<p>What does all this mean? Well, ultimately, we want to grant high-privileged <i>access<\/i> for a defined period of time to our system administrator&rsquo;s secondary user account. If we use the function to grant high-privileged group <i>membership<\/i> for two hours, we&rsquo;re still going to get a Kerberos ticket-granting ticket (TGT, which is the original passport) that lasts for 10 hours. This means that despite no longer being a member of the high-privileged group, we can still use tickets issued during membership of the high-privileged group to legitimately persist high-privileged <i>access<\/i>&mdash;that means our time-bound elevation can last beyond the <b>$TtlHours<\/b> value passed to the script.<\/p>\n<p>I thought about how to address this with Windows PowerShell&hellip;<\/p>\n<h2>Nice doggie<\/h2>\n<p>Windows Server 2012 R2 introduced a number of credential theft protections. The function also makes use of one of these features: a new Active Directory global security group called <a href=\"https:\/\/technet.microsoft.com\/en-us\/library\/dn518179.aspx#BKMK_AddtoProtectedUsers\" target=\"_blank\">Protected Users<\/a>, which affords a number of protections. Following are some of the safeguards immediately relevant to this discussion.<\/p>\n<p>Members of the Protected Users group can no longer:<\/p>\n<ul>\n<li>Use Kerberos long term keys: A Kerberos TGT is acquired at logon and cannot be reacquired automatically<\/li>\n<li>Renew user tickets (TGTs) beyond the initial four-hour lifetime<\/li>\n<\/ul>\n<p>Three important points about Protected Users:<\/p>\n<ul>\n<li>The second protection (four-hour TGTs) is only available if the domain functional level is Windows Server 2012 R2.<\/li>\n<li>You&rsquo;ll need to assign your PDCe role to a domain controller running Windows Server 2012 R2 (it can be assigned back later) for the Protected Users group object to be created and replicated in a domain where you have down-level domain controllers.<\/li>\n<li>The ability to apply Protected Users safeguards have been back-ported to Windows 8, Windows Server 2012, Windows 7 with SP1 and Windows Server 2008 R2 with SP1. For more information, take a look at <a href=\"https:\/\/technet.microsoft.com\/library\/security\/2871997\" target=\"_blank\">KB2871997<\/a>.<\/li>\n<\/ul>\n<p>The Windows PowerShell part is not far away now! Thank you for your patience, my friends.<\/p>\n<p>There&rsquo;s one more credential theft protection in Windows Server 2012 R2 that the function utilizes: <a href=\"https:\/\/technet.microsoft.com\/en-us\/library\/dn518179.aspx#BKMK_CreateAuthNPolicies\" target=\"_blank\">Authentication Policies<\/a>. With this we can configure a user&rsquo;s Kerberos TGT to exist for the same amount of time as the duration of our privileged group membership.<\/p>\n<p style=\"margin-left:30px\"><b>Note<\/b>&nbsp;&nbsp;For more details about prerequisites for authentication policies, see <a href=\"https:\/\/devblogs.microsoft.com\/scripting\/weekend-scripter-authentication-silos-part-1\/\" target=\"_blank\">Authentication Silos Part 1<\/a>.<\/p>\n<h2>At last: Windows PowerShell<\/h2>\n<p>If the <b>&ndash;ProtectedUser<\/b> switch is specified, the function does the following:<\/p>\n<ul>\n<li>Checks for the existence of the Protected Users group<\/li>\n<li>Checks whether our user account is a member of the group; if not, adds it<\/li>\n<li>Checks whether the dynamic group object time to live (TTL) is less than four hours; if it is, then&hellip;<\/li>\n<li>Checks whether the domain functional level is Windows Server 2012 R2; if it is, then&hellip;<\/li>\n<li>Creates an authentication policy with a TGT matching the TTL and assigns it to the user account<\/li>\n<li>Spins up a countdown<\/li>\n<li>Removes the authentication policy<\/li>\n<\/ul>\n<p>Here&rsquo;s how we check for the existence of the Protected Users group:<\/p>\n<p style=\"margin-left:30px\">$DomainDn = (Get-ADDomain $Domain).DistinguishedName<\/p>\n<p style=\"margin-left:30px\">$UsersContainerDn = &quot;CN=Users,$DomainDn&quot;<\/p>\n<p style=\"margin-left:30px\">Get-ADGroup -Identity &quot;CN=Protected Users,$UsersContainerDn&quot; -Properties members<\/p>\n<p>To check whether our user is a member of the group:<\/p>\n<p style=\"margin-left:30px\">if (($ProtectedUsersGroup).members -like $UserDn) {..}<\/p>\n<p>To perform the required addition:<\/p>\n<p style=\"margin-left:30px\">Add-ADGroupMember -Identity &quot;CN=Protected Users,$UsersContainerDn&quot; -Members $UserDn<\/p>\n<p>And here&rsquo;s how we check whether the dynamic group object TTL is less than four hours and then check the domain FFL:<\/p>\n<p style=\"margin-left:30px\">if ($TtlHours -lt 4) {<\/p>\n<p style=\"margin-left:30px\">$DomainFL = (Get-ADDomain $Domain).DomainMode<\/p>\n<p style=\"margin-left:30px\">if ($DomainFL -eq &quot;Windows2012R2Domain&quot;) {&hellip;}<\/p>\n<p>Now, create an authentication policy if the domain FFL is &lsquo;Windows2012R2Domain&rsquo;:<\/p>\n<p style=\"margin-left:30px\">$AuthPolName = &quot;Temp Auth Pol for $UserSamAccountName&quot;<\/p>\n<p style=\"margin-left:30px\">New-ADAuthenticationPolicy -Name $AuthPolName `<\/p>\n<p style=\"margin-left:30px\">-Description &quot;Temporary Authentication Policy to set $TtlHours hour TGT for $UserSamAccountName&quot; `<\/p>\n<p style=\"margin-left:30px\">-UserTGTLifetimeMins ($TtlHours * 60) `<\/p>\n<p style=\"margin-left:30px\">-Enforce `<\/p>\n<p style=\"margin-left:30px\">-ProtectedFromAccidentalDeletion $False<\/p>\n<p>Here, we create an authentication policy that references our user account name and description. The user TGT lifetime is set to match the dynamic group object lifetime. The <b>&ndash;UserTGTLifetimeMins<\/b> parameter accepts values in minutes&mdash;hence, the reason we multiple the <b>$TtlHours<\/b> variable by 60.<\/p>\n<p>The new authentication policy is not protected from accidental deletion, so we can easily remove it after the time-bound access has expired.<\/p>\n<p>Now we assign the authentication policy to our user account. You&rsquo;ll need to check that your version of <b>Set-ADUser<\/b> has the <b>&ndash;AuthenticationPolicy<\/b> parameter:<\/p>\n<p style=\"margin-left:30px\">Set-ADUser -Identity $UserSamAccountName -AuthenticationPolicy $AuthPolName&nbsp;<\/p>\n<p>We also set a couple of flags to be used later to trigger the countdown and the authentication policy deletion code later on in the function:<\/p>\n<p style=\"margin-left:30px\">$CountDown = $true<\/p>\n<p style=\"margin-left:30px\">$AuthPol = $true<\/p>\n<p>We looked at the countdown code in the last post. Here&rsquo;s the simple authentication policy deletion routine:<\/p>\n<p style=\"margin-left:30px\">if ($AuthPol) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Remove-ADAuthenticationPolicy -Identity $AuthPolName -Confirm:$false<\/p>\n<p style=\"margin-left:30px\">}<\/p>\n<p>We have to use <b>&ndash;Confirm:$false<\/b> to override the automatically trigged confirmation dialogue.<\/p>\n<h2>Putting it all together<\/h2>\n<p>Here&rsquo;s what happens when we execute the function with the <b>&ndash;ProtectedUser<\/b> and <b>&ndash;Verbose<\/b> parameters:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/wes-5-24-15-1.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/wes-5-24-15-1.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<p>Now, I log on to my administrative host with the &lsquo;Master Chief&rsquo; account. I can only access this host when I am a member of the Domain Admins group. Let&rsquo;s look at my group membership:<\/p>\n<p style=\"margin-left:30px\">(Get-ADUser -Identity MasterChief -Properties MemberOf).MemberOf<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/wes-5-24-15-2.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/wes-5-24-15-2.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<p>Let&rsquo;s look at the Kerberos TGT that is issued on the dedicated administrative workstation:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/wes-5-24-15-3.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/wes-5-24-15-3.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<p>This ticket is only valid for one hour, and its <b>Renew Time<\/b> is the same as the <b>End Time<\/b>, meaning that we have to reauthenticate after expiry. We can no longer persist our high-privileged access. I can safely pat the dog on its head!<\/p>\n<p>Whilst the ticket is valid, we can perform tasks, for example:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/wes-5-24-15-4.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/wes-5-24-15-4.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/wes-5-24-15-5.png\" style=\"font-size:12px\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/wes-5-24-15-5.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<p>As shown here, as soon as the ticket expires, our access is revoked:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/wes-5-24-15-6.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/wes-5-24-15-6.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/wes-5-24-15-7.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/wes-5-24-15-7.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<h2>Function summary<\/h2>\n<p>Without the <b>&ndash;ProtectedUser<\/b> switch, the function ensures that high-privileged group <i>membership<\/i> is removed after an allotted period of time.<\/p>\n<p>With the <b>&ndash;ProtectedUser<\/b> switch and a domain functional level of Windows Server 2012 R2, the TGT lifetime can match the TTL of the dynamic group object used to grant temporary high-privileged group membership, so our high-privileged<i> access<\/i> will be removed around the same time as our high-privileged group <i>membership<\/i> is removed.<\/p>\n<p>~Ian<\/p>\n<p>Thank you, Ian (and Phil)!<\/p>\n<p>I invite you to follow me on <a href=\"http:\/\/bit.ly\/scriptingguystwitter\" target=\"_blank\">Twitter<\/a> and <a href=\"http:\/\/bit.ly\/scriptingguysfacebook\" target=\"_blank\">Facebook<\/a>. If you have any questions, send email to me at <a href=\"mailto:scripter@microsoft.com\" target=\"_blank\">scripter@microsoft.com<\/a>, or post your questions on the <a href=\"http:\/\/bit.ly\/scriptingforum\" target=\"_blank\">Official Scripting Guys Forum<\/a>. See you tomorrow. Until then, peace.<\/p>\n<p><b>Ed Wilson, Microsoft Scripting Guy<\/b><span style=\"font-size:12px\">&nbsp;<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary: Guest blogger, and Microsoft PFE Ian Farr, continues his series about JIT administration with Windows PowerShell. Microsoft Scripting Guy, Ed Wilson, is here. Today, welcome back Ian Farr for the conclusion of his two-part blog. Before you dig into today&#039;s post, please read Use PowerShell for JIT Administration and PAM &ndash; Part 1. To [&hellip;]<\/p>\n","protected":false},"author":596,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[56,472,3,61,45],"class_list":["post-5971","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-guest-blogger","tag-ian-farr","tag-scripting-guy","tag-weekend-scripter","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Summary: Guest blogger, and Microsoft PFE Ian Farr, continues his series about JIT administration with Windows PowerShell. Microsoft Scripting Guy, Ed Wilson, is here. Today, welcome back Ian Farr for the conclusion of his two-part blog. Before you dig into today&#039;s post, please read Use PowerShell for JIT Administration and PAM &ndash; Part 1. To [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/5971","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/596"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=5971"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/5971\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=5971"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=5971"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=5971"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}