pygmystack / pygmy

the pygmy stack is a container stack for local development
MIT License
25 stars 12 forks source link

[bug] SSH keys that use a passphrase cannot be used with addkey #333

Closed lind101 closed 1 month ago

lind101 commented 3 years ago

Describe the bug When trying to add a SSH key that uses as passphrase via the addkey command the cli output for entrting the passprhrase is swallowed and the key is not added to the agent.

To Reproduce Steps to reproduce the behavior:

  1. Create a key with a passphrase: ssh-keygen -f ~/.ssh/id_pygmy_passphrase_test (Add passphrase when prompted)
  2. Add key to pygmy-go: pygmy-go --key ~/.ssh/id_pygmy_passphrase_test

Expected behavior At this point we'd expect to see a message saying something like the below and be able to see the key in subsequent containers

=Identity added: /Users/name/.ssh/id_pygmy_passphrase_test

What actually happens is that is the command completes silently with no output and the key is not availible in the containers.

Additional context I've pinpointed the issue to here: https://github.com/fubarhouse/pygmy-go/blob/main/service/library/sshkeyadd.go#L48

for _, line := range strings.Split(string(l), "\n") {
  if strings.Contains(line, "Identity added:") {
    fmt.Println(line)
  }
}

The prompt asking the user for their passphrase is contained within l at this point.

fubarhouse commented 3 years ago

Appreciate the investigation.

I'll have to do some testing w/ Stdin, but unfortunately it's not really a tiny change. I can't make any immediate promises for timeline. I have a day off work next week, I'll see how much I an get done then.

Regardless, I do appreciate the input and research. <3

lind101 commented 3 years ago

No worries, happy to help! I would offer to look myself, but unfortuantly my knowledge of Go is very limited (and would probably be more of a hinderance)!

I've worked around this by creating a SSH key without a passphrase for use with pygmy-go, so there is no rush :)

fubarhouse commented 3 years ago

Looked into this last week and unfortunetly I couldn't reproduce it.

I was genuinely surprised, I must admit. I expected a hard fail.

Could you please provide guided steps, OS information, and anything else such as output that may help me replicate this one?

lind101 commented 3 years ago

Hey @fubarhouse - that is strange, as it is a very repeatable and obvious error on my side. I'm running on macOS Catalina 10.15.7 (19H2).

When you ran the addkey command did you get displayed the prompt asking you to enter the key's passphrase?

I'm afraid I can't give you much else in terms of output as there isn't any, even when running in verbose mode. Like I mentioned in my original message, when debugging, I can see the passphrase prompt in the output of https://github.com/fubarhouse/pygmy-go/blob/main/service/library/sshkeyadd.go#L48

fubarhouse commented 3 years ago

I've created a test to track the progress on this:

Key setup:

https://github.com/fubarhouse/pygmy-go/blob/428842be4084823bb137c3355901e54a58c07ac0/.github/workflows/pygmy.yml#L57-L63

Key check: https://github.com/fubarhouse/pygmy-go/blob/428842be4084823bb137c3355901e54a58c07ac0/.github/workflows/pygmy.yml#L87-L93

fubarhouse commented 2 years ago

Initial support should come via #366 however we still need to work out...

fubarhouse commented 2 years ago

Lando's official stance is to not support this feature, however there might be a workaround to forward the host agent into the container. I might see if I can get a POC working, but that's kind of a systematic change. The PR will support everything around this except the step to actually add it into the agent. But, until this can be worked out properly this will be hidden and non-functional.

twerthmueller commented 2 years ago

I can confirm the problem, when a key has a passphrase. Currently I removed the passphrase from my key (ssh-keygen -p) and then it works as expected.

twerthmueller commented 2 years ago

Any update on this issue? I do not have a good feeling with a key without a passphrase.

tobybellwood commented 2 years ago

so, this can be worked around by bypassing pygmy, and mounting the SSH_AUTH_SOCK straight into the local container:

Still trying to work out whether this is more viable more widely though, but would appreciate road-testing!

Steps:

  1. Remove the "volumes_from" clause from the cli service in the docker-compose.yaml
  2. add - ${SSH_AUTH_SOCK}:/ssh-agent to your x-volumes as below
  3. add SSH_AUTH_SOCK: /ssh-agent to your x-environment as below
  4. docker-compose up -d to restart the containers
  5. verify keys in agent with ssh-add -l

In my testing (on linux), it works fine? It may be possible to add the SSH_AUTH_SOCK to the cli service only, but the structure of the YAML alias/anchors makes it hard.

Sample docker-compose snippet:

x-volumes:
  &default-volumes
    # Define all volumes you would like to have real-time mounted into the docker containers
    volumes:
      - ${SSH_AUTH_SOCK}:/ssh-agent ### Local overrides to mount host filesystem. Automatically removed in CI and PROD.
      - .:/app:delegated ### Local overrides to mount host filesystem. Automatically removed in CI and PROD.
      - files:/app/web/sites/default/files

x-environment:
  &default-environment
    SSH_AUTH_SOCK: /ssh-agent ### Local overrides to mount host filesystem. Automatically removed in CI and PROD.
    # Route that should be used locally, if you are using pygmy, this route *must* end with .docker.amazee.io
    LAGOON_ROUTE: &default-url http://${COMPOSE_PROJECT_NAME:-drupal9-example}.docker.amazee.io
christopher-hopper commented 1 year ago

Been reading up on this again recently. Have been following the topic in Lando and Docker issues queues since 2019.

Docker for Mac and Linux now (since 2020) provides a special "magic" volume path /run/host-services/ssh-auth.sock pointing at the host SSH agent socket so it can be mounted inside a container. You have to use the special volume mount exactly as

Then set the environment variable SSH_AUTH_SOCK=/run/host-services/ssh-auth.sock inside the container.

The example docker-compose.yml they give in the docs is as follows:

services:
  web:
    image: nginx:alpine
    volumes:
      - type: bind
        source: /run/host-services/ssh-auth.sock
        target: /run/host-services/ssh-auth.sock
    environment:
      - SSH_AUTH_SOCK=/run/host-services/ssh-auth.sock

References:

Will give it a try in a Lagoon docker-compose.yml then come back to share results. Sharing the source links now to help others who find this issue.

tobybellwood commented 1 year ago

I've got an example docker-compose here that I've done it for, and it "works on my machine", but it would be good to test more? https://github.com/lagoon-examples/drupal9-base/blob/buildkit/docker-compose.yml - lines 9 & 19 are where I mount it, then set the env var appropriately

fubarhouse commented 1 year ago

Do you know if this works on Windows @tobybellwood ?

tobybellwood commented 1 year ago

no idea - I do have a machine I can test on, but I'm guessing it's not a simple fix...

The rub is that the current ssh-agent implementation in pygmy may likely break shortly anyway (volumes_from in docker-compose v2) - so maybe all we can do is provide guidance for people to use locally - ideally in docker-compose.override.yml

larowlan commented 1 year ago

Reporting that https://github.com/pygmystack/pygmy/issues/333#issuecomment-1274091375 works (Linux). This is a fairly major security issue - requiring ssh keys without pass codes.

rocketeerbkw commented 1 year ago

The current method uses a shared ssh-agent container. When you add a password protected ssh-key to the agent, it's stored decrypted, so passphrases are only useful for protecting ssh keys at rest. Additionally, the passphrase on a keypair has no deterministic effect on the contents of the key, meaning you can change/remove the passphrase at any time and you don't have to update the public key on servers.

I wrote a script you can call that will automatically decrypt the key, add it to pygmy, then re-encrypt it. This is functionally the same thing as adding passphrase support to pgymy, so it should work until this gets a proper fix.

#!/bin/bash

keyfile=~/.ssh/id_rsa

read -s -p 'Passphrase: ' key_pass

ssh-keygen -p -P $key_pass -N '' -f $keyfile
pygmy addkey --key $keyfile
ssh-keygen -p -P '' -N $key_pass -f $keyfile

You can save it as pygmy-addkey-protected in a valid bin dir and call it anytime you restart pygmy. If you have multiple keys, you could change keyfile to support a cli argument.

tobybellwood commented 1 year ago

Now that the compose spec has resuscitated volumes_from an external container (https://github.com/docker/compose/issues/10417), we'll need to resolve this.

Brandon's solution in https://github.com/pygmystack/pygmy/issues/333#issuecomment-1517031004 seems the neatest way - to run a customised version of addkey if the -p or similar is passed to decrypt the key

luksak commented 1 year ago

This is probably the same issue as #312.

What is the status of this? This keeps me from using this version pygmy since a few years now... I am still stuck on pygmy-legacy.

rocketeerbkw commented 6 months ago

This is fixed in v0.12.0