PowerShell
PowerShell copied to clipboard
Support for RemoteSession over SSH with Password
Summary of the new feature / enhancement
It is currently possible with pwsh to connect from linux to windows over SSH with an pubkey or with the help of a regular password. Both methods are working, but the auth method with a password has some benefits because the remote shell will run under the users credentials with a valid windows token.
Commands that require a valid windows credentials token will then work Get-VM -ComputerName @("server1", "server2", "server2")
Proposed technical implementation details (optional)
Option1: SSHConnectionInfo does currently not allow to set an user password. it could await the output of "ssh" process on "Password:" and write the password into the input stream
Option2: Some command to upgrade the pssession with a valid WindowsUserToken like "Switch-User"
There are various Linux/UNIX solutions based around 'sshpass' but they all have the weakness that at some point the password is in the clear. The purpose of the public/private keys is that passwords are never sent over the net so cannot be subject to man-in-the-middle.
Windows authentication is an odd beast. My understanding is that you can use ssh with the public/private keys and gain full rights if the user is already currently logged into the machine, eg if you login with ssh to your own windows desktop machine while the desktop is logged in. So this does sound like a chicken and egg situation,
- use some secure mechanism to login to windows on the machine using username/password to start a session
- while that is alive you can login with ssh and the keys.
I would recommend against a custom PowerShell mechanism which involves passwords in cleartext.
My understanding is that the reason is that user profiles are only fully loaded from the registry etc with the username/password login. However Windows Desktop login today seems to use username and a pin.
That also said, it is a general problem that some component needs a password entered but it is deep in the chain and unaware of the actual UI mechanism in use. For instance gnupg lets you set up a password agent for entering the password. But then the whole point of the keys is to avoid this problem and let an ssh key agent manage the keys securely when hopping from one machine to another.
The problem is with linux&windows interop. Currently if you’re connected with pub key you will not get windows/ad user session, that would be needed in a lot of cases. Also the only time when password would be clear -when an app actually will echo it to the session, and it would be in memory, since connection is already encrypted before the login.
The problem is with linux&windows interop.
I think you would have the same problem if you SSH from Windows to Windows using SSH keys.
Currently if you’re connected with pub key you will not get windows/ad user session
Yes, unless the user is already logged in, eg try SSH into a Windows desktop using keys with user already logged into desktop.
Also the only time when password would be clear
Password in the clear is still in the clear whether it is in memory, environment variable or command line argument. If you are on a shared host you are at risk of exposing those credentials, for instance this is why if you look at modern cryptographic API they use char array for passwords, not strings because you can clear the array after use, not so with a string which will only disappear when the garbage collector gets round to it. The password is still at risk over an encrypted session with a man-in-the-middle attack, especially if you were cavalier about accepting entries into your .ssh/known_hosts and did not validate the thumbprints.
I am sure you may find a solution but it does not mean it would not be acceptable all, or pass a serious security review.
If you are already on Linux, I would try arranging a pipeline that uses the existing sshpass mechanism, it already exists and its problems are understood, before writing a new component that needs to pass a security review before acceptance.
So that you know that I have a bit of knowledge in this area, I wrote Wishstream which uses SSH.NET for the SSH layer. This API provides a callback mechanism when a password is required, so code does not have monitor a stream looking for password prompts etc, the password is provided directly to the SSH API which passes it to the server in the SSH packets. As an example, in my app when the callback was invoked I presented a dialog to enter the password.
Summary of the new feature / enhancement
It is currently possible with pwsh to connect from linux to windows over SSH with an pubkey or with the help of a regular password. Both methods are working, but the auth method with a password has some benefits because the remote shell will run under the users credentials with a valid windows token.
Actually that is not it. Some logons give you a session without any means of logging on from that session to another box. Classic case: I have a Kerberos Ticket Granting Ticket in my session; I want a session to remote box so I present my TGT to Kerberos and I get a ticket for the remote box. I present that to the box and get a session. I run a command in that session which wants to talk to a 3rd box but it can't ask Kerberos for ticket (no TGT). Search for "Two hop problem" :-)
If I logon to that remote box with my name and plain text password, there is the option for the box to keep the plain password in memory, and provide it on request, if the third box accepts plain text passwords, or something generated from them as a login we can get logged in.
Not surprisingly security folk don't like that.
Windows authentication is an odd beast. My understanding is that you can use ssh with the public/private keys and gain full rights if the user is already currently logged into the machine
If you are in the Administrators group, the keys and sshd_config are located in $env:ProgramData\ssh, so there is no need to log into your account on the Windows computer. I often connect to a Windows laptop that has just booted to the welcome screen and the network is up.
actually my use case - I'm building API/lib to run some posh scripts on remote win machines. So I need not only administrator local access, but a valid domain session. without that it seems I would be needed to go not so go route to create an agent that would run needed scripts from service account. this looks odd since PowerShell meant to be an instrument for local+remote host management. Microsoft stopped developing OMI for *nix platforms and remove proper PowerShell WSMan support for *nix platforms and made ssh support that is only partially usable. I think Microsoft SHOULD add proper ssh connection handling with password(and proper net user sessions for that case). that's what we have on every *nix system for remote administration. Without that it's hard to renderer remote admin of win hosts via ssh usable.
actually my use case - I'm building API/lib to run some posh scripts on remote win machines
If you are actually doing an API or lib then you could look at using SSH.NET to do the password authentication "correctly"
Microsoft SHOULD add proper ssh connection handling with password
However the rest of the world is moving away from SSH with password and recommending SSH keys and key agents. If you do "man ssh" on macOS or Linux, I don't think you will find a command line parameter or environment variable for password.
My theory ( only a theory ) is that a password is ultimately needed to authenticate with AD using the LDAP protocols, hence why things need an actual password at some point.
PowerShell meant to be an instrument for local+remote host management.
It is. But you can't make the double hop problem go away.
If I logon interactively to a windows machine that machine will use my credential to log on to other services (and this goes back before Kerberos came in). So I can connect to and manage any machine on the network, but crucially remote sessions don't get my credentials, so they can't logon to other further remote sessions. Although you're seeing this as an SSH / from-linux-to-windows issue, it's also a WSMan / from windows-to-windows issue. The one oddity is the security flaw-by-design in ssh which allows a session to opened using a plain text password which can the be accessed from the session.
OpenSSH itself recommends against non-interactive password auth as it makes it more likely for people to put passwords in scripts and passwords are less secure than pub key auth. Recommendation would be use keyboard-interactive password auth the first time to deploy your pub key.
I also understand that some hardware that supports SSH ONLY supports an OEM pre-defined password. In those cases, you can use SSH_ASKPASS as a workaround.
@SteveL-MSFT thanks for reply. But the problem is more complicated. I am needed not just an access via script, but from dotnet(c#), and usage of SSH_askpass in that cases looks like I would actually be needed to implement it in some extension to your lib, but this functionality is much more important . Let's look at some use cases: 1)listing of domain smb shares via remote posh call 2)making calls to other domain services like DC's and so on 3)actually I believe that lack of that( not only lack of ssh password auth, but it also seems lack of win-openssh ability to get user/domain user session from AD) is part of there reason why admin center currently win only, since only wsman supports user+pass auth that allows getting net user session Pubkey auth can actually work, but if win-openssh would start to support AD auth via stored in AD public key, that would allow getting proper network session
An alternative is to use Kerberos auth and enable delegation. Like WinRM using Kerberos delegation is more secure than things like CredSSP/plaintext password auth as your password isn't actually send across the wire. Sending your password across the wire is a massive risk because if the target host is compromised, or the network transport encryption used is breakable then the bad actors have your password to do whatever they want. The password is not time limited and can be used to easily translate to other authentication protocols that a service might need.
Using Kerberos with delegation not only stops your password from every leaving the device but it also allows you to constrain the services the delegation is for allowing you to limit the exposure when connecting to a compromised host. Even better is that if done correctly you don't even need to have a password embedded in your script, you can either rely on things like PAM to get a ticket for you at logon like Windows does or setup a keytab to avoid embedding a password in your script.
Three things need to be in place to use Kerberos authentication
- Kerberos is setup and configured on your client
- This is probably the hardest bit to solve but if you have Linux devices in your domain environment there's a good chance it's already done so
- In my case I just have installed the Kerberos libraries installed and DNS does the rest for me
- You can use the /etc/krb5.conf file if you cannot rely on things like DNS or want custom settings for your environment
- Client needs to be told to allow Kerberos auth
- This can be done through
~/.ssh/configor through the-Optionsparameter onInvoke-Command - I typically add the following to my
~/.ssh/configto avoid having to do it as part ofInvoke-Command
- This can be done through
Host *.domain.com
GSSAPIAuthentication yes
# This will do unconstrained kerb delegation, this can be dangerous so set as your own risk.
# Depending on your krb5.conf settings this might also require AD to be configured to allow
# this or not
GSSAPIDelegateCredentials yes
- Server
- The server needs to allow Kerberos auth,
GSSAPIAuthentication yesin thesshd_config - If using constrained or resource based delegation you need to configure AD accordingly
- The server needs to allow Kerberos auth,
Once setup you can utilise it in PowerShell
Invoke-Command -HostName server.domain.com { 'foo' } -UserName [email protected]
# If you don't have it enabled in your ssh config file
Invoke-Command -HostName server.domain.com { 'foo' } -UserName [email protected] -Options @{GSSAPIAuthentication='yes'}
In the end you have a few options available to you to avoid the double hop problem
- Auth that supports delegation in some way
- Kerberos (constrained or unconstrained), CredSSP for WinRM
- Kerberos (constrained or unconstrained), Plaintext Password for SSH
-Credentialoption on many cmdlets that can be used to auth on the next hop- Impersonation on the remote side with explicit credentials, useful when a cmdlet doesn't support a
-Credentialoption- Invoke-WithImpersonation is an example
While it would be nice if PowerShell did support a password option through something like the -Credential parameter it's unfortunately not practical to do so in the way it's been implemented currently. This is because ssh (the binary pwsh calls) doesn't have a native way to provide a password non-interactively outside of SSH_ASK_PASS. There exists tools like sshpass that try to provide a workaround for this scenario but they cannot be guaranteed to be present as it's separate from ssh itself. There's also the problems inherent with password auth like weak passwords, how to embed them safely in a script where other protocols are generally recommended.
In short delegation is a complex issue, it's full of security risks as how you do the delegation can have dramatic implications on server trust and what you are allowed to delegate to. I don't think PowerShell is in the position here to solve that problem unfortuantely.
@jborean93 in the docs for the RunspaceConnectioninfo for the SshConnectionInfo I don't see a way to use that in my C# project. https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.runspaces.runspaceconnectioninfo?view=powershellsdk-7.4.0
And that is the main problem. In 2024 ,after so many years from powershell core release, from the release of win-openssh it is really strange that there are simply no good way to manage windows hosts remotely from *nix. I believe it is the main reason why admin center could be deployed only on windows, since this problem just do not exist due to using of wsman, which is allowing just that. And actually Microsoft intentionally doing that: https://learn.microsoft.com/en-us/windows-server/administration/openssh/openssh_keymanagement
A remote session opened via key based authentication does not have associated user credentials and hence is not capable of outbound authentication as the user, this is by design.
If windows ssh server for example would have such thing as storing ad pub keys in AD and verify them via ad and auth user as net user that would also be good solution. We already have linux servers that authenticates into AD via keys stored in custom AD field
Class which defines connection path to a remote runspace that needs to be created. Transport specific connection paths will be derived from this.
Learn about OpenSSH Server key-based authentication, generation and deployment for Windows using built-in Windows tools or PowerShell.
in the docs for the RunspaceConnectioninfo for the SshConnectionInfo I don't see a way to use that in my C# project.
You can use this constructor to create an SSHConnectionInfo with custom options. The actual property is unfortunately not exposed publicly so you cannot set them after creating the object but this constructor will still at least be able to set them.
One thing to note is that I did notice SSHConnectionInfo requires a valid Runspace to be set on the default thread for it to work. It uses it to find the ssh executable do if running this from a pure C# code you would have to do
Runspace.DefaultRunspace = Runspace.CreateRunspace();
Runspace.DefaultRunspace.Open();
// Define the SSH options
Hashtable sshOptions = new()
{
{ "GSSAPIAuthentication", "yes" }
};
// Create the connection info with the options
SSHConnectionInfo connInfo = new("[email protected]", "computer", null, 22, "powershell", 30, sshOptions);
using Runspace remoteRunspace = RunspaceFactory.CreateRunspace(connInfo);
remoteRunspace.Open();
// You no longer need the thread Runspace to be set.
Runspace.DefaultRunspace.Close();
Runspace.DefaultRunspace = null;
using PowerShell ps = PowerShell.Create(remoteRunspace);
ps.AddScript("'test'");
ps.Invoke();
In 2024 ,after so many years from powershell core release, from the release of win-openssh it is really strange that there are simply no good way to manage windows hosts remotely from *nix.
It's honestly the same as well for the other way around, it's ssh which generally frowns upon password authentication in favour of other things like ssh key auth. If you really want to use password auth have a look out for the community meeting in March where I'm hoping to showcase my RemoteForge project which I have a sudo and ssh example with support for a credential provided in PowerShell
PS /home/jborean/dev/SSHForge> $sshInfo = New-SSHForgeInfo -Credential user
PowerShell credential request
Enter your credentials.
Password for user user: ...
PS /home/jborean/dev/SSHForge> Invoke-Remote $sshInfo { whoami }
user
@jborean93 many thanks! I would definitely try that!
Dupe of https://github.com/PowerShell/PowerShell/issues/5782
This issue has been marked as duplicate and has not had any activity for 1 day. It has been closed for housekeeping purposes.
📣 Hey @Nova-Logic, how did we do? We would love to hear your feedback with the link below! 🗣️
🔗 https://aka.ms/PSRepoFeedback