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

Pass public key when mapping to localhost ? #48

Closed
ghost opened this issue May 16, 2020 · 15 comments
Closed

Pass public key when mapping to localhost ? #48

ghost opened this issue May 16, 2020 · 15 comments

Comments

@ghost
Copy link

ghost commented May 16, 2020

Hello,
I try to map an user (git) to another server (which is Gitlab), in order to allow git ssh clone, but i have the same issue as the issue 30. I understand that, in order to avoid MITM, the public key can't be passed directly to the upstream.
But there's a side effect i did not see at first : i created a "other" upstream users, which is the fallback user when it's not git. The mapping is very easy : it only remap on localhost, on port 23 for example, where i mapped the original sshd process. It allows to ssh using the current configuration of server when it's not the git user, so it's a quite simple process.
It works perfectly using password, but not with ssh keys : as the "other" users did not have a private key, i have the mapping private key error : no key found . I don't think that creating a private/public pair key will work, as "other" users can be everyone else than "git". Something that can be considered is to pass the public key when it's on localhost ? If you have any others ideas, i'm in :)

When this will be solved, i still will have the same issue as the 30, and i don't know how to bypass it... If you have ideas on this too, it will be awesome.

Thanks,

@tg123
Copy link
Owner

tg123 commented May 16, 2020

workingdir cannot describe such complex scenario

thus, I started a YAML upstream to replace it last week.
What you want I think is mapping user * + publickey to privatekey

my YAML upstream does support it, you can have an early preview if you want
code is not fully completed, but I am going to get it done by next weekend.

I will update you how YAML to do so.

otherwise, the only way to do it is via building a customized sshpiper

@ghost
Copy link
Author

ghost commented May 17, 2020

Yeah sure, i will test it. But i'm not sure than still assigning to a private key will work (or i have to modify their own authorized_keys on the go to allow the internal private key, but that can be considered as MITM ? And i use oddjob_mkhomedir modules too, so their home doesn't exist before, that can be a problem too).

@tg123
Copy link
Owner

tg123 commented May 18, 2020

you can build and test yaml branch now
I am still writing tests to cover all scenorias

here is how to use it

./sshpiperd daemon -u yaml --upstream-yaml-file=sshpiperd.yaml

here is the example config and explained

  • simple@piper -> [email protected]
  • passmap@piper -> [email protected] (you can use password pass which will be mapped to root)
  • key1@piper -> [email protected] (you can use password key which will be mapped to privatekey pk1 when auth to upstream)
  • keymapany@piper -> [email protected] (any publickey from downstream will be mapped to pk1)
  • keymap@piper -> [email protected] (publickey from downstream in key_map.authorized_keys will be mapped to pk1)
  • k.* is same as above but use regex username matching

how this will be solution to your case

note: the different from from.authorized_keys and to.key_map.authorized_keys is that the first one means to authenticate the downstream while to.key_map.authorized_keys means the downstream is authenticated and searching for privatekey to upstream

cat sshpiperd.yaml

version: 1
pipes:
  - username: simple
    upstream_host: 172.17.0.2:22
    ignore_hostkey: true
    authmap:
      mapped_username: root
  - username: passmap
    upstream_host: 172.17.0.2:22
    ignore_hostkey: true
    authmap:
      mapped_username: root
      from:
        - type: password
          password: pass
      to:
        type: password
        password: root
  - username: key1
    upstream_host: 172.17.0.2:22
    ignore_hostkey: true
    authmap:
      mapped_username: root
      from:
        - type: password
          password: key
      to:
        type: privatekey
        private_key: pk1
  - username: keymapany
    upstream_host: 172.17.0.2:22
    ignore_hostkey: true
    authmap:
      mapped_username: root
      from:
        - type: publickey
          allow_any_public_key: true
      to:
        type: privatekey
        private_key: pk1

  - username: keymap
    upstream_host: 172.17.0.2:22
    ignore_hostkey: true
    authmap:
      mapped_username: root
      from:
        - type: publickey
          allow_any_public_key: true
      to:
        type: privatekey
        key_map: 
          - authorized_keys_data: c3NoLXJzYSBBQUFBQjNOemFDMXljMkVBQUFBREFRQUJBQUFCQVFESzduY1ZjQlcvMHhzd1JvTGZKUDVOQ0ZCaStQbzhyaC82UDBvOFUydWJHTFpsZHFYa2hGMXBNY1IyRDFhOWl1a1J6NWpSQ2F2UnEwMkJQcUc2b0NZVTI1aHJpV1ZTT0p1S2wwOWFrOTU1U09IUitIYVFZQjg3UUJldUQ3dy8vWVFpdmc0TGtaYVBKdE5RSUpnN2Mvb3Bic1V0SFo1T1RTMnp0T2ZSeDhhVkNvNWRRYzA3cVhsNDlFTDZEL1ZvWnYwYUI1VVRoYUJvaGtwUzZLQjFUNEhpcFp0Tm51cXZXSDM0RWR4Q1ZuRHFBcFlWa1BlcGdYbkQwd2VkN2tXZUMwcExWWVNaUktPS2orVWxSejBjSHdmT1R3MXVwbWYwMk1pTGgwdERBSzdMN1h3QmxpTzlpbzU1U3VzbWl4NkViNjgwNlE1RWtIcGp4RVhjU1RGckUyY0YK
            private_key: pk1
  - username: k.*
    username_regex_match: true
    upstream_host: 172.17.0.2:22
    ignore_hostkey: true
    authmap:
      mapped_username: root
      from:
        - type: publickey
          allow_any_public_key: true
      to:
        type: privatekey
        key_map: 
          - authorized_keys_data: c3NoLXJzYSBBQUFBQjNOemFDMXljMkVBQUFBREFRQUJBQUFCQVFESzduY1ZjQlcvMHhzd1JvTGZKUDVOQ0ZCaStQbzhyaC82UDBvOFUydWJHTFpsZHFYa2hGMXBNY1IyRDFhOWl1a1J6NWpSQ2F2UnEwMkJQcUc2b0NZVTI1aHJpV1ZTT0p1S2wwOWFrOTU1U09IUitIYVFZQjg3UUJldUQ3dy8vWVFpdmc0TGtaYVBKdE5RSUpnN2Mvb3Bic1V0SFo1T1RTMnp0T2ZSeDhhVkNvNWRRYzA3cVhsNDlFTDZEL1ZvWnYwYUI1VVRoYUJvaGtwUzZLQjFUNEhpcFp0Tm51cXZXSDM0RWR4Q1ZuRHFBcFlWa1BlcGdYbkQwd2VkN2tXZUMwcExWWVNaUktPS2orVWxSejBjSHdmT1R3MXVwbWYwMk1pTGgwdERBSzdMN1h3QmxpTzlpbzU1U3VzbWl4NkViNjgwNlE1RWtIcGp4RVhjU1RGckUyY0YK
            private_key: pk1
          - authorized_keys_data: otherkeys base64
            private_key: pk2

@ghost
Copy link
Author

ghost commented May 18, 2020

Hello, i'm testing it, but i dont see how this usercases can solve my problems, since the upstream auth still use a internal private key, so git can't use it to retrieve the good repositery, and if fallbackuser (so return on localhost sshd), the private key can't still be validated by all users.
I see that the first case allow to completly bypass the first auth ? That can be a solution (even by adding the public_key checking, because it can be the same as the second auth, since git only uses the passkey), but only if we can pass the public key to the second auth (as needed by git).

@tg123
Copy link
Owner

tg123 commented May 18, 2020

is this your case?

version: 1
pipes:
  - username: git
    upstream_host: gitlab.com
    # other settings...
  - username: .*
    username_regex_match: true
    upstream_host: localhost:23
    authmap:
    from:
      - type: publickey
        allow_any_public_key: true
    to:
      type: privatekey
      key_map: 
        - authorized_keys_data: user1_publickey_base64
          private_key: user1_private_key
        - authorized_keys_data: user2_publickey_base64
          private_key: user2_private_key
        - authorized_keys_data: user3_publickey_base64
          private_key: user3_private_key

        # .... list all known users here

@ghost
Copy link
Author

ghost commented May 18, 2020

For git, it will not work since it uses the passkey to authenticate you, and allows you go clone the project. (it will be just asking for the git password, which is generated by Gitlab, so no access possible).
For the second case, i don't know my list of users, as they can be created at glance using pam_ldap auth. That's the reason the only passkey than can be used is their own.

@tg123
Copy link
Owner

tg123 commented May 18, 2020

I am a bit confused, does workingdir work with git?
bc yaml is a superset of workingdir. it can do anything that workingdir could.
here my example just passthrough user git to upstream as what workingdir does

for 2nd case, how can you identify a user is a GOOD one now?
do they have something like publickey if users create through ldap?

