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

raw_exec windows: add support for setting the task user #9424

Open
rgl opened this issue Nov 23, 2020 · 7 comments
Open

raw_exec windows: add support for setting the task user #9424

rgl opened this issue Nov 23, 2020 · 7 comments
Labels
stage/accepted Confirmed, and intend to work on. No timeline committment though. theme/platform-windows type/enhancement

Comments

@rgl
Copy link

rgl commented Nov 23, 2020

I would like to set the user that will execute a task command in windows (like its already supported in linux); e.g.:

job "example" {
  datacenters = ["dc1"]
  task "task1" {
    user   = "test-user"
    driver = "raw_exec"
    config {
      command = "whoami.exe"
      args    = ["/all"]
    }
  }
}

It would also be pretty interesting to support Group Managed Service Accounts and Local Service Accounts (these do not have a user managed password, as such, are more convenient to use). Please note these require the application to run (or be wrapped) as a Windows service.

Please note that in Windows, you also need to define the password; which is something that is not yet supported by go exec.Command; I'm trying to figure out how can this be done in golang/go#42773.

@tgross
Copy link
Member

tgross commented Nov 30, 2020

Thanks for opening this @rgl.

Copying over a recommendation from golang/go#42773 (comment)

So in that case, if you're already running as Local System, you don't want to use these APIs that require a password. Rather, mint a token using something like NtCreateToken, and then pass that to the Token field:

attrs := &os.ProcAttr{
                Sys: &syscall.SysProcAttr{
                        Token: syscall.Token(theTokenThatYouJustMade),
                },
}

And then attrs is passed to os.StartProcess like usual.

@tgross tgross added theme/platform-windows stage/accepted Confirmed, and intend to work on. No timeline committment though. type/enhancement labels Nov 30, 2020
@rgl
Copy link
Author

rgl commented Nov 30, 2020

BTW, In the mean time I've found out about damon from https://www.hashicorp.com/resources/running-windows-microservices-on-nomad-at-jet-com and I'm trying to fiddle with it.

It has some interesting features (e.g. limit the cpu usage, run the application inside a job object) that should be integrated into nomad somehow.

So far I was able to run-as-another-user (using a password thou), but I'm still having problems running applications like whoami.exe /all or powershell.exe which do not run for some reason ("simple" console applications like a go hello world work thou).

@tomqwpl
Copy link

tomqwpl commented Jun 26, 2021

I also have this requirement, and am considering the best way to approach it. The immediate requirement is to support running as another user.

In Windows you can launch processes as another user without a password, they just don't have network credentials. I have GO code do do that, and can successfully run "whoami" and get it to return the correct result.

My ideal would be to end up with code in Nomad to do this. Second choice is to use a wrapper along the lines of "daemon" referenced above. What I don't really want to do is maintain a long term fork of Nomad containing the code, so what is the likelyhood of getting a PR accepted that would contain suitable code? Would it be better if there was a separate github project to do the S4U impersonation code, and then a PR on Nomad to make the Executor make use of that, or would it be better if all of the code was within the hashicorp estate as it were?

Short term I'm going to solve this by using something like daemon. It introduces an extra layer though. So already there is an instance of raw-exec plugin wrapping each process, there would then also be an instance of "daemon" as well. But it's the quickest short term solution.

@ddreier
Copy link
Contributor

ddreier commented Jan 27, 2022

We're also interested in this. As we onboard more Windows Console/Service applications onto Nomad we've run into some that rely on using network credentials to access file shares.

It would be great to be able to run these applications as an AD user. Even using a password would be fine because we could retrieve that from Vault.

@tomqwpl
Copy link

tomqwpl commented Jan 27, 2022

For info, what I ended up doing here was writing a replacement nomad task driver. The task driver (well the process monitor it spawns) then handles interfacing to windows to perform logon or impersonation before launching the requested workload. We're also adding interfacing to Windows for resource constraints and so on. So we use this in place of raw_exec. Once I worked out how task drivers worked, and particularly how the execution monitoring worked (which wasn't at all obvious, it's all handled by another process launched by the task driver to monitor that particular workload), it was reasonably straightforward to implement.

@antineutrino
Copy link

@tomqwpl
Do you have an example how your task driver is implemented?

@tomqwpl
Copy link

tomqwpl commented Feb 3, 2022

@antineutrino Right now nothing that I can share.
The key part is that to launch the process as another user on windows, you need to make use of the Windows LsaLogonUser API call with the MsV1_0S4ULogon constant and MSV1_0_S4U_LOGON struct in order to perform a logon without requiring a password. This gives you back a limited permission impersonation token (you don't have network credentials). But it's enough to run a process on the local machine as a different user. If you search up MSV1_0_S4U_LOGON you'll find example C code to do this bit (e.g https://stackoverflow.com/a/35670890/518627), it's then a case of translating that into Go, using syscall to make calls into secur32.dll as necessary, and then converting it into a form that's usable from a task driver.
I didn't find task drivers the simplest thing to understand the structure of, there are more processes and gRPC in there than I expected. So you need to understand how to do the LsaLogonUser part from go on the one hand, then you need to understand how to write a task driver that can make use of that on the other.
As I say, this isn't something that at the moment I can share the code for, though that might change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stage/accepted Confirmed, and intend to work on. No timeline committment though. theme/platform-windows type/enhancement
Projects
None yet
Development

No branches or pull requests

5 participants