gravitational / teleport

The easiest, and most secure way to access and protect all of your infrastructure.
https://goteleport.com
GNU Affero General Public License v3.0
17.63k stars 1.76k forks source link

Auto-configure group policy for Desktop Access Setup. #8805

Closed flyinghermit closed 2 years ago

flyinghermit commented 3 years ago

What

There are currently four different policy updates (allow RDP connection, disable NLA for RDP, enabling smart card, opening RDP port in firewall) required to prepare the primary windows server for Desktop Access. A way to automate these policy updates will help ease the initial trial.

How

Using Powershell scripts or registry files.

Why

Improves user experience.

benarent commented 3 years ago

+1 . I used https://github.com/aws-quickstart/quickstart-microsoft-activedirectory to setup my AD on AWS. It's open source, and could be good starting point. https://github.com/aws-quickstart/quickstart-microsoft-activedirectory/tree/main/scripts/Modules/Module-AD

klizhentas commented 2 years ago

When trying to get LDAPS and PKI infrastructure (for issuing certificates inside the domain) working with AWS Managed AD.

Most of it seems to be manual steps, such as the huge blog post you have to follow to get it enabled.

Azure managed AD comes with LDAPS enabled out of the box.

The big issue is that Microsoft doesn't provide good ways to automate group policy objects. Many customers will already have most of this infrastructure set up - but I'm unsure if this is the case with AWS managed AD. LDAPS (a Teleport requirement) isn't something that you'd have enabled just for regular domain usage unless you have a specific need for it.

@webvictim will try to get AWS managed AD setup deployed via automation this week and run the automation against it to see if I can fix any potential issues. If we at least have some recommended commands for customers which work in our demo environments, that will put us in a good place for deploying this with prospects.

From @klizhentas:

Can we use tctl desktop configure approach to automate that configuration similar to DB access?

zmb3 commented 2 years ago

Potentially of value: https://docs.microsoft.com/en-us/previous-versions/windows/desktop/gpmc/group-policy-management-console-scripting-samples

benarent commented 2 years ago

After spending two days recording a 30min 'Getting Started with Desktop Access' there are few other pain points I've found.

ibeckermayer commented 2 years ago

It looks like it may be possible to configure GPO via Powershell

ibeckermayer commented 2 years ago

Notes

Notes on this project, organized by the manually-configured section of the current documentation that needs to be replaced. Miscellaneous notes catalogued here in this section.

Had some success finding which registry keys were set using this function (source)

# This function retrieves settings it does not make changes to GPOs.

function Recurse-PolicyKeys{
 [CmdletBinding()]
 param(
   [Parameter(Mandatory=$true)]
   [string]$GPOName,

   [Parameter(Mandatory=$true)]
   [string]$Key
 )
 $current = Get-GPRegistryValue -Name $gpoName -Key $key
 foreach ($item in $current){
   if ($item.ValueName -ne $null){
   [array]$returnVal += $item 
 }
   else{
     Recurse-PolicyKeys -Key $item.fullkeypath -gpoName $gpoName
   }
 }
 return $returnVal
}

For example:

Recurse-PolicyKeys -GPOName "Teleport Access Policy" -Key "HKLM\Software"

Step 3/6: Configure a GPO to allow Teleport connections

Create another GPO and import the Teleport CA

I haven't tried this yet, but it appears to be accessible via

Get-GPRegistryValue -Name "Teleport Access Policy" -Key "HKLM\Software\Policies\Microsoft\SystemCertificates\Root\Certificates"

Enable the Smart Card service

Unlike some of the other settings, it didn't seem as though this registry was configured in the GPO via the manual process. That is to say, when I tried a

Get-GPRegistryValue -Name "Teleport Access Policy" -Key "HKLM\System\CurrentControlSet\Services\SCardSvr\Start"

I would get back the Get-GPRegistryValue : The following Group Policy registry setting was not found: ... error.

However this support thread implies that setting this value to "2" should do the trick:

Set-GPRegistryValue -Name "Teleport Access Policy" -Key "HKLM\System\CurrentControlSet\Services\SCardSvr\Start" -ValueName Start -Type DWord -Value 2

