Win32-OpenSSH icon indicating copy to clipboard operation
Win32-OpenSSH copied to clipboard

Connecting to the ssh-agent's pipe from within a Windows Docker container

Open heilkn opened this issue 5 years ago • 15 comments
trafficstars

Dear all, dear @manojampalam

Thank you very much for the information provided in https://github.com/PowerShell/Win32-OpenSSH/issues/1136. I could successfully mount the agent;s pipe into a windows docker container. When I run ssh-add in the container it does recognize the pipe. I know this, because it complains if I do not mount it. However, running ssh-add -l does not list any keys. :(

Any advice, what is missing here?

Kind regards

Konstantin

Please answer the following

What is failing Reading the agent's pipe from within a docker container

Expected output ssh-add -l listing a key that is available on the host

Actual output ssh-add -l listing nothing

heilkn avatar Apr 16 '20 14:04 heilkn

What do you mean by mounting agent's pipe into a windows docker container? Please provide repro steps.

bagajjal avatar Apr 16 '20 17:04 bagajjal

Good evening,

thank you very much for your attention. I am sorry if my initial description of the problem was not accurate enough. I will try to give a more precise documentation of the issue.

Setting up the environment

  1. Installed Windows 10 Pro using the image en_windows_10_multiple_editions_x64_dvd_6846432.iso obtained from my.visualstudio.com
  2. Downloaded the MediaCreationTool1909.exe and used that to upgrade the OS to version 10.0.18363.0. The OS comes with OpenSSH version 7.7.2.1 pre-installed. Veified with the command gcm ssh
  3. Run ssh-keygen and verify that there was a key created with gi ~/.ssh/id_rsa
  4. Installed Docker Desktop Version 2.2.05 (43884) running engine 19.03.8 using Windows Containers and experimental features
  5. Pull the image mcr.microsoft.com/powershell:lts-windowsservercore-1903 using the command docker pull
  6. Run docker run --rm -it mcr.microsoft.com/powershell:lts-windowsservercore-1903 and verify that the container has also OpenSSH version 7.7.2.1 installed using gcm ssh. Exist the container
  7. Again on the host: Start the ssh agent service running set-service ssh-agent -startup automatic and start-service ssh-agent in an elevated powershell
  8. Verify the agent is running with get-service ssh-agent

Reproducing the issue

  1. Add the default key to the agent running ssh-add
  2. Verify, the hosts ssh-agent has a key running ssh-add -l
  3. Run docker and mount the agent's pipe as a volume using docker run --rm -it -v \\.\pipe\openssh-ssh-agent:\\.\pipe\openssh-ssh-agent mcr.microsoft.com/powershell:lts-windowsservercore-1903
  4. Check the available keys running ssh-add -l within the container. Observe there are no keys present.

image

Thank you for your interest in this topic.

Kind regards

Konstantin

heilkn avatar Apr 16 '20 19:04 heilkn

How are you confirming that name pipe mount is successful?

I would suggest opening an issue here to understand any open issues (or) if someone has already tried this.

bagajjal avatar Apr 16 '20 19:04 bagajjal

If I do the same without mounting the pipe, it will give an error instead of listing no identities image

You can also verify the pipe being present in the container image

heilkn avatar Apr 16 '20 20:04 heilkn

I think, that given the circumstances and how ssh-add responds clearly indicates that he communication over the mounted pipe is working.

Please correct me, if I am wrong, but if I understand that correctly, the situation that ssh-add returns "The agent has no identities." only occurs if it receives 0 entries from the ssh-agent

	if (num == 0) {
		r = SSH_ERR_AGENT_NO_IDENTITIES;
		goto out;
	}

For this to happen, the agent must actually process the request. This happens either here

	case SSH2_AGENTC_REQUEST_IDENTITIES:
		process_request_identities(e);

