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

[vnet] add vnet-(un)install-service commands for Windows #52164

Merged
merged 1 commit into from
Feb 20, 2025

Conversation

nklaassen
Copy link
Contributor

@nklaassen nklaassen commented Feb 14, 2025

This PR adds the command tsh vnet-install-service to install the VNet Windows service. It does this by using the Windows Service Control Manager to configure a Windows service to start tsh.exe with the appropriate arguments.

tsh.exe should not be saved in a user-writable path or else the user could overwrite the exe and then start the service to get privilege escalation. To try to prevent misconfiguration, the installer asserts that tsh.exe must be installed under Program Files, usually C:\Program Files\ but this can be controlled by the environment variable PROGRAMFILES. If tsh.exe is not found there, or wintun.dll is not installed next to tsh.exe, the command fails. This will require a per-machine install of Connect so that tsh.exe is properly installed under PROGRAMFILES and so that the installer runs with admin rights, which are necessary in order to install the service. The following PR #52165 updates the Connect installer.

I'm also adding a tsh vnet-uninstall-service command which deletes the service configuration, although this will not be called by the Connect uninstaller which runs after tsh.exe has already been deleted. Fortunately all the uninstaller needs to do is delete the service configuration, which can be done in a single command. The tsh vnet-uninstall-service command may be useful if any users manually install the service for use with tsh instead of Connect.

@nklaassen nklaassen added no-changelog Indicates that a PR does not require a changelog entry vnet backport/branch/v17 labels Feb 14, 2025
@github-actions github-actions bot added size/md tsh tsh - Teleport's command line tool for logging into nodes running Teleport. labels Feb 14, 2025
@zmb3
Copy link
Collaborator

zmb3 commented Feb 14, 2025

This means Windows users might have up to 3 different tsh installs on their machine, right?

  1. Any version of tsh manually installed
  2. The version bundled with Teleport Connect
  3. The VNet version

How do we keep 2 and 3 in sync? What happens when the user updates Teleport Connect (and gets a new version of tsh along with it)?

@nklaassen
Copy link
Contributor Author

This means Windows users might have up to 3 different tsh installs on their machine, right?

  1. Any version of tsh manually installed
  2. The version bundled with Teleport Connect
  3. The VNet version

How do we keep 2 and 3 in sync? What happens when the user updates Teleport Connect (and gets a new version of tsh along with it)?

Every time the user runs the Connect installer, it will call tsh vnet-install-service, overwriting whatever is already there with an identical version of tsh to the version Connect is installed with. Unless there is another way to update Connect without running the installer that I don't know about?


