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

Creates new "prepared-query" ACL type and new token capture behavior. #1748

Merged
merged 9 commits into from
Feb 25, 2016

Conversation

slackpad
Copy link
Contributor

Prior to this change, prepared queries had the following behavior for
ACLs, which will need to change to support templates:

  1. A management token, or a token with read access to the service being
    queried needed to be provided in order to create a prepared query.
  2. The token used to create the prepared query was stored with the query
    in the state store and used to execute the query.
  3. A management token, or the token used to create the query needed to be
    supplied to perform and CRUD operations on an existing prepared query.

This was pretty subtle and complicated behavior, and won't work for
templates since the service name is computed at execution time. To solve
this, we introduce a new "prepared-query" ACL type, where the prefix
applies to the query name for static prepared query types and to the
prefix for template prepared query types.

With this change, the new behavior is:

  1. A management token, or a token with "prepared-query" write access to
    the query name or (soon) the given template prefix is required to do
    any CRUD operations on a prepared query, or to list prepared queries
    (the list is filtered by this ACL).
  2. You will no longer need a management token to list prepared queries,
    but you will only be able to see prepared queries that you have access
    to (you get an empty list instead of permission denied).
  3. When listing or getting a query, because it was easy to capture
    management tokens given the past behavior, this will always blank out
    the "Token" field (replacing the contents as <hidden>) for all tokens
    unless a management token is supplied. Going forward, we should
    discourage people from binding tokens for execution unless strictly
    necessary.
  4. No token will be captured by default when a prepared query is created.
    If the user wishes to supply an execution token then can pass it in via
    the "Token" field in the prepared query definition. Otherwise, this
    field will default to empty.
  5. At execution time, we will use the captured token if it exists with the
    prepared query definition, otherwise we will use the token that's passed
    in with the request, just like we do for other RPCs (or you can use the
    agent's configured token for DNS).
  6. Prepared queries with no name (accessible only by ID) will not require
    ACLs to create or modify (execution time will depend on the service ACL
    configuration). Our argument here is that these are designed to be
    ephemeral and the IDs are as good as an ACL. Management tokens will be
    able to list all of these.

These changes enable templates, but also enable delegation of authority to
manage the prepared query namespace.

// We prune entries the user doesn't have access to, and we redact any tokens
// unless the client has a management token. This eases the transition to
// delegated authority over prepared queries, since it was easy to capture
// management tokens prior to Consul 0.6.4.
Copy link
Contributor

Choose a reason for hiding this comment

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

Small phrase change:

capture management tokens in Consul 0.6.3 and earlier.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good call - that's clearer.

@ryanuber
Copy link
Member

@slackpad left minor comments. My biggest question here is what happens with the DNS interface if the tokens are eventually going to go away? It seems very restrictive to only allow the client's global ACL token access the PQ's. I suppose you could handle it by enforcing convention, where e.g. private-*.query.consul is hidden from DNS, but you also lose the ability to revoke access by ACL token. Also a bit strange that a user who creates a PQ and can query it from the API might have to jump through hoops to get someone with a management token to enable DNS access for the new query. The DNS interface is probably the most powerful way to use the PQ's so just want to make sure we have thought this through completely.

@slackpad
Copy link
Contributor Author

Incorporated all the feedback so far. I need to write the new ACL Guide documentation for prepared_query and then I think this should be good to ship.

@slackpad
Copy link
Contributor Author

One other thing I need to add - the new prepared_query ACL needs to be applied to the query name as well.

Prior to this change, prepared queries had the following behavior for
ACLs, which will need to change to support templates:

1. A management token, or a token with read access to the service being
   queried needed to be provided in order to create a prepared query.

2. The token used to create the prepared query was stored with the query
   in the state store and used to execute the query.

3. A management token, or the token used to create the query needed to be
   supplied to perform and CRUD operations on an existing prepared query.

This was pretty subtle and complicated behavior, and won't work for
templates since the service name is computed at execution time. To solve
this, we introduce a new "prepared-query" ACL type, where the prefix
applies to the query name for static prepared query types and to the
prefix for template prepared query types.

With this change, the new behavior is:

1. A management token, or a token with "prepared-query" write access to
   the query name or (soon) the given template prefix is required to do
   any CRUD operations on a prepared query, or to list prepared queries
   (the list is filtered by this ACL).

2. You will no longer need a management token to list prepared queries,
   but you will only be able to see prepared queries that you have access
   to (you get an empty list instead of permission denied).

3. When listing or getting a query, because it was easy to capture
   management tokens given the past behavior, this will always blank out
   the "Token" field (replacing the contents as <hidden>) for all tokens
   unless a management token is supplied. Going forward, we should
   discourage people from binding tokens for execution unless strictly
   necessary.

4. No token will be captured by default when a prepared query is created.
   If the user wishes to supply an execution token then can pass it in via
   the "Token" field in the prepared query definition. Otherwise, this
   field will default to empty.

5. At execution time, we will use the captured token if it exists with the
   prepared query definition, otherwise we will use the token that's passed
   in with the request, just like we do for other RPCs (or you can use the
   agent's configured token for DNS).

6. Prepared queries with no name (accessible only by ID) will not require
   ACLs to create or modify (execution time will depend on the service ACL
   configuration). Our argument here is that these are designed to be
   ephemeral and the IDs are as good as an ACL. Management tokens will be
   able to list all of these.

These changes enable templates, but also enable delegation of authority to
manage the prepared query namespace.
@slackpad
Copy link
Contributor Author

Squashed all the commits and reworded the initial big one with the details (since it was incorrect). My last change here will be to make the ACLs apply to the query names, not the service names. This was my mistake.

@slackpad
Copy link
Contributor Author

Got the docs in shape to define the final state of things, now need to update the implementation to match.

"testing"
)

func TestStructs_PreparedQuery_GetACLInfo(t *testing.T) {
Copy link
Member

Choose a reason for hiding this comment

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

Should this test be called GetACLPrefix?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep - good catch.

@ryanuber
Copy link
Member

@slackpad the docs are looking great and nothing stuck out to me - merge when you are ready!

@slackpad slackpad force-pushed the f-client-pq-acls branch 2 times, most recently from 459a278 to 247be4c Compare February 25, 2016 01:26
@@ -15,7 +15,7 @@ Prepared queries allow you to register a complex service query and then execute
it later via its ID or name to get a set of healthy nodes that provide a given
service. This is particularly useful in combination with Consul's
[DNS Interface](/docs/agent/dns.html) as it allows for much richer queries than
would be possible given the limited interface DNS provides.
would be possible given the limited syntax DNS provides.
Copy link
Contributor

Choose a reason for hiding this comment

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

DNS has a syntax, but it's an interface into Consul. How about:

given the limited entry points exposed by DNS.

?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sounds good - fixed

slackpad added a commit that referenced this pull request Feb 25, 2016
Creates new "prepared-query" ACL type and new token capture behavior.
@slackpad slackpad merged commit ad77f20 into master Feb 25, 2016
@slackpad
Copy link
Contributor Author

Got all the doc comments worked in - merged it!

@slackpad slackpad deleted the f-client-pq-acls branch February 25, 2016 02:07
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

Successfully merging this pull request may close these issues.

3 participants