or here

	/* check whether agent is locked */
	if (locked && type != SSH_AGENTC_UNLOCK) {
		sshbuf_reset(e->request);
		switch (type) {
		case SSH2_AGENTC_REQUEST_IDENTITIES:
			/* send empty lists */
			no_identities(e);
			break;

I think the first case is unlikely, since the agent has a key opened on the host. Therefore, it indicates that the problem might be that the agent is considered to be locked. Can you confirm this?

Maybe, I am am completely off and I should not read ssh-add.c and ssh-agent.c but some other files?

Kind regards

Konstantin

heilkn avatar Apr 16 '20 21:04 heilkn

Good evening,

Okay, so it looks like I was looking at wrong code. Windows ssh-agent implementation is here https://github.com/PowerShell/openssh-portable/tree/latestw_all/contrib/win32/win32compat/ssh-agent. Especially, the code returning an empty result is most probably https://github.com/PowerShell/openssh-portable/blob/latestw_all/contrib/win32/win32compat/ssh-agent/keyagent-request.c#L371

It looks like the problem might be that the user is different. If I run (without docker) an elevated powershell session and query ssh-add -l, it will list no identites, although I do get a non-empty list as my logged in user. Today, I tried to do a debugging session with the ssh-agent. Unfortunately, the pdb-symbols on microsofts servers do not contain any source information. However, I put a break point at the location process_request_identities (00007FF790613440) and agent_process_connection (00007FF790611FF0). Mysteriously, when I execute ssh-add -l it will never trigger the break point. Does anyone has a clue why none of both breakpoints is never reached?

Kind regards

Konstantin

heilkn avatar Apr 21 '20 21:04 heilkn

Using ssh-add, you can't retrieve other user's keys. We use DPAPI so the private keys stored in the user registry are safe and can only retrieved by the same user who added the private keys.

Please note that a new ssh-agent.exe process is created for every incoming request.

bagajjal avatar Apr 22 '20 04:04 bagajjal

Thank you for the confirmation with respect to the user account and the information regarding the new process. The latter explains why I never hit a break point.

Regarding the former point. Could you please elaborate what would be required in order to access a user's key over the forwarded pipe. Is it enough that the users have the same name? I am clearly missing enough information about windows' user authentication functionality. In the special case, how does ssh-agent verify the users identity. Which information is transferred?

Kind regards

Konstantin

heilkn avatar Apr 22 '20 06:04 heilkn

Hello!

With your information I could run a debug session. When I call ssh-add -l from within the container, the agent processes process_request_identities and calls get_user_root. In this method

  • con->client_type is 1 that is NONADMIN_USER
  • ImpersonateLoggedOnUser returns 1, which indicates success
  • RegOpenCurrentUser returns 5 that is ERROR_ACCESS_DENIED

So, if I want to get it to work, I need either a way to authenticate as the right user. Please, could anyone explain, what is required to get the right con->client_impersonation_token ? That is, what is the meaning of this value? How is it created, and what is required to do in the container or in the host, so that the container and host agree on that value.

Thank you very much in advance.

Kind regards

Konstantin

heilkn avatar Apr 24 '20 21:04 heilkn

It seems that it will not be possible to provide ssh keys to a container through a mount of the named pipe, unless there is a way to use the same user from within the container and the host.

In conclusion, in order to enable this workflow for CI, it is suggested to use the MinGW version of ssh-agent and ssh-add. Once can find one shipped with git for windows. This uses unix sockets which can be mounted into the container.

@Win32-OpenSSH team, do you think this workflow should be supported with the Win32 version of openssh? If not, then feel free to close this issue.

Thank you very much.

heilkn avatar May 04 '20 07:05 heilkn

@manojampalam, is this possible?

maertendMSFT avatar Aug 20 '20 23:08 maertendMSFT

I'm not sure what user context the container is running as, but it looks like its definitely the logged in user on host. If so, to achieve this, we need to have an adapter in-between:

ssh-agent ----- adapter ------ container

adapter will run in host as logged in user context so it has access to all the keys and exposes a different namedpipe that can be passed to the container. Adapter would simply redirect all IO traffic left to right and vice versa.

manojampalam avatar Aug 21 '20 00:08 manojampalam

Is this somehow related? https://gist.github.com/strarsis/e533f4bca5ae158481bbe53185848d49

I guess it is, a tool is used that can proxy the Windows OpenSSH agent to a WSL-compatible one. It doesn't have to be KeeAgent, it can be something else like Pageant.

strarsis avatar Feb 18 '22 18:02 strarsis

Hello. Thank you for the suggestion. However, I do not see how this can help. The problem is not that the client and server use a different transport like in the WSL case, but that the container uses a different user and thus has no access to host's user's key chain.

heilkn avatar Mar 18 '22 23:03 heilkn

I'm not sure what user context the container is running as, but it looks like its definitely the logged in user on host. If so, to achieve this, we need to have an adapter in-between:

ssh-agent ----- adapter ------ container

adapter will run in host as logged in user context so it has access to all the keys and exposes a different namedpipe that can be passed to the container. Adapter would simply redirect all IO traffic left to right and vice versa.

I have given this another thought. Are you sure about this? I think the rejected client_impersonation_token is defined in the container, is it not?

Kind regards

Konstantin

heilkn avatar Mar 19 '22 07:03 heilkn