func serviceNameAndInstallDir(username string) (string, string) {
serviceName := userServiceName(username)
serviceInstallDir := filepath.Join(`C:\Program Files`, serviceName)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does each user need a separate service? And why does each one need to be in a separate directory, directly within Program Files?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm giving each user a separate service simply so that each user can have a different version of Connect installed with a matching version of tsh running the service. Although, only one user can run the service at a time, if another user tries they will fail to create the named TUN interface. Context on Program Files #52164 (comment) the service exe can't be in a path that normal users can write to otherwise we risk arbitrary privilege escalation

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

each user can have a different version of Connect installed with a matching version of tsh running the service

This is not something that Windows handles terribly well... if multiple users need a program, it probably shouldn't be installed in a per-user manner i.e. under appdata/similar, and should be installed once under the program files folder instead.

If we really do need different versions, then IMO the service should be installed somewhere like Program Files\Teleport\<version>\<service name> instead, rather than polluting program files for every user. This would be pretty nasty on systems that have dozens, hundreds, or thousands of users log into them in their lifetime.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On Windows at least we currently don't offer an option to do a per-machine install of Connect rather than per-user. If that's a path we want to go down we could figure out the implications of a per-machine VNet service installation too, but so far I haven't been looking to change this just for the sake of VNet.

One complication of doing a per-version Service along with per-user Connect installations is what to do when one user uninstalls Connect. Do we delete the service for that version and break the other user's installation? do we attempt to maintain a list of which user installations are referencing that service at any given time?

The other complicating factor is that I currently only grant permission for the installing user to start the service, other users are not allowed to start it. Now, if the duplicated files are a concern there are a couple options:

  1. We could have a separate service for each user TeleportVNet-Alice, TeleportVNet-Bob, etc and have them all reference the same exe path Program Files\TeleportVNet\17.3.0\tsh.exe, but each service would have its own permissions
  2. We could have a single service for each version TeleportVNet-17.3.0 and tsh vnet-install-service could add the ACL to allow the current user to start the service without changing the existing permissions

These all seem messier than the per-user installation to me. I'm inclined to keep things as I have them unless and until we decide to support per-machine Connect installations on Windows.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One complication of doing a per-version Service along with per-user Connect installations is what to do when one user uninstalls Connect. Do we delete the service for that version and break the other user's installation? do we attempt to maintain a list of which user installations are referencing that service at any given time?

If we need to answer questions like these then the vnet feature should be restricted to machine-wide installations. Windows is not designed for services to be ran per-user, as shown by both the problems pointed out above, and the need for an elevated user to install/remove/change the service.

To add onto this, this gets even more complicated when users are removed and re-added (maybe representing the original human user, maybe not), which is relatively common in larger enterprise environments. Their SIDs change, but the username remains the same... so how should Teleport handle this?

If the application needs to manage system-wide resources (such as network interfaces), and run as a different user, and run in the background as a service, and be kept in-sync with "client" which is potentially used by multiple users, then the entire application needs to be installed once per machine, rather than per user.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Back when we were adding Windows support to Connect, it was not something we thought about too much and went with the defaults used by electron-builder, which is to install the app per user.

A customer once ran into a problem where they were running the installer (through some kind of MDM most probably) and wanted to install the app in Program Files, not in %localappdata%. The customer managed to solve this by using the \D switch to install Connect in a specific directory.

Changing this should be a matter of changing the NSIS section of electron-builder's config to set perMachine to true. As long as the installer gracefully handles this migration between earlier versions and 17.3, we should be fine. Based on Grzegorz's findings when experimenting with oneClick: false, it seems that it should work.

Hopefully it doesn't break setups where people use the \D switch to install it in Program Files. I don't know if changing perMachine to true does any extra stuff that would set it apart from running today's Connect installer with \D set to Program Files.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have switched to a per-machine installation. It simplifies things here a bit since the installer now already runs with admin rights and no files need to be copied.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have switched to a per-machine installation.

For compatibility reasons should the installer provide an option for per-user (without vnet support) or per-machine?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can have a look at making it an option but this will be more relevant to the installer PR #52165

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough. I don't know if this is needed at all - this is more of a product consideration than a technical one.

Base automatically changed from nklaassen/process-authentication to master February 18, 2025 22:56
@nklaassen nklaassen force-pushed the nklaassen/vnet-service-installer branch from 3af6c3f to cf95e40 Compare February 19, 2025 00:08
Trustee: windows.TRUSTEE{
TrusteeForm: windows.TRUSTEE_IS_NAME,
TrusteeType: windows.TRUSTEE_IS_WELL_KNOWN_GROUP,
TrusteeValue: windows.TrusteeValueFromString("Authenticated Users"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vnet tunnels are specific to each user (even if configured for the entire machine), right? If so, is there any meaningful security impact in one user starting/stopping/querying the service, if it is in use by another user?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose it would be similar to another user being able to disconnect the machine from a VPN, or connecting to a different VPN. So yes, there's some impact to other users being able to start and stop VNet, but I'm not sure there's much we can do about that with a per-machine installation. The VNet security invariants are not really ideal for multi-user machines in the first place, given that any user could make a TCP connection to one of your Teleport apps authenticated as the active VNet user. But again, this is similar to a VPN

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a blocker for this PR, but because of this we may want to add the ability to set the group allowed to start/stop the service at some point.

@nklaassen nklaassen force-pushed the nklaassen/vnet-service-installer branch from 3d1e007 to b822cfc Compare February 20, 2025 17:31
@nklaassen nklaassen added this pull request to the merge queue Feb 20, 2025
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Feb 20, 2025
@nklaassen nklaassen added this pull request to the merge queue Feb 20, 2025
Merged via the queue into master with commit 023f50b Feb 20, 2025
41 checks passed
@nklaassen nklaassen deleted the nklaassen/vnet-service-installer branch February 20, 2025 18:58
@public-teleport-github-review-bot

@nklaassen See the table below for backport results.

Branch Result
branch/v17 Create PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport/branch/v17 no-changelog Indicates that a PR does not require a changelog entry size/md tsh tsh - Teleport's command line tool for logging into nodes running Teleport. vnet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants