Public Key Authentication - ssh

I have been designing a blockchain based cryptocurrency and some of the blocks on the blockchain can have their data updated by the owner of the block. I tried implementing an ssh style of public key authentication: client generates a key pair and sends the public key over to the block where it allows the public keys listed under "admins" to change meta data of the block. The problem with this is that someone can send random known public keys to see if they are allowed to edit meta data, how does ssh prevent people from just sending some sort of string with a known public key to access the contents of the ssh? (I ask this because I want to implement something similar to my context)

Not sure if this is really a programming question, but:
SSH uses publickey keys to authenticate 'hosts' (servers) always and 'users' (clients) optionally (but often). The commonly used and de-facto standard implementation OpenSSH, for the latter case, uses a file for each user on the server, normally located under the user's home directory as $HOME/.ssh/authorized_keys, which lists the publickeys valid for that user. If the client process specifies a username and a publickey listed in that user's authorized_keys file, and uses the privatekey to sign certain data including a connection secret and nonces, that is considered to prove the identity of the user. (See RFC 4252 for details, but start with 4253 for context.) Other implementations need to have equivalent data, although not necessarily that exact file. The host/server usually allows the user/client to make several attempts, in case it has multiple keys and/or other methods to try, but this is configurable.
SSH by itself mostly doesn't control access; it just establishes the user/client's identity as a username configured on the 'host'. Using that identity to control access -- what security people call authorization as opposed to identification and authentication -- depends on the host. Many SSH hosts are Unix, and for Unix the same rules apply to accessing Unix over SSH as apply to other kinds of connection: this starts with the classic 'chmod bits' on each file allowing read,write,execute to user,group,other, and can include other things like ACLs, SELinux attributes, sudo rules, group match for signalling processes, special configuration of some things like NFS, and so on and so on. If the SSH host/server is NOT Unix, what security rules or policies it applies once you have connected and authenticated it are up to it and may be quite different.
OpenSSH (on a Unix host) also implements a few options in the authorized_keys file that impose additional restrictions on what the client can do (over that connection); see man sshd on your system or here under AUTHORIZED_KEYS FILE FORMAT. In addition, as noted there, OpenSSH supports a level of indirection: instead of directly listing every key in each applicable user's authorized_keys file you can use a (designated) 'CA' key to sign other keys, and then configure authorized_keys to accept any key signed by a listed CA key. These certificates can themselves include some restrictions; see man ssh-keygen under CERTIFICATES. This can be more convenient in a large environment with many users, hosts, or both.

Related

How is GitLab/GitHub authentication separated from an ordinary SSH-session?

