The fact that so far any token reasonably operating on repositories had to have the full repo scope and, as far as I'm aware, the repo scope allows making public repos private (which resets all traction you've ever got: stars, forks, etc.), or delete them all together, was ridiculous. Now there's a separate "Repository Administration" scope.
Moreover, you had to create purpose-suited GitHub accounts if you wanted to do cross-repo GitHub Actions (like updating a homebrew repo), and grant them access to only that repo, if you didn't want to have that GitHub Action have full access on your level.
So yeah, finally. Time to decommission all these existing tokens. Thanks GitHub!
God, "finally" was exactly my response. I can't believe how bad Github's ACLs and permissions are. This is much needed, our PATs are one of our most significant risks so we have jobs to audit them etc but... I just don't want them to be god mode just so that we can have scripts create repositories.
> Is there an argument for why non-expiring tokens are a bad idea that I'm missing here?
it's a band-aid on other people not being able to secure their system. Band-aid that solves nothing as if token valid for a week or a month leaks you're still fucked.
Now no expiry at all is a problem (you don't want someone digging out token from 2 years ago from somewhere to still work), but the node actively using service should be able to re-generate its own one.
Then you could also get away by super-short tokens (say week) that app just re-generates every few days.
For example app can use tokenN to generate tokenN+1 and have both of them be valid at the same time for a period (so app cluster have time to propagate the new access token before old one expires)
And so any leak of old data would be no threat, you wouldn't need to have months-long human-regenerated tokens, and it would be more leak-proof as just having week old token would be inconsequential.
Vs "bother someone every 6 months to click thru the stupid panel and put the key in right places just so your infrastructure keeps working". MS already does that in other places, it's aisine
> but the node actively using service should be able to re-generate its own one.
Which in order to do it would presumably need some meta-token you use to authenticate to get a token. how is that more secure? It sounds like I just need the meta-token instead of the token. So, same amount of security as just a non-expiring token
You'll want to look at Github Apps as thats closer to how those works vs how personal access tokens work. Apps have a private key that is associated to Github, which is used to create and sign JWTs that are valid for some period.
They are not getting rid of the 'classic' access tokens (at least not yet). I think this new feature is geared more towards organizations where credential rotation has to happen for audit/policy/regulatory reasons anyway; it's probably nice to have GitHub ensuring that you can't have a policy violation while also nagging a credential owner if a credential is about to expire.
Ok. But 1 year means I have less than a year, then less than a year again, then less than a year again. Can’t even do one month and just do the first of every month. These expiration times make no sense, or they make sense for machines but not humans.
You don't have to revoke a key as soon as it is rotated. If you rotate every week you can have a job that runs every week, offset by one day, to revoke.
Right, but there’s no way to do that on the same day every year, or even the “first Tuesday of every June” because that may or may not always fall within a year.
Also, these tokens have to be rotated by a human. So weekly is way too often.
> Right, but there’s no way to do that on the same day every year, or even the “first Tuesday of every June” because that may or may not always fall within a year.
If you don’t understand it, you must not work with a lot of humans doing human things. Ask a bunch of friends that don’t work with computers what today, plus one year is. You’ll hear everything from “365 days” to today’s date next year to 365.25 days. At no point do you hear the current time, on this date.
So if lots of things go wrong that you are having to rotate this in a year, you are doomed to fail because there’s also a time stamp on it. There’s no grace period, so things will break.
If there’s a revocation system, there’s no reason for a hard expiration of the token is still being used.
> If it were "one year and one day" you'd have the same exact problem.
No, it would not, at all. Think of it like this: if I ask you to put something on your calendar one year from now, what kind of calendar event would it be? It would probably be an "all day event" and you wouldn't even to think to ask "what time?"
> Revocation and expiration are virtually the same thing.
Revocation is an intentional act done by humans. Expiration happens simply by the passage of time in relation to the movement of Earth around the sun.
The irony is forced expiration will probably hamper adoption of the new tokens. Especially for low risk read-only tokens, I would rather deal with coarse permissions so I don't have to deal with constant alerts to rotate my tokens and having to update my app configs and re-deploy etc. I hope they reconsider this. By all means make me click through a warning or whatever, but at the end of the day I'm an adult, let me make my own decision.
To the people responding to this saying that "expiry is mandatory", you're missing a key aspect: expiry is mandatory for uncontrolled secrets.
Passwords and API Keys are uncontrolled. Once they've leaked, they're "out there", and you can't know where they've been copied, stored, and who has them. There is no central, authoritative list of "currently held credentials". They're literally "bearer tokens", like cash-in-hand versus something held in an account that's recorded on a ledger.
This makes password-like credentials inherently risky, so people work around these issues by:
- Restricting network access
- Restricting the time for which they are valid
- Restricting who can get any access at all.
These restrictions then "get in the way", even for legitimate use. Network access restriction mean that everyone has to be on the VPN. I mean the VPN, because you can't be on two VPNs (in general). This limits business activities such as querying across federated systems. All "access control" now involves the network team. The guys "running cables" have to be involved in database access!
Time restrictions mean that as things expire, they break. One year expiry is just long enough that people have moved on from their six-month contracts, and the new guy has no idea why everything went down at 4:55pm on a Friday. Sure, you can automate the rotation away, but then the automation system itself inherits the same security boundary as the tokens it is managing. You can't automate your way out of this, because then it becomes turtles all the way down.[1]
Restricting who can get any access at all because of the legitimate fear that they will leak their API keys hampers productivity. If developers can't be trusted not to copy-paste keys into their code[2], then they won't be given keys at all. This limits what they can do. Similarly, even read-only access will be restricted, so you end up with systems where data is copied over-and-over into other systems because direct access "wasn't an option".
Generally my advice to architects and developers is to avoid passwords or API Keys like the plague. Use something like Azure Active Directory with managed user identities, which allow "secretless" access. This access is also self-documenting, with a central authority tracking who has access. You can't "copy" a managed identity or "run off with it". There is no way to paste one of these into Git, or leave it on a laptop that is being disposed of.
[1] One particularly problematic security risk with things like GitHub PATs is due to GitHub Actions. Previously, Git was "just code", posing only a slightly greater risk than documentation. Now, it's managing deployments of apps, and their secrets, making it super dangerous to give anyone access to the repo! There have been several major breaches because of this.
[2] In the last year or so working with over a dozen developers moving into cloud apps, I observed literally every single one of them pasting API Keys or similar secrets directly into the code and then checking that in to Git.
It prevents you from having forever tokens floating around, somewhere left and forgotten many years ago and perhaps getting leaked one day through some vulnerability in that particular system.
Just automate the recycling of your tokens if you can't be bothered to review it once a year and generate a new one yourself. If security to your own repos is not worth of a one time 20 minute effort to automate this then I wonder what is.
This is absolutely a step in the right direction. GitHub permissions are ridiculously coarse-grained. Hopefully this will lead to more fine-grained permissions on GitHub in general.
I migrated from BitBucket recently and was surprised at how BitBucket was often ahead of GitHub in CI and API breadth. I guess I mistakenly thought GitHub would be miles ahead with its popularity and backing.
Say what? last time used it, check boxes in markdown still didn’t work there and CI was cheap knock-off of GitLab which doesn’t properly work with OAuth
I haven't used BitBucket for years, so I'm not commenting on that specifically - but to me it makes sense that the underdog necessarily forges ahead, because it needs some differentiator to persuade people away from the market leader.
Their pipelines was woefully underbaked and had tons of issues last I used it which was about 2 years ago. Pipelines was incredibly slow compared to Actions and was missing most of the features Actions has. You can't even define scheduled jobs from within the YAML file. You need to schedule them outside through the repository settings. It's also missing tons of triggers and the documentation is horrendous
I've not used their APIs but GitHub's is pretty huge. I highly doubt BitBucket's API is any better
If you're still using SSH to access your GitHub repos, please consider using HTTPS access tokens instead. The security is much more granular, they're easier to revoke and rotate, easier to generate and use safely, they work over HTTP proxies, you can specify a different user in the URL (https://myuser@github.com/....) allowing for easier use of multiple accounts, and of course, you can use them for the GitHub API too. Security-wise, most people don't use SSH securely and may fall victim to MITM.
I agree this seems to be the currently in vogue practice, but I am confused by it!
SSH keys are public-private key pairs, where the private portion can live in a hardware token or software agent that only signs individual challenges and never exposes the private key. (It's possible in theory, although admittedly not common, for the user agent to limit approvals to a particular repository using the techniques in https://github.com/StanfordSNR/guardian-agent . It would be nicer if GitHub would enforce granular permissions on SSH keys!)
If I understand right, HTTP access tokens are... bearer tokens where I have to handle the plaintext (so I can transmit it to GitHub) every time I want to use it? I agree it's nice to have GitHub enforcing more granular permissions, but even so the trade really doesn't seem worth it. I may not be getting something here.
The main reason to use HTTP access tokens is just for the more flexible user-facing functionality. Security-wise, the issue is (to me) not totally clear-cut.
Yes, with HTTP access tokens, you do have to transmit the plaintext each time. (OIDC would be much better, but The Industry Powers That Be decided that non-interactive networked clients had no need to benefit from federated identity and temporary tokens) But the attack vectors (broadly) are 1. at-rest storage (credential managers are good enough, I think) and 2. HTTPS MITM. If the attacker can somehow manage an HTTPS MITM, they get the plaintext token, and can then attack that account offline for as long as the token is valid. It's definitely not easy to HTTPS MITM, but the protocol is much larger and more complicated than SSH, so vulnerabilities are more likely. State actors can do it trivially, of course (though this wouldn't be the case if we hadn't thrown HTTP Client Certificates out with the bathwater!!).
SSH private keys are technically superior, because like you say, the private key can be unexposed (if you use a hardware token etc). This means that the attack vector left is SSH MITM. If the attacker can pull this off, they can only attack when you are connecting, because they don't have your private key to perform arbitrary offline attacks. But how likely is MITM? Well, when was the last time you verified the host keys of GitHub.com? How did you verify it? Are you absolutely sure it was correct, and the host keys transmitted during your initial SSH connection weren't a MITM? Even if they were correct, can the attacker still MITM you? Well, what if they disconnect each of your connection attempts, until you try from a different user/computer, or just remove or disable your host key cache? They might re-try the attack then, and hope you don't verify the host keys this time. All this assuming you didn't globally remove the host key checks in your SSH config (for example, if you connect to a lot of work hosts and you got annoyed by host key verification so you disabled it? maybe some automation script in a ci/cd process is doing this?)
Ultimately the decision of which to use rests with you. Personally, I already rely on HTTPS for most of my security on the internet, so I might as well rely on it for my code, and gain some extra functionality/convenience. But I do wish the HTTPS method used OIDC, and the SSH method had more fine-grained controls.
> This means that the attack vector left is SSH MITM. If the attacker can pull this off, they can only attack when you are connecting, because they don't have your private key to perform arbitrary offline attacks.
Not only that, but that MITM attack could only present modified data to your client; even a successful MITM attacker still cannot authenticate to github as if it were you. The authentication is symmetric, each side authenticates the other.
(A very simplified explanation, the real protocol is a bit more complex: each side combines its private key with the other side's public key, and due to some math the results are identical on both sides; the resulting number is used as a cryptographic key in the protocol. Since the attacker doesn't have access to your private key, it cannot combine it with github's real public key to obtain the cryptographic key github expects. It cannot "pass through" to you the real github public key, because then it wouldn't know the corresponding private key which it needs to do the MITM.)
Thanks for this analysis! To me the risk of bearer tokens seems bigger than just "at-rest storage"... My experience is that the security perimeter effectively ends up including every script or other piece of client software that wants to run Git or has access to the channel where the bearer token is entered. (How would you enforce that your credentials manager will only give the bearer token to some particular trusted HTTPS client software that is talking only to GitHub...?) You have to worry about the token getting logged in a debugging log, etc. And, when I give somebody an account that's authenticated with a bearer token, I'm always nervous maybe their hygiene is not so great and they'll end up accidentally pushing the token somewhere publicly visible. AFAIK you don't really have this attack surface when the credential is a private key stored in a hardware token or, at worst, a software agent that only keeps the decrypted version in private memory and only agrees to sign individual challenges.
On the question of HTTPS MITM vs. SSH MITM, I agree that the HTTPS PKI makes a MITM less likely than the (prevalent) use of TOFU for SSH authentication, but I don't think the risks (or what "MITM" means) are the same. If there's an HTTPS MITM when client authentication is via bearer token, the intermediary can steal the client's token and masquerade as them forever. If there's an SSH MITM when client authentication is via public key, then the intermediary can give bogus data to the client and can get data from the client, but to the best of my knowledge I don't think a true application-layer "MITM" is possible (barring downgrade attacks) -- the intermediary can't spin around and authenticate to GitHub, pretending to be the client. The session ID is part of the authentication scheme.
> How would you enforce that your credentials manager will only give the bearer token to some particular trusted HTTPS client software that is talking only to GitHub...?
I mean, if a client has enough privilege to be able to connect to my credentials manager in the first place, it's already game over. Whatever can execute that client can probably execute arbitrary code, and then use a privilege escalation vuln, so they can do whatever they want on the machine.
> You have to worry about the token getting logged in a debugging log, etc. And, when I give somebody an account that's authenticated with a bearer token, I'm always nervous maybe their hygiene is not so great and they'll end up accidentally pushing the token somewhere publicly visible
Yes, completely valid concern. Not that people don't already push their private SSH keys onto GitHub repos or Jira tickets/email, but that's a lot easier to detect and prevent. But on balance, the bearer is like a password; if the user has any other passwords you care about, you already have to deal with these concerns. The bearer is therefore a "slightly better" password, because you can set an expiration date, limit the scopes, rotate it easier, it's not reused on multiple sites, etc. MFA helps but of course is not a panacea.
And yes you're right with your second paragraph too. (I tried to mention it in my earlier comment but it wasn't clear) I do think that public-key crypto is much better security, but that it's harder for the user to get right, and people have underestimated the feasibility of SSH attacks. I think we're just lucky that there are much easier attacks than MITM so we haven't seen a rash of them. It's much easier to inject malware via a browser, or find an open ACL or network service, etc.
But how do you manage them in practice? At least with ssh everything is in one place in my .ssh folder. I suppose I could create a .tokens folder or somesuch.
On most posix systems everything running as your UID has access to everything in your home directory.
I have no private key material or credentials in my .ssh folder (other than usernames and hostnames). All of my SSH private keys are stored in hardware.
Yes; if you dig into the links I left, Git can use a variety of credential managers to protect them.
Speaking of ssh key passwords: until OpenSSH 7.8 (2018-08-24), private keys using the PEM format were vulnerable to brute-force password cracking. You had to specify the -o option to use the more secure OpenSSH-format keys. Today the -o option is the default (and thus gone), but you might want to rotate your keys if they're from before September 2018.
> The whole things sounds like "okay so some of you are incompetent, let's put some measures that annoy the ones that are"
The proper measure is to secure SSH keys. For me it seems crazy that I must Google github host key fingerprints. SSH must retrieve those keys over some standard URL like https://github.com/.well-known/ssh rather than asking user a question that he'll ignore.
My guess would be that HTTPS checks the certificate, but SSH does not (does it?). First time you connect to a server with SSH, you have to accept a fingerprint. And once in a while it complains for some reason, and the typical move is to erase the file that stores those fingerprints, right?
Well this is not the right way to do it (vulnerable to MITM), but that's how I see most people use it.
Your hardware key mostly ensures that nobody steals your private key, but it cannot magically authenticate the remote server (which is what you need against MITM).
> [...] And once in a while it complains for some reason, and the typical move is to erase the file that stores those fingerprints, right? Well this is not the right way to do it (vulnerable to MITM), but that's how I see most people use it.
Yes, that's vulnerable to MITM, but with a caveat: that MITM could impersonate github to your machine, but it could not impersonate your machine to github. That is, it could present modified data to your git client, but it would have no access to your github account. With HTTPS without client certificates, once someone successfully impersonates github to your git client, they have the same access to github that your git client has. (HTTPS with client certificates would be as secure as using SSH keys, since the MITM could not impersonate the client to the github server.)
You mean HTTPS access tokens that are sent in the clear and accessible to any proxy server in the middle?
They are a good replacement of password based auth, and yes they are new. But that doesn't mean they are better than ssh keys.
Each time you authenticate to github you send that token in the clear (inside the TLS session, but there it's in the clear). This means that any proxy server on the way, anyone with access to github's infrastructure who gets to read logs of traffic, etc. can get a means to impersonate you. That's a major problem with this authentication protocol, and a step back from signature based ed25519 keys that ssh uses. There are HTTP auth schemes 10 times better than that (TLS-SRP, etc). I'm not saying that HTTPS access tokens were a bad addition, they are better than doing the same thing you do with these tokens but with passwords. But they are worse than ssh keys.
FTR you can also specify different users with ssh keys, by having custom hosts in ~/.ssh/config that point to different identity files.
Typically proxy servers don’t have access to the contents within an ssl session unless they are MITM the whole transaction. And at that point they could just MITM passwords and everything else sent through the session.
They are worse than ssh keys but I think are still acceptable as I don’t use any proxies that MITM my ssl sessions and I’d be able to detect if someone tried (assuming the root CA don’t go crazy and start allowing it).
Depends on the type of proxy you are using, but yes, I should have pointed that out that many proxies do not access encrypted contents. Doesn't change the fact that such traffic is way more dangerous if the tokens are in the clear.
For ssh you also have multiple types of proxying, some which send your keys to the proxy server (very bad), others which base on encrypted tunnels and don't do that. HTTPS is I think similar to that.
> at that point they could just MITM passwords and everything else sent through the session.
For proxy servers you are right. but any read only vulnerability can be turned into a write vulnerability. e.g. that attacker who has read-only access to logs of github traffic can turn use that for an attack where they push commits, etc.
> Doesn't change the fact that such traffic is way more dangerous if the tokens are in the clear.
It’s very important as tokens are not in the clear, they are encrypted in the ssl session. They are not visible to anyone other than the client initiating the session and the server authenticate by the server cert.
Apparently they are a different kind of token (github_pat_ instead of ghp_) in a separate part of the settings. So you can't just set the permissions of your existing tokens.
An expiration date is also required for those new tokens with a max of 1 year.
I use PATs for things like a reverse proxy from CloudFlare workers to cache hits to a private repo accessed via the GH REST API. If I have to remember to rotate my keys every year, that's going to suck.
What I want for this usecase is a non-expiring PAT that is Organization instead of User based and can be tied to a single repo.
Amazing to think that there are a number of bits of critical infrastructure that are dependent on GitHub sending an email a week before it goes offline after running just fine for a year.
Sure, but when does the russian doll end? Who implements the automation? How is it tested in CI? Who watches the automation to make sure it is working? Who fixes it when it is broken once a year. What happens if I get hit by a bus or leave the company?
If Github could just solve the issue with a PAT that solves my usecase, it seems like a far less brittle solution.
It doesn't end, that's why the number of developers is increasing indefinitely. The crazy thing is that it seems to work, as society has still yet to fall apart.
...or maybe society is falling apart and it's the fault of programmers. Maybe we're building an unstable web of automated abstractions supported by a decreasing number of specialists operating at the physical layers closer to reality. Maybe one day it will all collapse like the collaterized debt obligation market in 2007 and we'll be back to making websites with PHP and FTP.
> What happens if I get hit by a bus or leave the company?
What happens now if you get hit by a bus and the token you issued is leaked, and someone has to rotate it? I would assume you have that documented, tested, preferably automated?
> An expiration date is also required for those new tokens with a max of 1 year.
Gah, so close, yet so far.
But I guess that makes sense for personal tokens and I really need to finally look at applications, I assume they have fine-grained ACLs in the first place?
Edit:
> The permissions available to fine-grained personal access tokens are the same permissions available to GitHub Apps, and repository targeting works the same too.
Yes, if what you have is "I need persistent, scoped access" you want an app. The fact that so many people on HN are saying "ah darn it expires" is truly frightening and I hope Github publishes a deprecation plan for PAT classic.
> The fact that so many people on HN are saying "ah darn it expires" is truly frightening
It’s also completely unsurprising: it’s very easy to grow a small PAT-based tool into a large PAT-based system, Apps is a significant overhead for a small too, and the migration path is not simple.
And things get a lot worse when trying to create automation for your company, as your now need to involve the organisation owners / admins in order for them to set up and configure the GHA via a fun game of Simon Says.
Shouldn't things that expire like access tokens and certificates actually last slightly longer than these fixed calendar lengths to make renewal or rotation possible on the same day/week every year?
For example, if I generate this token on Jan 1, 2023 and it lasts 1 year, I'll now need to generate the new one around December 21st, 2023 to make sure I have some lead time to deal with issues and not wait until the last second. Now, when I rotate the second time, I need to do it around December 14th, 2024...
I'm hoping this leads to being able to set the permissions for GitHub Actions tokens as well. For instance, an organization should be able to say "the token for this action should also have read-only access to check out other organization private repositories".
I like GitHub based comment systems like Utterances and Giscus, but when you try to leave a comment you get a permission request page that says it can "act on your behalf" in your account which is ridiculously broad (and I think not actually true?). Will they be able to fix that now?
"Act on your behalf" is a common (and not great) way of indicating that the app will do <above permissions> wearing your nametag. It doesn't give the app blanket permissions against your account, just that it gets to do the above things _in your name_ rather than just as itself (`modeless posted this comment` versus `Utterances posted this comment`)
Do these new tokens still require the organization and user consent? I’m not able to use GitPod as a freelancer because my clients don’t want to approve the application so GitPod can’t access the repo. I work around the issue by creating a private repo with my SSH private key that has the client’s code as a submodule and configures GitPod to fetch the submodule using that ssh key. It’s silly that I have to do that.
I finally have a reason to update my tokens that GitHub has been bugging me about. Each time I would read all their perfectly good suggestions and then not change my tokens.
Anyone know if there’s an API that lets you rotate these new tokens? Iirc this didn’t exist for the older ones. I looked at the linked docs but didn’t see anything.
Yeah, that's the main one I had in mind. API key lets you select what characters to include, which features are visible for that API key, etc. I want to say I wrote code that interacted with these back in 2012 or so and this wasn't new.
Meanwhile GitHub just got scoped API keys in 2022. Cloudflare got scoped API keys maybe last year or two years ago? Like to me this has felt like a baseline of API token design for a long time.
The fact that so far any token reasonably operating on repositories had to have the full repo scope and, as far as I'm aware, the repo scope allows making public repos private (which resets all traction you've ever got: stars, forks, etc.), or delete them all together, was ridiculous. Now there's a separate "Repository Administration" scope.
Moreover, you had to create purpose-suited GitHub accounts if you wanted to do cross-repo GitHub Actions (like updating a homebrew repo), and grant them access to only that repo, if you didn't want to have that GitHub Action have full access on your level.
So yeah, finally. Time to decommission all these existing tokens. Thanks GitHub!