This will require more experimentation to confirm -- for example, when I change this setting via powershell (to say "1"), it doesn't show up as changed in the editor. So it's not clear that it's actually doing what I want it to do.

Open firewall to inbound RDP connections

These two settings I found when tinkering around (Get-GPRegistryValue -Name "Teleport Access Policy" -Key "HKLM\Software\Policies\Microsoft\WindowsFirewall):

Set-GPRegistryValue -Name "Teleport Access Policy" -Key "HKLM\Software\Policies\Microsoft\WindowsFirewall" -ValueName PolicyVersion -Type DWord -Value 534
Set-GPRegistryValue -Name "Teleport Access Policy" -Key "HKLM\Software\Policies\Microsoft\WindowsFirewall\FirewallRules" -ValueName RemoteDesktop-UserMode-In-TCP -Type String -Value "v2.20|Action=Allow|Active=TRUE|Dir=In|Protocol=6|LPort=3389|App=%SystemRoot%\system32\svchost.exe|Svc=termservice|Name=@FirewallAPI.dll,-28775|Desc=@FirewallAPI.dll,-28756|EmbedCtxt=@FirewallAPI.dll,-28752|"

ref1, ref2

robpomeroy commented 2 years ago

I'm building (and plan to open source) an Ansible playbook to automate the configuration of AD. To solve the GP configuration problem, I create a GPO manually, export it (backup), and then insert variables into the export to make it generic. For want of a GPO Ansible module, I simulate idempotency by running test scripts before taking actions. The following is for step Step 2/6. Prevent the service account from performing interactive logins, which demonstrates this approach:

- name: Test GPO - Block interactive login for Teleport Service
  ansible.windows.win_powershell:
    script: |
      Get-GPO -Name "Block interactive login for Teleport Service"
  register: gpo_test
  changed_when: false

- name: Create GPO - Block interactive login for Teleport Service
  ansible.windows.win_powershell:
    script: |
      (New-GPO -Name "Block interactive login for Teleport Service" | New-GPLink -Target "{{ domain_dn }}").GpoId.Guid
  register: gpo_create
  when: gpo_test.error

- name: Get SID of Teleport Service
  ansible.windows.win_powershell:
    script: |
      (Get-ADUser -Identity "Teleport Service").SID.Value
  register: teleport_sid
  changed_when: false
  when: gpo_test.error

- name: Create GPO backup directories
  ansible.windows.win_file:
    path: C:\Windows\Temp\block_interactive\{{ item.path }}
    state: directory
  with_filetree: ../templates/block_interactive
  when: item.state == 'directory' and gpo_test.error

- name: Copy GPO backup files
  ansible.windows.win_template:
    src: "{{ item.src }}"
    # Remove the ".j2" extension when copying
    dest: C:\Windows\Temp\block_interactive\{{ item.path.rstrip(".j2") }}
    trim_blocks: no
  with_filetree: ../templates/block_interactive
  when: item.state == "file" and gpo_test.error

- name: Import GPO - Block interactive login for Teleport Service
  ansible.windows.win_powershell:
    script: |
      Import-GPO -BackupGpoName "Block interactive login for Teleport Service" -Path "C:\Windows\Temp\block_interactive" -TargetGuid "{{ gpo_create.output[0] }}"
  when: gpo_test.error

Then in the GPO export files, we place variables as required. For example, in DomainSysvol\GPO\Machine\microsoft\windows nt\SecEdit\GptTmpl.inf.j2:

[Unicode]
Unicode=yes
[Version]
signature="$CHICAGO$"
Revision=1
[Privilege Rights]
SeDenyInteractiveLogonRight = *{{ teleport_sid.output[0] }}
SeDenyRemoteInteractiveLogonRight = *{{ teleport_sid.output[0] }}

You have to be super mindful of file encoding. The GptTmpl.inf file for example exports as UTF-16. You need to convert it to UTF-8, otherwise the Ansible win_template module mangles it during upload/interpolation. I also discovered that without the trim_blocks parameter, PowerShell segfaults during the import!

Haven't yet worked out how to automate the problem @benarent calls out, of importing the user CA certificate.

robpomeroy commented 2 years ago

@ibeckermayer:

Get-GPRegistryValue -Name "Teleport Access Policy" -Key "HKLM\Software\Policies\Microsoft\SystemCertificates\Root\Certificates"

Doesn't this just change the local Group Policy, rather than amending the settings in a (potentially domain-wide) GPO?

robpomeroy commented 2 years ago

Ansible playbooks ready, to configure a Teleport server and prep an Active Directory domain: https://github.com/robpomeroy/teleport-ansible

First disclaimer: there are flaws! PRs welcome. Second disclaimer: I do not work for Teleport.

benarent commented 2 years ago

@robpomeroy Thank you. This is super cool. I've still be hand rolling my setup but this will help a lot. I'll try it next time I need to configure Teleport Desktop Access.

For the CA automation, we might be able to use Machine ID. Which is a new feature in Teleport 9, I've created a feature request to add Teleport Desktop Access support to tbot. https://github.com/gravitational/teleport/issues/11070 . Can you also send me an email, ben@goteleport.com and I'll send out a swag package for your efforts.

zmb3 commented 2 years ago

Thanks @robpomeroy! The export/import approach was on my list of things to try, I just didn't know how to replace the vars that needed changing. Will take a closer look at this today!

ibeckermayer commented 2 years ago

@ibeckermayer:

Get-GPRegistryValue -Name "Teleport Access Policy" -Key "HKLM\Software\Policies\Microsoft\SystemCertificates\Root\Certificates"

Doesn't this just change the local Group Policy, rather than amending the settings in a (potentially domain-wide) GPO?

Good question, I'm not sure what the answer is. I was assuming (hoping) that if a GPO applied to the whole domain, and I changed some registry value corresponding to the GPO's setting, that setting would be propagated throughout the domain. I wasn't able to find any good info on that online, and so the plan is to test this empirically.

Your approach of exporting a configured GPO and then importing it is also on the list of things to try. To reiterate my colleagues, thanks for building this and communicating it here. We'll kick this project higher up the priority list.

robpomeroy commented 2 years ago

@benarent - thanks, I've emailed you.

@zmb3 - I basically scoured the export, looking for things that might need to be replaced. I probably went overboard, because the Import-GPO cmdlet supposedly handles certain replacements automatically (if you're pulling in a backup from a different domain). The most important replacement was the SID of the Teleport service account. All sorted thanks to Ansible/Jinja2 templates and lots of googling PowerShell parameters...

@ibeckermayer - GPOs are "physically" stored in the file system (in SYSVOL). The GP registry value cmdlet wouldn't modify that I don't think.

It's pure stubbornness on my part that I persisted with Ansible. It would have be far easier just to run the commands in the v9 Getting Started guide! 😂

ibeckermayer commented 2 years ago

@robpomeroy Got it, thanks for clarifying. This is my first time working in depth with Windows/AD and so I am learning about it on the fly.

If I'm understanding correctly, GPO's are stored in the SYSVOL on the DC and SYSVOL is what's replicated to the clients. The registry values, on the other hand, handle settings specific to each machine individually.

It seems as though there is som overlap between the settings GPOs store in SYSVOL and the settings set in the registries. Do you know if its always the case that the SYSVOL rules override those in individual registries? Or perhaps those rules are parsed and written into the registries on each individual machine and if somebody on a non-DC machine tries to change them they are reverted.

Based on your solution, it seems like there isn't a good programmatic API for directly modifying GPO's stored in SYSVOL.

ibeckermayer commented 2 years ago

It seems as though there is som overlap between the settings GPOs store in SYSVOL and the settings set in the registries. Do you know if its always the case that the SYSVOL rules override those in individual registries? Or perhaps those rules are parsed and written into the registries on each individual machine and if somebody on a non-DC machine tries to change them they are reverted.

It looks like this answers my question: https://stackoverflow.com/a/1162276/6277051

robpomeroy commented 2 years ago

@ibeckermayer Partially. One of the problems is that grizzled Windows sysadmins use “Group Policy” to mean two different things. At one level, it’s the tool for controlling settings on an individual Windows computer (other than Win Home - unless you hack it). At the higher level - and this is the level sysadmins usually mean - it’s the centralised tool Active Directory uses to impose configuration on all the machines within the domain.

As you’ve read, central GP will re-impose its will every 90 minutes by default. So anything you set on a single machine is liable to be undone on the next refresh - unless you do something hacky, like change the permissions on registry keys to prevent it. But end users on machines should not be local admins and should not have that power anyway. GP is all about compliance. Best not to circumvent it.

And really, this is what Teleport wants anyway. You’re using AD and Group Policy (centrally) to make sure machines get the right certificates, permissions and firewall settings. This way, you don’t need to configure each individual machine separately. If you’ve ever come across Rudder, you’ll recognise the similarity.

Centrally, one of the ways Group Policy manages client machines is to modify their registry settings. That’s why often you’ll see posts telling you two ways to do something - the regedit way and the GP way. But GP also manages non-registry settings, can deploy and run scripts, create files & shortcuts, manage the firewall, modify the certificate store (in non-registry ways), etc.

I’m going to be offline for a couple of weeks now, but I’m more than happy to hop on a call after that, to discuss further if I can help.

Incidentally, when you look closely at deploying Teleport to non-domain-joined machines, you may well want to use standalone GP for that (e.g. via PowerShell or, more likely, C#). Just bear in mind it won’t be available for Home users.

ibeckermayer commented 2 years ago

@robpomeroy thanks for taking the time to explain that in detail, its all much clearer to me now.

The one comment I don't understand is

Incidentally, when you look closely at deploying Teleport to non-domain-joined machines, you may well want to use standalone GP for that (e.g. via PowerShell or, more likely, C#). Just bear in mind it won’t be available for Home users.

  1. Does that imply that the standalone GP's are categorically different from the AD GPs? Or can the two be used interchangeably?
  2. Do you mean that these GP's can be built via PS/C#? Presuming there's a categorical difference between GP's and AD GP's, can AD GP's also be built with PS/C#?
  3. Who are home users in this context?

A call might be quite helpful! If you're still up for it when you're back, please email me at isaiah@goteleport.com.

robpomeroy commented 2 years ago

@ibeckermayer

I didn't explain that very well. 🙂

Probably most Group Policy settings are the same whether or not a computer is joined to a domain. An Active Directory domain has some additional settings that are specific to a domain, but the main difference is the centralised management and enforcement.

Many Group Policy settings can be changed using other methods. For instance, Group Policy settings can manage the Windows firewall. But you can also manage that using PowerShell, the netsh command, the MMC (GUI), Windows APIs (e.g. using C#), etc.

If a computer were not joined to a domain, since you don't have the luxury of centralised management, Group Policy might not be the easiest method to manage whatever settings are required by Teleport. A Teleport installer or native Windows client would use whatever method was most convenient for the programmer. And as we have seen here, Group Policy is not always convenient for programmers!

By "Home users" I was referring to the Home edition of Windows (as opposed to Windows Pro or Windows Enterprise). Windows Home doesn't have Group Policy out of the box, so you can't use it at all, to manage Windows Home. Also Windows Home cannot be joined to a domain.

This is perhaps academic at the moment, because Teleport for Windows currently makes heavy use of Windows PKI, which you wouldn't often see outside an Active Directory domain environment. I'd suggest the Teleport team consider making use of Smallstep for a more universal, ready -to-roll open source PKI solution. But you may have something even better up your sleeves!

ibeckermayer commented 2 years ago

@robpomeroy Thank you, now it makes sense. I was holding out hope that there might be some standard way to generate the necessary GPO's with C#, but it sounds like the parameterized GPO export is the way to go. (Not that I doubted your choice, I just didn't understand it myself).

This is perhaps academic at the moment, because Teleport for Windows currently makes heavy use of Windows PKI, which you wouldn't often see outside an Active Directory domain environment.

Yes, for now we're focused on improving support for the primary environment we expect customers to use.

zmb3 commented 2 years ago

Released in 10.2.4.