-
Notifications
You must be signed in to change notification settings - Fork 5.6k
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
fix: Adds proper CSRF protection to ArgoCD API #16856
base: master
Are you sure you want to change the base?
Conversation
Reviewers, FYI: some questions already answered in #2672 |
634136f
to
a45d18b
Compare
Codecov ReportAttention:
Additional details and impacted files@@ Coverage Diff @@
## master #16856 +/- ##
==========================================
- Coverage 49.31% 49.30% -0.02%
==========================================
Files 272 272
Lines 47975 48044 +69
==========================================
+ Hits 23660 23686 +26
- Misses 21973 22009 +36
- Partials 2342 2349 +7 ☔ View full report in Codecov by Sentry. |
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
a45d18b
to
ab8bb46
Compare
(I wrote https://blog.calif.io/p/argo-cd-csrf) This fixes the issue, but there may be problems. Gorilla, or CSRF tokens in general make sense for web forms (application/x-www-form-urlencoded) but not JSON. First, the browser now has to make a redundant request to fetch the X-Csrf-Token first, before calling the API. Second, we have to use some csrf.UnsafeSkipCheck to bypass the token check when calling the API. This exception case may lead to bypasses in itself. My suggestion would be to properly parse the Content-type header before the request body and strictly require application/json. This would trigger the default cross-site protections implemented by browsers: A preflight CORS request is sent, then Argo CD does not return Access-Control-Allow-Origin header, then the request fails). This is a key point that made the exploit possible because Argo CD allows text/plain content-type for JSON body (see the list of CORS-safelisted request headers). I assume Argo CD does not really have a lot of cross-site use cases, judging from the fact there's no CORS header (Access-Control-Allow-Origin) implemented by the HTTP server. So maybe adding gorilla-csrf is an overhead we can avoid. |
Thank you for review @jessesuen ! Addressed both suggestions! |
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
258c9a3
to
a4c96db
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
I'd recommend holding off on this until we're certain that it's necessary in addition to content-type checking. Sounds like there are potential performance tradeoffs as well as additional maintenance to be sure the CSRF protection is functioning as expected. |
Just for consideration: We were holding off the original PR because we thought SameSite cookies would solve the issue at hand, but apparently it didn't. Worst case now would be when we think the Content-Type restriction solves the issue, but it doesn't. Yes, it will have a slight performance impact. Yes maintenance might be a little bit more complex. But it will definitely implement current best practices. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's fair. In that case, I think we should merge this as a new feature, and we should add update 1) API docs and 2) upgrade docs to outline the change in API behavior.
@@ -240,6 +242,7 @@ func NewCommand() *cobra.Command { | |||
command.Flags().StringVar(&repoServerAddress, "repo-server", env.StringFromEnv("ARGOCD_SERVER_REPO_SERVER", common.DefaultRepoServerAddr), "Repo server address") | |||
command.Flags().StringVar(&dexServerAddress, "dex-server", env.StringFromEnv("ARGOCD_SERVER_DEX_SERVER", common.DefaultDexServerAddr), "Dex server address") | |||
command.Flags().BoolVar(&disableAuth, "disable-auth", env.ParseBoolFromEnv("ARGOCD_SERVER_DISABLE_AUTH", false), "Disable client authentication") | |||
command.Flags().BoolVar(&disableCsrf, "disable-csrf", false, "Disable API CSRF protection") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably make this configurable via argocd-cmd-params-cm.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch.
Agree, it should be a feature, not a a fix. |
Where are we with this PR? Are we waiting? If so, what are we waiting for? We should make it clear in the PR so others who visit in the future will know the status. |
I'll just bump this since @kencochrane 's comment had no real response. |
Sounds like there's general consensus behind the feature, so we're waiting for the things mentioned above: #16856 (review) |
Closes #2496
Based on #2672 - mostly the same code with some changes mostly in UI ( token handling is done in requests.ts file).
This PR adds proper CSRF protection to the ArgoCD REST API by implementing the Gorilla CSRF framework (https://github.com/gorilla/csrf).
Behaviour for CSRF token validation is as follows:
GET
,HEAD
,TRACE
andOPTIONS
verbsX-Csrf-Token
header value sent with the request, except for the conditions mentioned belowargocd.token
) with the request, CSRF checks are always performedAuthorization: Bearer
HTTP header and is not including the authorization cookie in the request (i.e. is a stateless REST API client), the CSRF validation is skipped (theAuthorization
header basically verified the request already)Authorization
header, the onlyPOST
method allowed is on/api/v1/session
to create a session for the client and retrieve the credentials for further communication--disable-csrf
is provided forargocd-server
command, when set CSRF checks will be disabled completey.This introduces a new key in argocd-secret for storing the key used to sign CSRF token, named server.csrfkey, which is similar to server.secretkey - that is, will be generated if the key does not exist in the secret on server start, otherwise will persist.
The retrieve a token, the client can issue a GET (or HEAD or OPTIONS if implemented by API) request on an arbitrary REST API endpoint. Preferably, this is
/api/v1/session/userinfo
. The server will send back a valid token in theX-CSRF-Token
header in the response, as long as the user is correctly authenticated. Endpoints that are generally unprotected (currently/api/version
and/api/v1/settings
) will not send the appropriate header.