@ghost
Copy link
Author

ghost commented May 18, 2020

Yep it was allright with workingdir and git, the problem is the same : git (the upstream server) need the publickey from the user to auth him and give him access to the good repository, so any transformation of the original public key will always fail to log on the upstream.
for the second case, workingdir was working too, but with 2 solutions possible : pass the original publickey (still the same problem as before), or creating a private/public key for each user, store them in the upstream/user directory and modifiying their own .ssh/authorized_keys to this publickey. The second solution can work, using the fallback user, but it means than everyone's authorized_keys contains a line they don't agreed.

@tg123
Copy link
Owner

tg123 commented May 18, 2020

can you elaborate on

it means than everyone's authorized_keys contains a line they don't agreed

a little bit?

do you mean that fallback user use a SHARED authorized_keys?

that is not true in in new yaml config

a fallback user can have multiple authorized_keys and each of them can map to a private_key

somethings like below:

  • user1 -> show user1_public_key -> piper -> show_mapped_user1_private_key -> upstream
  • user2 -> show user2_public_key -> piper -> show_mapped_user2_private_key -> upstream
  • user3 -> show user3_public_key -> piper -> show_mapped_user3_private_key -> upstream

@ghost
Copy link
Author

ghost commented May 18, 2020

Sure, but this means i still have to modify their own .ssh/authorized_keys with mapped_private_key, so it can be considered as a MITM.

@tg123
Copy link
Owner

tg123 commented May 18, 2020

do you mean .ssh/authorized_keys on upstream server?

so for localhost
what you want might be

  - username: .*
    username_regex_match: true
    upstream_host: localhost:23
    authmap:
    from:
      - type: publickey
        allow_any_public_key: true
    to:
      type: privatekey
      private_key: $HOME_OF_USER/.ssh/id_rsa

right?

here to support dynamic placeholder $HOME_OF_USER right?

@ghost
Copy link
Author

ghost commented May 18, 2020

The idea seems the right one, but i'm still blocking on the fact that this require to create for each user a pair of public/private key on their home, and adding the public key on their own authorized_keys.
I know it's a workaround in order to avoir to pass the very first public key to the upstream, but as i see, each attempt to create a private key for each user can be considered as MITM too... So i don't think this can be solved :/

@tg123
Copy link
Owner

tg123 commented May 18, 2020

sshpiper is MITM no matter you use public key or not

sshpiper works in steps below

  1. downstream < --- encrypted ---> sshpiper
  2. sshpiper decrypts data from downstream (can only be decrypted by sshpiper bc this is the conn to piper)
  3. sshpiper re-encrypts data
  4. sshpiper < --- encrypted ---> upstream (can only be decrypted by upstream)

this happens no matter password/public auth or even none auth.

the reason publickey cannot send to upstream is that

  1. sshpiper claims I have the public key1 to upstream (which declares it owns private key1 implicitly)
  2. upstream encrypts some random number using public key1 and sent is back to sshpiper
  3. sshpiper cannot decrypt it bc sshpiper do not have private key1 to do so
  4. upsteam asks sshpiper to show the random number
  5. sshpiper failed to do so and connection closed by upstream

the reason why password works is that
downstream has to send full password text to sshpiper
as a result, upstream does not know whether the connection is from sshpiper (mid man) or downstream

asymmetric keys are designed to prevent some one steals your password in the mid
bc, even you steal the password (public key), the upsteam can also you are fake.

back to your case, you have to be a man in the mid to do piper things.

@ghost
Copy link
Author

ghost commented May 19, 2020

Hi, thank you for this explanation ! I tested, and it can be used to do what i want, using several private keys. It's a less invasive solution, so it's ok for me :) Thanks a lot !

@TomFreudenberg
Copy link
Contributor

TomFreudenberg commented Aug 31, 2020

Hi, running in the same use case (git)

Do I understand it correct, that to work with SSH_KEYS (authorized keys)
they can't be passed thru transparent?

So - if I want to use that scenario - the keys must be available also on the sshpiperd server?

Just to make it clear

CLIENT PC --> SSHPIPERD Server (Internet) --> GITEA Server (DMZ)

on CLIENT PC there is an id (ssh-keygen) like me@gitea / [email protected]

The content of .pub is installed as SSH Key on a gitea User Profile (like Github)

To allow:

git clone gitea@sshpiper-server/user/repo

normally the local private key is used.


Is this possible to config via sshpiper?

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants