Execute resource on windows as alternate user

I want to run a command as a non-default user in windows, so I tried this:

command 'run myprog' do
  command '.\\myprog.exe'
  directory 'c:\\myprog'
  user 'myuser'
end

This gives me an error:

Mixlib::ShellOut::InvalidCommandOption: You must supply both a username and password when supplying a user in windows

If I add a password attribute

password: my3ecret00Password

I then get this error:

 FATAL: NoMethodError: undefined method `password' for Chef::Resource::Execute

How do I add a password so I can execute a command as a non-default user on windows?

If you want to impersonate a different account, use the shell_out function in a ruby_block:

ruby_block 'install sql server' do
  block do
    Chef::Resource::RubyBlock.send(:include, Chef::Mixin::ShellOut)
    command_to_run = "c:\\path\\myprog.exe"
    shell_out(command_to_run,
      {
        :user   => 'username',
        :password   => 'password'
      }
    )
  end
end

Note: If you want the command to run to be a block of powershell, then use powershell_out.

Thanks. I’ve tried that but get the error:

Errno::NOERROR: No error - CreateProcessAsUserW (You must hold the 'Replace a process level token' permission)

According to this StackOverflow answer, the problem is that I need to grant my user the SeAssignPrimaryTokenPrivilege.

Even though I have done so according to the instructions here and I can confirm it with this:

PS C:\Users\Administrator> Get-UserRightsGrantedToAccount myuser

Account                                                     Right
-------                                                     -----
myuser                                                      {SeAssignPrimaryTokenPrivilege}

(Same results whether I prepend the machine name and a backslash to the username)

I’m still getting that same error. Ideas?

Ahh. Right. Yes you need that “right” but what can be confusing is that its actually the user running the chef run and not necessarily the user being impersonated that needs that right.

Did you grant it to the user under which chef-client runs?

How do I determine the user that chef-client runs as? I assumed that was Administrator, who should already have that right.

I am using test kitchen at the moment and the only other user in the mix is the ‘vagrant’.
I tried granting the privilege to that user and it “works” (there are problems, more on that below).

So when I am running my recipe against a “real” node how will I know which user the chef-client will be running as? Will it be the SYSTEM user? Is there a way to determine programmatically which user this is? Just run whoami?

Now on to my problem. Now when I run my recipe it just hangs.

If I go to my windows VM and log in as the user I want to run that command as, and run the command manually, it pops up a dialog entitled “User Account Control” , saying: "Do you want to allow the following program from an unknown publisher to make changes to this computer?"
If offers me the opportunity to type in my password, or that of another user, with the somewhat misleading “to continue, type an administrator password” (in fact this is not necessary, I can type in the password of the user I’m logged in as). So if I do that it works.

So my guess is that while running chef it is coming up against this dialog even though I have no way to type in a password in that dialog while running chef non-interactively.

Any ideas? Is shell_out supposed to take care of this? The program I am trying to run is an InnoSetup installer.

I really need it installed as a non-administrative user. I could (I suppose) install it as administrator and then recursively change the owner of all the files it creates to my non-admin user. That would probably be good enough. Other ideas welcome.

BTW I appreciate your help. I have posted several questions and this is the first time I’ve gotten an answer.

Sorry but I’m back to square one here. Now I am just trying to run a simple command-line program as another user and I’m still getting the error, although both the user running chef-client and the user who I want to impersonate have the SeAssignPrimaryTokenPrivilege granted.

If I manually log in as the user I want to impersonate and run the command, it works fine.

When I run my chef recipe, though, I still get

ruby_block[install BiocInstaller] (BBS-provision-cookbook-windows::default line 136) had an error: Errno::NOERROR: No error - CreateProcessAsUserW (You must hold the 'Replace a process level token' permission)

In this case I really do need to be able to run this command as another user, I cannot work around it.
This is a big part of our infrastructure so I have to be able to do this.

I have also tried granting similar privileges to both users (the user who runs chef-client and the user I want to impersonate):

  • SeCreateTokenPrivilege
  • SeImpersonatePrivilege

Even with all 3 privileges granted to both users, I still get the error.

I thought of maybe setting up a scheduled task that runs as another user and then starting the task from my recipe, but that is going to be onerous as ultimately the recipe will need to do a lot of things as another user.

Hope someone can help.

Sorry I did not catch your last reply. A few things here:

  • In the case of your vagrant box. I’m assuming you or maybe test-kitchen logged in as the vagrant account? If thats the case, then its the vagrant user that is running chef.
  • To find out what user is running any given process you can run Get-WmiObject win32_process | Select-Object Name,@{n='Owner';e={$_.GetOwner().User}} | sort name Chef’s perocess will be ruby.exe
  • If the exe your impersonated user is running needs to escalate, you need to make sure that user is an administrator otherwise you may very well see the process hang

Futzing around with right assignments can sometimes not be the best idea and you may find that a scheduled task is the better approach if the right assignments get in the way.

Thanks for your reply.

The exe I want to run as an impersonated user does not need to escalate.
It runs fine when I am logged in as that user.

As I mentioned, scheduled tasks are not a good fit for what I am trying to do.

I would really like to be able to do this, which is basically just the windows equivalent of an execute resource specifying the user property. It is annoying that something so seemingly trivial is so difficult. I imagine that others must need this as well.

I hate to go there, but this could be a deal-breaker, and we have not yet committed to Chef. At a glance it seems like Puppet supports this, though I can’t be sure. I don’t have time to check into Ansible and Salt right now.

Sorry you are having trouble. You had mentioned before that if you log on manually as the user you are trying to impersonate and run the command, you are presented with a UAC prompt. This definitely indicates that the program is attempting to elevate to admin privileges. Is that user in the local administrator group?

Sorry if the thread was confusing. The first time I tried this I was trying to run an InnoSetup installer and I did get a UAC dialog.

Later I tried to run just a command-line program. I logged in manually as the user I want to impersonate and ran this command line program and it worked fine, with no UAC dialog.

That user is not in the local administrator group. Do you think adding it to that group would help?

I don’t really want the user to be in that group but I could add it just for the duration of the recipe.

Are there other alternatives besides shell_out and impersonation? It seems like there are various ways in PowerShell to run a command as another user…

Its possible things are just fine, but you are not seeing the output. shell_out returns an object and not the output. Try this:

ruby_block 'Install Chocolatey' do
  block do
    Chef::Resource::RubyBlock.send(:include, Chef::Mixin::ShellOut)
    cmd = shell_out!("ipconfig",
      {
        :user   => 'other_user',
        :password   => 'Pass@word1'
      }
    )
    puts cmd.stdout
  end
end

Note that shell_out! (as opposed to shell_out) will raise an error if the command fails.

Well, I know things are not fine because the command changes the state of the node, and I can tell it did not run because it did not change the state, plus I get the error described above.

Anyway, the result of the suggested shell_out! command is the same:

 FATAL: Errno::NOERROR: ruby_block[ipconfig] (BBS-provision-cookbook-windows::default line 253) had an error: Errno::NOERROR: No error - CreateProcessAsUserW (You must hold the 'Replace a process level token' permission)

dtenenba and I worked through this offline. I’m posting some findings for internet posterity:

The impersonation succeeds if the user running the chef run has the Replace a process level token permission. In the case of a Test-Kitchen run via vagrant, that will likely be the vagrant user unless you have created a separate account.

You can have chef apply the permission with this in a ruby_block:

Chef::ReservedNames::Win32::Security.add_account_right('vagrant', 'SeAssignPrimaryTokenPrivilege')

But here’s a kicker: If you set that for the user currently loged in, it won’t take effect until that user logs out and back in. Therefore setting that right just before impersonation will fail. You would need to set the right and then perform the impersonation in a separate chef run.

Ideally, you would give the user this right as part of the base box creation so that its already set after a vagrant up.

Alternatively, but very hacky, you could check to see if the right exists using:

Chef::ReservedNames::Win32::Security.get_account_right('vagrant').include?('SeAssignPrimaryTokenPrivilege')

If its missing set it and skip the impersonation leaving that for the next converge.

Matt

2 Likes

how to use attributes in place of user name and password?