I read the question: How does the GitHub authentification work? and https://unix.stackexchange.com/questions/315615/is-ssh-public-key-associated-with-a-user Which is exactly what I am wondering. I am still missing a better answer.
When I test my SSH-key-pair I connect to user git#gitlab.com. My stored Public key has a fingerprint of base64. When the SSH Client(me) want to connect to the server(My gitlab/github account server) it sends its ID(fingerprint), the server checks it ".ssh/authorised_keys" and loops through the Fingerprints after the correct public key to encrypt the challenge.
On Github/Gitlab there are several thousand of users, they all use the same username ("git") to initiate a web (SaaS)session. So how is this separated on the server? I don't get root access on gitlab/github, of course. I only get access to my account though the generic user-session git#gitlab.com. But how is this implemented?
When I use SSH in other situations I have a specific username which I use to [my-username]#router.com
E.g.
If I would set up my own GitLab on a local NAS/Server. How can I create an account (User#local-gitlab.com) but the access rights are limited to the Fingerprint of the differents users SSH-key-pairs?
User: ID:001
User: ID:002
User: ID:003
Somehow I need to limit the access for ID:001 when he/she initiate a ssh-session with my server on account "User".
I can't speak for GitLab, but for GitHub, there is a dedicated service that terminates these connections, contacts the authentication service with the key in question, and then receives the response about whether the user is allowed to access that repo, and if so, contacts the servers storing the data.
GitHub has more than 65 million users, many users have multiple SSH keys, and there are also deploy keys for servers, so using the command directive with an OpenSSH authorized_keys file would be extremely slow, since it would involved parsing and reading probably gigabytes of data each time a connection was made.
If you need this yourself for a small set of users, the command directive in authorized_keys is a viable approach. If you need something more scalable, you can create a custom server with something like libssh and perform authentication yourself, either in that process, or in a separate process.
I found this question+answer: https://security.stackexchange.com/questions/34216/how-to-secure-ssh-such-that-multiple-users-can-log-in-to-one-account. Which highlights that you can put restrictions on authorised_keys. Don't know if that provides precise answer for my question, but it looks like it.
command="/usr/local/bin/restricted-app",from="192.0.2.0/24",no-agent-forwarding,no-port-forwarding,no-x11-forwarding ssh-rsa AAAA… git#gitlab.com
I guess there is several thousand of those lines at gitlabs/githubs servers in .ssh/authorized_keys where every single line points out access to only that gitlab/hub account.
Please comment if you don't agree.

Complications after resetting ssh key

Unfortunately I forgot my id_rsa key passphrase. Since the only solution I found so far is to reset the key by a new SSH key. I now have the problem that I need to add the new key to each server I'm connected to. Is there a possibility to do this automatically? Maybe by copying the information from the "known_hosts" file of the old key to the new one?
This is not quite a duplicate of How to reset or change the passphrase for a GitHub SSH key?, but the answer there is valid.
You have to remember that the whole point of the passphrase mechanism was to prevent access by untrusted hosts. The machinery is specifically setup so only a machine with the proper passphrase (or several) can connect to the server.
The known hosts are only useful to you as a todo list. You need to access one by one somehow (not SSH), to send the new passphrase you generated. The known hosts itself is not the security mechanism, it's just a small part (the less important part, security can do without). It will save you typing some ys in the future.
I'm sorry to say you have to manually get to each machine. If by some miracle you had another vpnish API that all your servers shared you could automate that, but most of us don't.

How does the GitHub authentification work?

If you follow the GitHub HowTo "Generating SSH Keys", you get three files in your ~/.ssh directory: known_hosts, id_rsa, and id_rsa.pub.
The file known_hosts is used for the server authentication, id_rsa is used for the client authentification (here is an article, that explains the difference).
Why should I create / why GitHub does need both -- a host and a user authentification files? How does the GitHub authentification work?
Thx
This is just plain old SSH authentication; nothing about it is specific to GitHub.
id_rsa and id_rsa.pub are the two halves of your key: the private key and the public key. Effectively, the public key is the lock for the private key. You put the lock (public key) on whatever servers you want easy access to, without too much worry that someone else will see it, because it's just a lock. You keep the (private) key on your machine, and use it to log into those servers; they see you have a key fitting the lock, and let you in.
(Not to say that you should put your public key on completely untrustworthy machines; there are malicious tricks that can take advantage of shortcuts like ssh -A.)
known_hosts doesn't actually have much to do with this; it's just where ssh stores the fingerprints of all the servers you've connected to, so it can throw up a big scary warning if the fingerprint changes. (That would mean it's not the same machine: either something has changed radically on the server side, or your connection has been hijacked.)
So, anyway, one of the protocols Git itself understands is SSH. When you use git#github.com:... as a repository URL, Git is just connecting over SSH. Of course, GitHub doesn't want you mucking around on their machines, so they only let you do Git things, not get a full shell.
As usual, the Arch wiki has a whole lot more words on this.
known_hosts stores the server's identity the first time you connect, so that you know the next time that you're connecting to the same server. This prevents someone from pretending to be the server the next time you connect (but sadly not the first time)
id_rsa is your secret key that proves that you are really you. Never give this away.
id_rsa.pub is the public key, its purpose for authentication is basically just to prove that you have the secret key without giving it out. This key you can give to anyone what needs it since there's nothing secret about it.
When you connect to the server, SSH first checks that the server has the correct key (ie it should match the one in known hosts. If the client is comfortable that the server is genuine, it uses its private key to sign the following data and sends it to the server;
string session identifier
byte SSH_MSG_USERAUTH_REQUEST
string user name
string service name
string "publickey"
boolean TRUE
string public key algorithm name
string public key to be used for authentication
The server verifies the signature using the public key (which you earlier uploaded to Github), and if it is correct, the client is authenticated.
The known_hosts file is used by ssh whenever you actually connect to a host via SSH. It stores a signed key of sorts for the server. Then, if it changes, you will know.
ssh-keygen -t rsa -C yourgithub#accountemail.com is used to generate the SSH key in which you will give the id_rsa.pub to github. Then, when you connect to github you have the private key id_rsa in your ~/.ssh folder which is then used to validate your information with github.
This is a very low-level explanation, but the private key (non .pub) file is your end, the .pub is for github and the known_hosts is for your box to know what is what.
You can also generate a config file in ~/.ssh for use to specify which key goes to which host..
authorized_keys and known_hosts are entirely different..
Your SSH server (sshd, ie) uses authorized_keys, or whatever file is defined within your /etc/ssh/sshd_config/ for knowing the public side of another key. So when a user connects to your server, they pass their private key, your SSH server verifies against the public key it has within authorized_keys and if it doesn't match, it doesn't work.
Github maintains an authorized_keys so-to-speak on their users. Your public key goes into your authorized_keys on your account and then when you connect via ssh to clone,push,etc, it checks your private key you send over with your public key they already know.

ssh-keys generation issue for dynamic-ip changing workstations for Gitolite usage

I want to use Gitolite for Git access control.
My question is on ssh keygen for dynamic IP changing workstations. So, do I need to generate ssh keys every time whenever my IP changes. This going to be tedious work for all developers as they use laptops and they need to generate keys and push to Gitolite repo.
Is there any workaround or some other solutions for this ssh public keys generation problem for Gitolite use?
Key generation has nothing to do with IP address from the client perspective.
When you generate an SSH key-pair, for lack of a better analogy, you're generating some files which contain really long numbers which can be used to encrypt or decrypt things. The private key is stored in .ssh/id_rsa (for an RSA key) and the public key is stored in .ssh/id_rsa.pub
You can move that key pair to any machine you wish. You should make sure that the private key is always well protected. The public key, you can give to anyone or copy it wherever you like. It's public. You can also have multiple keys on a machine, with different keys used for different hosts. This is controlled by a .ssh/config file. However, most users don't need that, and stick with a single key pair.
Specifically in the case of gitolite, you'll be storing the public keys of your users in the gitolite-admin/keys directory.
In any case, the fact that your laptop's IP address is changing will have no effect on your keys.

Sharing SSH keys

I use a private SSH key and passwordless entry for a number of user accounts on a server that hosts a number of websites.
I use the same private key for each user account. (because I'm lazy? or is that the "right" way).
I now want to authorise another trusted computer in a different part of the country. If I copy the contents of my ~/.ssh onto that machine will that work without any other set up?
Will both machines be able to maintain a connection at the same time?
Update: as an additional security recommendation, you should generate a new set of keys for a new machine and send your new public key out to the various hosts you use it on, rather than copying your private keys. If you're just moving everything to a new computer however, you can take your keys with you, but remember to destroy them securely on the old computer.
The correct answer is to copy your .ssh directory from the old machine to the new. This part is easy (scp -r .ssh user#newmachinehost:~ will do fine—or you can type the keys in character-by-character, up to you).
BUT—I think the missing link to answer this question is what you have to do after you copy your private keys to the new machine.
I had to run the following for each key (I have 3 separate keys for various organizations)
ssh-add .ssh/[key-filename]
If the filename argument is omitted, id_rsa is assumed.
Once you do this to each key (and enter they key's passphrase if required; it will prompt you), ssh will be able to use those keys to authenticate.
Otherwise, no amount of copying will do much. SSH will ignore the keys in .ssh until they are explicitly used (via ssh -i [keyfilename] ...).
This should work, and both machines should be able to maintain a connection at the same time - I've had to copy my ~/.ssh directory a few times before when hard drives have crashed.
Copying ~/.ssh between systems is fine so long as it's limited to just files like authorized_keys, config, and known_hosts. If you want two hosts to be able to access each other, each host needs its own private SSH key, which must then be added to the other host's authorized_keys file.
It is not a good idea to copy private keys across systems!
Think of real world secrets. Each person who learns the secret increases the chance of it being revealed.
Every time you copy your private key to a new system, you increase your risk of exposure because copied private keys are less secure than the weakest system they live on (because the other systems aren't invulnerable either).
If your laptop gets stolen, you need to revoke all private keys (and saved passwords) that were stored there. This becomes problematic when the only way to log into servers is with that very key. You'd better remember to generate a new key on your desktop and install it on each system you revoke the old key from!
Now consider your desktop gets hacked and somebody steals your private key without your knowledge. Perhaps you had shared this key between your work laptop and your personal desktop, but your desktop doesn't really need access to your work system (because you have good work/life balance). That attacker can now access your work system even without having compromised your laptop. The infosec team at work forces you to hand over your laptop so they can audit it, but after a week of analysis, they find nothing. Not so fun.
These may seem far-fetched and unlikely, especially if you're not a prime target (e.g. an executive or sysadmin), but it's just a good practice, especially given how easy it is to create new keys for each system and install their public keys on each appropriate server. (Consider one of the myriads of config/dotfile propagation systems if this seems daunting.)
Additionally, it means you'll upgrade the security of each key to meet the standards as they improve. As you retire old systems and remove their keys, you rotate out their weaker keys. (And if some trash picker finds your old laptop and undeletes your keys, they won't grant any access.)
This is secure so long as you don't share you private key. Just place the public key in the remote machine's ~/.ssh/authorized_keys file for passwordless entry. Don't share the private key though.
The keys are just for authentication. You can log on as many times as you wish with the same key, so long as you can log on with that private key once.