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

nsqadmin: X-Forwarded-User based ACL #914

Merged
merged 2 commits into from
Jul 23, 2017

Conversation

chen-anders
Copy link
Contributor

@chen-anders chen-anders commented Jul 11, 2017

This PR introduces a small access-control-list mechanism via the X-Forwarded-User HTTP headers.

NSQAdmin can be started with one or more -authorized-user=<user> flags and NSQAdmin will be in a view-only mode for non-admin users. Only authorized admin users can perform administrative actions (e.g. pause/unpause/create/delete topics or channels).

If no -authorized-user=<user> is specified, we default to allowing any user to perform administrative actions.

This approach assumes that there is some authenticating proxy in front of nsqadmin that will strip out incoming X-Forwarded-User headers.

@freerobby
Copy link

Is there an assumption here that the proxy is performing some authentication before passing on the username? If so there may be a security hole where an end-user passes in a (non-standard) X-Forwarded-User header that a proxy doesn't know to strip out, and now the end-user can perform what the developer thinks are locked down actions.

(It's also possible I'm misunderstanding the auth mechanism use case).

@mreiferson
Copy link
Member

Yes, and should be documented as such. This approach is only useful if you can trust your proxy and internal network, e.g. oauth2_proxy strips any incoming X-Forwarded-User.

@mreiferson mreiferson changed the title View-Only NSQAdmin Dashboard via X-Forwarded-User access control nsqadmin: X-Forwarded-User based ACL Jul 11, 2017
@@ -55,6 +56,7 @@ var (
func init() {
flagSet.Var(&nsqlookupdHTTPAddresses, "lookupd-http-address", "lookupd HTTP address (may be given multiple times)")
flagSet.Var(&nsqdHTTPAddresses, "nsqd-http-address", "nsqd HTTP address (may be given multiple times)")
flagSet.Var(&allowAuthorizedUsers, "authorized-user", "Authorized Users (for performing admin actions); Any user will have admin privileges if this field is empty.")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe admin-user would be a more straightforward name for this

@chen-anders chen-anders force-pushed the anders/admin-control-via-xff branch from 27d590f to 09c03a0 Compare July 11, 2017 15:58
nsqadmin/http.go Outdated
@@ -755,6 +784,21 @@ func (s *httpServer) doConfig(w http.ResponseWriter, req *http.Request, ps httpr
return v, nil
}

func (s *httpServer) authorizedAdminRequest(req *http.Request) (bool) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we call this fun isAuthorizedAdminRequest?

nsqadmin/http.go Outdated
adminUsers := s.ctx.nsqadmin.getOpts().AdminUsers
if len(adminUsers) == 0 {
return true
} else {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't need this else since the above block returns

nsqadmin/http.go Outdated
if len(adminUsers) == 0 {
return true
} else {
user := req.Header.Get("X-FORWARDED-USER")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since we're in here, let's make this header user-configurable?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

default to X-Forwarded-User

@@ -14,8 +14,18 @@ require('./lib/ajax_setup');
require('./lib/handlebars_helpers');

var start = function() {
new AppView();
Router.start();
$.ajax({
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there should be a way for us to inject this data into the template rather than create a new endpoint and have to perform this AJAX request

nsqadmin/http.go Outdated
@@ -100,6 +99,8 @@ func NewHTTPServer(ctx *Context) *httpServer {
router.Handle("POST", "/api/topics", http_api.Decorate(s.createTopicChannelHandler, log, http_api.V1))
router.Handle("POST", "/api/topics/:topic", http_api.Decorate(s.topicActionHandler, log, http_api.V1))
router.Handle("POST", "/api/topics/:topic/:channel", http_api.Decorate(s.channelActionHandler, log, http_api.V1))


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👮 whitespace police, let's drop this change

nsqadmin/http.go Outdated
@@ -73,7 +73,6 @@ func NewHTTPServer(ctx *Context) *httpServer {
}

router.Handle("GET", "/ping", http_api.Decorate(s.pingHandler, log, http_api.PlainText))

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👮 whitespace police, let's drop this change

@chen-anders chen-anders force-pushed the anders/admin-control-via-xff branch from e6a6f01 to e58afcf Compare July 11, 2017 16:19
@@ -47,6 +47,8 @@ var (
httpClientTLSKey = flagSet.String("http-client-tls-key", "", "path to key file for the HTTP client")

allowConfigFromCIDR = flagSet.String("allow-config-from-cidr", "127.0.0.1/8", "A CIDR from which to allow HTTP requests to the /config endpoint")
aclHttpHeader = flagSet.String("acl-http-header", "X-Forwarded-User", "HTTP header to check for authenticated users (default: X-Forwarded-User)")
Copy link
Member

@ploxiln ploxiln Jul 11, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you have to note the default in the help string yourself, if you specify the default in the flag declaration as you have done. For example, allow-config-from-cidr is described like so in nsqadmin --help:

  -allow-config-from-cidr string
    	A CIDR from which to allow HTTP requests to the /config endpoint (default "127.0.0.1/8")

(We only manually note the default in help strings when we cannot set the default in the flag declaration.)

EDIT: set -> cannot set

@ploxiln
Copy link
Member

ploxiln commented Jul 11, 2017

This is looking pretty good to me, thanks for being so responsive to review comments!

@mreiferson
Copy link
Member

@chen-anders anything else you want to do here? If not, can you squash this down to one commit and prefix it with nsqadmin: ? Thanks!

@chen-anders chen-anders force-pushed the anders/admin-control-via-xff branch from 02e04f6 to fb5103b Compare July 23, 2017 05:27
@chen-anders
Copy link
Contributor Author

@mreiferson Complete.

@mreiferson mreiferson force-pushed the anders/admin-control-via-xff branch from fb5103b to bc39218 Compare July 23, 2017 18:39
@mreiferson
Copy link
Member

Pushed a commit to update bindata and tweak the flag help text.

@ploxiln
Copy link
Member

ploxiln commented Jul 23, 2017

👍

@ploxiln ploxiln merged commit c3f1bc4 into nsqio:master Jul 23, 2017
@chen-anders chen-anders deleted the anders/admin-control-via-xff branch March 17, 2019 02:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants